github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/builder/dockerfile/instructions/parse_test.go (about) 1 package instructions 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/docker/docker/builder/dockerfile/command" 8 "github.com/docker/docker/builder/dockerfile/parser" 9 "github.com/docker/docker/internal/testutil" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func TestCommandsExactlyOneArgument(t *testing.T) { 15 commands := []string{ 16 "MAINTAINER", 17 "WORKDIR", 18 "USER", 19 "STOPSIGNAL", 20 } 21 22 for _, command := range commands { 23 ast, err := parser.Parse(strings.NewReader(command)) 24 require.NoError(t, err) 25 _, err = ParseInstruction(ast.AST.Children[0]) 26 assert.EqualError(t, err, errExactlyOneArgument(command).Error()) 27 } 28 } 29 30 func TestCommandsAtLeastOneArgument(t *testing.T) { 31 commands := []string{ 32 "ENV", 33 "LABEL", 34 "ONBUILD", 35 "HEALTHCHECK", 36 "EXPOSE", 37 "VOLUME", 38 } 39 40 for _, command := range commands { 41 ast, err := parser.Parse(strings.NewReader(command)) 42 require.NoError(t, err) 43 _, err = ParseInstruction(ast.AST.Children[0]) 44 assert.EqualError(t, err, errAtLeastOneArgument(command).Error()) 45 } 46 } 47 48 func TestCommandsNoDestinationArgument(t *testing.T) { 49 commands := []string{ 50 "ADD", 51 "COPY", 52 } 53 54 for _, command := range commands { 55 ast, err := parser.Parse(strings.NewReader(command + " arg1")) 56 require.NoError(t, err) 57 _, err = ParseInstruction(ast.AST.Children[0]) 58 assert.EqualError(t, err, errNoDestinationArgument(command).Error()) 59 } 60 } 61 62 func TestCommandsTooManyArguments(t *testing.T) { 63 commands := []string{ 64 "ENV", 65 "LABEL", 66 } 67 68 for _, command := range commands { 69 node := &parser.Node{ 70 Original: command + "arg1 arg2 arg3", 71 Value: strings.ToLower(command), 72 Next: &parser.Node{ 73 Value: "arg1", 74 Next: &parser.Node{ 75 Value: "arg2", 76 Next: &parser.Node{ 77 Value: "arg3", 78 }, 79 }, 80 }, 81 } 82 _, err := ParseInstruction(node) 83 assert.EqualError(t, err, errTooManyArguments(command).Error()) 84 } 85 } 86 87 func TestCommandsBlankNames(t *testing.T) { 88 commands := []string{ 89 "ENV", 90 "LABEL", 91 } 92 93 for _, command := range commands { 94 node := &parser.Node{ 95 Original: command + " =arg2", 96 Value: strings.ToLower(command), 97 Next: &parser.Node{ 98 Value: "", 99 Next: &parser.Node{ 100 Value: "arg2", 101 }, 102 }, 103 } 104 _, err := ParseInstruction(node) 105 assert.EqualError(t, err, errBlankCommandNames(command).Error()) 106 } 107 } 108 109 func TestHealthCheckCmd(t *testing.T) { 110 node := &parser.Node{ 111 Value: command.Healthcheck, 112 Next: &parser.Node{ 113 Value: "CMD", 114 Next: &parser.Node{ 115 Value: "hello", 116 Next: &parser.Node{ 117 Value: "world", 118 }, 119 }, 120 }, 121 } 122 cmd, err := ParseInstruction(node) 123 assert.NoError(t, err) 124 hc, ok := cmd.(*HealthCheckCommand) 125 assert.True(t, ok) 126 expected := []string{"CMD-SHELL", "hello world"} 127 assert.Equal(t, expected, hc.Health.Test) 128 } 129 130 func TestParseOptInterval(t *testing.T) { 131 flInterval := &Flag{ 132 name: "interval", 133 flagType: stringType, 134 Value: "50ns", 135 } 136 _, err := parseOptInterval(flInterval) 137 testutil.ErrorContains(t, err, "cannot be less than 1ms") 138 139 flInterval.Value = "1ms" 140 _, err = parseOptInterval(flInterval) 141 require.NoError(t, err) 142 } 143 144 func TestErrorCases(t *testing.T) { 145 cases := []struct { 146 name string 147 dockerfile string 148 expectedError string 149 }{ 150 { 151 name: "copyEmptyWhitespace", 152 dockerfile: `COPY 153 quux \ 154 bar`, 155 expectedError: "COPY requires at least two arguments", 156 }, 157 { 158 name: "ONBUILD forbidden FROM", 159 dockerfile: "ONBUILD FROM scratch", 160 expectedError: "FROM isn't allowed as an ONBUILD trigger", 161 }, 162 { 163 name: "ONBUILD forbidden MAINTAINER", 164 dockerfile: "ONBUILD MAINTAINER docker.io", 165 expectedError: "MAINTAINER isn't allowed as an ONBUILD trigger", 166 }, 167 { 168 name: "ARG two arguments", 169 dockerfile: "ARG foo bar", 170 expectedError: "ARG requires exactly one argument", 171 }, 172 { 173 name: "MAINTAINER unknown flag", 174 dockerfile: "MAINTAINER --boo joe@example.com", 175 expectedError: "Unknown flag: boo", 176 }, 177 { 178 name: "Chaining ONBUILD", 179 dockerfile: `ONBUILD ONBUILD RUN touch foobar`, 180 expectedError: "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed", 181 }, 182 { 183 name: "Invalid instruction", 184 dockerfile: `foo bar`, 185 expectedError: "unknown instruction: FOO", 186 }, 187 } 188 for _, c := range cases { 189 r := strings.NewReader(c.dockerfile) 190 ast, err := parser.Parse(r) 191 192 if err != nil { 193 t.Fatalf("Error when parsing Dockerfile: %s", err) 194 } 195 n := ast.AST.Children[0] 196 _, err = ParseInstruction(n) 197 testutil.ErrorContains(t, err, c.expectedError) 198 } 199 200 }