123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- package instructions
- import (
- "strings"
- "testing"
- "github.com/docker/docker/builder/dockerfile/command"
- "github.com/docker/docker/builder/dockerfile/parser"
- "github.com/docker/docker/internal/testutil"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- func TestCommandsExactlyOneArgument(t *testing.T) {
- commands := []string{
- "MAINTAINER",
- "WORKDIR",
- "USER",
- "STOPSIGNAL",
- }
- for _, command := range commands {
- ast, err := parser.Parse(strings.NewReader(command))
- require.NoError(t, err)
- _, err = ParseInstruction(ast.AST.Children[0])
- assert.EqualError(t, err, errExactlyOneArgument(command).Error())
- }
- }
- func TestCommandsAtLeastOneArgument(t *testing.T) {
- commands := []string{
- "ENV",
- "LABEL",
- "ONBUILD",
- "HEALTHCHECK",
- "EXPOSE",
- "VOLUME",
- }
- for _, command := range commands {
- ast, err := parser.Parse(strings.NewReader(command))
- require.NoError(t, err)
- _, err = ParseInstruction(ast.AST.Children[0])
- assert.EqualError(t, err, errAtLeastOneArgument(command).Error())
- }
- }
- func TestCommandsAtLeastTwoArgument(t *testing.T) {
- commands := []string{
- "ADD",
- "COPY",
- }
- for _, command := range commands {
- ast, err := parser.Parse(strings.NewReader(command + " arg1"))
- require.NoError(t, err)
- _, err = ParseInstruction(ast.AST.Children[0])
- assert.EqualError(t, err, errAtLeastTwoArguments(command).Error())
- }
- }
- func TestCommandsTooManyArguments(t *testing.T) {
- commands := []string{
- "ENV",
- "LABEL",
- }
- for _, command := range commands {
- node := &parser.Node{
- Original: command + "arg1 arg2 arg3",
- Value: strings.ToLower(command),
- Next: &parser.Node{
- Value: "arg1",
- Next: &parser.Node{
- Value: "arg2",
- Next: &parser.Node{
- Value: "arg3",
- },
- },
- },
- }
- _, err := ParseInstruction(node)
- assert.EqualError(t, err, errTooManyArguments(command).Error())
- }
- }
- func TestCommandsBlankNames(t *testing.T) {
- commands := []string{
- "ENV",
- "LABEL",
- }
- for _, command := range commands {
- node := &parser.Node{
- Original: command + " =arg2",
- Value: strings.ToLower(command),
- Next: &parser.Node{
- Value: "",
- Next: &parser.Node{
- Value: "arg2",
- },
- },
- }
- _, err := ParseInstruction(node)
- assert.EqualError(t, err, errBlankCommandNames(command).Error())
- }
- }
- func TestHealthCheckCmd(t *testing.T) {
- node := &parser.Node{
- Value: command.Healthcheck,
- Next: &parser.Node{
- Value: "CMD",
- Next: &parser.Node{
- Value: "hello",
- Next: &parser.Node{
- Value: "world",
- },
- },
- },
- }
- cmd, err := ParseInstruction(node)
- assert.NoError(t, err)
- hc, ok := cmd.(*HealthCheckCommand)
- assert.True(t, ok)
- expected := []string{"CMD-SHELL", "hello world"}
- assert.Equal(t, expected, hc.Health.Test)
- }
- func TestParseOptInterval(t *testing.T) {
- flInterval := &Flag{
- name: "interval",
- flagType: stringType,
- Value: "50ns",
- }
- _, err := parseOptInterval(flInterval)
- testutil.ErrorContains(t, err, "cannot be less than 1ms")
- flInterval.Value = "1ms"
- _, err = parseOptInterval(flInterval)
- require.NoError(t, err)
- }
- func TestErrorCases(t *testing.T) {
- cases := []struct {
- name string
- dockerfile string
- expectedError string
- }{
- {
- name: "copyEmptyWhitespace",
- dockerfile: `COPY
- quux \
- bar`,
- expectedError: "COPY requires at least two arguments",
- },
- {
- name: "ONBUILD forbidden FROM",
- dockerfile: "ONBUILD FROM scratch",
- expectedError: "FROM isn't allowed as an ONBUILD trigger",
- },
- {
- name: "ONBUILD forbidden MAINTAINER",
- dockerfile: "ONBUILD MAINTAINER docker.io",
- expectedError: "MAINTAINER isn't allowed as an ONBUILD trigger",
- },
- {
- name: "ARG two arguments",
- dockerfile: "ARG foo bar",
- expectedError: "ARG requires exactly one argument",
- },
- {
- name: "MAINTAINER unknown flag",
- dockerfile: "MAINTAINER --boo joe@example.com",
- expectedError: "Unknown flag: boo",
- },
- {
- name: "Chaining ONBUILD",
- dockerfile: `ONBUILD ONBUILD RUN touch foobar`,
- expectedError: "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed",
- },
- {
- name: "Invalid instruction",
- dockerfile: `foo bar`,
- expectedError: "unknown instruction: FOO",
- },
- }
- for _, c := range cases {
- r := strings.NewReader(c.dockerfile)
- ast, err := parser.Parse(r)
- if err != nil {
- t.Fatalf("Error when parsing Dockerfile: %s", err)
- }
- n := ast.AST.Children[0]
- _, err = ParseInstruction(n)
- if err != nil {
- testutil.ErrorContains(t, err, c.expectedError)
- return
- }
- t.Fatalf("No error when executing test %s", c.name)
- }
- }
|