validate-dockerfile
Version:
Validates a Dockerfile
280 lines (213 loc) • 7.91 kB
JavaScript
;
/**
* Tests for specific Dockerfile instructions
*/
var validateDockerfile = require('../');
var EOL = require('os').EOL;
function shouldBeValid (result) {
result.should.be.an.Object;
result.should.have.property('valid', true);
result.should.not.have.property('message');
result.should.not.have.property('line');
result.should.not.have.property('priority');
}
function expectsSuccess (line) {
return function () {
var dockerfile = ['FROM vader/death-star',
line,
'CMD ["destroy", "Yavin IV"]'].join(EOL);
var result = validateDockerfile(dockerfile);
shouldBeValid(result);
};
}
function expectsFailure (line) {
return function () {
var dockerfile = ['FROM vader/death-star',
line,
'CMD ["destroy", "Yavin IV"]'].join(EOL);
var result = validateDockerfile(dockerfile);
result.should.be.an.Object;
result.should.have.property('valid', false);
result.should.have.property('errors');
result.errors.should.be.an.Array;
result.errors.length.should.eql(1);
result.errors[0].should.have.property('message', 'Bad parameters');
result.errors[0].should.have.property('priority', 1);
result.errors[0].should.have.property('line', 2);
};
}
describe('required instructions', function () {
describe('from', function () {
it('Should take a standard FROM', expectsSuccess(''));
it('should allow versions', function () {
var dockerfile = 'FROM vader/deathstar:2' + EOL + 'CMD ["destroy", "Yavin IV"]';
var result = validateDockerfile(dockerfile);
shouldBeValid(result);
});
it('Should allow underscores', function() {
var dockerfile = 'FROM vader/death_star:2' + EOL + 'CMD ["destroy", "Yavin IV"]';
var result = validateDockerfile(dockerfile);
shouldBeValid(result);
});
it('Should allow dashes in the tag', function() {
var dockerfile = 'FROM vader/death_star:2-dev' + EOL + 'CMD ["destroy", "Yavin IV"]';
var result = validateDockerfile(dockerfile);
shouldBeValid(result);
});
it('Should allow dashes', function() {
var dockerfile = 'FROM vader/death-star:2' + EOL + 'CMD ["destroy", "Yavin IV"]';
var result = validateDockerfile(dockerfile);
result.should.be.an.Object;
result.should.have.property('valid', true);
result.should.not.have.property('message');
result.should.not.have.property('line');
});
it('Should allow multiple slashes', function() {
var dockerfile = 'FROM vader/death_star/hangar/tie' + EOL + 'CMD ["destroy", "X-Wing"]';
var result = validateDockerfile(dockerfile);
shouldBeValid(result);
});
it('Should allow registry url', function() {
var dockerfile = 'FROM thyferra.io/bacta/canister' + EOL + 'CMD ["heal", "Skywalker"]';
var result = validateDockerfile(dockerfile);
shouldBeValid(result);
});
it('Should reject with capital letters', function () {
var dockerfile = 'FROM Vader/Death-Star' + EOL + 'CMD ["destroy", "Yavin IV"]';
var result = validateDockerfile(dockerfile);
result.should.be.an.Object;
result.should.have.property('valid', false);
result.should.have.property('errors');
result.errors.should.be.an.Array;
result.errors.length.should.eql(1);
result.errors[0].should.have.property('message', 'Bad parameters');
result.errors[0].should.have.property('line', 1);
});
});
describe('cmd', function () {
it('Should take a standard CMD', expectsSuccess(''));
it.skip('Should reject with invalid parameters');
});
});
describe('generic instructions', function() {
describe('formatting', function() {
it('should allow multiple spaces between command and params', expectsSuccess(
'RUN kessel'
));
it('should allow pure whitespace lines', expectsSuccess(
' '
));
it('should allow escaped newlines', expectsSuccess(
'RUN echo "A long time ago"\\' + EOL + 'echo "In a galaxy far, far away"'
));
it('should allow multiple escaped newlines', expectsSuccess(
'RUN echo "It is a period of civil war. Rebel"\\' + EOL + 'echo "spaceships, striking from a hidden"\\' + EOL + 'echo "base, have won their first victory"\\' + EOL + 'echo "against the evil Galactic Empire."'
));
});
});
describe('optional instructions', function () {
describe('maintainer', function () {
it('Should take a standard MAINTAINER', expectsSuccess(
'MAINTAINER Grand Moff Tarkin <wtarkin@empire.com>'
));
it('Should reject with no parameters', expectsFailure(
'MAINTAINER'
));
it('Should reject with just a space', expectsFailure(
'MAINTAINER '
));
});
describe('expose', function () {
it('Should take a standard EXPOSE', expectsSuccess(
'EXPOSE 80'
));
it('allows multiple ports', expectsSuccess(
'EXPOSE 80 443'
));
// See, if the Imperials had used unit testing, they'd be much better off
it('Should reject with letters', expectsFailure(
'EXPOSE exhaust port'
));
});
describe('env', function () {
it('Should take a standard ENV', expectsSuccess(
'ENV battlestation fully_armed'
));
it('allows multiple characters', expectsSuccess(
'ENV tk_421 absent'
));
it('Should reject with no second parameter', expectsFailure(
'ENV stand_by'
));
});
describe('user', function () {
it('Should take a standard USER', expectsSuccess(
'USER not_r2'
));
it('Rejects a username starting with a number', expectsFailure(
'USER 1138'
));
it('Should reject a username with > 31 characters', expectsFailure(
'USER RUARRRRRRRRRRRRRRRRRRRRRRRRRRRRRGH'
));
});
// Skipping these until we have actual regexes
describe.skip('run', function() {});
describe.skip('onbuild', function() {});
describe.skip('entrypoint', function() {});
describe('add', function () {
addCopy('ADD');
});
describe('copy', function() {
addCopy('COPY');
});
// ADD and COPY are annoyingly identical.
function addCopy (cmd) {
it('Should take a standard filepath ' +cmd, expectsSuccess(
cmd + ' ./tie-fighter /hangar'
));
it('Should take a standard url ' + cmd, expectsSuccess(
cmd + ' http://superlaser.com /Alderaan'
));
it('Allows ' + cmd + ' commands that reference homedir', expectsSuccess(
cmd + ' ~/tie-fighter ~/hangar'
));
it('Rejects a malformed URL', expectsFailure(
cmd + ' htp://superlaser.com /Alderaan'
));
it('Rejects a ' + cmd + ' with one parameter', expectsFailure(
cmd + ' ./tie-fighter'
));
it('Rejects an ' + cmd + ' that goes above the current dir', expectsFailure(
cmd + ' ../superior-firepower/superlaser /superlaser'
));
it('Rejects an ' + cmd + ' that goes above the current dir even when ../ is hidden', expectsFailure(
cmd + ' ./grand-moff/../../superior-firepower/superlaser /superlaser'
));
}
describe('volume', function () {
it('Should take a standard VOLUME', expectsSuccess(
'VOLUME ./1.72x10tothe7thpower'
));
it('Should take a JSON array VOLUME', expectsSuccess(
'VOLUME ["./1.72x10tothe7thpower"]'
));
it('Should take a JSON array VOLUME with multiple items', expectsSuccess(
'VOLUME ["./1.72x10tothe7thpower", "./4/3pi_r_square"]'
));
it('Should take a VOLUME that references homedir', expectsSuccess(
'VOLUME ~/1.72x10tothe7thpower'
));
it('Rejects improper JSON', expectsFailure(
'VOLUME ["1.72'
));
});
describe('workdir', function () {
it('Should take a standard WORKDIR', expectsSuccess(
'WORKDIR ./Despayre'
));
it('Should take a WORKDIR that references homedir', expectsSuccess(
'WORKDIR ~/Despayre'
));
});
});