// TestImplicitFetch tests that 'rkt run/prepare' will always bypass the on-disk store // if the tag is "latest". func TestImplicitFetch(t *testing.T) { foundMsg := "found image in local store" ctx := newRktRunCtx() defer ctx.cleanup() // 1. Fetch the image. // TODO(yifan): Add other ACI with different schemes. importImageAndFetchHash(t, ctx, "docker://busybox:ubuntu-12.04") importImageAndFetchHash(t, ctx, "docker://busybox:latest") // 2. Try run/prepare with specified tag, should get the $foundMsg. cmds := []string{ fmt.Sprintf("%s --insecure-skip-verify run --mds-register=false docker://busybox:ubuntu-12.04", ctx.cmd()), fmt.Sprintf("%s --insecure-skip-verify prepare docker://busybox:ubuntu-12.04", ctx.cmd()), } for _, cmd := range cmds { t.Logf("Running test %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } if err := child.Expect(foundMsg); err != nil { t.Fatalf("Expected %q but not found: %v", foundMsg, err) } if err := child.Wait(); err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } } // 3. Try run/prepare with/without tag ':latest', should not get $foundMsg. cmds = []string{ fmt.Sprintf("%s --insecure-skip-verify run --mds-register=false docker://busybox", ctx.cmd()), fmt.Sprintf("%s --insecure-skip-verify run --mds-register=false docker://busybox", ctx.cmd()), fmt.Sprintf("%s --insecure-skip-verify prepare docker://busybox:latest", ctx.cmd()), fmt.Sprintf("%s --insecure-skip-verify prepare docker://busybox:latest", ctx.cmd()), } for _, cmd := range cmds { t.Logf("Running test %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } if err := child.Expect(foundMsg); err == nil { t.Fatalf("%q should not be found", foundMsg) } if err := child.Wait(); err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } } }
// TestRunPrepareLocal tests that 'rkt run/prepare' will only use the on-disk store if flag is --local func TestRunPrepareLocal(t *testing.T) { notAvailableMsg := "not available in local store" foundMsg := "using image in local store" ctx := newRktRunCtx() defer ctx.cleanup() cmds := []string{ fmt.Sprintf("%s --insecure-skip-verify run --local --mds-register=false docker://busybox", ctx.cmd()), fmt.Sprintf("%s --insecure-skip-verify run --local --mds-register=false docker://busybox:latest", ctx.cmd()), fmt.Sprintf("%s --insecure-skip-verify prepare --local docker://busybox", ctx.cmd()), fmt.Sprintf("%s --insecure-skip-verify prepare --local docker://busybox:latest", ctx.cmd()), } // 1. Try run/prepare with the image not available in the store, should get $notAvailableMsg. for _, cmd := range cmds { t.Logf("Running test %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } if err := expectWithOutput(child, notAvailableMsg); err != nil { t.Fatalf("%q should be found", notAvailableMsg) } child.Wait() } // 2. Fetch the image importImageAndFetchHash(t, ctx, "docker://busybox") importImageAndFetchHash(t, ctx, "docker://busybox:latest") // 3. Try run/prepare with the image available in the store, should get $foundMsg. for _, cmd := range cmds { t.Logf("Running test %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } if err := expectWithOutput(child, foundMsg); err != nil { t.Fatalf("%q should be found", foundMsg) } if err := child.Wait(); err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } } }
func TestSuccess(t *testing.T) { patchTestACI("rkt-inspect-exit0.aci", "--exec=/inspect --print-msg=Hello --exit-code=0") defer os.Remove("rkt-inspect-exit0.aci") ctx := newRktRunCtx() defer ctx.cleanup() child, err := gexpect.Spawn(fmt.Sprintf("%s --debug --insecure-skip-verify run ./rkt-inspect-exit0.aci", ctx.cmd())) if err != nil { t.Fatalf("Cannot exec rkt") } err = child.Expect("Hello") if err != nil { t.Fatalf("Missing hello") } forbidden := "main process exited, code=exited, status=" _, receiver := child.AsyncInteractChannels() for { msg, open := <-receiver if !open { break } if strings.Contains(msg, forbidden) { t.Fatalf("Forbidden text received") } } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } }
func TestExitCode(t *testing.T) { for i := 0; i < 3; i++ { t.Logf("%d\n", i) imageFile := patchTestACI("rkt-inspect-exit.aci", fmt.Sprintf("--exec=/inspect --print-msg=Hello --exit-code=%d", i)) defer os.Remove(imageFile) ctx := newRktRunCtx() defer ctx.cleanup() cmd := fmt.Sprintf(`/bin/sh -c "`+ `%s --debug --insecure-skip-verify run --mds-register=false %s ;`+ `UUID=$(%s list --full|grep exited|awk '{print $1}') ;`+ `echo -n 'status=' ;`+ `%s status $UUID|grep '^rkt-inspect.*=[0-9]*$'|cut -d= -f2"`, ctx.cmd(), imageFile, ctx.cmd(), ctx.cmd()) t.Logf("%s\n", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt") } err = expectWithOutput(child, fmt.Sprintf("status=%d", i)) if err != nil { t.Fatalf("Failed to get the status") } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } } }
func TestAppIsolatorCPU(t *testing.T) { ok := cgroup.IsIsolatorSupported("cpu") if !ok { t.Skip("CPU isolator not supported.") } ctx := newRktRunCtx() defer ctx.cleanup() t.Logf("Running test: %v", cpuTest.testName) aciFileName := patchTestACI("rkt-inspect-isolators.aci", cpuTest.aciBuildArgs...) defer os.Remove(aciFileName) rktCmd := fmt.Sprintf("%s --insecure-skip-verify run --mds-register=false %s", ctx.cmd(), aciFileName) t.Logf("Command: %v", rktCmd) child, err := gexpect.Spawn(rktCmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } expectedLine := "CPU Quota: " + strconv.Itoa(CPUQuota) if err := expectWithOutput(child, expectedLine); err != nil { t.Fatalf("Didn't receive expected output %q: %v", expectedLine, err) } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } }
func TestCgroups(t *testing.T) { ctx := newRktRunCtx() defer ctx.cleanup() t.Logf("Running test: %v", cgroupsTest.testName) aciFileName := patchTestACI("rkt-inspect-isolators.aci", cgroupsTest.aciBuildArgs...) defer os.Remove(aciFileName) rktCmd := fmt.Sprintf("%s --insecure-skip-verify run --mds-register=false %s", ctx.cmd(), aciFileName) t.Logf("Command: %v", rktCmd) child, err := gexpect.Spawn(rktCmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } expectedLine := "check-cgroups: SUCCESS" if err := expectWithOutput(child, expectedLine); err != nil { t.Fatalf("Didn't receive expected output %q: %v", expectedLine, err) } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } }
func TestAppIsolatorMemory(t *testing.T) { ok := cgroup.IsIsolatorSupported("memory") if !ok { t.Skip("Memory isolator not supported.") } ctx := newRktRunCtx() defer ctx.cleanup() t.Logf("Running test: %v", memoryTest.testName) aciFileName := "rkt-inspect-isolators.aci" patchTestACI(aciFileName, memoryTest.aciBuildArgs...) defer os.Remove(aciFileName) rktCmd := fmt.Sprintf("%s %s", ctx.cmd(), memoryTest.rktArgs) t.Logf("Command: %v", rktCmd) child, err := gexpect.Spawn(rktCmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } expectedLine := "Memory Limit: " + strconv.Itoa(maxMemoryUsage) if err := expectWithOutput(child, expectedLine); err != nil { t.Fatalf("Didn't receive expected output %q: %v", expectedLine, err) } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } }
/* * Default-restricted private-net * --- * Container launches http server on all its interfaces * Host must be able to connects to container's http server via container's * eth0's IPv4 * TODO: verify that the container isn't NATed */ func TestPrivateNetDefaultRestrictedConnectivity(t *testing.T) { httpServeAddr := "0.0.0.0:54321" iface := "eth0" testImageArgs := []string{fmt.Sprintf("--exec=/inspect --print-ipv4=%v --serve-http=%v", iface, httpServeAddr)} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) ctx := newRktRunCtx() defer ctx.cleanup() defer ctx.reset() cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --private-net=default-restricted --mds-register=false %s", ctx.cmd(), testImage) t.Logf("Command: %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } expectedRegex := `IPv4: (.*)\r` result, _ := child.ExpectRegexFind(expectedRegex) if len(result) == 0 { t.Fatalf("Expected %q but not found", expectedRegex) } httpGetAddr := fmt.Sprintf("http://%v:54321", result[1]) var wg sync.WaitGroup // Child opens the server wg.Add(1) go func() { defer wg.Done() err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } }() // Host connects to the child wg.Add(1) go func() { defer wg.Done() expectedRegex := `serving on` result, _ := child.ExpectRegexFind(expectedRegex) if len(result) == 0 { t.Fatalf("Expected %q but not found", expectedRegex) } body, err := test_netutils.HttpGet(httpGetAddr) if err != nil { log.Fatalf("%v\n", err) } log.Printf("HTTP-Get received: %s", body) if err != nil { log.Fatalf("%v\n", err) } }() wg.Wait() }
func preparePidFileRace(t *testing.T, ctx *rktRunCtx, sleepImage string) (*gexpect.ExpectSubprocess, *gexpect.ExpectSubprocess, string, string) { // Start the pod runCmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --mds-register=false --interactive %s", ctx.cmd(), sleepImage) t.Logf("%s", runCmd) runChild, err := gexpect.Spawn(runCmd) if err != nil { t.Fatalf("Cannot exec rkt") } err = expectWithOutput(runChild, "Enter text:") if err != nil { t.Fatalf("Waited for the prompt but not found: %v", err) } // Check the ppid file is really created cmd := fmt.Sprintf(`%s list --full|grep running`, ctx.cmd()) output, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput() if err != nil { t.Fatalf("Couldn't list the pods: %v", err) } UUID := strings.Split(string(output), "\t")[0] pidFileName := filepath.Join(ctx.dataDir(), "pods/run", UUID, "ppid") if _, err := os.Stat(pidFileName); err != nil { t.Fatalf("Pid file missing: %v", err) } // Temporarily move the ppid file away pidFileNameBackup := pidFileName + ".backup" if err := os.Rename(pidFileName, pidFileNameBackup); err != nil { t.Fatalf("Cannot move ppid file away: %v", err) } // Start the "enter" command without the pidfile enterCmd := fmt.Sprintf("%s --debug enter %s /inspect --print-msg=RktEnterWorksFine", ctx.cmd(), UUID) t.Logf("%s", enterCmd) enterChild, err := gexpect.Spawn(enterCmd) if err != nil { t.Fatalf("Cannot exec rkt enter") } // Enter should be able to wait until the ppid file appears time.Sleep(1 * time.Second) return runChild, enterChild, pidFileName, pidFileNameBackup }
func TestVolumes(t *testing.T) { readFileImage := patchTestACI("rkt-inspect-read-file.aci", "--exec=/inspect --read-file") defer os.Remove(readFileImage) writeFileImage := patchTestACI("rkt-inspect-write-file.aci", "--exec=/inspect --write-file --read-file") defer os.Remove(writeFileImage) volRwReadFileImage := patchTestACI("rkt-inspect-vol-rw-read-file.aci", "--exec=/inspect --read-file", "--mounts=dir1,path=/dir1,readOnly=false") defer os.Remove(volRwReadFileImage) volRwWriteFileImage := patchTestACI("rkt-inspect-vol-rw-write-file.aci", "--exec=/inspect --write-file --read-file", "--mounts=dir1,path=/dir1,readOnly=false") defer os.Remove(volRwWriteFileImage) volRoReadFileImage := patchTestACI("rkt-inspect-vol-ro-read-file.aci", "--exec=/inspect --read-file", "--mounts=dir1,path=/dir1,readOnly=true") defer os.Remove(volRoReadFileImage) volRoWriteFileImage := patchTestACI("rkt-inspect-vol-ro-write-file.aci", "--exec=/inspect --write-file --read-file", "--mounts=dir1,path=/dir1,readOnly=true") defer os.Remove(volRoWriteFileImage) ctx := newRktRunCtx() defer ctx.cleanup() tmpdir, err := ioutil.TempDir("", "rkt-tests.") if err != nil { t.Fatalf("Cannot create temporary directory: %v", err) } defer os.RemoveAll(tmpdir) tmpfile := filepath.Join(tmpdir, "file") err = ioutil.WriteFile(tmpfile, []byte("host"), 0600) if err != nil { t.Fatalf("Cannot create temporary file: %v", err) } for i, tt := range volTests { cmd := strings.Replace(tt.rktCmd, "^TMPDIR^", tmpdir, -1) cmd = strings.Replace(cmd, "^RKT_BIN^", ctx.cmd(), -1) cmd = strings.Replace(cmd, "^READ_FILE^", readFileImage, -1) cmd = strings.Replace(cmd, "^WRITE_FILE^", writeFileImage, -1) cmd = strings.Replace(cmd, "^VOL_RO_READ_FILE^", volRoReadFileImage, -1) cmd = strings.Replace(cmd, "^VOL_RO_WRITE_FILE^", volRoWriteFileImage, -1) cmd = strings.Replace(cmd, "^VOL_RW_READ_FILE^", volRwReadFileImage, -1) cmd = strings.Replace(cmd, "^VOL_RW_WRITE_FILE^", volRwWriteFileImage, -1) t.Logf("Running test #%v: %v", i, cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } err = expectWithOutput(child, tt.expect) if err != nil { fmt.Printf("Command: %s\n", cmd) t.Fatalf("Expected %q but not found #%v: %v", tt.expect, i, err) } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } } }
func main() { log.Printf("Testing Ping interact... \n") child, err := gexpect.Spawn("ping -c8 127.0.0.1") if err != nil { panic(err) } child.Interact() log.Printf("Success\n") }
// expectedRunRkt tries to fetch and run a prog.aci from host within // given directory on host. Note that directory can be anything - it's // useful for ensuring that image name is unique and for descriptive // purposes. func expectedRunRkt(ctx *rktRunCtx, t *testing.T, host, dir, line string) { cmd := fmt.Sprintf(`%s --debug --insecure-skip-verify run --mds-register=false %s/%s/prog.aci`, ctx.cmd(), host, dir) t.Logf("Running rkt: %s", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Failed to run rkt: %v", err) } defer child.Wait() if err := expectWithOutput(child, line); err != nil { t.Fatalf("Didn't receive expected output %q: %v", line, err) } }
func TestCaps(t *testing.T) { ctx := newRktRunCtx() defer ctx.cleanup() for i, tt := range capsTests { var stage1FileName = "rkt-inspect-print-caps-stage1.aci" var stage2FileName = "rkt-inspect-print-caps-stage2.aci" stage1Args := []string{"--exec=/inspect --print-caps-pid=1 --print-user"} stage2Args := []string{"--exec=/inspect --print-caps-pid=0 --print-user"} if tt.capIsolator != "" { stage1Args = append(stage1Args, "--capability="+tt.capIsolator) stage2Args = append(stage2Args, "--capability="+tt.capIsolator) } patchTestACI(stage1FileName, stage1Args...) patchTestACI(stage2FileName, stage2Args...) defer os.Remove(stage1FileName) defer os.Remove(stage2FileName) for _, stage := range []int{1, 2} { t.Logf("Running test #%v: %v [stage %v]", i, tt.testName, stage) cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --set-env=CAPABILITY=%d ./rkt-inspect-print-caps-stage%d.aci", ctx.cmd(), int(tt.capa), stage) t.Logf("Command: %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } expectedLine := tt.capa.String() if (stage == 1 && tt.capInStage1Expected) || (stage == 2 && tt.capInStage2Expected) { expectedLine += "=enabled" } else { expectedLine += "=disabled" } err = expectWithOutput(child, expectedLine) if err != nil { t.Fatalf("Expected %q but not found: %v", expectedLine, err) } err = expectWithOutput(child, "User: uid=0 euid=0 gid=0 egid=0") if err != nil { t.Fatalf("Expected user 0 but not found: %v", err) } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } } ctx.reset() } }
func main() { waitChan := make(chan string) fmt.Printf("Starting screen.. \n") child, err := gexpect.Spawn("screen") if err != nil { panic(err) } sender, reciever := child.AsyncInteractChannels() go func() { waitString := "" count := 0 for { select { case waitString = <-waitChan: count++ case msg, open := <-reciever: if !open { return } fmt.Printf("Recieved: %s\n", msg) if strings.Contains(msg, waitString) { if count >= 1 { waitChan <- msg count -= 1 } } } } }() wait := func(str string) { waitChan <- str <-waitChan } fmt.Printf("Waiting until started.. \n") wait(" ") fmt.Printf("Sending Enter.. \n") sender <- "\n" wait("$") fmt.Printf("Sending echo.. \n") sender <- "echo Hello World\n" wait("Hello World") fmt.Printf("Received echo. \n") }
func main() { fmt.Printf("Starting python.. \n") child, err := gexpect.Spawn("python") if err != nil { panic(err) } fmt.Printf("Expecting >>>.. \n") child.Expect(">>>") fmt.Printf("print 'Hello World'..\n") child.SendLine("print 'Hello World'") child.Expect(">>>") fmt.Printf("Interacting.. \n") child.Interact() fmt.Printf("Done \n") child.Close() }
func getImageId(ctx *rktRunCtx, name string) (string, error) { cmd := fmt.Sprintf(`/bin/sh -c "%s image list --fields=key,appname --no-legend | grep %s | awk '{print $1}'"`, ctx.cmd(), name) child, err := gexpect.Spawn(cmd) if err != nil { return "", fmt.Errorf("Cannot exec rkt: %v", err) } imageID, err := child.ReadLine() imageID = strings.TrimSpace(imageID) imageID = string(bytes.Trim([]byte(imageID), "\x00")) if err != nil { return "", fmt.Errorf("Cannot exec: %v", err) } if err := child.Wait(); err != nil { return "", fmt.Errorf("rkt didn't terminate correctly: %v", err) } return imageID, nil }
func TestNonRootCaps(t *testing.T) { ctx := newRktRunCtx() defer ctx.cleanup() for i, tt := range capsTests { var fileName = "rkt-inspect-print-caps-nonroot.aci" var args []string args = []string{"--exec=/inspect --print-caps-pid=0 --print-user", "--user=9000", "--group=9000"} if tt.capIsolator != "" { args = append(args, "--capability="+tt.capIsolator) } patchTestACI(fileName, args...) defer os.Remove(fileName) t.Logf("Running test #%v: %v [non-root]", i, tt.testName) cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --set-env=CAPABILITY=%d ./%s", ctx.cmd(), int(tt.capa), fileName) t.Logf("Command: %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } expectedLine := tt.capa.String() if tt.nonrootCapExpected { expectedLine += "=enabled" } else { expectedLine += "=disabled" } err = expectWithOutput(child, expectedLine) if err != nil { t.Fatalf("Expected %q but not found: %v", expectedLine, err) } err = expectWithOutput(child, "User: uid=9000 euid=9000 gid=9000 egid=9000") if err != nil { t.Fatalf("Expected user 9000 but not found: %v", err) } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } ctx.reset() } }
/* * No private net * --- * Container launches http server which must be reachable by the host via the * localhost address */ func TestPrivateNetOmittedConnectivity(t *testing.T) { httpServeAddr := "0.0.0.0:54321" httpGetAddr := "http://127.0.0.1:54321" testImageArgs := []string{"--exec=/inspect --serve-http=" + httpServeAddr} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) ctx := newRktRunCtx() defer ctx.cleanup() defer ctx.reset() cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --mds-register=false %s", ctx.cmd(), testImage) t.Logf("Command: %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } // Child opens the server c := make(chan struct{}) go func() { err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } c <- struct{}{} }() // Host connects to the child go func() { expectedRegex := `serving on` result, _ := child.ExpectRegexFind(expectedRegex) if len(result) == 0 { t.Fatalf("Expected %q but not found", expectedRegex) } body, err := test_netutils.HttpGet(httpGetAddr) if err != nil { log.Fatalf("%v\n", err) } log.Printf("HTTP-Get received: %s", body) }() <-c }
func removeImageId(ctx *rktRunCtx, imageID string, shouldWork bool) error { expect := fmt.Sprintf(rmImageReferenced, imageID) if shouldWork { expect = rmImageOk } cmd := fmt.Sprintf("%s image rm %s", ctx.cmd(), imageID) child, err := gexpect.Spawn(cmd) if err != nil { return fmt.Errorf("Cannot exec: %v", err) } if err := expectWithOutput(child, expect); err != nil { return fmt.Errorf("Expected %q but not found: %v", expect, err) } if err := child.Wait(); err != nil { return fmt.Errorf("rkt didn't terminate correctly: %v", err) } return nil }
func TestInteractive(t *testing.T) { ctx := newRktRunCtx() defer ctx.cleanup() for i, tt := range interactiveTests { t.Logf("Running test #%v: %v", i, tt.testName) aciFileName := "rkt-inspect-interactive.aci" patchTestACI(aciFileName, tt.aciBuildArgs...) defer os.Remove(aciFileName) rktCmd := fmt.Sprintf("%s %s", ctx.cmd(), tt.rktArgs) t.Logf("Command: %v", rktCmd) child, err := gexpect.Spawn(rktCmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } if tt.say != "" { err = expectTimeoutWithOutput(child, "Enter text:", time.Minute) if err != nil { t.Fatalf("Waited for the prompt but not found #%v: %v", i, err) } err = child.SendLine(tt.say) if err != nil { t.Fatalf("Failed to send %q on the prompt #%v: %v", tt.say, i, err) } } err = expectTimeoutWithOutput(child, tt.expect, time.Minute) if err != nil { t.Fatalf("Expected %q but not found #%v: %v", tt.expect, i, err) } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } } }
func main() { log.Printf("Testing Ftp... ") child, err := gexpect.Spawn("ftp ftp.openbsd.org") if err != nil { panic(err) } child.Expect("Name") child.SendLine("anonymous") child.Expect("Password") child.SendLine("*****@*****.**") child.Expect("ftp> ") child.SendLine("cd /pub/OpenBSD/3.7/packages/i386") child.Expect("ftp> ") child.SendLine("bin") child.Expect("ftp> ") child.SendLine("prompt") child.Expect("ftp> ") child.SendLine("pwd") child.Expect("ftp> ") log.Printf("Success\n") }
/* * Default private-net * --- * Container must be in a separate network namespace with private-net */ func TestPrivateNetDefaultNetNS(t *testing.T) { testImageArgs := []string{"--exec=/inspect --print-netns"} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) ctx := newRktRunCtx() defer ctx.cleanup() cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --private-net=default --mds-register=false %s", ctx.cmd(), testImage) t.Logf("Command: %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } expectedRegex := `NetNS: (net:\[\d+\])` result, _ := child.ExpectRegexFind(expectedRegex) if len(result) == 0 { t.Fatalf("Expected %q but not found", expectedRegex) } ns, err := os.Readlink("/proc/self/ns/net") if err != nil { t.Fatalf("Cannot evaluate NetNS symlink: %v", err) } if nsChanged := ns != result[1]; !nsChanged { t.Fatalf("container did not leave host netns") } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } ctx.reset() }
func TestFailure(t *testing.T) { patchTestACI("rkt-inspect-exit20.aci", "--exec=/inspect --print-msg=Hello --exit-code=20") defer os.Remove("rkt-inspect-exit20.aci") ctx := newRktRunCtx() defer ctx.cleanup() child, err := gexpect.Spawn(fmt.Sprintf("%s --debug --insecure-skip-verify run ./rkt-inspect-exit20.aci", ctx.cmd())) if err != nil { t.Fatalf("Cannot exec rkt") } err = child.Expect("Hello") if err != nil { t.Fatalf("Missing hello") } err = child.Expect("main process exited, code=exited, status=20") if err != nil { t.Fatalf("Missing hello") } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } }
// Test running pod manifests that contains just one app. // TODO(yifan): Add more tests for port mappings. and multiple apps. func TestPodManifest(t *testing.T) { ctx := newRktRunCtx() defer ctx.cleanup() tmpdir, err := ioutil.TempDir("", "rkt-tests.") if err != nil { t.Fatalf("Cannot create temporary directory: %v", err) } defer os.RemoveAll(tmpdir) boolFalse, boolTrue := false, true tests := []struct { imageName string imagePatches []string podManifest *schema.PodManifest shouldSuccess bool expectedResult string }{ { // Simple read. "rkt-test-run-pod-manifest-read.aci", []string{}, &schema.PodManifest{ Apps: []schema.RuntimeApp{ { Name: baseAppName, App: &types.App{ Exec: []string{"/inspect", "--read-file"}, User: "******", Group: "0", Environment: []types.EnvironmentVariable{ {"FILE", "/dir1/file"}, }, }, }, }, }, true, "dir1", }, { // Simple read after write with volume mounted. "rkt-test-run-pod-manifest-vol-rw.aci", []string{}, &schema.PodManifest{ Apps: []schema.RuntimeApp{ { Name: baseAppName, App: &types.App{ Exec: []string{"/inspect", "--write-file", "--read-file"}, User: "******", Group: "0", Environment: []types.EnvironmentVariable{ {"FILE", "/dir1/file"}, {"CONTENT", "host:foo"}, }, MountPoints: []types.MountPoint{ {"dir1", "/dir1", false}, }, }, }, }, Volumes: []types.Volume{ {"dir1", "host", tmpdir, nil}, }, }, true, "host:foo", }, { // Simple read after write with read-only mount point, should fail. "rkt-test-run-pod-manifest-vol-ro.aci", []string{}, &schema.PodManifest{ Apps: []schema.RuntimeApp{ { Name: baseAppName, App: &types.App{ Exec: []string{"/inspect", "--write-file", "--read-file"}, User: "******", Group: "0", Environment: []types.EnvironmentVariable{ {"FILE", "/dir1/file"}, {"CONTENT", "bar"}, }, MountPoints: []types.MountPoint{ {"dir1", "/dir1", true}, }, }, }, }, Volumes: []types.Volume{ {"dir1", "host", tmpdir, nil}, }, }, false, `Cannot write to file "/dir1/file": open /dir1/file: read-only file system`, }, { // Simple read after write with volume mounted. // Override the image's mount point spec. This should fail as the volume is // read-only in pod manifest, (which will override the mount point in both image/pod manifest). "rkt-test-run-pod-manifest-vol-rw-override.aci", []string{ "--mounts=dir1,path=/dir1,readOnly=false", }, &schema.PodManifest{ Apps: []schema.RuntimeApp{ { Name: baseAppName, App: &types.App{ Exec: []string{"/inspect", "--write-file", "--read-file"}, User: "******", Group: "0", Environment: []types.EnvironmentVariable{ {"FILE", "/dir1/file"}, {"CONTENT", "bar"}, }, MountPoints: []types.MountPoint{ {"dir1", "/dir1", false}, }, }, }, }, Volumes: []types.Volume{ {"dir1", "host", tmpdir, &boolTrue}, }, }, false, `Cannot write to file "/dir1/file": open /dir1/file: read-only file system`, }, { // Simple read after write with volume mounted. // Override the image's mount point spec. "rkt-test-run-pod-manifest-vol-rw-override.aci", []string{ "--mounts=dir1,path=/dir1,readOnly=true", }, &schema.PodManifest{ Apps: []schema.RuntimeApp{ { Name: baseAppName, App: &types.App{ Exec: []string{"/inspect", "--write-file", "--read-file"}, User: "******", Group: "0", Environment: []types.EnvironmentVariable{ {"FILE", "/dir2/file"}, {"CONTENT", "host:bar"}, }, MountPoints: []types.MountPoint{ {"dir1", "/dir2", false}, }, }, }, }, Volumes: []types.Volume{ {"dir1", "host", tmpdir, nil}, }, }, true, "host:bar", }, { // Simple read after write with volume mounted, no apps in pod manifest. "rkt-test-run-pod-manifest-vol-rw-no-app.aci", []string{ "--exec=/inspect --write-file --read-file --file-name=/dir1/file --content=host:baz", "--mounts=dir1,path=/dir1,readOnly=false", }, &schema.PodManifest{ Apps: []schema.RuntimeApp{ {Name: baseAppName}, }, Volumes: []types.Volume{ {"dir1", "host", tmpdir, nil}, }, }, true, "host:baz", }, { // Simple read after write with volume mounted, no apps in pod manifest. // This should succeed even the mount point in image manifest is readOnly, // because it is overrided by the volume's readOnly. "rkt-test-run-pod-manifest-vol-ro-no-app.aci", []string{ "--exec=/inspect --write-file --read-file --file-name=/dir1/file --content=host:zaz", "--mounts=dir1,path=/dir1,readOnly=true", }, &schema.PodManifest{ Apps: []schema.RuntimeApp{ {Name: baseAppName}, }, Volumes: []types.Volume{ {"dir1", "host", tmpdir, &boolFalse}, }, }, true, "host:zaz", }, { // Simple read after write with read-only volume mounted, no apps in pod manifest. // This should fail as the volume is read-only. "rkt-test-run-pod-manifest-vol-ro-no-app.aci", []string{ "--exec=/inspect --write-file --read-file --file-name=/dir1/file --content=baz", "--mounts=dir1,path=/dir1,readOnly=false", }, &schema.PodManifest{ Apps: []schema.RuntimeApp{ {Name: baseAppName}, }, Volumes: []types.Volume{ {"dir1", "host", tmpdir, &boolTrue}, }, }, false, `Cannot write to file "/dir1/file": open /dir1/file: read-only file system`, }, } for i, tt := range tests { patchTestACI(tt.imageName, tt.imagePatches...) hash := importImageAndFetchHash(t, ctx, tt.imageName) defer os.Remove(tt.imageName) tt.podManifest.ACKind = schema.PodManifestKind tt.podManifest.ACVersion = schema.AppContainerVersion imgName := types.MustACIdentifier(tt.imageName) imgID, err := types.NewHash(hash) if err != nil { t.Fatalf("Cannot generate types.Hash from %v: %v", hash, err) } for i := range tt.podManifest.Apps { ra := &tt.podManifest.Apps[i] ra.Image.Name = imgName ra.Image.ID = *imgID } manifestFile := generatePodManifestFile(t, tt.podManifest) defer os.Remove(manifestFile) // 1. Test 'rkt run'. runCmd := fmt.Sprintf("%s run --pod-manifest=%s", ctx.cmd(), manifestFile) t.Logf("Running 'run' test #%v: %v", i, runCmd) child, err := gexpect.Spawn(runCmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } if tt.expectedResult != "" { if err := child.Expect(tt.expectedResult); err != nil { t.Fatalf("Expected %q but not found: %v", tt.expectedResult, err) } } if err := child.Wait(); err != nil { if tt.shouldSuccess { t.Fatalf("rkt didn't terminate correctly: %v", err) } } verifyHostFile(t, tmpdir, "file", i, tt.expectedResult) // 2. Test 'rkt prepare' + 'rkt run-prepared'. cmds := strings.Fields(ctx.cmd()) prepareCmd := exec.Command(cmds[0], cmds[1:]...) prepareArg := fmt.Sprintf("--pod-manifest=%s", manifestFile) prepareCmd.Args = append(prepareCmd.Args, "--insecure-skip-verify", "prepare", prepareArg) output, err := prepareCmd.Output() if err != nil { t.Fatalf("Cannot read the output: %v", err) } podIDStr := strings.TrimSpace(string(output)) podID, err := types.NewUUID(podIDStr) if err != nil { t.Fatalf("%q is not a valid UUID: %v", podIDStr, err) } runPreparedCmd := fmt.Sprintf("%s run-prepared %s", ctx.cmd(), podID.String()) t.Logf("Running 'run' test #%v: %v", i, runPreparedCmd) child, err = gexpect.Spawn(runPreparedCmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } if tt.expectedResult != "" { if err := child.Expect(tt.expectedResult); err != nil { t.Fatalf("Expected %q but not found: %v", tt.expectedResult, err) } } if err := child.Wait(); err != nil { if tt.shouldSuccess { t.Fatalf("rkt didn't terminate correctly: %v", err) } } verifyHostFile(t, tmpdir, "file", i, tt.expectedResult) } }
func TestImageRm(t *testing.T) { patchTestACI(unreferencedACI, fmt.Sprintf("--name=%s", unreferencedApp)) defer os.Remove(unreferencedACI) ctx := newRktRunCtx() defer ctx.cleanup() cmd := fmt.Sprintf("%s --insecure-skip-verify fetch %s", ctx.cmd(), unreferencedACI) t.Logf("Fetching %s: %v", unreferencedACI, cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec: %v", err) } if err := child.Wait(); err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } cmd = fmt.Sprintf("%s --insecure-skip-verify run %s", ctx.cmd(), referencedACI) t.Logf("Running %s: %v", referencedACI, cmd) child, err = gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec: %v", err) } if err := child.Wait(); err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } t.Logf("Retrieving stage1 imageID") stage1ImageID, err := getImageId(ctx, stage1App) if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } t.Logf("Retrieving %s imageID", referencedApp) referencedImageID, err := getImageId(ctx, referencedApp) if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } t.Logf("Retrieving %s imageID", unreferencedApp) unreferencedImageID, err := getImageId(ctx, unreferencedApp) if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } t.Logf("Removing stage1 image (should fail as referenced)") if err := removeImageId(ctx, stage1ImageID, false); err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("Removing image for app %s (should fail as referenced)", referencedApp) if err := removeImageId(ctx, referencedImageID, false); err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("Removing image for app %s (should work)", unreferencedApp) if err := removeImageId(ctx, unreferencedImageID, true); err != nil { t.Fatalf("unexpected error: %v", err) } cmd = fmt.Sprintf("%s gc --grace-period=0s", ctx.cmd()) t.Logf("Running gc: %v", cmd) child, err = gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec: %v", err) } if err := child.Wait(); err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } t.Logf("Removing stage1 image (should work)") if err := removeImageId(ctx, stage1ImageID, true); err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("Removing image for app %s (should work)", referencedApp) if err := removeImageId(ctx, referencedImageID, true); err != nil { t.Fatalf("unexpected error: %v", err) } }
// TestImageExport tests 'rkt image export', it will import some existing // image, export it with rkt image export and check that the exported ACI hash // matches the hash of the imported ACI func TestImageExport(t *testing.T) { testImage := "rkt-inspect-image-export.aci" testImageName := "coreos.com/rkt-image-export-test" expectManifest := strings.Replace(manifestExportTemplate, "IMG_NAME", testImageName, -1) tmpDir, err := ioutil.TempDir("", "rkt-TestImageExport-") if err != nil { panic(fmt.Sprintf("Cannot create temp dir: %v", err)) } defer os.RemoveAll(tmpDir) tmpManifest, err := ioutil.TempFile(tmpDir, "manifest") if err != nil { panic(fmt.Sprintf("Cannot create temp manifest: %v", err)) } defer tmpManifest.Close() tmpManifestName := tmpManifest.Name() if err := ioutil.WriteFile(tmpManifestName, []byte(expectManifest), 0600); err != nil { panic(fmt.Sprintf("Cannot write to temp manifest: %v", err)) } defer os.Remove(tmpManifestName) patchTestACI(testImage, "--manifest", tmpManifestName) defer os.Remove(testImage) ctx := newRktRunCtx() defer ctx.cleanup() testImageKey := importImageAndFetchHash(t, ctx, testImage) testImageHash, err := getHash(testImage) if err != nil { panic(fmt.Sprintf("Error getting image hash: %v", err)) } tests := []struct { image string shouldFind bool expectedHash string }{ { testImageName, true, testImageHash, }, { testImageKey, true, testImageHash, }, { "sha512-not-existed", false, "", }, { "some~random~aci~name", false, "", }, } for i, tt := range tests { outputAciPath := filepath.Join(tmpDir, fmt.Sprintf("exported-%d.aci", i)) runCmd := fmt.Sprintf("%s image export %s %s", ctx.cmd(), tt.image, outputAciPath) t.Logf("Running 'image export' test #%v: %v", i, runCmd) child, err := gexpect.Spawn(runCmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } if err := child.Wait(); err != nil { if !tt.shouldFind && err.Error() == "exit status 1" { continue } else if tt.shouldFind || err.Error() != "exit status 1" { t.Fatalf("rkt didn't terminate correctly: %v", err) } } exportedHash, err := getHash(outputAciPath) if err != nil { t.Fatalf("Error getting exported image hash: %v", err) } if exportedHash != tt.expectedHash { t.Fatalf("Expected hash %q but got %s", tt.expectedHash, exportedHash) } } }
// TestRunPrepareFromFile tests that when 'rkt run/prepare' a local ACI, it will bypass the // on-disk store. func TestRunPrepareFromFile(t *testing.T) { foundMsg := "found image in local store" image := "rkt-inspect-implicit-fetch.aci" imagePath := patchTestACI(image, "--exec=/inspect") defer os.Remove(imagePath) tests := []string{ imagePath, "file://" + imagePath, } ctx := newRktRunCtx() defer ctx.cleanup() importImageAndFetchHash(t, ctx, imagePath) for _, tt := range tests { // 1. Try run/prepare with '--local', should not get the $foundMsg, since we will ignore the '--local' when // the image is a filepath. cmds := []string{ fmt.Sprintf("%s --insecure-skip-verify run --mds-register=false --local %s", ctx.cmd(), tt), fmt.Sprintf("%s --insecure-skip-verify prepare --local %s", ctx.cmd(), tt), } for _, cmd := range cmds { t.Logf("Running test %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } if err := child.Expect(foundMsg); err == nil { t.Fatalf("%q should not be found", foundMsg) } if err := child.Wait(); err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } } // 2. Try run/prepare without '--local', should not get $foundMsg either. cmds = []string{ fmt.Sprintf("%s --insecure-skip-verify run --mds-register=false %s", ctx.cmd(), tt), fmt.Sprintf("%s --insecure-skip-verify prepare %s", ctx.cmd(), tt), } for _, cmd := range cmds { t.Logf("Running test %v", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } if err := child.Expect(foundMsg); err == nil { t.Fatalf("%q should not be found", foundMsg) } if err := child.Wait(); err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } } } }
// TestCatManifest tests 'rkt image cat-manifest', it will: // Read some existing image manifest via the image name, and verify the result. // Read some existing image manifest via the image hash, and verify the result. // Read some non-existing image manifest via the image name, and verify nothing is found. // Read some non-existing image manifest via the image hash, and verify nothing is found. func TestCatManifest(t *testing.T) { testImage := "rkt-inspect-image-cat-manifest.aci" testImageName := "coreos.com/rkt-cat-manifest-test" expectManifest := strings.Replace(manifestTemplate, "IMG_NAME", testImageName, -1) tmpManifest, err := ioutil.TempFile("", "rkt-TestCatManifest-") if err != nil { t.Fatalf("Cannot create temp manifest: %v", err) } if err := ioutil.WriteFile(tmpManifest.Name(), []byte(expectManifest), 0600); err != nil { t.Fatalf("Cannot write to temp manifest: %v", err) } defer os.Remove(tmpManifest.Name()) patchTestACI(testImage, "--manifest", tmpManifest.Name()) defer os.Remove(testImage) ctx := newRktRunCtx() defer ctx.cleanup() testImageHash := importImageAndFetchHash(t, ctx, testImage) tests := []struct { image string shouldFind bool expect string }{ { testImageName, true, expectManifest, }, { testImageHash, true, expectManifest, }, { "sha512-not-existed", false, "", }, { "some~random~aci~name", false, "", }, } for i, tt := range tests { runCmd := fmt.Sprintf("%s image cat-manifest %s", ctx.cmd(), tt.image) t.Logf("Running 'run' test #%v: %v", i, runCmd) child, err := gexpect.Spawn(runCmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } if tt.expect != "" { if err := expectWithOutput(child, tt.expect); err != nil { t.Fatalf("Expected %q but not found: %v", tt.expect, err) } } if err := child.Wait(); err != nil { if tt.shouldFind || err.Error() != "exit status 1" { t.Fatalf("rkt didn't terminate correctly: %v", err) } } } }
// TestImageRender tests 'rkt image render', it will import some existing empty // image with a dependency on an image with the inspect binary, render it with // rkt image render and check that the exported image has the /inspect file and // that its hash matches the original inspect binary hash func TestImageRender(t *testing.T) { baseImage := os.Getenv("RKT_INSPECT_IMAGE") if baseImage == "" { panic("Empty RKT_INSPECT_IMAGE environment variable") } emptyImage := os.Getenv("RKT_EMPTY_IMAGE") if emptyImage == "" { panic("Empty RKT_INSPECT_IMAGE environment variable") } testImageName := "coreos.com/rkt-image-render-test" inspectFile := os.Getenv("INSPECT_BINARY") if inspectFile == "" { panic("Empty INSPECT_BINARY environment variable") } inspectHash, err := getHash(inspectFile) if err != nil { panic("Cannot get inspect binary's hash") } expectManifest := strings.Replace(manifestRenderTemplate, "IMG_NAME", testImageName, -1) tmpDir, err := ioutil.TempDir("", "rkt-TestImageRender-") if err != nil { panic(fmt.Sprintf("Cannot create temp dir: %v", err)) } 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(expectManifest), 0600); err != nil { panic(fmt.Sprintf("Cannot write to temp manifest: %v", err)) } defer os.Remove(tmpManifest.Name()) testImage := patchACI(emptyImage, "rkt-inspect-image-render.aci", "--manifest", tmpManifest.Name()) defer os.Remove(testImage) ctx := newRktRunCtx() defer ctx.cleanup() _ = importImageAndFetchHash(t, ctx, baseImage) testImageShortHash := importImageAndFetchHash(t, ctx, testImage) tests := []struct { image string shouldFind bool expectedHash string }{ { testImageName, true, inspectHash, }, { testImageShortHash, true, inspectHash, }, { "sha512-not-existed", false, "", }, { "some~random~aci~name", false, "", }, } for i, tt := range tests { outputPath := filepath.Join(tmpDir, fmt.Sprintf("rendered-%d", i)) runCmd := fmt.Sprintf("%s image render --rootfs-only %s %s", ctx.cmd(), tt.image, outputPath) t.Logf("Running 'image render' test #%v: %v", i, runCmd) child, err := gexpect.Spawn(runCmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } if err := child.Wait(); err != nil { if !tt.shouldFind && err.Error() == "exit status 1" { continue } else if tt.shouldFind || err.Error() != "exit status 1" { t.Fatalf("rkt didn't terminate correctly: %v", err) } } renderedInspectHash, err := getHash(filepath.Join(outputPath, "inspect")) if err != nil { t.Fatalf("Cannot get rendered inspect binary's hash") } if renderedInspectHash != tt.expectedHash { t.Fatalf("Expected /inspect hash %q but got %s", tt.expectedHash, renderedInspectHash) } } }
func TestEnv(t *testing.T) { printVarFromManifestImage := patchTestACI("rkt-inspect-print-var-from-manifest.aci", "--exec=/inspect --print-env=VAR_FROM_MANIFEST") defer os.Remove(printVarFromManifestImage) printVarOtherImage := patchTestACI("rkt-inspect-print-var-other.aci", "--exec=/inspect --print-env=VAR_OTHER") defer os.Remove(printVarOtherImage) sleepImage := patchTestACI("rkt-inspect-sleep.aci", "--exec=/inspect --read-stdin") defer os.Remove(sleepImage) ctx := newRktRunCtx() defer ctx.cleanup() replacePlaceholders := func(cmd string) string { fixed := cmd fixed = strings.Replace(fixed, "^RKT_BIN^", ctx.cmd(), -1) fixed = strings.Replace(fixed, "^PRINT_VAR_FROM_MANIFEST^", printVarFromManifestImage, -1) fixed = strings.Replace(fixed, "^PRINT_VAR_OTHER^", printVarOtherImage, -1) fixed = strings.Replace(fixed, "^SLEEP^", sleepImage, -1) return fixed } for i, tt := range envTests { // 'run' tests runCmd := replacePlaceholders(tt.runCmd) t.Logf("Running 'run' test #%v: %v", i, runCmd) child, err := gexpect.Spawn(runCmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } err = expectWithOutput(child, tt.runExpect) if err != nil { t.Fatalf("Expected %q but not found: %v", tt.runExpect, err) } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } // 'enter' tests sleepCmd := replacePlaceholders(tt.sleepCmd) t.Logf("Running 'enter' test #%v: sleep: %v", i, sleepCmd) child, err = gexpect.Spawn(sleepCmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } err = expectWithOutput(child, "Enter text:") if err != nil { t.Fatalf("Waited for the prompt but not found #%v: %v", i, err) } enterCmd := replacePlaceholders(tt.enterCmd) t.Logf("Running 'enter' test #%v: enter: %v", i, enterCmd) enterChild, err := gexpect.Spawn(enterCmd) if err != nil { t.Fatalf("Cannot exec rkt #%v: %v", i, err) } err = expectWithOutput(enterChild, tt.runExpect) if err != nil { t.Fatalf("Expected %q but not found: %v", tt.runExpect, err) } err = enterChild.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } err = child.SendLine("Bye") if err != nil { t.Fatalf("rkt couldn't write to the container: %v", err) } err = expectWithOutput(child, "Received text: Bye") if err != nil { t.Fatalf("Expected Bye but not found #%v: %v", i, err) } err = child.Wait() if err != nil { t.Fatalf("rkt didn't terminate correctly: %v", err) } ctx.reset() } }