func cleanContainers(c *check.C) *docker.Project { client, err := dockerclient.NewEnvClient() c.Assert(err, check.IsNil) filterArgs := filters.NewArgs() filterArgs, err = filters.ParseFlag(d.KermitLabelFilter, filterArgs) c.Assert(err, check.IsNil) containers, err := client.ContainerList(context.Background(), types.ContainerListOptions{ All: true, Filter: filterArgs, }) c.Assert(err, check.IsNil) for _, container := range containers { c.Logf("cleaning container %s…", container.ID) if err := client.ContainerRemove(context.Background(), container.ID, types.ContainerRemoveOptions{ Force: true, }); err != nil { c.Errorf("Error while removing container %s : %v\n", container.ID, err) } } return docker.NewProject(client) }
// ensure tags cannot create ambiguity with image ids func (s *DockerSuite) TestTagTruncationAmbiguity(c *check.C) { imageID, err := buildImage("notbusybox:latest", `FROM busybox MAINTAINER dockerio`, true) if err != nil { c.Fatal(err) } truncatedImageID := stringid.TruncateID(imageID) truncatedTag := fmt.Sprintf("notbusybox:%s", truncatedImageID) id := inspectField(c, truncatedTag, "Id") // Ensure inspect by image id returns image for image id c.Assert(id, checker.Equals, imageID) c.Logf("Built image: %s", imageID) // test setting tag fails _, _, err = dockerCmdWithError("tag", "busybox:latest", truncatedTag) if err != nil { c.Fatalf("Error tagging with an image id: %s", err) } id = inspectField(c, truncatedTag, "Id") // Ensure id is imageID and not busybox:latest c.Assert(id, checker.Not(checker.Equals), imageID) }
func (s *DockerSwarmSuite) TestServiceLogs(c *check.C) { testRequires(c, ExperimentalDaemon) d := s.AddDaemon(c, true, true) // we have multiple services here for detecting the goroutine issue #28915 services := map[string]string{ "TestServiceLogs1": "hello1", "TestServiceLogs2": "hello2", } for name, message := range services { out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", fmt.Sprintf("echo %s; tail -f /dev/null", message)) c.Assert(err, checker.IsNil) c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "") } // make sure task has been deployed. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, len(services)) for name, message := range services { out, err := d.Cmd("service", "logs", name) c.Assert(err, checker.IsNil) c.Logf("log for %q: %q", name, out) c.Assert(out, checker.Contains, message) } }
func myLog(c *check.C, args ...interface{}) { if len(args) == 1 { c.Log(fmt.Sprintf("%s: %v\n", c.TestName(), args[0])) return } newArgs := make([]interface{}, len(args)-1) for i, a := range args[1:] { switch a := a.(type) { default: j, err := json.Marshal(a) if err == nil { newArgs[i] = fmt.Sprintf("%T: %s", a, j) } else { newArgs[i] = fmt.Sprintf("%s", a) } case bool: newArgs[i] = a case int: newArgs[i] = a case uint: newArgs[i] = a case uint64: newArgs[i] = a case string: newArgs[i] = a } } fmtStr := fmt.Sprintf("%s: %s\n", c.TestName(), args[0].(string)) c.Logf(fmtStr, newArgs...) }
func checkPsAncestorFilterOutput(c *check.C, out string, filterName string, expectedIDs []string) { actualIDs := []string{} if out != "" { actualIDs = strings.Split(out[:len(out)-1], "\n") } sort.Strings(actualIDs) sort.Strings(expectedIDs) if len(actualIDs) != len(expectedIDs) { c.Fatalf("Expected filtered container(s) for %s ancestor filter to be %v:%v, got %v:%v", filterName, len(expectedIDs), expectedIDs, len(actualIDs), actualIDs) } if len(expectedIDs) > 0 { same := true for i := range expectedIDs { if actualIDs[i] != expectedIDs[i] { c.Logf("%s, %s", actualIDs[i], expectedIDs[i]) same = false break } } if !same { c.Fatalf("Expected filtered container(s) for %s ancestor filter to be %v, got %v", filterName, expectedIDs, actualIDs) } } }
func (s *DockerSuite) TestRunPrivilegedAllowedDevices(c *check.C) { testRequires(c, DaemonIsLinux, NotUserNamespace) file := "/sys/fs/cgroup/devices/devices.list" out, _ := dockerCmd(c, "run", "--privileged", "busybox", "cat", file) c.Logf("out: %q", out) c.Assert(strings.TrimSpace(out), checker.Equals, "a *:* rwm") }
// Stop will send a SIGINT every second and wait for the daemon to stop. // If it times out, a SIGKILL is sent. // Stop will not delete the daemon directory. If a purged daemon is needed, // instantiate a new one with NewDaemon. // If an error occurs while starting the daemon, the test will fail. func (d *Daemon) Stop(c *check.C) { err := d.StopWithError() if err != nil { if err != errDaemonNotStarted { c.Fatalf("Error while stopping the daemon %s : %v", d.id, err) } else { c.Logf("Daemon %s is not started", d.id) } } }
func runDockerCp(c *check.C, src, dst string) (err error) { c.Logf("running `docker cp %s %s`", src, dst) args := []string{"cp", src, dst} out, _, err := runCommandWithOutput(exec.Command(dockerBinary, args...)) if err != nil { err = fmt.Errorf("error executing `docker cp` command: %s: %s", err, out) } return }
func startContainerGetOutput(c *check.C, cID string) (out string, err error) { c.Logf("running `docker start -a %s`", cID) args := []string{"start", "-a", cID} out, _, err = runCommandWithOutput(exec.Command(dockerBinary, args...)) if err != nil { err = fmt.Errorf("error executing `docker start` command: %s: %s", err, out) } return }
func containerStartOutputEquals(c *check.C, cID, contents string) (err error) { c.Logf("checking that container %q start output contains %q\n", cID, contents) out, err := startContainerGetOutput(c, cID) if err != nil { return err } if out != contents { err = fmt.Errorf("output contents not equal - expected %q, got %q", contents, out) } return }
func symlinkTargetEquals(c *check.C, symlink, expectedTarget string) (err error) { c.Logf("checking that the symlink %q points to %q\n", symlink, expectedTarget) actualTarget, err := os.Readlink(symlink) if err != nil { return err } if actualTarget != expectedTarget { return fmt.Errorf("symlink target points to %q not %q", actualTarget, expectedTarget) } return nil }
func cleanupExecRoot(c *check.C, execRoot string) { // Cleanup network namespaces in the exec root of this // daemon because this exec root is specific to this // daemon instance and has no chance of getting // cleaned up when a new daemon is instantiated with a // new exec root. netnsPath := filepath.Join(execRoot, "netns") filepath.Walk(netnsPath, func(path string, info os.FileInfo, err error) error { if err := syscall.Unmount(path, syscall.MNT_FORCE); err != nil { c.Logf("unmount of %s failed: %v", path, err) } os.Remove(path) return nil }) }
func (s *DockerSwarmSuite) TearDownTest(c *check.C) { testRequires(c, DaemonIsLinux) s.daemonsLock.Lock() for _, d := range s.daemons { d.Stop() // raft state file is quite big (64MB) so remove it after every test walDir := filepath.Join(d.root, "swarm/raft/wal") if err := os.RemoveAll(walDir); err != nil { c.Logf("error removing %v: %v", walDir, err) } } s.daemons = nil s.daemonsLock.Unlock() s.portIndex = 0 s.ds.TearDownTest(c) }
func fileContentEquals(c *check.C, filename, contents string) (err error) { c.Logf("checking that file %q contains %q\n", filename, contents) fileBytes, err := ioutil.ReadFile(filename) if err != nil { return } expectedBytes, err := ioutil.ReadAll(strings.NewReader(contents)) if err != nil { return } if !bytes.Equal(fileBytes, expectedBytes) { err = fmt.Errorf("file content not equal - expected %q, got %q", string(expectedBytes), string(fileBytes)) } return }
// ensure tags cannot create ambiguity with image ids func (s *DockerSuite) TestTagTruncationAmbiguity(c *check.C) { //testRequires(c, DaemonIsLinux) // Don't attempt to pull on Windows as not in hub. It's installed // as an image through .ensure-frozen-images-windows if daemonPlatform != "windows" { if err := pullImageIfNotExist("busybox:latest"); err != nil { c.Fatal("couldn't find the busybox:latest image locally and failed to pull it") } } imageID, err := buildImage("notbusybox:latest", `FROM busybox MAINTAINER dockerio`, true) if err != nil { c.Fatal(err) } truncatedImageID := stringid.TruncateID(imageID) truncatedTag := fmt.Sprintf("notbusybox:%s", truncatedImageID) id, err := inspectField(truncatedTag, "Id") if err != nil { c.Fatalf("Error inspecting by image id: %s", err) } // Ensure inspect by image id returns image for image id c.Assert(id, checker.Equals, imageID) c.Logf("Built image: %s", imageID) // test setting tag fails _, _, err = dockerCmdWithError("tag", "busybox:latest", truncatedTag) if err != nil { c.Fatalf("Error tagging with an image id: %s", err) } id, err = inspectField(truncatedTag, "Id") if err != nil { c.Fatalf("Error inspecting by image id: %s", err) } // Ensure id is imageID and not busybox:latest c.Assert(id, checker.Not(checker.Equals), imageID) }
func checkPsAncestorFilterOutput(c *check.C, out string, filterName string, expectedIDs []string) { actualIDs := []string{} if out != "" { actualIDs = strings.Split(out[:len(out)-1], "\n") } sort.Strings(actualIDs) sort.Strings(expectedIDs) c.Assert(actualIDs, checker.HasLen, len(expectedIDs), check.Commentf("Expected filtered container(s) for %s ancestor filter to be %v:%v, got %v:%v", filterName, len(expectedIDs), expectedIDs, len(actualIDs), actualIDs)) if len(expectedIDs) > 0 { same := true for i := range expectedIDs { if actualIDs[i] != expectedIDs[i] { c.Logf("%s, %s", actualIDs[i], expectedIDs[i]) same = false break } } c.Assert(same, checker.Equals, true, check.Commentf("Expected filtered container(s) for %s ancestor filter to be %v, got %v", filterName, expectedIDs, actualIDs)) } }
func (s *DockerSwarmSuite) TearDownTest(c *check.C) { testRequires(c, DaemonIsLinux) s.daemonsLock.Lock() for _, d := range s.daemons { if d != nil { d.Stop(c) // FIXME(vdemeester) should be handled by SwarmDaemon ? // raft state file is quite big (64MB) so remove it after every test walDir := filepath.Join(d.Root, "swarm/raft/wal") if err := os.RemoveAll(walDir); err != nil { c.Logf("error removing %v: %v", walDir, err) } d.CleanupExecRoot(c) } } s.daemons = nil s.daemonsLock.Unlock() s.portIndex = 0 s.ds.TearDownTest(c) }
func (s *DockerSuite) TestHelpTextVerify(c *check.C) { testRequires(c, DaemonIsLinux) // Make sure main help text fits within 80 chars and that // on non-windows system we use ~ when possible (to shorten things). // Test for HOME set to its default value and set to "/" on linux // Yes on windows setting up an array and looping (right now) isn't // necessary because we just have one value, but we'll need the // array/loop on linux so we might as well set it up so that we can // test any number of home dirs later on and all we need to do is // modify the array - the rest of the testing infrastructure should work homes := []string{homedir.Get()} // Non-Windows machines need to test for this special case of $HOME if runtime.GOOS != "windows" { homes = append(homes, "/") } homeKey := homedir.Key() baseEnvs := appendBaseEnv(true) // Remove HOME env var from list so we can add a new value later. for i, env := range baseEnvs { if strings.HasPrefix(env, homeKey+"=") { baseEnvs = append(baseEnvs[:i], baseEnvs[i+1:]...) break } } for _, home := range homes { // Dup baseEnvs and add our new HOME value newEnvs := make([]string, len(baseEnvs)+1) copy(newEnvs, baseEnvs) newEnvs[len(newEnvs)-1] = homeKey + "=" + home scanForHome := runtime.GOOS != "windows" && home != "/" // Check main help text to make sure its not over 80 chars helpCmd := exec.Command(dockerBinary, "help") helpCmd.Env = newEnvs out, _, err := runCommandWithOutput(helpCmd) c.Assert(err, checker.IsNil, check.Commentf(out)) lines := strings.Split(out, "\n") foundTooLongLine := false for _, line := range lines { if !foundTooLongLine && len(line) > 80 { c.Logf("Line is too long:\n%s", line) foundTooLongLine = true } // All lines should not end with a space c.Assert(line, checker.Not(checker.HasSuffix), " ", check.Commentf("Line should not end with a space")) if scanForHome && strings.Contains(line, `=`+home) { c.Fatalf("Line should use '%q' instead of %q:\n%s", homedir.GetShortcutString(), home, line) } if runtime.GOOS != "windows" { i := strings.Index(line, homedir.GetShortcutString()) if i >= 0 && i != len(line)-1 && line[i+1] != '/' { c.Fatalf("Main help should not have used home shortcut:\n%s", line) } } } // Make sure each cmd's help text fits within 90 chars and that // on non-windows system we use ~ when possible (to shorten things). // Pull the list of commands from the "Commands:" section of docker help helpCmd = exec.Command(dockerBinary, "help") helpCmd.Env = newEnvs out, _, err = runCommandWithOutput(helpCmd) c.Assert(err, checker.IsNil, check.Commentf(out)) i := strings.Index(out, "Commands:") c.Assert(i, checker.GreaterOrEqualThan, 0, check.Commentf("Missing 'Commands:' in:\n%s", out)) cmds := []string{} // Grab all chars starting at "Commands:" helpOut := strings.Split(out[i:], "\n") // First line is just "Commands:" if isLocalDaemon { // Replace first line with "daemon" command since it's not part of the list of commands. helpOut[0] = " daemon" } else { // Skip first line helpOut = helpOut[1:] } // Create the list of commands we want to test cmdsToTest := []string{} for _, cmd := range helpOut { // Stop on blank line or non-idented line if cmd == "" || !unicode.IsSpace(rune(cmd[0])) { break } // Grab just the first word of each line cmd = strings.Split(strings.TrimSpace(cmd), " ")[0] cmds = append(cmds, cmd) // Saving count for later cmdsToTest = append(cmdsToTest, cmd) } // Add some 'two word' commands - would be nice to automatically // calculate this list - somehow cmdsToTest = append(cmdsToTest, "volume create") cmdsToTest = append(cmdsToTest, "volume inspect") cmdsToTest = append(cmdsToTest, "volume ls") cmdsToTest = append(cmdsToTest, "volume rm") for _, cmd := range cmdsToTest { var stderr string args := strings.Split(cmd+" --help", " ") // Check the full usage text helpCmd := exec.Command(dockerBinary, args...) helpCmd.Env = newEnvs out, stderr, _, err = runCommandWithStdoutStderr(helpCmd) c.Assert(len(stderr), checker.Equals, 0, check.Commentf("Error on %q help. non-empty stderr:%q", cmd, stderr)) c.Assert(out, checker.Not(checker.HasSuffix), "\n\n", check.Commentf("Should not have blank line on %q\n", cmd)) c.Assert(out, checker.Contains, "--help", check.Commentf("All commands should mention '--help'. Command '%v' did not.\n", cmd)) c.Assert(err, checker.IsNil, check.Commentf(out)) // Check each line for lots of stuff lines := strings.Split(out, "\n") for _, line := range lines { c.Assert(len(line), checker.LessOrEqualThan, 107, check.Commentf("Help for %q is too long:\n%s", cmd, line)) if scanForHome && strings.Contains(line, `"`+home) { c.Fatalf("Help for %q should use ~ instead of %q on:\n%s", cmd, home, line) } i := strings.Index(line, "~") if i >= 0 && i != len(line)-1 && line[i+1] != '/' { c.Fatalf("Help for %q should not have used ~:\n%s", cmd, line) } // If a line starts with 4 spaces then assume someone // added a multi-line description for an option and we need // to flag it c.Assert(line, checker.Not(checker.HasPrefix), " ", check.Commentf("Help for %q should not have a multi-line option", cmd)) // Options should NOT end with a period if strings.HasPrefix(line, " -") && strings.HasSuffix(line, ".") { c.Fatalf("Help for %q should not end with a period: %s", cmd, line) } // Options should NOT end with a space c.Assert(line, checker.Not(checker.HasSuffix), " ", check.Commentf("Help for %q should not end with a space", cmd)) } // For each command make sure we generate an error // if we give a bad arg args = strings.Split(cmd+" --badArg", " ") out, _, err = dockerCmdWithError(args...) c.Assert(err, checker.NotNil, check.Commentf(out)) // Be really picky c.Assert(stderr, checker.Not(checker.HasSuffix), "\n\n", check.Commentf("Should not have a blank line at the end of 'docker rm'\n")) // Now make sure that each command will print a short-usage // (not a full usage - meaning no opts section) if we // are missing a required arg or pass in a bad arg // These commands will never print a short-usage so don't test noShortUsage := map[string]string{ "images": "", "login": "", "logout": "", "network": "", "stats": "", } if _, ok := noShortUsage[cmd]; !ok { // For each command run it w/o any args. It will either return // valid output or print a short-usage var dCmd *exec.Cmd var stdout, stderr string var args []string // skipNoArgs are ones that we don't want to try w/o // any args. Either because it'll hang the test or // lead to incorrect test result (like false negative). // Whatever the reason, skip trying to run w/o args and // jump to trying with a bogus arg. skipNoArgs := map[string]struct{}{ "daemon": {}, "events": {}, "load": {}, } ec := 0 if _, ok := skipNoArgs[cmd]; !ok { args = strings.Split(cmd, " ") dCmd = exec.Command(dockerBinary, args...) stdout, stderr, ec, err = runCommandWithStdoutStderr(dCmd) } // If its ok w/o any args then try again with an arg if ec == 0 { args = strings.Split(cmd+" badArg", " ") dCmd = exec.Command(dockerBinary, args...) stdout, stderr, ec, err = runCommandWithStdoutStderr(dCmd) } if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { c.Fatalf("Bad output from %q\nstdout:%q\nstderr:%q\nec:%d\nerr:%q", args, stdout, stderr, ec, err) } // Should have just short usage c.Assert(stderr, checker.Contains, "\nUsage:\t", check.Commentf("Missing short usage on %q\n", args)) // But shouldn't have full usage c.Assert(stderr, checker.Not(checker.Contains), "--help=false", check.Commentf("Should not have full usage on %q\n", args)) c.Assert(stderr, checker.Not(checker.HasSuffix), "\n\n", check.Commentf("Should not have a blank line on %q\n", args)) } } // Number of commands for standard release and experimental release standard := 41 experimental := 1 expected := standard + experimental if isLocalDaemon { expected++ // for the daemon command } c.Assert(len(cmds), checker.LessOrEqualThan, expected, check.Commentf("Wrong # of cmds, it should be: %d\nThe list:\n%q", expected, cmds)) } }
func (s *DockerRegistrySuite) TestListDanglingImagesWithDigests(c *check.C) { // setup image1 digest1, err := setupImageWithTag(c, "dangle1") c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) imageReference1 := fmt.Sprintf("%s@%s", repoName, digest1) c.Logf("imageReference1 = %s", imageReference1) // pull image1 by digest dockerCmd(c, "pull", imageReference1) // list images out, _ := dockerCmd(c, "images", "--digests") // make sure repo shown, tag=<none>, digest = $digest1 re1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1.String() + `\s`) c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out)) // setup image2 digest2, err := setupImageWithTag(c, "dangle2") //error setting up image c.Assert(err, checker.IsNil) imageReference2 := fmt.Sprintf("%s@%s", repoName, digest2) c.Logf("imageReference2 = %s", imageReference2) // pull image1 by digest dockerCmd(c, "pull", imageReference1) // pull image2 by digest dockerCmd(c, "pull", imageReference2) // list images out, _ = dockerCmd(c, "images", "--digests", "--filter=\"dangling=true\"") // make sure repo shown, tag=<none>, digest = $digest1 c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out)) // make sure repo shown, tag=<none>, digest = $digest2 re2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2.String() + `\s`) c.Assert(re2.MatchString(out), checker.True, check.Commentf("expected %q: %s", re2.String(), out)) // pull dangle1 tag dockerCmd(c, "pull", repoName+":dangle1") // list images out, _ = dockerCmd(c, "images", "--digests", "--filter=\"dangling=true\"") // make sure image 1 has repo, tag, <none> AND repo, <none>, digest reWithDigest1 := regexp.MustCompile(`\s*` + repoName + `\s*dangle1\s*` + digest1.String() + `\s`) c.Assert(reWithDigest1.MatchString(out), checker.False, check.Commentf("unexpected %q: %s", reWithDigest1.String(), out)) // make sure image 2 has repo, <none>, digest c.Assert(re2.MatchString(out), checker.True, check.Commentf("expected %q: %s", re2.String(), out)) // pull dangle2 tag dockerCmd(c, "pull", repoName+":dangle2") // list images, show tagged images out, _ = dockerCmd(c, "images", "--digests") // make sure image 1 has repo, tag, digest c.Assert(reWithDigest1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest1.String(), out)) // make sure image 2 has repo, tag, digest reWithDigest2 := regexp.MustCompile(`\s*` + repoName + `\s*dangle2\s*` + digest2.String() + `\s`) c.Assert(reWithDigest2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest2.String(), out)) // list images, no longer dangling, should not match out, _ = dockerCmd(c, "images", "--digests", "--filter=\"dangling=true\"") // make sure image 1 has repo, tag, digest c.Assert(reWithDigest1.MatchString(out), checker.False, check.Commentf("unexpected %q: %s", reWithDigest1.String(), out)) // make sure image 2 has repo, tag, digest c.Assert(reWithDigest2.MatchString(out), checker.False, check.Commentf("unexpected %q: %s", reWithDigest2.String(), out)) }
func (s *DockerSuite) TestHelpTextVerify(c *check.C) { testRequires(c, DaemonIsLinux) // Make sure main help text fits within 80 chars and that // on non-windows system we use ~ when possible (to shorten things). // Test for HOME set to its default value and set to "/" on linux // Yes on windows setting up an array and looping (right now) isn't // necessary because we just have one value, but we'll need the // array/loop on linux so we might as well set it up so that we can // test any number of home dirs later on and all we need to do is // modify the array - the rest of the testing infrastructure should work homes := []string{homedir.Get()} // Non-Windows machines need to test for this special case of $HOME if runtime.GOOS != "windows" { homes = append(homes, "/") } homeKey := homedir.Key() baseEnvs := appendBaseEnv(true) // Remove HOME env var from list so we can add a new value later. for i, env := range baseEnvs { if strings.HasPrefix(env, homeKey+"=") { baseEnvs = append(baseEnvs[:i], baseEnvs[i+1:]...) break } } for _, home := range homes { // Dup baseEnvs and add our new HOME value newEnvs := make([]string, len(baseEnvs)+1) copy(newEnvs, baseEnvs) newEnvs[len(newEnvs)-1] = homeKey + "=" + home scanForHome := runtime.GOOS != "windows" && home != "/" // Check main help text to make sure its not over 80 chars helpCmd := exec.Command(dockerBinary, "help") helpCmd.Env = newEnvs out, _, err := runCommandWithOutput(helpCmd) c.Assert(err, checker.IsNil, check.Commentf(out)) lines := strings.Split(out, "\n") foundTooLongLine := false for _, line := range lines { if !foundTooLongLine && len(line) > 80 { c.Logf("Line is too long:\n%s", line) foundTooLongLine = true } // All lines should not end with a space c.Assert(line, checker.Not(checker.HasSuffix), " ", check.Commentf("Line should not end with a space")) if scanForHome && strings.Contains(line, `=`+home) { c.Fatalf("Line should use '%q' instead of %q:\n%s", homedir.GetShortcutString(), home, line) } if runtime.GOOS != "windows" { i := strings.Index(line, homedir.GetShortcutString()) if i >= 0 && i != len(line)-1 && line[i+1] != '/' { c.Fatalf("Main help should not have used home shortcut:\n%s", line) } } } // Make sure each cmd's help text fits within 90 chars and that // on non-windows system we use ~ when possible (to shorten things). // Pull the list of commands from the "Commands:" section of docker help helpCmd = exec.Command(dockerBinary, "help") helpCmd.Env = newEnvs out, _, err = runCommandWithOutput(helpCmd) c.Assert(err, checker.IsNil, check.Commentf(out)) i := strings.Index(out, "Commands:") c.Assert(i, checker.GreaterOrEqualThan, 0, check.Commentf("Missing 'Commands:' in:\n%s", out)) cmds := []string{} // Grab all chars starting at "Commands:" helpOut := strings.Split(out[i:], "\n") // First line is just "Commands:" if isLocalDaemon { // Replace first line with "daemon" command since it's not part of the list of commands. helpOut[0] = " daemon" } else { // Skip first line helpOut = helpOut[1:] } // Create the list of commands we want to test cmdsToTest := []string{} for _, cmd := range helpOut { // Stop on blank line or non-idented line if cmd == "" || !unicode.IsSpace(rune(cmd[0])) { break } // Grab just the first word of each line cmd = strings.Split(strings.TrimSpace(cmd), " ")[0] cmds = append(cmds, cmd) // Saving count for later cmdsToTest = append(cmdsToTest, cmd) } // Add some 'two word' commands - would be nice to automatically // calculate this list - somehow cmdsToTest = append(cmdsToTest, "volume create") cmdsToTest = append(cmdsToTest, "volume inspect") cmdsToTest = append(cmdsToTest, "volume ls") cmdsToTest = append(cmdsToTest, "volume rm") // Divide the list of commands into go routines and run the func testcommand on the commands in parallel // to save runtime of test errChan := make(chan error) for index := 0; index < len(cmdsToTest); index++ { go func(index int) { errChan <- testCommand(cmdsToTest[index], newEnvs, scanForHome, home) }(index) } for index := 0; index < len(cmdsToTest); index++ { err := <-errChan if err != nil { c.Fatal(err) } } // Number of commands for standard release and experimental release standard := 41 experimental := 1 expected := standard + experimental if isLocalDaemon { expected++ // for the daemon command } c.Assert(len(cmds), checker.LessOrEqualThan, expected, check.Commentf("Wrong # of cmds, it should be: %d\nThe list:\n%q", expected, cmds)) } }
func (s *DockerRegistrySuite) TestListImagesWithDigests(c *check.C) { // setup image1 digest1, err := setupImageWithTag(c, "tag1") c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) imageReference1 := fmt.Sprintf("%s@%s", repoName, digest1) c.Logf("imageReference1 = %s", imageReference1) // pull image1 by digest dockerCmd(c, "pull", imageReference1) // list images out, _ := dockerCmd(c, "images", "--digests") // make sure repo shown, tag=<none>, digest = $digest1 re1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1.String() + `\s`) c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out)) // setup image2 digest2, err := setupImageWithTag(c, "tag2") //error setting up image c.Assert(err, checker.IsNil) imageReference2 := fmt.Sprintf("%s@%s", repoName, digest2) c.Logf("imageReference2 = %s", imageReference2) // pull image1 by digest dockerCmd(c, "pull", imageReference1) // pull image2 by digest dockerCmd(c, "pull", imageReference2) // list images out, _ = dockerCmd(c, "images", "--digests") // make sure repo shown, tag=<none>, digest = $digest1 c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out)) // make sure repo shown, tag=<none>, digest = $digest2 re2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2.String() + `\s`) c.Assert(re2.MatchString(out), checker.True, check.Commentf("expected %q: %s", re2.String(), out)) // pull tag1 dockerCmd(c, "pull", repoName+":tag1") // list images out, _ = dockerCmd(c, "images", "--digests") // make sure image 1 has repo, tag, <none> AND repo, <none>, digest reWithTag1 := regexp.MustCompile(`\s*` + repoName + `\s*tag1\s*<none>\s`) reWithDigest1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1.String() + `\s`) c.Assert(reWithDigest1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest1.String(), out)) c.Assert(reWithTag1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithTag1.String(), out)) // make sure image 2 has repo, <none>, digest c.Assert(re2.MatchString(out), checker.True, check.Commentf("expected %q: %s", re2.String(), out)) // pull tag 2 dockerCmd(c, "pull", repoName+":tag2") // list images out, _ = dockerCmd(c, "images", "--digests") // make sure image 1 has repo, tag, digest c.Assert(reWithTag1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithTag1.String(), out)) // make sure image 2 has repo, tag, digest reWithTag2 := regexp.MustCompile(`\s*` + repoName + `\s*tag2\s*<none>\s`) reWithDigest2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2.String() + `\s`) c.Assert(reWithTag2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithTag2.String(), out)) c.Assert(reWithDigest2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest2.String(), out)) // list images out, _ = dockerCmd(c, "images", "--digests") // make sure image 1 has repo, tag, digest c.Assert(reWithTag1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithTag1.String(), out)) // make sure image 2 has repo, tag, digest c.Assert(reWithTag2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithTag2.String(), out)) // make sure busybox has tag, but not digest busyboxRe := regexp.MustCompile(`\s*busybox\s*latest\s*<none>\s`) c.Assert(busyboxRe.MatchString(out), checker.True, check.Commentf("expected %q: %s", busyboxRe.String(), out)) }
func (s *DockerRegistrySuite) TestListImagesWithDigests(c *check.C) { // setup image1 digest1, err := setupImageWithTag("tag1") if err != nil { c.Fatalf("error setting up image: %v", err) } imageReference1 := fmt.Sprintf("%s@%s", repoName, digest1) c.Logf("imageReference1 = %s", imageReference1) // pull image1 by digest cmd := exec.Command(dockerBinary, "pull", imageReference1) out, _, err := runCommandWithOutput(cmd) if err != nil { c.Fatalf("error pulling by digest: %s, %v", out, err) } // list images cmd = exec.Command(dockerBinary, "images", "--digests") out, _, err = runCommandWithOutput(cmd) if err != nil { c.Fatalf("error listing images: %s, %v", out, err) } // make sure repo shown, tag=<none>, digest = $digest1 re1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1 + `\s`) if !re1.MatchString(out) { c.Fatalf("expected %q: %s", re1.String(), out) } // setup image2 digest2, err := setupImageWithTag("tag2") if err != nil { c.Fatalf("error setting up image: %v", err) } imageReference2 := fmt.Sprintf("%s@%s", repoName, digest2) c.Logf("imageReference2 = %s", imageReference2) // pull image1 by digest cmd = exec.Command(dockerBinary, "pull", imageReference1) out, _, err = runCommandWithOutput(cmd) if err != nil { c.Fatalf("error pulling by digest: %s, %v", out, err) } // pull image2 by digest cmd = exec.Command(dockerBinary, "pull", imageReference2) out, _, err = runCommandWithOutput(cmd) if err != nil { c.Fatalf("error pulling by digest: %s, %v", out, err) } // list images cmd = exec.Command(dockerBinary, "images", "--digests") out, _, err = runCommandWithOutput(cmd) if err != nil { c.Fatalf("error listing images: %s, %v", out, err) } // make sure repo shown, tag=<none>, digest = $digest1 if !re1.MatchString(out) { c.Fatalf("expected %q: %s", re1.String(), out) } // make sure repo shown, tag=<none>, digest = $digest2 re2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2 + `\s`) if !re2.MatchString(out) { c.Fatalf("expected %q: %s", re2.String(), out) } // pull tag1 cmd = exec.Command(dockerBinary, "pull", repoName+":tag1") out, _, err = runCommandWithOutput(cmd) if err != nil { c.Fatalf("error pulling tag1: %s, %v", out, err) } // list images cmd = exec.Command(dockerBinary, "images", "--digests") out, _, err = runCommandWithOutput(cmd) if err != nil { c.Fatalf("error listing images: %s, %v", out, err) } // make sure image 1 has repo, tag, <none> AND repo, <none>, digest reWithTag1 := regexp.MustCompile(`\s*` + repoName + `\s*tag1\s*<none>\s`) reWithDigest1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1 + `\s`) if !reWithTag1.MatchString(out) { c.Fatalf("expected %q: %s", reWithTag1.String(), out) } if !reWithDigest1.MatchString(out) { c.Fatalf("expected %q: %s", reWithDigest1.String(), out) } // make sure image 2 has repo, <none>, digest if !re2.MatchString(out) { c.Fatalf("expected %q: %s", re2.String(), out) } // pull tag 2 cmd = exec.Command(dockerBinary, "pull", repoName+":tag2") out, _, err = runCommandWithOutput(cmd) if err != nil { c.Fatalf("error pulling tag2: %s, %v", out, err) } // list images cmd = exec.Command(dockerBinary, "images", "--digests") out, _, err = runCommandWithOutput(cmd) if err != nil { c.Fatalf("error listing images: %s, %v", out, err) } // make sure image 1 has repo, tag, digest if !reWithTag1.MatchString(out) { c.Fatalf("expected %q: %s", re1.String(), out) } // make sure image 2 has repo, tag, digest reWithTag2 := regexp.MustCompile(`\s*` + repoName + `\s*tag2\s*<none>\s`) reWithDigest2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2 + `\s`) if !reWithTag2.MatchString(out) { c.Fatalf("expected %q: %s", reWithTag2.String(), out) } if !reWithDigest2.MatchString(out) { c.Fatalf("expected %q: %s", reWithDigest2.String(), out) } // list images cmd = exec.Command(dockerBinary, "images", "--digests") out, _, err = runCommandWithOutput(cmd) if err != nil { c.Fatalf("error listing images: %s, %v", out, err) } // make sure image 1 has repo, tag, digest if !reWithTag1.MatchString(out) { c.Fatalf("expected %q: %s", re1.String(), out) } // make sure image 2 has repo, tag, digest if !reWithTag2.MatchString(out) { c.Fatalf("expected %q: %s", re2.String(), out) } // make sure busybox has tag, but not digest busyboxRe := regexp.MustCompile(`\s*busybox\s*latest\s*<none>\s`) if !busyboxRe.MatchString(out) { c.Fatalf("expected %q: %s", busyboxRe.String(), out) } }