Пример #1
0
func TestStage1LoadingFromConfigNoDiscovery(t *testing.T) {
	// We shouldn't be using discovery in this setup, but enable
	// it, just in case.
	setup := newStubStage1Setup(t, taas.GetDefaultServerSetup())
	defer setup.cleanup()

	cfg := &config.Stage1Data{
		Name:     setup.name,
		Version:  setup.version,
		Location: setup.getLocation(stubStage1PathAbs),
	}
	setup.generateStage1Config(cfg)
	cmd := fmt.Sprintf("%s --insecure-options=image,tls --debug run %s", setup.ctx.Cmd(), getInspectImagePath())
	child := spawnOrFail(setup.t, cmd)
	defer waitOrFail(setup.t, child, 0)
	discoveringStr := fmt.Sprintf("searching for app image %s", setup.name)
	for {
		matches, output, err := expectRegexWithOutput(child, `(?m)^image:.+$`)
		if err != nil {
			if strings.Index(output, stubStage1Output) < 0 {
				t.Fatalf("got no success notice from stub stage1, output:\n%s", output)
			}
			break
		}
		if strings.Index(matches[0], discoveringStr) >= 0 {
			t.Fatalf("rkt performs discovery for stage1 image, but it should not")
		}
	}
}
Пример #2
0
func TestFetchNoStoreCacheControl(t *testing.T) {
	imageName := "rkt-inspect-fetch-nostore-cachecontrol"
	imageFileName := fmt.Sprintf("%s.aci", imageName)
	// no spaces between words, because of an actool limitation
	successMsg := "deferredSignatureDownloadWasSuccessful"

	args := []string{
		fmt.Sprintf("--exec=/inspect --print-msg='%s'", successMsg),
		fmt.Sprintf("--name=%s", imageName),
	}
	image := patchTestACI(imageFileName, args...)
	defer os.Remove(image)

	asc := runSignImage(t, image, 1)
	defer os.Remove(asc)
	ascBase := filepath.Base(asc)

	setup := taas.GetDefaultServerSetup()
	setup.Server = taas.ServerQuay
	server := runServer(t, setup)
	defer server.Close()
	fileSet := make(map[string]string, 2)
	fileSet[imageFileName] = image
	fileSet[ascBase] = asc
	if err := server.UpdateFileSet(fileSet); err != nil {
		t.Fatalf("Failed to populate a file list in test aci server: %v", err)
	}

	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	runRktTrust(t, ctx, "", 1)

	tests := []struct {
		imageArg string
		imageURL string
	}{
		{"https://127.0.0.1/" + imageFileName, "https://127.0.0.1/" + imageFileName},
		{"localhost/" + imageName, "https://127.0.0.1:443/localhost/" + imageFileName},
	}

	for _, tt := range tests {
		cmd := fmt.Sprintf("%s --no-store --debug --insecure-options=tls,image fetch %s", ctx.Cmd(), tt.imageArg)
		expectedMessage := fmt.Sprintf("fetching image from %s", tt.imageURL)
		runRktAndCheckRegexOutput(t, cmd, expectedMessage)

		cmd = fmt.Sprintf("%s --no-store --debug --insecure-options=tls,image fetch %s", ctx.Cmd(), tt.imageArg)
		expectedMessage = fmt.Sprintf("image for %s isn't expired, not fetching.", tt.imageURL)
		runRktAndCheckRegexOutput(t, cmd, expectedMessage)

		ctx.Reset()
	}
}
Пример #3
0
func runAuthServer(t *testing.T, auth taas.AuthType) (*taas.Server, string) {
	setup := taas.GetDefaultServerSetup()
	setup.Auth = auth
	setup.Port = taas.PortRandom
	server := runServer(t, setup)
	image := patchTestACI(authACIName, fmt.Sprintf("--exec=/inspect --print-msg='%s'", authSuccessfulDownload))
	fileSet := make(map[string]string, 1)
	fileSet[authACIName] = image
	if err := server.UpdateFileSet(fileSet); err != nil {
		t.Fatalf("Failed to populate a file list in test aci server: %v", err)
	}
	return server, image
}
Пример #4
0
func TestDifferentDiscoveryLabels(t *testing.T) {
	manifestTemplate := `{"acKind":"ImageManifest","acVersion":"0.8.6","name":"IMG_NAME","labels":[{"name":"version","value":"1.2.0"},{"name":"arch","value":"amd64"},{"name":"os","value":"linux"}]}`
	emptyImage := getEmptyImagePath()
	imageName := "localhost/rkt-test-different-discovery-labels-image"
	manifest := strings.Replace(manifestTemplate, "IMG_NAME", imageName, -1)
	tmpDir := createTempDirOrPanic("rkt-TestDifferentDiscoveryLabels-")
	defer os.RemoveAll(tmpDir)

	tmpManifest, err := ioutil.TempFile(tmpDir, "manifest")
	if err != nil {
		panic(fmt.Sprintf("Cannot create temp manifest: %v", err))
	}
	if err := ioutil.WriteFile(tmpManifest.Name(), []byte(manifest), 0600); err != nil {
		panic(fmt.Sprintf("Cannot write to temp manifest: %v", err))
	}
	defer os.Remove(tmpManifest.Name())

	image := patchACI(emptyImage, "rkt-test-different-discovery-labels-image.aci", "--manifest", tmpManifest.Name())
	imageFileName := fmt.Sprintf("%s.aci", filepath.Base(imageName))
	defer os.Remove(image)

	asc := runSignImage(t, image, 1)
	defer os.Remove(asc)
	ascBase := filepath.Base(asc)

	setup := taas.GetDefaultServerSetup()
	server := runServer(t, setup)
	defer server.Close()
	fileSet := make(map[string]string, 2)
	fileSet[imageFileName] = image
	fileSet[ascBase] = asc
	if err := server.UpdateFileSet(fileSet); err != nil {
		t.Fatalf("Failed to populate a file list in test aci server: %v", err)
	}

	tests := []struct {
		imageName       string
		expectedMessage string
	}{
		{imageName + ":2.0", fmt.Sprintf("requested value for label %q: %q differs from fetched aci label value: %q", "version", "2.0", "1.2.0")},
		{imageName + ":latest", fmt.Sprintf("requested value for label %q: %q differs from fetched aci label value: %q", "version", "latest", "1.2.0")},
		{imageName + ",arch=armv7b", fmt.Sprintf("requested value for label %q: %q differs from fetched aci label value: %q", "arch", "armv7b", "amd64")},
		{imageName + ",unexistinglabel=bla", fmt.Sprintf("requested label %q not provided by the image manifest", "unexistinglabel")},
	}

	for _, tt := range tests {
		testDifferentDiscoveryNameLabels(t, tt.imageName, tt.expectedMessage)
	}
}
Пример #5
0
func TestStage1LoadingFromFlagsHttp(t *testing.T) {
	// We need no discovery, so use random port.
	serverSetup := taas.GetDefaultServerSetup()
	serverSetup.Protocol = taas.ProtocolHttp
	serverSetup.Port = taas.PortRandom
	setup := newStubStage1Setup(t, serverSetup)
	defer setup.cleanup()

	flag := fmt.Sprintf("--stage1-url=%q", setup.getLocation(stubStage1UrlHttp))
	expectedFirstRun := fmt.Sprintf("image: remote fetching from URL %q", setup.getLocation(stubStage1UrlHttp))
	expectedSecondRun := fmt.Sprintf("image: using image from local store for url %s", setup.getLocation(stubStage1UrlHttp))

	setup.check(flag, expectedFirstRun)
	setup.check(flag, expectedSecondRun)
}
Пример #6
0
func TestRenderOnFetch(t *testing.T) {
	// If overlayfs is not supported, we don't render images on fetch
	if !common.SupportsOverlay() {
		t.Skip("Overlay fs not supported.")
	}
	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	server := runServer(t, taas.GetDefaultServerSetup())
	defer server.Close()

	fileSet, imageList := generateComplexDependencyTree(t, ctx)
	for _, img := range imageList {
		defer os.Remove(img.fileName)
	}

	if err := server.UpdateFileSet(fileSet); err != nil {
		t.Fatalf("Failed to populate a file list in test aci server: %v", err)
	}

	for i := len(imageList) - 1; i >= 0; i-- {
		img := imageList[i]
		if img.prefetch {
			t.Logf("Importing image %q: %q", img.imageName, img.fileName)
			testImageShortHash, err := importImageAndFetchHash(t, ctx, "", img.fileName)
			if err != nil {
				t.Fatalf("%v", err)
			}
			t.Logf("Imported image %q: %s", img.imageName, testImageShortHash)
		}
	}

	fetchCmd := fmt.Sprintf("%s --debug --insecure-options=image,tls fetch %s", ctx.Cmd(), topImage)
	child := spawnOrFail(t, fetchCmd)

	treeStoreDir := filepath.Join(ctx.DataDir(), "cas", "tree")
	trees, err := ioutil.ReadDir(treeStoreDir)
	if err != nil {
		panic(fmt.Sprintf("Cannot read tree store dir: %v", err))
	}

	// We expect 2 trees: stage1 and the image
	if len(trees) != 2 {
		t.Fatalf("Expected 2 trees but found %d", len(trees))
	}

	waitOrFail(t, child, 0)
}
Пример #7
0
// TestImageDependencies generates ACIs with a complex dependency tree and
// fetches them via the discovery mechanism. Some dependencies are already
// cached in the CAS, and some dependencies are fetched via the discovery
// mechanism. This is to reproduce the scenario in explained in:
// https://github.com/coreos/rkt/issues/1752#issue-117121841
func TestImageDependencies(t *testing.T) {
	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	server := runServer(t, taas.GetDefaultServerSetup())
	defer server.Close()

	fileSet, imageList := generateComplexDependencyTree(t, ctx)
	for _, img := range imageList {
		defer os.Remove(img.fileName)
	}

	if err := server.UpdateFileSet(fileSet); err != nil {
		t.Fatalf("Failed to populate a file list in test aci server: %v", err)
	}

	for i := len(imageList) - 1; i >= 0; i-- {
		img := imageList[i]
		if img.prefetch {
			t.Logf("Importing image %q: %q", img.imageName, img.fileName)
			testImageShortHash, err := importImageAndFetchHash(t, ctx, "", img.fileName)
			if err != nil {
				t.Fatalf("%v", err)
			}
			t.Logf("Imported image %q: %s", img.imageName, testImageShortHash)
		}
	}

	runCmd := fmt.Sprintf("%s --debug --insecure-options=image,tls run %s", ctx.Cmd(), topImage)
	child := spawnOrFail(t, runCmd)

	expectedList := []string{
		fmt.Sprintf("image: fetching image from %s/localhost/image-a.aci", server.URL),
		"image: using image from local store for image name localhost/image-b",
		fmt.Sprintf("image: fetching image from %s/localhost/image-c.aci", server.URL),
		fmt.Sprintf("image: fetching image from %s/localhost/image-d.aci", server.URL),
		"image: using image from local store for image name coreos.com/rkt-inspect",
		"HelloDependencies",
	}

	for _, expected := range expectedList {
		if err := expectWithOutput(child, expected); err != nil {
			t.Fatalf("Expected %q but not found: %v", expected, err)
		}
	}

	waitOrFail(t, child, 0)
}
Пример #8
0
func TestDeferredSignatureDownload(t *testing.T) {
	imageName := "localhost/rkt-inspect-deferred-signature-download"
	imageFileName := fmt.Sprintf("%s.aci", filepath.Base(imageName))
	// no spaces between words, because of an actool limitation
	successMsg := "deferredSignatureDownloadWasSuccessful"

	args := []string{
		fmt.Sprintf("--exec=/inspect --print-msg='%s'", successMsg),
		fmt.Sprintf("--name=%s", imageName),
	}
	image := patchTestACI(imageFileName, args...)
	defer os.Remove(image)

	asc := runSignImage(t, image, 1)
	defer os.Remove(asc)
	ascBase := filepath.Base(asc)

	setup := taas.GetDefaultServerSetup()
	setup.Server = taas.ServerQuay
	server := runServer(t, setup)
	defer server.Close()
	fileSet := make(map[string]string, 2)
	fileSet[imageFileName] = image
	fileSet[ascBase] = asc
	if err := server.UpdateFileSet(fileSet); err != nil {
		t.Fatalf("Failed to populate a file list in test aci server: %v", err)
	}

	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	runRktTrust(t, ctx, "", 1)

	runCmd := fmt.Sprintf("%s --debug --insecure-options=tls run %s", ctx.Cmd(), imageName)
	child := spawnOrFail(t, runCmd)
	defer waitOrFail(t, child, 0)

	expectedMessages := []string{
		"server requested deferring the signature download",
		successMsg,
	}
	for _, msg := range expectedMessages {
		if err := expectWithOutput(child, msg); err != nil {
			t.Fatalf("Could not find expected msg %q, output follows:\n%v", msg, err)
		}
	}
}
Пример #9
0
func TestStage1LoadingFromConfigHttp(t *testing.T) {
	// We don't need discovery in this test, so get random port.
	serverSetup := taas.GetDefaultServerSetup()
	serverSetup.Protocol = taas.ProtocolHttp
	serverSetup.Port = taas.PortRandom
	setup := newStubStage1Setup(t, serverSetup)
	defer setup.cleanup()
	expectedFirstRun := fmt.Sprintf("image: remote fetching from URL %q", setup.getLocation(stubStage1UrlHttp))
	expectedSecondRun := fmt.Sprintf("image: using image from local store for image name %s:%s", setup.name, setup.version)
	cfg := &config.Stage1Data{
		Name:     setup.name,
		Version:  setup.version,
		Location: setup.getLocation(stubStage1UrlHttp),
	}

	t.Logf("Generating stage1 configuration file with name %q, version %q and location %q", setup.name, setup.version, setup.getLocation(stubStage1UrlHttp))
	setup.generateStage1Config(cfg)
	setup.check("", expectedFirstRun)
	setup.check("", expectedSecondRun)
}
Пример #10
0
func TestStage1LoadingFromConfig(t *testing.T) {
	// We don't need discovery in this test, so get random port,
	// but keep https.
	serverSetup := taas.GetDefaultServerSetup()
	serverSetup.Port = taas.PortRandom
	setup := newStubStage1Setup(t, serverSetup)
	defer setup.cleanup()

	tests := []struct {
		name              string
		version           string
		location          string
		expectedFirstRun  string
		expectedSecondRun string
		skipReason        string
	}{
		// typical scenario - config file with correct name,
		// version and location, we expect the stage1 image to
		// be taken from file in the first run, and then from
		// store on subsequent runs
		{
			name:              setup.name,
			version:           setup.version,
			location:          setup.getLocation(stubStage1PathAbs),
			expectedFirstRun:  fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)),
			expectedSecondRun: fmt.Sprintf("image: using image from local store for image name %s:%s", setup.name, setup.version),
		},

		// wrong name, resulting in always loading the stage1
		// image from disk
		{
			name:              "example.com/stage1",
			version:           setup.version,
			location:          setup.getLocation(stubStage1PathAbs),
			expectedFirstRun:  fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)),
			expectedSecondRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)),
		},

		// wrong version, resulting in always loading the stage1
		// image from disk
		{
			name:              setup.name,
			version:           "3.2.1",
			location:          setup.getLocation(stubStage1PathAbs),
			expectedFirstRun:  fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)),
			expectedSecondRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)),
		},

		// loading stage1 from http URL
		{
			name:       setup.name,
			version:    setup.version,
			location:   setup.getLocation(stubStage1UrlHttp),
			skipReason: "tested in TestStage1LoadingFromConfigHttp",
		},

		// loading stage1 from docker URL
		{
			name:       setup.name,
			version:    setup.version,
			location:   setup.getLocation(stubStage1UrlDocker),
			skipReason: "tested in TestStage1LoadingFromConfigDocker",
		},

		// loading stage1 from https URL
		{
			name:              setup.name,
			version:           setup.version,
			location:          setup.getLocation(stubStage1UrlHttps),
			expectedFirstRun:  fmt.Sprintf("image: remote fetching from URL %q", setup.getLocation(stubStage1UrlHttps)),
			expectedSecondRun: fmt.Sprintf("image: using image from local store for image name %s:%s", setup.name, setup.version),
		},

		// loading stage1 from file URL
		{
			name:              setup.name,
			version:           setup.version,
			location:          setup.getLocation(stubStage1UrlFile),
			expectedFirstRun:  fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)),
			expectedSecondRun: fmt.Sprintf("image: using image from local store for image name %s:%s", setup.name, setup.version),
		},
	}

	for _, tt := range tests {
		if tt.skipReason != "" {
			t.Logf("skipping the testcase with name %q, version %q and location %q, reason - %s", tt.name, tt.version, tt.location, tt.skipReason)
			continue
		}
		cfg := &config.Stage1Data{
			Name:     tt.name,
			Version:  tt.version,
			Location: tt.location,
		}
		t.Logf("Generating stage1 configuration file with name %q, version %q and location %q", tt.name, tt.version, tt.location)
		setup.generateStage1Config(cfg)
		setup.check("", tt.expectedFirstRun)
		setup.check("", tt.expectedSecondRun)
		setup.ctx.Reset()
	}
}
Пример #11
0
func TestStage1LoadingFromFlags(t *testing.T) {
	// We use discovery in this test.
	setup := newStubStage1Setup(t, taas.GetDefaultServerSetup())
	defer setup.cleanup()

	tests := []struct {
		flag              string
		expectedFirstRun  string
		expectedSecondRun string
		skipReason        string
	}{
		// --stage1-path with a relative path
		{
			flag:              fmt.Sprintf("--stage1-path=%q", setup.getLocation(stubStage1PathRel)),
			expectedFirstRun:  fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathRel)),
			expectedSecondRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathRel)),
		},

		// --stage1-path with an absolute path
		{
			flag:              fmt.Sprintf("--stage1-path=%q", setup.getLocation(stubStage1PathAbs)),
			expectedFirstRun:  fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)),
			expectedSecondRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)),
		},

		// --stage1-url with an http URL
		{
			flag:       "--stage1-url=http://...",
			skipReason: "tested in TestStage1LoadingFromFlagsHttp",
		},

		// --stage1-url with an docker URL
		{
			flag:       "--stage1-url=docker://...",
			skipReason: "tested in TestStage1LoadingFromFlagsDocker",
		},

		// --stage1-url with an https URL
		{
			flag:              fmt.Sprintf("--stage1-url=%q", setup.getLocation(stubStage1UrlHttps)),
			expectedFirstRun:  fmt.Sprintf("image: remote fetching from URL %q", setup.getLocation(stubStage1UrlHttps)),
			expectedSecondRun: fmt.Sprintf("image: using image from local store for url %s", setup.getLocation(stubStage1UrlHttps)),
		},

		// --stage1-url with an file URL
		{
			flag:              fmt.Sprintf("--stage1-url=%q", setup.getLocation(stubStage1UrlFile)),
			expectedFirstRun:  fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)),
			expectedSecondRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)),
		},

		// --stage1-name
		{
			flag:              fmt.Sprintf("--stage1-name=%s", setup.getLocation(stubStage1Name)),
			expectedFirstRun:  fmt.Sprintf("image: searching for app image %s", setup.name),
			expectedSecondRun: fmt.Sprintf("image: using image from local store for image name %s", setup.getLocation(stubStage1Name)),
		},

		// --stage1-hash
		{
			flag:       "--stage1-hash=...",
			skipReason: "tested in TestStage1LoadingFromFlagsHash",
		},

		// --stage1-from-dir
		{
			flag:       "--stage1-from-dir=...",
			skipReason: "tested in TestStage1LoadingFromFlagsFromDir",
		},
	}

	for _, tt := range tests {
		if tt.skipReason != "" {
			t.Logf("skipping the testcase with the flag %s, reason - %s", tt.flag, tt.skipReason)
			continue
		}
		setup.check(tt.flag, tt.expectedFirstRun)
		setup.check(tt.flag, tt.expectedSecondRun)
		setup.ctx.Reset()
	}
}
Пример #12
0
// TestImageDependencies generates ACIs with a complex dependency tree and
// fetches them via the discovery mechanism. Some dependencies are already
// cached in the CAS, and some dependencies are fetched via the discovery
// mechanism. This is to reproduce the scenario in explained in:
// https://github.com/coreos/rkt/issues/1752#issue-117121841
func TestImageDependencies(t *testing.T) {
	tmpDir := createTempDirOrPanic("rkt-TestImageDeps-")
	defer os.RemoveAll(tmpDir)

	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	server := runServer(t, taas.GetDefaultServerSetup())
	defer server.Close()

	baseImage := getInspectImagePath()
	_ = importImageAndFetchHash(t, ctx, "", baseImage)
	emptyImage := getEmptyImagePath()
	fileSet := make(map[string]string)

	// Scenario from https://github.com/coreos/rkt/issues/1752#issue-117121841
	//
	// A->B
	// A->C
	// A->D
	//
	// B: prefetched
	//
	// C->B
	// C->E
	//
	// D->B
	// D->E

	topImage := "localhost/image-a"
	imageList := []struct {
		shortName string
		imageName string
		deps      string
		version   string
		prefetch  bool

		manifest string
		fileName string
	}{
		{
			shortName: "a",
			imageName: topImage,
			deps:      `{"imageName":"localhost/image-b"}, {"imageName":"localhost/image-c"}, {"imageName":"localhost/image-d"}`,
			version:   "1",
		},
		{
			shortName: "b",
			imageName: "localhost/image-b",
			deps:      ``,
			version:   "1",
			prefetch:  true,
		},
		{
			shortName: "c",
			imageName: "localhost/image-c",
			deps:      `{"imageName":"localhost/image-b"}, {"imageName":"localhost/image-e", "labels": [{"name": "version", "value": "1"}]}`,
			version:   "1",
		},
		{
			shortName: "d",
			imageName: "localhost/image-d",
			deps:      `{"imageName":"localhost/image-b"}, {"imageName":"localhost/image-e", "labels": [{"name": "version", "value": "1"}]}`,
			version:   "1",
		},
		{
			shortName: "e",
			imageName: "localhost/image-e",
			deps:      `{"imageName":"coreos.com/rkt-inspect"}`,
			version:   "1",
		},
	}

	for i, _ := range imageList {
		// We need a reference rather than a new copy from "range"
		// because we modify the content
		img := &imageList[i]

		img.manifest = manifestDepsTemplate
		img.manifest = strings.Replace(img.manifest, "IMG_NAME", img.imageName, -1)
		img.manifest = strings.Replace(img.manifest, "DEPENDENCIES", img.deps, -1)
		img.manifest = strings.Replace(img.manifest, "VERSION", img.version, -1)

		tmpManifest, err := ioutil.TempFile(tmpDir, "manifest-"+img.shortName+"-")
		if err != nil {
			panic(fmt.Sprintf("Cannot create temp manifest: %v", err))
		}
		defer os.Remove(tmpManifest.Name())
		if err := ioutil.WriteFile(tmpManifest.Name(), []byte(img.manifest), 0600); err != nil {
			panic(fmt.Sprintf("Cannot write to temp manifest: %v", err))
		}

		baseName := "image-" + img.shortName + ".aci"
		img.fileName = patchACI(emptyImage, baseName, "--manifest", tmpManifest.Name())
		defer os.Remove(img.fileName)
		fileSet[baseName] = img.fileName
	}

	if err := server.UpdateFileSet(fileSet); err != nil {
		t.Fatalf("Failed to populate a file list in test aci server: %v", err)
	}

	for i := len(imageList) - 1; i >= 0; i-- {
		img := imageList[i]
		if img.prefetch {
			t.Logf("Importing image %q: %q", img.imageName, img.fileName)
			testImageShortHash := importImageAndFetchHash(t, ctx, "", img.fileName)
			t.Logf("Imported image %q: %s", img.imageName, testImageShortHash)
		}
	}

	runCmd := fmt.Sprintf("%s --debug --insecure-options=image,tls run %s", ctx.Cmd(), topImage)
	child := spawnOrFail(t, runCmd)

	expectedList := []string{
		fmt.Sprintf("image: fetching image from %s/localhost/image-a.aci", server.URL),
		"image: using image from local store for image name localhost/image-b",
		fmt.Sprintf("image: fetching image from %s/localhost/image-c.aci", server.URL),
		fmt.Sprintf("image: fetching image from %s/localhost/image-d.aci", server.URL),
		"image: using image from local store for image name coreos.com/rkt-inspect",
		"HelloDependencies",
	}

	for _, expected := range expectedList {
		if err := expectWithOutput(child, expected); err != nil {
			t.Fatalf("Expected %q but not found: %v", expected, err)
		}
	}

	waitOrFail(t, child, 0)
}