github.com/jonsyu1/godel@v0.0.0-20171017211503-64567a0cf169/apps/distgo/cmd/docker/build_test.go (about)

     1  // Copyright 2016 Palantir Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package docker_test
    16  
    17  import (
    18  	"context"
    19  	"encoding/base64"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"math/rand"
    23  	"os"
    24  	"path"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/docker/docker/api/types"
    29  	"github.com/docker/docker/api/types/filters"
    30  	dockercli "github.com/docker/docker/client"
    31  	"github.com/nmiyake/pkg/dirs"
    32  	"github.com/stretchr/testify/require"
    33  
    34  	"github.com/palantir/godel/apps/distgo/cmd/build"
    35  	"github.com/palantir/godel/apps/distgo/cmd/dist"
    36  	"github.com/palantir/godel/apps/distgo/cmd/docker"
    37  	"github.com/palantir/godel/apps/distgo/params"
    38  	"github.com/palantir/godel/apps/distgo/pkg/git"
    39  	"github.com/palantir/godel/apps/distgo/pkg/git/gittest"
    40  	"github.com/palantir/godel/apps/distgo/pkg/osarch"
    41  )
    42  
    43  const (
    44  	testMain = `package main
    45  
    46  import "fmt"
    47  
    48  var testVersionVar = "defaultVersion"
    49  
    50  func main() {
    51  	fmt.Println(testVersionVar)
    52  }
    53  `
    54  	dockerfile = `FROM alpine:3.5
    55  `
    56  	configFile = `test_key: 'test_value'
    57  test_key_2: test_value_2
    58  `
    59  	slsDepDockerFile = `FROM alpine:3.5
    60  
    61  COPY foo-sls.tgz .
    62  COPY foo-bin.tgz .
    63  COPY bar-sls.tgz .
    64  `
    65  	dockerRepoPrefix = "test-docker-dist"
    66  )
    67  
    68  func TestDockerDist(t *testing.T) {
    69  	tmp, cleanup, err := dirs.TempDir("", "")
    70  	defer cleanup()
    71  	require.NoError(t, err)
    72  
    73  	for i, currCase := range []struct {
    74  		name          string
    75  		spec          func(projectDir string, randomPad string) []params.ProductBuildSpecWithDeps
    76  		setupProject  func(projectDir, pad string) error
    77  		cleanup       func(cli *dockercli.Client, projectDir, pad string)
    78  		preDistAction func(projectDir string, buildSpec []params.ProductBuildSpecWithDeps)
    79  		validate      func(caseNum int, name string, pad string, cli *dockercli.Client)
    80  	}{
    81  		{
    82  			name: "docker dist with dependent images",
    83  			setupProject: func(projectDir, pad string) error {
    84  				gittest.InitGitDir(t, projectDir)
    85  				// initialize foo
    86  				fooDir := path.Join(projectDir, "foo")
    87  				if err := os.Mkdir(fooDir, 0777); err != nil {
    88  					return err
    89  				}
    90  				if err := ioutil.WriteFile(path.Join(fooDir, "main.go"), []byte(testMain), 0644); err != nil {
    91  					return err
    92  				}
    93  				fooDockerDir := path.Join(fooDir, "docker")
    94  				if err = os.Mkdir(fooDockerDir, 0777); err != nil {
    95  					return err
    96  				}
    97  				fooDockerFile := fmt.Sprintf("FROM %v:0.1.0\n", fullRepoName("bar", pad))
    98  				if err = ioutil.WriteFile(path.Join(fooDockerDir, "Dockerfile"), []byte(fooDockerFile), 0777); err != nil {
    99  					return err
   100  				}
   101  
   102  				// initialize bar
   103  				barDir := path.Join(projectDir, "bar")
   104  				if err := os.Mkdir(barDir, 0777); err != nil {
   105  					return err
   106  				}
   107  				if err = ioutil.WriteFile(path.Join(barDir, "main.go"), []byte(testMain), 0644); err != nil {
   108  					return err
   109  				}
   110  				barDockerDir := path.Join(barDir, "docker")
   111  				if err = os.Mkdir(barDockerDir, 0777); err != nil {
   112  					return err
   113  				}
   114  				if err = ioutil.WriteFile(path.Join(barDockerDir, "Dockerfile"), []byte(dockerfile), 0777); err != nil {
   115  					return err
   116  				}
   117  
   118  				// commit
   119  				gittest.CommitAllFiles(t, projectDir, "Commit")
   120  				return nil
   121  			},
   122  			spec: func(projectDir string, pad string) []params.ProductBuildSpecWithDeps {
   123  				allSpec := make(map[string]params.ProductBuildSpec)
   124  				barSpec := params.NewProductBuildSpec(
   125  					projectDir,
   126  					"bar",
   127  					git.ProjectInfo{
   128  						Version: "0.1.0",
   129  					},
   130  					params.Product{
   131  						Build: params.Build{
   132  							MainPkg: "./bar",
   133  							OSArchs: []osarch.OSArch{
   134  								{
   135  									OS:   "linux",
   136  									Arch: "amd64",
   137  								},
   138  							},
   139  						},
   140  						DockerImages: []params.DockerImage{
   141  							{
   142  								Repository: fullRepoName("bar", pad),
   143  								Tag:        "0.1.0",
   144  								ContextDir: "bar/docker",
   145  								Info:       &params.DefaultDockerImageInfo{},
   146  							},
   147  						},
   148  					}, params.Project{
   149  						GroupID: "com.test.group",
   150  					},
   151  				)
   152  				allSpec["bar"] = barSpec
   153  				barSpecWithDeps, err := params.NewProductBuildSpecWithDeps(barSpec, allSpec)
   154  				require.NoError(t, err)
   155  				fooSpec := params.NewProductBuildSpec(
   156  					projectDir,
   157  					"foo",
   158  					git.ProjectInfo{
   159  						Version: "0.1.0",
   160  					},
   161  					params.Product{
   162  						Build: params.Build{
   163  							MainPkg: "./foo",
   164  							OSArchs: []osarch.OSArch{
   165  								{
   166  									OS:   "linux",
   167  									Arch: "amd64",
   168  								},
   169  							},
   170  						},
   171  						DockerImages: []params.DockerImage{
   172  							{
   173  								Repository: fullRepoName("foo", pad),
   174  								Tag:        "0.1.0",
   175  								ContextDir: "foo/docker",
   176  								Deps: []params.DockerDep{
   177  									{
   178  										Product:    "bar",
   179  										Type:       params.DockerDepDocker,
   180  										TargetFile: "",
   181  									},
   182  								},
   183  								Info: &params.DefaultDockerImageInfo{},
   184  							},
   185  						},
   186  					},
   187  					params.Project{
   188  						GroupID: "com.test.group",
   189  					},
   190  				)
   191  				allSpec["foo"] = fooSpec
   192  				fooSpecWithDeps, err := params.NewProductBuildSpecWithDeps(fooSpec, allSpec)
   193  				require.NoError(t, err)
   194  
   195  				return []params.ProductBuildSpecWithDeps{fooSpecWithDeps, barSpecWithDeps}
   196  			},
   197  			cleanup: func(cli *dockercli.Client, projectDir, pad string) {
   198  				images := []string{fmt.Sprintf("%v:0.1.0", fullRepoName("foo", pad)),
   199  					fmt.Sprintf("%v:0.1.0", fullRepoName("bar", pad))}
   200  				err := removeImages(cli, images)
   201  				if err != nil {
   202  					t.Logf("Failed to remove images: %v", err)
   203  				}
   204  			},
   205  			preDistAction: func(projectDir string, buildSpec []params.ProductBuildSpecWithDeps) {
   206  				gittest.CreateGitTag(t, projectDir, "0.1.0")
   207  			},
   208  			validate: func(caseNum int, name string, pad string, cli *dockercli.Client) {
   209  				filter := filters.NewArgs()
   210  				filter.Add("reference", fmt.Sprintf("%v:0.1.0", fullRepoName("foo", pad)))
   211  				images, err := cli.ImageList(context.Background(), types.ImageListOptions{Filters: filter})
   212  				require.NoError(t, err, "Case %d: %s", caseNum, name)
   213  				require.True(t, len(images) > 0, "Case %d: %s", caseNum, name)
   214  				filter = filters.NewArgs()
   215  				filter.Add("reference", fmt.Sprintf("%v:0.1.0", fullRepoName("bar", pad)))
   216  				images, err = cli.ImageList(context.Background(), types.ImageListOptions{Filters: filter})
   217  				require.NoError(t, err, "Case %d: %s", caseNum, name)
   218  				require.True(t, len(images) > 0, "Case %d: %s", caseNum, name)
   219  			},
   220  		},
   221  		{
   222  			name: "docker dist with build script args",
   223  			setupProject: func(projectDir, pad string) error {
   224  				gittest.InitGitDir(t, projectDir)
   225  				// initialize foo
   226  				fooDir := path.Join(projectDir, "foo")
   227  				if err := os.Mkdir(fooDir, 0777); err != nil {
   228  					return err
   229  				}
   230  				if err := ioutil.WriteFile(path.Join(fooDir, "main.go"), []byte(testMain), 0644); err != nil {
   231  					return err
   232  				}
   233  				fooDockerDir := path.Join(fooDir, "docker")
   234  				if err = os.Mkdir(fooDockerDir, 0777); err != nil {
   235  					return err
   236  				}
   237  				if err = ioutil.WriteFile(path.Join(fooDockerDir, "Dockerfile"), []byte(dockerfile), 0777); err != nil {
   238  					return err
   239  				}
   240  
   241  				// commit
   242  				gittest.CommitAllFiles(t, projectDir, "Commit")
   243  				return nil
   244  			},
   245  			spec: func(projectDir string, pad string) []params.ProductBuildSpecWithDeps {
   246  				allSpec := make(map[string]params.ProductBuildSpec)
   247  				fooSpec := params.NewProductBuildSpec(
   248  					projectDir,
   249  					"foo",
   250  					git.ProjectInfo{
   251  						Version: "0.1.0",
   252  					},
   253  					params.Product{
   254  						Build: params.Build{
   255  							MainPkg: "./foo",
   256  							OSArchs: []osarch.OSArch{
   257  								{
   258  									OS:   "linux",
   259  									Arch: "amd64",
   260  								},
   261  							},
   262  						},
   263  						DockerImages: []params.DockerImage{
   264  							{
   265  								Repository: fullRepoName("foo", pad),
   266  								Tag:        "0.1.0",
   267  								ContextDir: "foo/docker",
   268  								BuildArgsScript: `echo "--label"
   269  echo "test_label=test_value"`,
   270  								Info: &params.DefaultDockerImageInfo{},
   271  							},
   272  						},
   273  					},
   274  					params.Project{
   275  						GroupID: "com.test.group",
   276  					},
   277  				)
   278  				allSpec["foo"] = fooSpec
   279  				fooSpecWithDeps, err := params.NewProductBuildSpecWithDeps(fooSpec, allSpec)
   280  				require.NoError(t, err)
   281  
   282  				return []params.ProductBuildSpecWithDeps{fooSpecWithDeps}
   283  			},
   284  			cleanup: func(cli *dockercli.Client, projectDir, pad string) {
   285  				images := []string{fmt.Sprintf("%v:0.1.0", fullRepoName("foo", pad))}
   286  				err := removeImages(cli, images)
   287  				if err != nil {
   288  					t.Logf("Failed to remove images: %v", err)
   289  				}
   290  			},
   291  			preDistAction: func(projectDir string, buildSpec []params.ProductBuildSpecWithDeps) {
   292  				gittest.CreateGitTag(t, projectDir, "0.1.0")
   293  			},
   294  			validate: func(caseNum int, name string, pad string, cli *dockercli.Client) {
   295  				filter := filters.NewArgs()
   296  				filter.Add("reference", fmt.Sprintf("%v:0.1.0", fullRepoName("foo", pad)))
   297  				images, err := cli.ImageList(context.Background(), types.ImageListOptions{Filters: filter})
   298  				require.NoError(t, err, "Case %d: %s", caseNum, name)
   299  				require.True(t, len(images) > 0, "Case %d: %s", caseNum, name)
   300  				image := images[0]
   301  				inspect, _, err := cli.ImageInspectWithRaw(context.Background(), image.ID)
   302  				require.NoError(t, err, "Case %d: %s", caseNum, name)
   303  				actualValue, ok := inspect.Config.Labels["test_label"]
   304  				require.True(t, ok, "Case %d: %s", caseNum, name)
   305  				require.Equal(t, "test_value", actualValue, "Case%d: %s", caseNum, name)
   306  			},
   307  		},
   308  		{
   309  			name: "sls docker dist",
   310  			setupProject: func(projectDir, pad string) error {
   311  				gittest.InitGitDir(t, projectDir)
   312  				// initialize foo
   313  				fooDir := path.Join(projectDir, "foo")
   314  				if err := os.Mkdir(fooDir, 0777); err != nil {
   315  					return err
   316  				}
   317  				if err := ioutil.WriteFile(path.Join(fooDir, "main.go"), []byte(testMain), 0644); err != nil {
   318  					return err
   319  				}
   320  				fooDockerDir := path.Join(fooDir, "docker")
   321  				if err = os.Mkdir(fooDockerDir, 0777); err != nil {
   322  					return err
   323  				}
   324  				if err = ioutil.WriteFile(path.Join(fooDockerDir, "Dockerfile"), []byte(dockerfile), 0777); err != nil {
   325  					return err
   326  				}
   327  				if err = ioutil.WriteFile(path.Join(fooDockerDir, docker.ConfigurationFileName), []byte(configFile), 0777); err != nil {
   328  					return err
   329  				}
   330  
   331  				// commit
   332  				gittest.CommitAllFiles(t, projectDir, "Commit")
   333  				return nil
   334  			},
   335  			spec: func(projectDir string, pad string) []params.ProductBuildSpecWithDeps {
   336  				allSpec := make(map[string]params.ProductBuildSpec)
   337  				fooSpec := params.NewProductBuildSpec(
   338  					projectDir,
   339  					"foo",
   340  					git.ProjectInfo{
   341  						Version: "0.1.0",
   342  					},
   343  					params.Product{
   344  						Build: params.Build{
   345  							MainPkg: "./foo",
   346  							OSArchs: []osarch.OSArch{
   347  								{
   348  									OS:   "linux",
   349  									Arch: "amd64",
   350  								},
   351  							},
   352  						},
   353  						DockerImages: []params.DockerImage{
   354  							{
   355  								Repository: fullRepoName("foo", pad),
   356  								Tag:        "0.1.0",
   357  								ContextDir: "foo/docker",
   358  								Deps: []params.DockerDep{
   359  									{
   360  										Product:    "bar",
   361  										Type:       params.DockerDepDocker,
   362  										TargetFile: "",
   363  									},
   364  								},
   365  								Info: &params.SLSDockerImageInfo{
   366  									ProuductType: "test_type",
   367  									GroupID:      "com.palantir.godel",
   368  									Extensions: map[string]interface{}{
   369  										"test_key": "test_value",
   370  									},
   371  								},
   372  							},
   373  						},
   374  					},
   375  					params.Project{
   376  						GroupID: "com.test.group",
   377  					},
   378  				)
   379  				allSpec["foo"] = fooSpec
   380  				fooSpecWithDeps, err := params.NewProductBuildSpecWithDeps(fooSpec, allSpec)
   381  				require.NoError(t, err)
   382  
   383  				return []params.ProductBuildSpecWithDeps{fooSpecWithDeps}
   384  			},
   385  			cleanup: func(cli *dockercli.Client, projectDir, pad string) {
   386  				images := []string{fmt.Sprintf("%v:0.1.0", fullRepoName("foo", pad))}
   387  				err := removeImages(cli, images)
   388  				if err != nil {
   389  					t.Logf("Failed to remove images: %v", err)
   390  				}
   391  			},
   392  			preDistAction: func(projectDir string, buildSpec []params.ProductBuildSpecWithDeps) {
   393  				gittest.CreateGitTag(t, projectDir, "0.1.0")
   394  			},
   395  			validate: func(caseNum int, name string, pad string, cli *dockercli.Client) {
   396  				filter := filters.NewArgs()
   397  				filter.Add("reference", fmt.Sprintf("%v:0.1.0", fullRepoName("foo", pad)))
   398  				images, err := cli.ImageList(context.Background(), types.ImageListOptions{Filters: filter})
   399  				require.NoError(t, err, "Case %d: %s", caseNum, name)
   400  				require.True(t, len(images) > 0, "Case %d: %s", caseNum, name)
   401  				image := images[0]
   402  				inspect, _, err := cli.ImageInspectWithRaw(context.Background(), image.ID)
   403  				require.NoError(t, err, "Case %d: %s", caseNum, name)
   404  				actualManifestEncoded, ok := inspect.Config.Labels[docker.ManifestLabel]
   405  				require.True(t, ok, "Case %d: %s", caseNum, name)
   406  				actualManifest, err := base64.StdEncoding.DecodeString(actualManifestEncoded)
   407  				require.NoError(t, err, "Case %d: %s", caseNum, name)
   408  				expectedManifest := "manifest-version: \"1.0\"\n" +
   409  					"product-group: com.palantir.godel\n" +
   410  					"product-name: foo\n" +
   411  					"product-version: 0.1.0\n" +
   412  					"product-type: test_type\n" +
   413  					"extensions:\n  test_key: test_value\n"
   414  				require.Equal(t, expectedManifest, string(actualManifest), "Case %d: %s", caseNum, name)
   415  				actualConfigEncoded, ok := inspect.Config.Labels[docker.ConfigurationLabel]
   416  				require.True(t, ok, "Case %d: %s", caseNum, name)
   417  				actualConfig, err := base64.StdEncoding.DecodeString(actualConfigEncoded)
   418  				require.NoError(t, err, "Case %d: %s", caseNum, name)
   419  				require.Equal(t, configFile, string(actualConfig), "Case %d: %s", caseNum, name)
   420  			},
   421  		},
   422  		{
   423  			name: "docker dist with dependent sls dist",
   424  			setupProject: func(projectDir, pad string) error {
   425  				gittest.InitGitDir(t, projectDir)
   426  				// initialize foo
   427  				fooDir := path.Join(projectDir, "foo")
   428  				if err := os.Mkdir(fooDir, 0777); err != nil {
   429  					return err
   430  				}
   431  				if err := ioutil.WriteFile(path.Join(fooDir, "main.go"), []byte(testMain), 0644); err != nil {
   432  					return err
   433  				}
   434  
   435  				// initialize bar
   436  				barDir := path.Join(projectDir, "bar")
   437  				if err := os.Mkdir(barDir, 0777); err != nil {
   438  					return err
   439  				}
   440  				if err = ioutil.WriteFile(path.Join(barDir, "main.go"), []byte(testMain), 0644); err != nil {
   441  					return err
   442  				}
   443  				barDockerDir := path.Join(barDir, "docker")
   444  				if err = os.Mkdir(barDockerDir, 0777); err != nil {
   445  					return err
   446  				}
   447  				if err = ioutil.WriteFile(path.Join(barDockerDir, "Dockerfile"), []byte(slsDepDockerFile), 0777); err != nil {
   448  					return err
   449  				}
   450  
   451  				// commit
   452  				gittest.CommitAllFiles(t, projectDir, "Commit")
   453  				return nil
   454  			},
   455  			spec: func(projectDir string, pad string) []params.ProductBuildSpecWithDeps {
   456  				allSpec := make(map[string]params.ProductBuildSpec)
   457  				fooSpec := params.NewProductBuildSpec(
   458  					projectDir,
   459  					"foo",
   460  					git.ProjectInfo{
   461  						Version: "0.1.0",
   462  					},
   463  					params.Product{
   464  						Build: params.Build{
   465  							MainPkg: "./foo",
   466  							OSArchs: []osarch.OSArch{
   467  								{
   468  									OS:   "linux",
   469  									Arch: "amd64",
   470  								},
   471  							},
   472  						},
   473  						Dist: []params.Dist{
   474  							{
   475  								Info: &params.SLSDistInfo{},
   476  							},
   477  							{
   478  								Info: &params.BinDistInfo{},
   479  							},
   480  						},
   481  					},
   482  					params.Project{
   483  						GroupID: "com.test.group",
   484  					},
   485  				)
   486  				allSpec["foo"] = fooSpec
   487  				fooSpecWithDeps, err := params.NewProductBuildSpecWithDeps(fooSpec, allSpec)
   488  				require.NoError(t, err)
   489  				barSpec := params.NewProductBuildSpec(
   490  					projectDir,
   491  					"bar",
   492  					git.ProjectInfo{
   493  						Version: "0.1.0",
   494  					},
   495  					params.Product{
   496  						Build: params.Build{
   497  							MainPkg: "./bar",
   498  							OSArchs: []osarch.OSArch{
   499  								{
   500  									OS:   "linux",
   501  									Arch: "amd64",
   502  								},
   503  							},
   504  						},
   505  						DockerImages: []params.DockerImage{
   506  							{
   507  								Repository: fullRepoName("bar", pad),
   508  								Tag:        "0.1.0",
   509  								ContextDir: "bar/docker",
   510  								Info:       &params.DefaultDockerImageInfo{},
   511  								Deps: []params.DockerDep{
   512  									{
   513  										Product:    "bar",
   514  										Type:       params.DockerDepSLS,
   515  										TargetFile: "bar-sls.tgz",
   516  									},
   517  									{
   518  										Product:    "foo",
   519  										Type:       params.DockerDepBin,
   520  										TargetFile: "foo-bin.tgz",
   521  									},
   522  									{
   523  										Product:    "foo",
   524  										Type:       params.DockerDepSLS,
   525  										TargetFile: "foo-sls.tgz",
   526  									},
   527  								},
   528  							},
   529  						},
   530  						Dist: []params.Dist{
   531  							{
   532  								Info: &params.SLSDistInfo{},
   533  							},
   534  						},
   535  					}, params.Project{
   536  						GroupID: "com.test.group",
   537  					},
   538  				)
   539  				allSpec["bar"] = barSpec
   540  				barSpecWithDeps, err := params.NewProductBuildSpecWithDeps(barSpec, allSpec)
   541  				require.NoError(t, err)
   542  				return []params.ProductBuildSpecWithDeps{fooSpecWithDeps, barSpecWithDeps}
   543  			},
   544  			cleanup: func(cli *dockercli.Client, projectDir, pad string) {
   545  				images := []string{fmt.Sprintf("%v:0.1.0", fullRepoName("bar", pad))}
   546  				err := removeImages(cli, images)
   547  				if err != nil {
   548  					t.Logf("Failed to remove images: %v", err)
   549  				}
   550  			},
   551  			preDistAction: func(projectDir string, buildSpec []params.ProductBuildSpecWithDeps) {
   552  				gittest.CreateGitTag(t, projectDir, "0.1.0")
   553  			},
   554  			validate: func(caseNum int, name string, pad string, cli *dockercli.Client) {
   555  				filter := filters.NewArgs()
   556  				filter.Add("reference", fmt.Sprintf("%v:0.1.0", fullRepoName("bar", pad)))
   557  				images, err := cli.ImageList(context.Background(), types.ImageListOptions{Filters: filter})
   558  				require.NoError(t, err, "Case %d: %s", caseNum, name)
   559  				require.True(t, len(images) > 0, "Case %d: %s", caseNum, name)
   560  			},
   561  		},
   562  	} {
   563  		cli, err := dockercli.NewEnvClient()
   564  		require.NoError(t, err)
   565  
   566  		currTmpDir, err := ioutil.TempDir(tmp, "")
   567  		require.NoError(t, err, "Case %d: %s", i, currCase.name)
   568  		pad := randomPad(8)
   569  
   570  		err = currCase.setupProject(currTmpDir, pad)
   571  		require.NoError(t, err, "Case %d: %s", i, currCase.name)
   572  		spec := currCase.spec(currTmpDir, pad)
   573  
   574  		if currCase.preDistAction != nil {
   575  			currCase.preDistAction(currTmpDir, spec)
   576  		}
   577  
   578  		if currCase.cleanup != nil {
   579  			defer currCase.cleanup(cli, currTmpDir, pad)
   580  		}
   581  
   582  		for _, currSpecWithDeps := range spec {
   583  			err = build.Run(build.RequiresBuild(currSpecWithDeps, nil).Specs(), nil, build.Context{}, ioutil.Discard)
   584  			require.NoError(t, err, "Case %d: %s", i, currCase.name)
   585  			err = dist.Run(currSpecWithDeps, ioutil.Discard)
   586  			require.NoError(t, err, "Case %d: %s", i, currCase.name)
   587  		}
   588  
   589  		orderedSpecs, err := docker.OrderBuildSpecs(spec)
   590  		require.NoError(t, err, "Case %d: %s", i, currCase.name)
   591  		err = docker.RunBuild(orderedSpecs, false, os.Stdout)
   592  		require.NoError(t, err, "Case %d: %s", i, currCase.name)
   593  
   594  		if currCase.validate != nil {
   595  			currCase.validate(i, currCase.name, pad, cli)
   596  		}
   597  	}
   598  }
   599  
   600  func fullRepoName(product string, pad string) string {
   601  	return fmt.Sprintf("%v-%v-%v", dockerRepoPrefix, product, pad)
   602  }
   603  
   604  func randomPad(n int) string {
   605  	var letters = []rune("abcdefghijklmnopqrstuvwxyz1234567890")
   606  	b := make([]rune, n)
   607  	rand.Seed(time.Now().UTC().UnixNano())
   608  	for i := range b {
   609  		b[i] = letters[rand.Intn(len(letters))]
   610  	}
   611  	return string(b)
   612  }
   613  
   614  func removeImages(cli *dockercli.Client, images []string) error {
   615  	for _, image := range images {
   616  		_, err := cli.ImageRemove(context.Background(), image, types.ImageRemoveOptions{})
   617  		if err != nil {
   618  			return err
   619  		}
   620  	}
   621  	return nil
   622  }