@@ -7,11 +7,14 @@ import (
77 "io/ioutil"
88 "os"
99 "reflect"
10+ "regexp"
1011 "strings"
1112 "testing"
1213 "time"
1314
1415 docker "github.com/fsouza/go-dockerclient"
16+
17+ "github.com/openshift/imagebuilder/dockerfile/parser"
1518)
1619
1720func TestVolumeSet (t * testing.T ) {
@@ -159,6 +162,19 @@ func TestMultiStageParseHeadingArg(t *testing.T) {
159162 if len (stages ) != 3 {
160163 t .Fatalf ("expected 3 stages, got %d" , len (stages ))
161164 }
165+
166+ fromImages := []string {"golang:1.9" , "busybox:latest" , "golang:1.9" }
167+ for i , stage := range stages {
168+ from , err := stage .Builder .From (stage .Node )
169+ if err != nil {
170+ t .Fatal (err )
171+ }
172+
173+ if expected := fromImages [i ]; from != expected {
174+ t .Fatalf ("expected %s, got %s" , expected , from )
175+ }
176+ }
177+
162178 t .Logf ("stages: %#v" , stages )
163179}
164180
@@ -192,6 +208,216 @@ RUN echo $FOO $BAR`))
192208 }
193209}
194210
211+ func resolveNodeArgs (b * Builder , node * parser.Node ) error {
212+ for _ , c := range node .Children {
213+ if c .Value != "arg" {
214+ continue
215+ }
216+ step := b .Step ()
217+ if err := step .Resolve (c ); err != nil {
218+ return err
219+ }
220+ if err := b .Run (step , NoopExecutor , false ); err != nil {
221+ return err
222+ }
223+ }
224+ return nil
225+ }
226+
227+ func builderHasArgument (b * Builder , argString string ) bool {
228+ for _ , arg := range b .Arguments () {
229+ if arg == argString {
230+ return true
231+ }
232+ }
233+ return false
234+ }
235+
236+ func TestMultiStageHeadingArgRedefine (t * testing.T ) {
237+ n , err := ParseFile ("dockerclient/testdata/multistage/Dockerfile.heading-redefine" )
238+ if err != nil {
239+ t .Fatal (err )
240+ }
241+ stages , err := NewStages (n , NewBuilder (map [string ]string {}))
242+ if err != nil {
243+ t .Fatal (err )
244+ }
245+ if len (stages ) != 2 {
246+ t .Fatalf ("expected 2 stages, got %d" , len (stages ))
247+ }
248+
249+ for _ , stage := range stages {
250+ if err := resolveNodeArgs (stage .Builder , stage .Node ); err != nil {
251+ t .Fatal (err )
252+ }
253+ }
254+
255+ firstStageHasArg := false
256+ for _ , arg := range stages [0 ].Builder .Arguments () {
257+ if match , err := regexp .MatchString (`FOO=.*` , arg ); err == nil && match {
258+ firstStageHasArg = true
259+ break
260+ } else if err != nil {
261+ t .Fatal (err )
262+ }
263+ }
264+ if firstStageHasArg {
265+ t .Fatalf ("expected FOO to not be present in first stage" )
266+ }
267+
268+ if ! builderHasArgument (stages [1 ].Builder , "FOO=latest" ) {
269+ t .Fatalf ("expected FOO=latest in second stage arguments list, got %v" , stages [1 ].Builder .Arguments ())
270+ }
271+ }
272+
273+ func TestMultiStageHeadingArgRedefineOverride (t * testing.T ) {
274+ n , err := ParseFile ("dockerclient/testdata/multistage/Dockerfile.heading-redefine" )
275+ if err != nil {
276+ t .Fatal (err )
277+ }
278+ stages , err := NewStages (n , NewBuilder (map [string ]string {"FOO" : "7" }))
279+ if err != nil {
280+ t .Fatal (err )
281+ }
282+ if len (stages ) != 2 {
283+ t .Fatalf ("expected 2 stages, got %d" , len (stages ))
284+ }
285+
286+ for _ , stage := range stages {
287+ if err := resolveNodeArgs (stage .Builder , stage .Node ); err != nil {
288+ t .Fatal (err )
289+ }
290+ }
291+
292+ firstStageHasArg := false
293+ for _ , arg := range stages [0 ].Builder .Arguments () {
294+ if match , err := regexp .MatchString (`FOO=.*` , arg ); err == nil && match {
295+ firstStageHasArg = true
296+ break
297+ } else if err != nil {
298+ t .Fatal (err )
299+ }
300+ }
301+ if firstStageHasArg {
302+ t .Fatalf ("expected FOO to not be present in first stage" )
303+ }
304+
305+ if ! builderHasArgument (stages [1 ].Builder , "FOO=7" ) {
306+ t .Fatalf ("expected FOO=7 in second stage arguments list, got %v" , stages [1 ].Builder .Arguments ())
307+ }
308+ }
309+
310+ func TestArgs (t * testing.T ) {
311+ for _ , tc := range []struct {
312+ name string
313+ dockerfile string
314+ args map [string ]string
315+ expectedValue string
316+ }{
317+ {
318+ name : "argOverride" ,
319+ dockerfile : "FROM centos\n ARG FOO=stuff\n ARG FOO=things\n " ,
320+ args : map [string ]string {},
321+ expectedValue : "FOO=things" ,
322+ },
323+ {
324+ name : "argOverrideWithBuildArgs" ,
325+ dockerfile : "FROM centos\n ARG FOO=stuff\n ARG FOO=things\n " ,
326+ args : map [string ]string {"FOO" : "bar" },
327+ expectedValue : "FOO=bar" ,
328+ },
329+ {
330+ name : "headingArgRedefine" ,
331+ dockerfile : "ARG FOO=stuff\n FROM centos\n ARG FOO\n " ,
332+ args : map [string ]string {},
333+ expectedValue : "FOO=stuff" ,
334+ },
335+ {
336+ name : "headingArgRedefineWithBuildArgs" ,
337+ dockerfile : "ARG FOO=stuff\n FROM centos\n ARG FOO\n " ,
338+ args : map [string ]string {"FOO" : "bar" },
339+ expectedValue : "FOO=bar" ,
340+ },
341+ {
342+ name : "headingArgRedefineDefault" ,
343+ dockerfile : "ARG FOO=stuff\n FROM centos\n ARG FOO=defaultfoovalue\n " ,
344+ args : map [string ]string {},
345+ expectedValue : "FOO=defaultfoovalue" ,
346+ },
347+ {
348+ name : "headingArgRedefineDefaultWithBuildArgs" ,
349+ dockerfile : "ARG FOO=stuff\n FROM centos\n ARG FOO=defaultfoovalue\n " ,
350+ args : map [string ]string {"FOO" : "bar" },
351+ expectedValue : "FOO=bar" ,
352+ },
353+ } {
354+ t .Run (tc .name , func (t * testing.T ) {
355+ node , err := ParseDockerfile (strings .NewReader (tc .dockerfile ))
356+ if err != nil {
357+ t .Fatal (err )
358+ }
359+
360+ b := NewBuilder (tc .args )
361+ if err := resolveNodeArgs (b , node ); err != nil {
362+ t .Fatal (err )
363+ }
364+
365+ if ! builderHasArgument (b , tc .expectedValue ) {
366+ t .Fatalf ("expected %s to be contained in arguments list: %v" , tc .expectedValue , b .Arguments ())
367+ }
368+ })
369+ }
370+ }
371+
372+ func TestMultiStageArgScope (t * testing.T ) {
373+ n , err := ParseFile ("dockerclient/testdata/multistage/Dockerfile.arg-scope" )
374+ if err != nil {
375+ t .Fatal (err )
376+ }
377+ args := map [string ]string {
378+ "SECRET" : "secretthings" ,
379+ "BAR" : "notsecretthings" ,
380+ }
381+ stages , err := NewStages (n , NewBuilder (args ))
382+ if err != nil {
383+ t .Fatal (err )
384+ }
385+ if len (stages ) != 2 {
386+ t .Fatalf ("expected 2 stages, got %d" , len (stages ))
387+ }
388+
389+ for _ , stage := range stages {
390+ if err := resolveNodeArgs (stage .Builder , stage .Node ); err != nil {
391+ t .Fatal (err )
392+ }
393+ }
394+
395+ if ! builderHasArgument (stages [0 ].Builder , "SECRET=secretthings" ) {
396+ t .Fatalf ("expected SECRET=secretthings to be contained in first stage arguments list: %v" , stages [0 ].Builder .Arguments ())
397+ }
398+
399+ secondStageArguments := stages [1 ].Builder .Arguments ()
400+ secretInSecondStage := false
401+ for _ , arg := range secondStageArguments {
402+ if match , err := regexp .MatchString (`SECRET=.*` , arg ); err == nil && match {
403+ secretInSecondStage = true
404+ break
405+ } else if err != nil {
406+ t .Fatal (err )
407+ }
408+ }
409+ if secretInSecondStage {
410+ t .Fatalf ("expected SECRET to not be present in second stage" )
411+ }
412+
413+ if ! builderHasArgument (stages [1 ].Builder , "FOO=test" ) {
414+ t .Fatalf ("expected FOO=test to be present in second stage arguments list: %v" , secondStageArguments )
415+ }
416+ if ! builderHasArgument (stages [1 ].Builder , "BAR=notsecretthings" ) {
417+ t .Fatalf ("expected BAR=notsecretthings to be present in second stage arguments list: %v" , secondStageArguments )
418+ }
419+ }
420+
195421func TestRun (t * testing.T ) {
196422 f , err := os .Open ("dockerclient/testdata/Dockerfile.add" )
197423 if err != nil {
0 commit comments