Signed-off-by: Antonio Murdaca <me@runcom.ninja>
| ... | ... |
@@ -1,4 +1,4 @@ |
| 1 |
-.PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration test-integration-cli test-docker-py validate |
|
| 1 |
+.PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration-cli test-docker-py validate |
|
| 2 | 2 |
|
| 3 | 3 |
# env vars passed through directly to Docker's build scripts |
| 4 | 4 |
# to allow things like `make DOCKER_CLIENTONLY=1 binary` easily |
| ... | ... |
@@ -62,14 +62,11 @@ docs-test: docs-build |
| 62 | 62 |
$(DOCKER_RUN_DOCS) "$(DOCKER_DOCS_IMAGE)" ./test.sh |
| 63 | 63 |
|
| 64 | 64 |
test: build |
| 65 |
- $(DOCKER_RUN_DOCKER) hack/make.sh binary cross test-unit test-integration test-integration-cli test-docker-py |
|
| 65 |
+ $(DOCKER_RUN_DOCKER) hack/make.sh binary cross test-unit test-integration-cli test-docker-py |
|
| 66 | 66 |
|
| 67 | 67 |
test-unit: build |
| 68 | 68 |
$(DOCKER_RUN_DOCKER) hack/make.sh test-unit |
| 69 | 69 |
|
| 70 |
-test-integration: build |
|
| 71 |
- $(DOCKER_RUN_DOCKER) hack/make.sh test-integration |
|
| 72 |
- |
|
| 73 | 70 |
test-integration-cli: build |
| 74 | 71 |
$(DOCKER_RUN_DOCKER) hack/make.sh binary test-integration-cli |
| 75 | 72 |
|
| ... | ... |
@@ -57,7 +57,6 @@ DEFAULT_BUNDLES=( |
| 57 | 57 |
test-docker-py |
| 58 | 58 |
|
| 59 | 59 |
dynbinary |
| 60 |
- test-integration |
|
| 61 | 60 |
|
| 62 | 61 |
cover |
| 63 | 62 |
cross |
| ... | ... |
@@ -216,7 +215,6 @@ find_dirs() {
|
| 216 | 216 |
find . -not \( \ |
| 217 | 217 |
\( \ |
| 218 | 218 |
-path './vendor/*' \ |
| 219 |
- -o -path './integration/*' \ |
|
| 220 | 219 |
-o -path './integration-cli/*' \ |
| 221 | 220 |
-o -path './contrib/*' \ |
| 222 | 221 |
-o -path './pkg/mflag/example/*' \ |
| 223 | 222 |
deleted file mode 100644 |
| ... | ... |
@@ -1,25 +0,0 @@ |
| 1 |
-#!/bin/bash |
|
| 2 |
-set -e |
|
| 3 |
- |
|
| 4 |
-DEST=$1 |
|
| 5 |
- |
|
| 6 |
-INIT=$DEST/../dynbinary/dockerinit-$VERSION |
|
| 7 |
-[ -x "$INIT" ] || {
|
|
| 8 |
- source "${MAKEDIR}/.dockerinit"
|
|
| 9 |
- INIT="$DEST/dockerinit" |
|
| 10 |
-} |
|
| 11 |
-export TEST_DOCKERINIT_PATH="$INIT" |
|
| 12 |
- |
|
| 13 |
-bundle_test_integration() {
|
|
| 14 |
- LDFLAGS=" |
|
| 15 |
- $LDFLAGS |
|
| 16 |
- -X $DOCKER_PKG/dockerversion.INITSHA1 \"$DOCKER_INITSHA1\" |
|
| 17 |
- " go_test_dir ./integration \ |
|
| 18 |
- "-coverpkg $(find_dirs '*.go' | sed 's,^\.,'$DOCKER_PKG',g' | paste -d, -s)" |
|
| 19 |
-} |
|
| 20 |
- |
|
| 21 |
-# this "grep" hides some really irritating warnings that "go test -coverpkg" |
|
| 22 |
-# spews when it is given packages that aren't used |
|
| 23 |
-bundle_test_integration 2>&1 \ |
|
| 24 |
- | grep --line-buffered -v '^warning: no packages being tested depend on ' \ |
|
| 25 |
- | tee -a "$DEST/test.log" |
| ... | ... |
@@ -858,3 +858,185 @@ func (s *DockerSuite) TestContainerApiRename(c *check.C) {
|
| 858 | 858 |
c.Fatalf("Failed to rename container, expected %v, got %v. Container rename API failed", newName, name)
|
| 859 | 859 |
} |
| 860 | 860 |
} |
| 861 |
+ |
|
| 862 |
+func (s *DockerSuite) TestContainerApiKill(c *check.C) {
|
|
| 863 |
+ name := "test-api-kill" |
|
| 864 |
+ runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") |
|
| 865 |
+ out, _, err := runCommandWithOutput(runCmd) |
|
| 866 |
+ if err != nil {
|
|
| 867 |
+ c.Fatalf("Error on container creation: %v, output: %q", err, out)
|
|
| 868 |
+ } |
|
| 869 |
+ |
|
| 870 |
+ status, _, err := sockRequest("POST", "/containers/"+name+"/kill", nil)
|
|
| 871 |
+ c.Assert(status, check.Equals, http.StatusNoContent) |
|
| 872 |
+ c.Assert(err, check.IsNil) |
|
| 873 |
+ |
|
| 874 |
+ state, err := inspectField(name, "State.Running") |
|
| 875 |
+ if err != nil {
|
|
| 876 |
+ c.Fatal(err) |
|
| 877 |
+ } |
|
| 878 |
+ if state != "false" {
|
|
| 879 |
+ c.Fatalf("got wrong State from container %s: %q", name, state)
|
|
| 880 |
+ } |
|
| 881 |
+} |
|
| 882 |
+ |
|
| 883 |
+func (s *DockerSuite) TestContainerApiRestart(c *check.C) {
|
|
| 884 |
+ name := "test-api-restart" |
|
| 885 |
+ runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") |
|
| 886 |
+ out, _, err := runCommandWithOutput(runCmd) |
|
| 887 |
+ if err != nil {
|
|
| 888 |
+ c.Fatalf("Error on container creation: %v, output: %q", err, out)
|
|
| 889 |
+ } |
|
| 890 |
+ |
|
| 891 |
+ status, _, err := sockRequest("POST", "/containers/"+name+"/restart?t=1", nil)
|
|
| 892 |
+ c.Assert(status, check.Equals, http.StatusNoContent) |
|
| 893 |
+ c.Assert(err, check.IsNil) |
|
| 894 |
+ |
|
| 895 |
+ if err := waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 5); err != nil {
|
|
| 896 |
+ c.Fatal(err) |
|
| 897 |
+ } |
|
| 898 |
+} |
|
| 899 |
+ |
|
| 900 |
+func (s *DockerSuite) TestContainerApiStart(c *check.C) {
|
|
| 901 |
+ name := "testing-start" |
|
| 902 |
+ config := map[string]interface{}{
|
|
| 903 |
+ "Image": "busybox", |
|
| 904 |
+ "Cmd": []string{"/bin/sh", "-c", "/bin/top"},
|
|
| 905 |
+ "OpenStdin": true, |
|
| 906 |
+ } |
|
| 907 |
+ |
|
| 908 |
+ status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
|
|
| 909 |
+ c.Assert(status, check.Equals, http.StatusCreated) |
|
| 910 |
+ c.Assert(err, check.IsNil) |
|
| 911 |
+ |
|
| 912 |
+ conf := make(map[string]interface{})
|
|
| 913 |
+ status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf)
|
|
| 914 |
+ c.Assert(status, check.Equals, http.StatusNoContent) |
|
| 915 |
+ c.Assert(err, check.IsNil) |
|
| 916 |
+ |
|
| 917 |
+ // second call to start should give 304 |
|
| 918 |
+ status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf)
|
|
| 919 |
+ c.Assert(status, check.Equals, http.StatusNotModified) |
|
| 920 |
+ c.Assert(err, check.IsNil) |
|
| 921 |
+} |
|
| 922 |
+ |
|
| 923 |
+func (s *DockerSuite) TestContainerApiStop(c *check.C) {
|
|
| 924 |
+ name := "test-api-stop" |
|
| 925 |
+ runCmd := exec.Command(dockerBinary, "run", "-di", "--name", name, "busybox", "top") |
|
| 926 |
+ out, _, err := runCommandWithOutput(runCmd) |
|
| 927 |
+ if err != nil {
|
|
| 928 |
+ c.Fatalf("Error on container creation: %v, output: %q", err, out)
|
|
| 929 |
+ } |
|
| 930 |
+ |
|
| 931 |
+ status, _, err := sockRequest("POST", "/containers/"+name+"/stop?t=1", nil)
|
|
| 932 |
+ c.Assert(status, check.Equals, http.StatusNoContent) |
|
| 933 |
+ c.Assert(err, check.IsNil) |
|
| 934 |
+ |
|
| 935 |
+ if err := waitInspect(name, "{{ .State.Running }}", "false", 5); err != nil {
|
|
| 936 |
+ c.Fatal(err) |
|
| 937 |
+ } |
|
| 938 |
+ |
|
| 939 |
+ // second call to start should give 304 |
|
| 940 |
+ status, _, err = sockRequest("POST", "/containers/"+name+"/stop?t=1", nil)
|
|
| 941 |
+ c.Assert(status, check.Equals, http.StatusNotModified) |
|
| 942 |
+ c.Assert(err, check.IsNil) |
|
| 943 |
+} |
|
| 944 |
+ |
|
| 945 |
+func (s *DockerSuite) TestContainerApiWait(c *check.C) {
|
|
| 946 |
+ name := "test-api-wait" |
|
| 947 |
+ runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "sleep", "5") |
|
| 948 |
+ out, _, err := runCommandWithOutput(runCmd) |
|
| 949 |
+ if err != nil {
|
|
| 950 |
+ c.Fatalf("Error on container creation: %v, output: %q", err, out)
|
|
| 951 |
+ } |
|
| 952 |
+ |
|
| 953 |
+ status, body, err := sockRequest("POST", "/containers/"+name+"/wait", nil)
|
|
| 954 |
+ c.Assert(status, check.Equals, http.StatusOK) |
|
| 955 |
+ c.Assert(err, check.IsNil) |
|
| 956 |
+ |
|
| 957 |
+ if err := waitInspect(name, "{{ .State.Running }}", "false", 5); err != nil {
|
|
| 958 |
+ c.Fatal(err) |
|
| 959 |
+ } |
|
| 960 |
+ |
|
| 961 |
+ var waitres types.ContainerWaitResponse |
|
| 962 |
+ if err := json.Unmarshal(body, &waitres); err != nil {
|
|
| 963 |
+ c.Fatalf("unable to unmarshal response body: %v", err)
|
|
| 964 |
+ } |
|
| 965 |
+ |
|
| 966 |
+ if waitres.StatusCode != 0 {
|
|
| 967 |
+ c.Fatalf("Expected wait response StatusCode to be 0, got %d", waitres.StatusCode)
|
|
| 968 |
+ } |
|
| 969 |
+} |
|
| 970 |
+ |
|
| 971 |
+func (s *DockerSuite) TestContainerApiCopy(c *check.C) {
|
|
| 972 |
+ name := "test-container-api-copy" |
|
| 973 |
+ runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test.txt") |
|
| 974 |
+ _, err := runCommand(runCmd) |
|
| 975 |
+ c.Assert(err, check.IsNil) |
|
| 976 |
+ |
|
| 977 |
+ postData := types.CopyConfig{
|
|
| 978 |
+ Resource: "/test.txt", |
|
| 979 |
+ } |
|
| 980 |
+ |
|
| 981 |
+ status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
|
|
| 982 |
+ c.Assert(err, check.IsNil) |
|
| 983 |
+ c.Assert(status, check.Equals, http.StatusOK) |
|
| 984 |
+ |
|
| 985 |
+ found := false |
|
| 986 |
+ for tarReader := tar.NewReader(bytes.NewReader(body)); ; {
|
|
| 987 |
+ h, err := tarReader.Next() |
|
| 988 |
+ if err != nil {
|
|
| 989 |
+ if err == io.EOF {
|
|
| 990 |
+ break |
|
| 991 |
+ } |
|
| 992 |
+ c.Fatal(err) |
|
| 993 |
+ } |
|
| 994 |
+ if h.Name == "test.txt" {
|
|
| 995 |
+ found = true |
|
| 996 |
+ break |
|
| 997 |
+ } |
|
| 998 |
+ } |
|
| 999 |
+ c.Assert(found, check.Equals, true) |
|
| 1000 |
+} |
|
| 1001 |
+ |
|
| 1002 |
+func (s *DockerSuite) TestContainerApiCopyResourcePathEmpty(c *check.C) {
|
|
| 1003 |
+ name := "test-container-api-copy-resource-empty" |
|
| 1004 |
+ runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox", "touch", "/test.txt") |
|
| 1005 |
+ _, err := runCommand(runCmd) |
|
| 1006 |
+ c.Assert(err, check.IsNil) |
|
| 1007 |
+ |
|
| 1008 |
+ postData := types.CopyConfig{
|
|
| 1009 |
+ Resource: "", |
|
| 1010 |
+ } |
|
| 1011 |
+ |
|
| 1012 |
+ status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
|
|
| 1013 |
+ c.Assert(err, check.IsNil) |
|
| 1014 |
+ c.Assert(status, check.Equals, http.StatusInternalServerError) |
|
| 1015 |
+ c.Assert(string(body), check.Matches, "Path cannot be empty\n") |
|
| 1016 |
+} |
|
| 1017 |
+ |
|
| 1018 |
+func (s *DockerSuite) TestContainerApiCopyResourcePathNotFound(c *check.C) {
|
|
| 1019 |
+ name := "test-container-api-copy-resource-not-found" |
|
| 1020 |
+ runCmd := exec.Command(dockerBinary, "run", "--name", name, "busybox") |
|
| 1021 |
+ _, err := runCommand(runCmd) |
|
| 1022 |
+ c.Assert(err, check.IsNil) |
|
| 1023 |
+ |
|
| 1024 |
+ postData := types.CopyConfig{
|
|
| 1025 |
+ Resource: "/notexist", |
|
| 1026 |
+ } |
|
| 1027 |
+ |
|
| 1028 |
+ status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
|
|
| 1029 |
+ c.Assert(err, check.IsNil) |
|
| 1030 |
+ c.Assert(status, check.Equals, http.StatusInternalServerError) |
|
| 1031 |
+ c.Assert(string(body), check.Matches, "Could not find the file /notexist in container "+name+"\n") |
|
| 1032 |
+} |
|
| 1033 |
+ |
|
| 1034 |
+func (s *DockerSuite) TestContainerApiCopyContainerNotFound(c *check.C) {
|
|
| 1035 |
+ postData := types.CopyConfig{
|
|
| 1036 |
+ Resource: "/something", |
|
| 1037 |
+ } |
|
| 1038 |
+ |
|
| 1039 |
+ status, _, err := sockRequest("POST", "/containers/notexists/copy", postData)
|
|
| 1040 |
+ c.Assert(err, check.IsNil) |
|
| 1041 |
+ c.Assert(status, check.Equals, http.StatusNotFound) |
|
| 1042 |
+} |
| ... | ... |
@@ -35,7 +35,7 @@ func (s *DockerSuite) TestApiImagesFilter(c *check.C) {
|
| 35 | 35 |
c.Fatal(err, out) |
| 36 | 36 |
} |
| 37 | 37 |
} |
| 38 |
- type image struct{ RepoTags []string }
|
|
| 38 |
+ type image types.Image |
|
| 39 | 39 |
getImages := func(filter string) []image {
|
| 40 | 40 |
v := url.Values{}
|
| 41 | 41 |
v.Set("filter", filter)
|
| ... | ... |
@@ -98,3 +98,25 @@ func (s *DockerSuite) TestApiImagesSaveAndLoad(c *check.C) {
|
| 98 | 98 |
c.Fatal("load did not work properly")
|
| 99 | 99 |
} |
| 100 | 100 |
} |
| 101 |
+ |
|
| 102 |
+func (s *DockerSuite) TestApiImagesDelete(c *check.C) {
|
|
| 103 |
+ name := "test-api-images-delete" |
|
| 104 |
+ out, err := buildImage(name, "FROM hello-world\nENV FOO bar", false) |
|
| 105 |
+ if err != nil {
|
|
| 106 |
+ c.Fatal(err) |
|
| 107 |
+ } |
|
| 108 |
+ defer deleteImages(name) |
|
| 109 |
+ id := strings.TrimSpace(out) |
|
| 110 |
+ |
|
| 111 |
+ if out, err := exec.Command(dockerBinary, "tag", name, "test:tag1").CombinedOutput(); err != nil {
|
|
| 112 |
+ c.Fatal(err, out) |
|
| 113 |
+ } |
|
| 114 |
+ |
|
| 115 |
+ status, _, err := sockRequest("DELETE", "/images/"+id, nil)
|
|
| 116 |
+ c.Assert(status, check.Equals, http.StatusConflict) |
|
| 117 |
+ c.Assert(err, check.IsNil) |
|
| 118 |
+ |
|
| 119 |
+ status, _, err = sockRequest("DELETE", "/images/test:tag1", nil)
|
|
| 120 |
+ c.Assert(status, check.Equals, http.StatusOK) |
|
| 121 |
+ c.Assert(err, check.IsNil) |
|
| 122 |
+} |
| 101 | 123 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,25 @@ |
| 0 |
+package main |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "net/http" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/go-check/check" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func (s *DockerSuite) TestApiOptionsRoute(c *check.C) {
|
|
| 9 |
+ status, _, err := sockRequest("OPTIONS", "/", nil)
|
|
| 10 |
+ c.Assert(status, check.Equals, http.StatusOK) |
|
| 11 |
+ c.Assert(err, check.IsNil) |
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+func (s *DockerSuite) TestApiGetEnabledCors(c *check.C) {
|
|
| 15 |
+ res, body, err := sockRequestRaw("GET", "/version", nil, "")
|
|
| 16 |
+ body.Close() |
|
| 17 |
+ c.Assert(err, check.IsNil) |
|
| 18 |
+ c.Assert(res.StatusCode, check.Equals, http.StatusOK) |
|
| 19 |
+ // TODO: @runcom incomplete tests, why old integration tests had this headers |
|
| 20 |
+ // and here none of the headers below are in the response? |
|
| 21 |
+ //c.Log(res.Header) |
|
| 22 |
+ //c.Assert(res.Header.Get("Access-Control-Allow-Origin"), check.Equals, "*")
|
|
| 23 |
+ //c.Assert(res.Header.Get("Access-Control-Allow-Headers"), check.Equals, "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
|
|
| 24 |
+} |
| ... | ... |
@@ -734,7 +734,7 @@ func (s *DockerDaemonSuite) TestDaemonUnixSockCleanedUp(c *check.C) {
|
| 734 | 734 |
} |
| 735 | 735 |
} |
| 736 | 736 |
|
| 737 |
-func (s *DockerDaemonSuite) TestDaemonwithwrongkey(c *check.C) {
|
|
| 737 |
+func (s *DockerDaemonSuite) TestDaemonWithWrongkey(c *check.C) {
|
|
| 738 | 738 |
type Config struct {
|
| 739 | 739 |
Crv string `json:"crv"` |
| 740 | 740 |
D string `json:"d"` |
| 741 | 741 |
deleted file mode 100644 |
| ... | ... |
@@ -1,23 +0,0 @@ |
| 1 |
-## Legacy integration tests |
|
| 2 |
- |
|
| 3 |
-`./integration` contains Docker's legacy integration tests. |
|
| 4 |
-It is DEPRECATED and will eventually be removed. |
|
| 5 |
- |
|
| 6 |
-### If you are a *CONTRIBUTOR* and want to add a test: |
|
| 7 |
- |
|
| 8 |
-* Consider mocking out side effects and contributing a *unit test* in the subsystem |
|
| 9 |
-you're modifying. For example, the remote API has unit tests in `./api/server/server_unit_tests.go`. |
|
| 10 |
-The events subsystem has unit tests in `./events/events_test.go`. And so on. |
|
| 11 |
- |
|
| 12 |
-* For end-to-end integration tests, please contribute to `./integration-cli`. |
|
| 13 |
- |
|
| 14 |
- |
|
| 15 |
-### If you are a *MAINTAINER* |
|
| 16 |
- |
|
| 17 |
-Please don't allow patches adding new tests to `./integration`. |
|
| 18 |
- |
|
| 19 |
-### If you are *LOOKING FOR A WAY TO HELP* |
|
| 20 |
- |
|
| 21 |
-Please consider porting tests away from `./integration` and into either unit tests or CLI tests. |
|
| 22 |
- |
|
| 23 |
-Any help will be greatly appreciated! |
| 24 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,680 +0,0 @@ |
| 1 |
-package docker |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "bufio" |
|
| 5 |
- "bytes" |
|
| 6 |
- "encoding/json" |
|
| 7 |
- "io" |
|
| 8 |
- "io/ioutil" |
|
| 9 |
- "net" |
|
| 10 |
- "net/http" |
|
| 11 |
- "net/http/httptest" |
|
| 12 |
- "testing" |
|
| 13 |
- "time" |
|
| 14 |
- |
|
| 15 |
- "github.com/docker/docker/api" |
|
| 16 |
- "github.com/docker/docker/api/server" |
|
| 17 |
- "github.com/docker/docker/api/types" |
|
| 18 |
- "github.com/docker/docker/engine" |
|
| 19 |
- "github.com/docker/docker/runconfig" |
|
| 20 |
- "github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar" |
|
| 21 |
-) |
|
| 22 |
- |
|
| 23 |
-func TestPostContainersKill(t *testing.T) {
|
|
| 24 |
- eng := NewTestEngine(t) |
|
| 25 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 26 |
- |
|
| 27 |
- containerID := createTestContainer(eng, |
|
| 28 |
- &runconfig.Config{
|
|
| 29 |
- Image: unitTestImageID, |
|
| 30 |
- Cmd: runconfig.NewCommand("/bin/cat"),
|
|
| 31 |
- OpenStdin: true, |
|
| 32 |
- }, |
|
| 33 |
- t, |
|
| 34 |
- ) |
|
| 35 |
- |
|
| 36 |
- startContainer(eng, containerID, t) |
|
| 37 |
- |
|
| 38 |
- // Give some time to the process to start |
|
| 39 |
- containerWaitTimeout(eng, containerID, t) |
|
| 40 |
- |
|
| 41 |
- if !containerRunning(eng, containerID, t) {
|
|
| 42 |
- t.Errorf("Container should be running")
|
|
| 43 |
- } |
|
| 44 |
- |
|
| 45 |
- r := httptest.NewRecorder() |
|
| 46 |
- req, err := http.NewRequest("POST", "/containers/"+containerID+"/kill", bytes.NewReader([]byte{}))
|
|
| 47 |
- if err != nil {
|
|
| 48 |
- t.Fatal(err) |
|
| 49 |
- } |
|
| 50 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 51 |
- assertHttpNotError(r, t) |
|
| 52 |
- if r.Code != http.StatusNoContent {
|
|
| 53 |
- t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
|
|
| 54 |
- } |
|
| 55 |
- if containerRunning(eng, containerID, t) {
|
|
| 56 |
- t.Fatalf("The container hasn't been killed")
|
|
| 57 |
- } |
|
| 58 |
-} |
|
| 59 |
- |
|
| 60 |
-func TestPostContainersRestart(t *testing.T) {
|
|
| 61 |
- eng := NewTestEngine(t) |
|
| 62 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 63 |
- |
|
| 64 |
- containerID := createTestContainer(eng, |
|
| 65 |
- &runconfig.Config{
|
|
| 66 |
- Image: unitTestImageID, |
|
| 67 |
- Cmd: runconfig.NewCommand("/bin/top"),
|
|
| 68 |
- OpenStdin: true, |
|
| 69 |
- }, |
|
| 70 |
- t, |
|
| 71 |
- ) |
|
| 72 |
- |
|
| 73 |
- startContainer(eng, containerID, t) |
|
| 74 |
- |
|
| 75 |
- // Give some time to the process to start |
|
| 76 |
- containerWaitTimeout(eng, containerID, t) |
|
| 77 |
- |
|
| 78 |
- if !containerRunning(eng, containerID, t) {
|
|
| 79 |
- t.Errorf("Container should be running")
|
|
| 80 |
- } |
|
| 81 |
- |
|
| 82 |
- req, err := http.NewRequest("POST", "/containers/"+containerID+"/restart?t=1", bytes.NewReader([]byte{}))
|
|
| 83 |
- if err != nil {
|
|
| 84 |
- t.Fatal(err) |
|
| 85 |
- } |
|
| 86 |
- r := httptest.NewRecorder() |
|
| 87 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 88 |
- assertHttpNotError(r, t) |
|
| 89 |
- if r.Code != http.StatusNoContent {
|
|
| 90 |
- t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
|
|
| 91 |
- } |
|
| 92 |
- |
|
| 93 |
- // Give some time to the process to restart |
|
| 94 |
- containerWaitTimeout(eng, containerID, t) |
|
| 95 |
- |
|
| 96 |
- if !containerRunning(eng, containerID, t) {
|
|
| 97 |
- t.Fatalf("Container should be running")
|
|
| 98 |
- } |
|
| 99 |
- |
|
| 100 |
- containerKill(eng, containerID, t) |
|
| 101 |
-} |
|
| 102 |
- |
|
| 103 |
-func TestPostContainersStart(t *testing.T) {
|
|
| 104 |
- eng := NewTestEngine(t) |
|
| 105 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 106 |
- |
|
| 107 |
- containerID := createTestContainer( |
|
| 108 |
- eng, |
|
| 109 |
- &runconfig.Config{
|
|
| 110 |
- Image: unitTestImageID, |
|
| 111 |
- Cmd: runconfig.NewCommand("/bin/cat"),
|
|
| 112 |
- OpenStdin: true, |
|
| 113 |
- }, |
|
| 114 |
- t, |
|
| 115 |
- ) |
|
| 116 |
- |
|
| 117 |
- hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{})
|
|
| 118 |
- |
|
| 119 |
- req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
|
|
| 120 |
- if err != nil {
|
|
| 121 |
- t.Fatal(err) |
|
| 122 |
- } |
|
| 123 |
- |
|
| 124 |
- req.Header.Set("Content-Type", "application/json")
|
|
| 125 |
- |
|
| 126 |
- r := httptest.NewRecorder() |
|
| 127 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 128 |
- assertHttpNotError(r, t) |
|
| 129 |
- if r.Code != http.StatusNoContent {
|
|
| 130 |
- t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
|
|
| 131 |
- } |
|
| 132 |
- |
|
| 133 |
- containerAssertExists(eng, containerID, t) |
|
| 134 |
- |
|
| 135 |
- req, err = http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
|
|
| 136 |
- if err != nil {
|
|
| 137 |
- t.Fatal(err) |
|
| 138 |
- } |
|
| 139 |
- |
|
| 140 |
- req.Header.Set("Content-Type", "application/json")
|
|
| 141 |
- |
|
| 142 |
- r = httptest.NewRecorder() |
|
| 143 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 144 |
- |
|
| 145 |
- // Starting an already started container should return a 304 |
|
| 146 |
- assertHttpNotError(r, t) |
|
| 147 |
- if r.Code != http.StatusNotModified {
|
|
| 148 |
- t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
|
|
| 149 |
- } |
|
| 150 |
- containerAssertExists(eng, containerID, t) |
|
| 151 |
- containerKill(eng, containerID, t) |
|
| 152 |
-} |
|
| 153 |
- |
|
| 154 |
-func TestPostContainersStop(t *testing.T) {
|
|
| 155 |
- eng := NewTestEngine(t) |
|
| 156 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 157 |
- |
|
| 158 |
- containerID := createTestContainer(eng, |
|
| 159 |
- &runconfig.Config{
|
|
| 160 |
- Image: unitTestImageID, |
|
| 161 |
- Cmd: runconfig.NewCommand("/bin/top"),
|
|
| 162 |
- OpenStdin: true, |
|
| 163 |
- }, |
|
| 164 |
- t, |
|
| 165 |
- ) |
|
| 166 |
- |
|
| 167 |
- startContainer(eng, containerID, t) |
|
| 168 |
- |
|
| 169 |
- // Give some time to the process to start |
|
| 170 |
- containerWaitTimeout(eng, containerID, t) |
|
| 171 |
- |
|
| 172 |
- if !containerRunning(eng, containerID, t) {
|
|
| 173 |
- t.Errorf("Container should be running")
|
|
| 174 |
- } |
|
| 175 |
- |
|
| 176 |
- // Note: as it is a POST request, it requires a body. |
|
| 177 |
- req, err := http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
|
|
| 178 |
- if err != nil {
|
|
| 179 |
- t.Fatal(err) |
|
| 180 |
- } |
|
| 181 |
- r := httptest.NewRecorder() |
|
| 182 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 183 |
- assertHttpNotError(r, t) |
|
| 184 |
- if r.Code != http.StatusNoContent {
|
|
| 185 |
- t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
|
|
| 186 |
- } |
|
| 187 |
- if containerRunning(eng, containerID, t) {
|
|
| 188 |
- t.Fatalf("The container hasn't been stopped")
|
|
| 189 |
- } |
|
| 190 |
- |
|
| 191 |
- req, err = http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
|
|
| 192 |
- if err != nil {
|
|
| 193 |
- t.Fatal(err) |
|
| 194 |
- } |
|
| 195 |
- |
|
| 196 |
- r = httptest.NewRecorder() |
|
| 197 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 198 |
- |
|
| 199 |
- // Stopping an already stopper container should return a 304 |
|
| 200 |
- assertHttpNotError(r, t) |
|
| 201 |
- if r.Code != http.StatusNotModified {
|
|
| 202 |
- t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
|
|
| 203 |
- } |
|
| 204 |
-} |
|
| 205 |
- |
|
| 206 |
-func TestPostContainersWait(t *testing.T) {
|
|
| 207 |
- eng := NewTestEngine(t) |
|
| 208 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 209 |
- |
|
| 210 |
- containerID := createTestContainer(eng, |
|
| 211 |
- &runconfig.Config{
|
|
| 212 |
- Image: unitTestImageID, |
|
| 213 |
- Cmd: runconfig.NewCommand("/bin/sleep", "1"),
|
|
| 214 |
- OpenStdin: true, |
|
| 215 |
- }, |
|
| 216 |
- t, |
|
| 217 |
- ) |
|
| 218 |
- startContainer(eng, containerID, t) |
|
| 219 |
- |
|
| 220 |
- setTimeout(t, "Wait timed out", 3*time.Second, func() {
|
|
| 221 |
- r := httptest.NewRecorder() |
|
| 222 |
- req, err := http.NewRequest("POST", "/containers/"+containerID+"/wait", bytes.NewReader([]byte{}))
|
|
| 223 |
- if err != nil {
|
|
| 224 |
- t.Fatal(err) |
|
| 225 |
- } |
|
| 226 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 227 |
- assertHttpNotError(r, t) |
|
| 228 |
- var apiWait engine.Env |
|
| 229 |
- if err := apiWait.Decode(r.Body); err != nil {
|
|
| 230 |
- t.Fatal(err) |
|
| 231 |
- } |
|
| 232 |
- if apiWait.GetInt("StatusCode") != 0 {
|
|
| 233 |
- t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.GetInt("StatusCode"))
|
|
| 234 |
- } |
|
| 235 |
- }) |
|
| 236 |
- |
|
| 237 |
- if containerRunning(eng, containerID, t) {
|
|
| 238 |
- t.Fatalf("The container should be stopped after wait")
|
|
| 239 |
- } |
|
| 240 |
-} |
|
| 241 |
- |
|
| 242 |
-func TestPostContainersAttach(t *testing.T) {
|
|
| 243 |
- eng := NewTestEngine(t) |
|
| 244 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 245 |
- |
|
| 246 |
- containerID := createTestContainer(eng, |
|
| 247 |
- &runconfig.Config{
|
|
| 248 |
- Image: unitTestImageID, |
|
| 249 |
- Cmd: runconfig.NewCommand("/bin/cat"),
|
|
| 250 |
- OpenStdin: true, |
|
| 251 |
- }, |
|
| 252 |
- t, |
|
| 253 |
- ) |
|
| 254 |
- // Start the process |
|
| 255 |
- startContainer(eng, containerID, t) |
|
| 256 |
- |
|
| 257 |
- stdin, stdinPipe := io.Pipe() |
|
| 258 |
- stdout, stdoutPipe := io.Pipe() |
|
| 259 |
- |
|
| 260 |
- // Try to avoid the timeout in destroy. Best effort, don't check error |
|
| 261 |
- defer func() {
|
|
| 262 |
- closeWrap(stdin, stdinPipe, stdout, stdoutPipe) |
|
| 263 |
- containerKill(eng, containerID, t) |
|
| 264 |
- }() |
|
| 265 |
- |
|
| 266 |
- // Attach to it |
|
| 267 |
- c1 := make(chan struct{})
|
|
| 268 |
- go func() {
|
|
| 269 |
- defer close(c1) |
|
| 270 |
- |
|
| 271 |
- r := &hijackTester{
|
|
| 272 |
- ResponseRecorder: httptest.NewRecorder(), |
|
| 273 |
- in: stdin, |
|
| 274 |
- out: stdoutPipe, |
|
| 275 |
- } |
|
| 276 |
- |
|
| 277 |
- req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
|
|
| 278 |
- if err != nil {
|
|
| 279 |
- t.Fatal(err) |
|
| 280 |
- } |
|
| 281 |
- |
|
| 282 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 283 |
- assertHttpNotError(r.ResponseRecorder, t) |
|
| 284 |
- }() |
|
| 285 |
- |
|
| 286 |
- // Acknowledge hijack |
|
| 287 |
- setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
|
|
| 288 |
- stdout.Read([]byte{})
|
|
| 289 |
- stdout.Read(make([]byte, 4096)) |
|
| 290 |
- }) |
|
| 291 |
- |
|
| 292 |
- setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
|
|
| 293 |
- if err := assertPipe("hello\n", string([]byte{1, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
|
|
| 294 |
- t.Fatal(err) |
|
| 295 |
- } |
|
| 296 |
- }) |
|
| 297 |
- |
|
| 298 |
- // Close pipes (client disconnects) |
|
| 299 |
- if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
|
|
| 300 |
- t.Fatal(err) |
|
| 301 |
- } |
|
| 302 |
- |
|
| 303 |
- // Wait for attach to finish, the client disconnected, therefore, Attach finished his job |
|
| 304 |
- setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
|
|
| 305 |
- <-c1 |
|
| 306 |
- }) |
|
| 307 |
- |
|
| 308 |
- // We closed stdin, expect /bin/cat to still be running |
|
| 309 |
- // Wait a little bit to make sure container.monitor() did his thing |
|
| 310 |
- containerWaitTimeout(eng, containerID, t) |
|
| 311 |
- |
|
| 312 |
- // Try to avoid the timeout in destroy. Best effort, don't check error |
|
| 313 |
- cStdin, _ := containerAttach(eng, containerID, t) |
|
| 314 |
- cStdin.Close() |
|
| 315 |
- containerWait(eng, containerID, t) |
|
| 316 |
-} |
|
| 317 |
- |
|
| 318 |
-func TestPostContainersAttachStderr(t *testing.T) {
|
|
| 319 |
- eng := NewTestEngine(t) |
|
| 320 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 321 |
- |
|
| 322 |
- containerID := createTestContainer(eng, |
|
| 323 |
- &runconfig.Config{
|
|
| 324 |
- Image: unitTestImageID, |
|
| 325 |
- Cmd: runconfig.NewCommand("/bin/sh", "-c", "/bin/cat >&2"),
|
|
| 326 |
- OpenStdin: true, |
|
| 327 |
- }, |
|
| 328 |
- t, |
|
| 329 |
- ) |
|
| 330 |
- // Start the process |
|
| 331 |
- startContainer(eng, containerID, t) |
|
| 332 |
- |
|
| 333 |
- stdin, stdinPipe := io.Pipe() |
|
| 334 |
- stdout, stdoutPipe := io.Pipe() |
|
| 335 |
- |
|
| 336 |
- // Try to avoid the timeout in destroy. Best effort, don't check error |
|
| 337 |
- defer func() {
|
|
| 338 |
- closeWrap(stdin, stdinPipe, stdout, stdoutPipe) |
|
| 339 |
- containerKill(eng, containerID, t) |
|
| 340 |
- }() |
|
| 341 |
- |
|
| 342 |
- // Attach to it |
|
| 343 |
- c1 := make(chan struct{})
|
|
| 344 |
- go func() {
|
|
| 345 |
- defer close(c1) |
|
| 346 |
- |
|
| 347 |
- r := &hijackTester{
|
|
| 348 |
- ResponseRecorder: httptest.NewRecorder(), |
|
| 349 |
- in: stdin, |
|
| 350 |
- out: stdoutPipe, |
|
| 351 |
- } |
|
| 352 |
- |
|
| 353 |
- req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
|
|
| 354 |
- if err != nil {
|
|
| 355 |
- t.Fatal(err) |
|
| 356 |
- } |
|
| 357 |
- |
|
| 358 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 359 |
- assertHttpNotError(r.ResponseRecorder, t) |
|
| 360 |
- }() |
|
| 361 |
- |
|
| 362 |
- // Acknowledge hijack |
|
| 363 |
- setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
|
|
| 364 |
- stdout.Read([]byte{})
|
|
| 365 |
- stdout.Read(make([]byte, 4096)) |
|
| 366 |
- }) |
|
| 367 |
- |
|
| 368 |
- setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
|
|
| 369 |
- if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
|
|
| 370 |
- t.Fatal(err) |
|
| 371 |
- } |
|
| 372 |
- }) |
|
| 373 |
- |
|
| 374 |
- // Close pipes (client disconnects) |
|
| 375 |
- if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
|
|
| 376 |
- t.Fatal(err) |
|
| 377 |
- } |
|
| 378 |
- |
|
| 379 |
- // Wait for attach to finish, the client disconnected, therefore, Attach finished his job |
|
| 380 |
- setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
|
|
| 381 |
- <-c1 |
|
| 382 |
- }) |
|
| 383 |
- |
|
| 384 |
- // We closed stdin, expect /bin/cat to still be running |
|
| 385 |
- // Wait a little bit to make sure container.monitor() did his thing |
|
| 386 |
- containerWaitTimeout(eng, containerID, t) |
|
| 387 |
- |
|
| 388 |
- // Try to avoid the timeout in destroy. Best effort, don't check error |
|
| 389 |
- cStdin, _ := containerAttach(eng, containerID, t) |
|
| 390 |
- cStdin.Close() |
|
| 391 |
- containerWait(eng, containerID, t) |
|
| 392 |
-} |
|
| 393 |
- |
|
| 394 |
-func TestOptionsRoute(t *testing.T) {
|
|
| 395 |
- eng := NewTestEngine(t) |
|
| 396 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 397 |
- |
|
| 398 |
- r := httptest.NewRecorder() |
|
| 399 |
- req, err := http.NewRequest("OPTIONS", "/", nil)
|
|
| 400 |
- if err != nil {
|
|
| 401 |
- t.Fatal(err) |
|
| 402 |
- } |
|
| 403 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 404 |
- assertHttpNotError(r, t) |
|
| 405 |
- if r.Code != http.StatusOK {
|
|
| 406 |
- t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
|
|
| 407 |
- } |
|
| 408 |
-} |
|
| 409 |
- |
|
| 410 |
-func TestGetEnabledCors(t *testing.T) {
|
|
| 411 |
- eng := NewTestEngine(t) |
|
| 412 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 413 |
- |
|
| 414 |
- r := httptest.NewRecorder() |
|
| 415 |
- |
|
| 416 |
- req, err := http.NewRequest("GET", "/version", nil)
|
|
| 417 |
- if err != nil {
|
|
| 418 |
- t.Fatal(err) |
|
| 419 |
- } |
|
| 420 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 421 |
- assertHttpNotError(r, t) |
|
| 422 |
- if r.Code != http.StatusOK {
|
|
| 423 |
- t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
|
|
| 424 |
- } |
|
| 425 |
- |
|
| 426 |
- allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
|
|
| 427 |
- allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
|
|
| 428 |
- allowMethods := r.Header().Get("Access-Control-Allow-Methods")
|
|
| 429 |
- |
|
| 430 |
- if allowOrigin != "*" {
|
|
| 431 |
- t.Errorf("Expected header Access-Control-Allow-Origin to be \"*\", %s found.", allowOrigin)
|
|
| 432 |
- } |
|
| 433 |
- if allowHeaders != "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth" {
|
|
| 434 |
- t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth\", %s found.", allowHeaders)
|
|
| 435 |
- } |
|
| 436 |
- if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
|
|
| 437 |
- t.Errorf("Expected header Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
|
|
| 438 |
- } |
|
| 439 |
-} |
|
| 440 |
- |
|
| 441 |
-func TestDeleteImages(t *testing.T) {
|
|
| 442 |
- eng := NewTestEngine(t) |
|
| 443 |
- //we expect errors, so we disable stderr |
|
| 444 |
- eng.Stderr = ioutil.Discard |
|
| 445 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 446 |
- |
|
| 447 |
- initialImages := getImages(eng, t, true, "") |
|
| 448 |
- |
|
| 449 |
- d := getDaemon(eng) |
|
| 450 |
- if err := d.Repositories().Tag("test", "test", unitTestImageName, true); err != nil {
|
|
| 451 |
- t.Fatal(err) |
|
| 452 |
- } |
|
| 453 |
- |
|
| 454 |
- images := getImages(eng, t, true, "") |
|
| 455 |
- |
|
| 456 |
- if len(images[0].RepoTags) != len(initialImages[0].RepoTags)+1 {
|
|
| 457 |
- t.Errorf("Expected %d images, %d found", len(initialImages[0].RepoTags)+1, len(images[0].RepoTags))
|
|
| 458 |
- } |
|
| 459 |
- |
|
| 460 |
- req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
|
|
| 461 |
- if err != nil {
|
|
| 462 |
- t.Fatal(err) |
|
| 463 |
- } |
|
| 464 |
- |
|
| 465 |
- r := httptest.NewRecorder() |
|
| 466 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 467 |
- if r.Code != http.StatusConflict {
|
|
| 468 |
- t.Fatalf("Expected http status 409-conflict, got %v", r.Code)
|
|
| 469 |
- } |
|
| 470 |
- |
|
| 471 |
- req2, err := http.NewRequest("DELETE", "/images/test:test", nil)
|
|
| 472 |
- if err != nil {
|
|
| 473 |
- t.Fatal(err) |
|
| 474 |
- } |
|
| 475 |
- |
|
| 476 |
- r2 := httptest.NewRecorder() |
|
| 477 |
- server.ServeRequest(eng, api.APIVERSION, r2, req2) |
|
| 478 |
- assertHttpNotError(r2, t) |
|
| 479 |
- if r2.Code != http.StatusOK {
|
|
| 480 |
- t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
|
|
| 481 |
- } |
|
| 482 |
- |
|
| 483 |
- delImages := []types.ImageDelete{}
|
|
| 484 |
- err = json.Unmarshal(r2.Body.Bytes(), &delImages) |
|
| 485 |
- if err != nil {
|
|
| 486 |
- t.Fatal(err) |
|
| 487 |
- } |
|
| 488 |
- |
|
| 489 |
- if len(delImages) != 1 {
|
|
| 490 |
- t.Fatalf("Expected %d event (untagged), got %d", 1, len(delImages))
|
|
| 491 |
- } |
|
| 492 |
- images = getImages(eng, t, false, "") |
|
| 493 |
- |
|
| 494 |
- if len(images) != len(initialImages) {
|
|
| 495 |
- t.Errorf("Expected %d image, %d found", len(initialImages), len(images))
|
|
| 496 |
- } |
|
| 497 |
-} |
|
| 498 |
- |
|
| 499 |
-func TestPostContainersCopy(t *testing.T) {
|
|
| 500 |
- eng := NewTestEngine(t) |
|
| 501 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 502 |
- |
|
| 503 |
- // Create a container and remove a file |
|
| 504 |
- containerID := createTestContainer(eng, |
|
| 505 |
- &runconfig.Config{
|
|
| 506 |
- Image: unitTestImageID, |
|
| 507 |
- Cmd: runconfig.NewCommand("touch", "/test.txt"),
|
|
| 508 |
- }, |
|
| 509 |
- t, |
|
| 510 |
- ) |
|
| 511 |
- containerRun(eng, containerID, t) |
|
| 512 |
- |
|
| 513 |
- r := httptest.NewRecorder() |
|
| 514 |
- |
|
| 515 |
- var copyData engine.Env |
|
| 516 |
- copyData.Set("Resource", "/test.txt")
|
|
| 517 |
- copyData.Set("HostPath", ".")
|
|
| 518 |
- |
|
| 519 |
- jsonData := bytes.NewBuffer(nil) |
|
| 520 |
- if err := copyData.Encode(jsonData); err != nil {
|
|
| 521 |
- t.Fatal(err) |
|
| 522 |
- } |
|
| 523 |
- |
|
| 524 |
- req, err := http.NewRequest("POST", "/containers/"+containerID+"/copy", jsonData)
|
|
| 525 |
- if err != nil {
|
|
| 526 |
- t.Fatal(err) |
|
| 527 |
- } |
|
| 528 |
- req.Header.Add("Content-Type", "application/json")
|
|
| 529 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 530 |
- assertHttpNotError(r, t) |
|
| 531 |
- |
|
| 532 |
- if r.Code != http.StatusOK {
|
|
| 533 |
- t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
|
|
| 534 |
- } |
|
| 535 |
- |
|
| 536 |
- found := false |
|
| 537 |
- for tarReader := tar.NewReader(r.Body); ; {
|
|
| 538 |
- h, err := tarReader.Next() |
|
| 539 |
- if err != nil {
|
|
| 540 |
- if err == io.EOF {
|
|
| 541 |
- break |
|
| 542 |
- } |
|
| 543 |
- t.Fatal(err) |
|
| 544 |
- } |
|
| 545 |
- if h.Name == "test.txt" {
|
|
| 546 |
- found = true |
|
| 547 |
- break |
|
| 548 |
- } |
|
| 549 |
- } |
|
| 550 |
- if !found {
|
|
| 551 |
- t.Fatalf("The created test file has not been found in the copied output")
|
|
| 552 |
- } |
|
| 553 |
-} |
|
| 554 |
- |
|
| 555 |
-func TestPostContainersCopyWhenContainerNotFound(t *testing.T) {
|
|
| 556 |
- eng := NewTestEngine(t) |
|
| 557 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 558 |
- |
|
| 559 |
- r := httptest.NewRecorder() |
|
| 560 |
- |
|
| 561 |
- var copyData engine.Env |
|
| 562 |
- copyData.Set("Resource", "/test.txt")
|
|
| 563 |
- copyData.Set("HostPath", ".")
|
|
| 564 |
- |
|
| 565 |
- jsonData := bytes.NewBuffer(nil) |
|
| 566 |
- if err := copyData.Encode(jsonData); err != nil {
|
|
| 567 |
- t.Fatal(err) |
|
| 568 |
- } |
|
| 569 |
- |
|
| 570 |
- req, err := http.NewRequest("POST", "/containers/id_not_found/copy", jsonData)
|
|
| 571 |
- if err != nil {
|
|
| 572 |
- t.Fatal(err) |
|
| 573 |
- } |
|
| 574 |
- req.Header.Add("Content-Type", "application/json")
|
|
| 575 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 576 |
- if r.Code != http.StatusNotFound {
|
|
| 577 |
- t.Fatalf("404 expected for id_not_found Container, received %v", r.Code)
|
|
| 578 |
- } |
|
| 579 |
-} |
|
| 580 |
- |
|
| 581 |
-// Regression test for https://github.com/docker/docker/issues/6231 |
|
| 582 |
-func TestConstainersStartChunkedEncodingHostConfig(t *testing.T) {
|
|
| 583 |
- eng := NewTestEngine(t) |
|
| 584 |
- defer mkDaemonFromEngine(eng, t).Nuke() |
|
| 585 |
- |
|
| 586 |
- r := httptest.NewRecorder() |
|
| 587 |
- |
|
| 588 |
- var testData engine.Env |
|
| 589 |
- testData.Set("Image", "docker-test-image")
|
|
| 590 |
- testData.SetAuto("Volumes", map[string]struct{}{"/foo": {}})
|
|
| 591 |
- testData.Set("Cmd", "true")
|
|
| 592 |
- jsonData := bytes.NewBuffer(nil) |
|
| 593 |
- if err := testData.Encode(jsonData); err != nil {
|
|
| 594 |
- t.Fatal(err) |
|
| 595 |
- } |
|
| 596 |
- |
|
| 597 |
- req, err := http.NewRequest("POST", "/containers/create?name=chunk_test", jsonData)
|
|
| 598 |
- if err != nil {
|
|
| 599 |
- t.Fatal(err) |
|
| 600 |
- } |
|
| 601 |
- |
|
| 602 |
- req.Header.Add("Content-Type", "application/json")
|
|
| 603 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 604 |
- assertHttpNotError(r, t) |
|
| 605 |
- |
|
| 606 |
- var testData2 engine.Env |
|
| 607 |
- testData2.SetAuto("Binds", []string{"/tmp:/foo"})
|
|
| 608 |
- jsonData = bytes.NewBuffer(nil) |
|
| 609 |
- if err := testData2.Encode(jsonData); err != nil {
|
|
| 610 |
- t.Fatal(err) |
|
| 611 |
- } |
|
| 612 |
- |
|
| 613 |
- req, err = http.NewRequest("POST", "/containers/chunk_test/start", jsonData)
|
|
| 614 |
- if err != nil {
|
|
| 615 |
- t.Fatal(err) |
|
| 616 |
- } |
|
| 617 |
- |
|
| 618 |
- req.Header.Add("Content-Type", "application/json")
|
|
| 619 |
- // This is a cheat to make the http request do chunked encoding |
|
| 620 |
- // Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite |
|
| 621 |
- // https://golang.org/src/pkg/net/http/request.go?s=11980:12172 |
|
| 622 |
- req.ContentLength = -1 |
|
| 623 |
- server.ServeRequest(eng, api.APIVERSION, r, req) |
|
| 624 |
- assertHttpNotError(r, t) |
|
| 625 |
- |
|
| 626 |
- type config struct {
|
|
| 627 |
- HostConfig struct {
|
|
| 628 |
- Binds []string |
|
| 629 |
- } |
|
| 630 |
- } |
|
| 631 |
- |
|
| 632 |
- req, err = http.NewRequest("GET", "/containers/chunk_test/json", nil)
|
|
| 633 |
- if err != nil {
|
|
| 634 |
- t.Fatal(err) |
|
| 635 |
- } |
|
| 636 |
- |
|
| 637 |
- r2 := httptest.NewRecorder() |
|
| 638 |
- req.Header.Add("Content-Type", "application/json")
|
|
| 639 |
- server.ServeRequest(eng, api.APIVERSION, r2, req) |
|
| 640 |
- assertHttpNotError(r, t) |
|
| 641 |
- |
|
| 642 |
- c := config{}
|
|
| 643 |
- |
|
| 644 |
- json.Unmarshal(r2.Body.Bytes(), &c) |
|
| 645 |
- |
|
| 646 |
- if len(c.HostConfig.Binds) == 0 {
|
|
| 647 |
- t.Fatal("Chunked Encoding not handled")
|
|
| 648 |
- } |
|
| 649 |
- |
|
| 650 |
- if c.HostConfig.Binds[0] != "/tmp:/foo" {
|
|
| 651 |
- t.Fatal("Chunked encoding not properly handled, expected binds to be /tmp:/foo, got:", c.HostConfig.Binds[0])
|
|
| 652 |
- } |
|
| 653 |
-} |
|
| 654 |
- |
|
| 655 |
-// Mocked types for tests |
|
| 656 |
-type NopConn struct {
|
|
| 657 |
- io.ReadCloser |
|
| 658 |
- io.Writer |
|
| 659 |
-} |
|
| 660 |
- |
|
| 661 |
-func (c *NopConn) LocalAddr() net.Addr { return nil }
|
|
| 662 |
-func (c *NopConn) RemoteAddr() net.Addr { return nil }
|
|
| 663 |
-func (c *NopConn) SetDeadline(t time.Time) error { return nil }
|
|
| 664 |
-func (c *NopConn) SetReadDeadline(t time.Time) error { return nil }
|
|
| 665 |
-func (c *NopConn) SetWriteDeadline(t time.Time) error { return nil }
|
|
| 666 |
- |
|
| 667 |
-type hijackTester struct {
|
|
| 668 |
- *httptest.ResponseRecorder |
|
| 669 |
- in io.ReadCloser |
|
| 670 |
- out io.Writer |
|
| 671 |
-} |
|
| 672 |
- |
|
| 673 |
-func (t *hijackTester) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
| 674 |
- bufrw := bufio.NewReadWriter(bufio.NewReader(t.in), bufio.NewWriter(t.out)) |
|
| 675 |
- conn := &NopConn{
|
|
| 676 |
- ReadCloser: t.in, |
|
| 677 |
- Writer: t.out, |
|
| 678 |
- } |
|
| 679 |
- return conn, bufrw, nil |
|
| 680 |
-} |
| 681 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,235 +0,0 @@ |
| 1 |
-package docker |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "io" |
|
| 5 |
- "io/ioutil" |
|
| 6 |
- "testing" |
|
| 7 |
- "time" |
|
| 8 |
- |
|
| 9 |
- "github.com/docker/docker/runconfig" |
|
| 10 |
-) |
|
| 11 |
- |
|
| 12 |
-func TestRestartStdin(t *testing.T) {
|
|
| 13 |
- daemon := mkDaemon(t) |
|
| 14 |
- defer nuke(daemon) |
|
| 15 |
- container, _, err := daemon.Create(&runconfig.Config{
|
|
| 16 |
- Image: GetTestImage(daemon).ID, |
|
| 17 |
- Cmd: runconfig.NewCommand("cat"),
|
|
| 18 |
- |
|
| 19 |
- OpenStdin: true, |
|
| 20 |
- }, |
|
| 21 |
- &runconfig.HostConfig{},
|
|
| 22 |
- "", |
|
| 23 |
- ) |
|
| 24 |
- if err != nil {
|
|
| 25 |
- t.Fatal(err) |
|
| 26 |
- } |
|
| 27 |
- defer daemon.Rm(container) |
|
| 28 |
- |
|
| 29 |
- stdin := container.StdinPipe() |
|
| 30 |
- stdout := container.StdoutPipe() |
|
| 31 |
- if err := container.Start(); err != nil {
|
|
| 32 |
- t.Fatal(err) |
|
| 33 |
- } |
|
| 34 |
- if _, err := io.WriteString(stdin, "hello world"); err != nil {
|
|
| 35 |
- t.Fatal(err) |
|
| 36 |
- } |
|
| 37 |
- if err := stdin.Close(); err != nil {
|
|
| 38 |
- t.Fatal(err) |
|
| 39 |
- } |
|
| 40 |
- container.WaitStop(-1 * time.Second) |
|
| 41 |
- output, err := ioutil.ReadAll(stdout) |
|
| 42 |
- if err != nil {
|
|
| 43 |
- t.Fatal(err) |
|
| 44 |
- } |
|
| 45 |
- if err := stdout.Close(); err != nil {
|
|
| 46 |
- t.Fatal(err) |
|
| 47 |
- } |
|
| 48 |
- if string(output) != "hello world" {
|
|
| 49 |
- t.Fatalf("Unexpected output. Expected %s, received: %s", "hello world", string(output))
|
|
| 50 |
- } |
|
| 51 |
- |
|
| 52 |
- // Restart and try again |
|
| 53 |
- stdin = container.StdinPipe() |
|
| 54 |
- stdout = container.StdoutPipe() |
|
| 55 |
- if err := container.Start(); err != nil {
|
|
| 56 |
- t.Fatal(err) |
|
| 57 |
- } |
|
| 58 |
- if _, err := io.WriteString(stdin, "hello world #2"); err != nil {
|
|
| 59 |
- t.Fatal(err) |
|
| 60 |
- } |
|
| 61 |
- if err := stdin.Close(); err != nil {
|
|
| 62 |
- t.Fatal(err) |
|
| 63 |
- } |
|
| 64 |
- container.WaitStop(-1 * time.Second) |
|
| 65 |
- output, err = ioutil.ReadAll(stdout) |
|
| 66 |
- if err != nil {
|
|
| 67 |
- t.Fatal(err) |
|
| 68 |
- } |
|
| 69 |
- if err := stdout.Close(); err != nil {
|
|
| 70 |
- t.Fatal(err) |
|
| 71 |
- } |
|
| 72 |
- if string(output) != "hello world #2" {
|
|
| 73 |
- t.Fatalf("Unexpected output. Expected %s, received: %s", "hello world #2", string(output))
|
|
| 74 |
- } |
|
| 75 |
-} |
|
| 76 |
- |
|
| 77 |
-func TestStdin(t *testing.T) {
|
|
| 78 |
- daemon := mkDaemon(t) |
|
| 79 |
- defer nuke(daemon) |
|
| 80 |
- container, _, err := daemon.Create(&runconfig.Config{
|
|
| 81 |
- Image: GetTestImage(daemon).ID, |
|
| 82 |
- Cmd: runconfig.NewCommand("cat"),
|
|
| 83 |
- |
|
| 84 |
- OpenStdin: true, |
|
| 85 |
- }, |
|
| 86 |
- &runconfig.HostConfig{},
|
|
| 87 |
- "", |
|
| 88 |
- ) |
|
| 89 |
- if err != nil {
|
|
| 90 |
- t.Fatal(err) |
|
| 91 |
- } |
|
| 92 |
- defer daemon.Rm(container) |
|
| 93 |
- |
|
| 94 |
- stdin := container.StdinPipe() |
|
| 95 |
- stdout := container.StdoutPipe() |
|
| 96 |
- if err := container.Start(); err != nil {
|
|
| 97 |
- t.Fatal(err) |
|
| 98 |
- } |
|
| 99 |
- defer stdin.Close() |
|
| 100 |
- defer stdout.Close() |
|
| 101 |
- if _, err := io.WriteString(stdin, "hello world"); err != nil {
|
|
| 102 |
- t.Fatal(err) |
|
| 103 |
- } |
|
| 104 |
- if err := stdin.Close(); err != nil {
|
|
| 105 |
- t.Fatal(err) |
|
| 106 |
- } |
|
| 107 |
- container.WaitStop(-1 * time.Second) |
|
| 108 |
- output, err := ioutil.ReadAll(stdout) |
|
| 109 |
- if err != nil {
|
|
| 110 |
- t.Fatal(err) |
|
| 111 |
- } |
|
| 112 |
- if string(output) != "hello world" {
|
|
| 113 |
- t.Fatalf("Unexpected output. Expected %s, received: %s", "hello world", string(output))
|
|
| 114 |
- } |
|
| 115 |
-} |
|
| 116 |
- |
|
| 117 |
-func TestTty(t *testing.T) {
|
|
| 118 |
- daemon := mkDaemon(t) |
|
| 119 |
- defer nuke(daemon) |
|
| 120 |
- container, _, err := daemon.Create(&runconfig.Config{
|
|
| 121 |
- Image: GetTestImage(daemon).ID, |
|
| 122 |
- Cmd: runconfig.NewCommand("cat"),
|
|
| 123 |
- |
|
| 124 |
- OpenStdin: true, |
|
| 125 |
- }, |
|
| 126 |
- &runconfig.HostConfig{},
|
|
| 127 |
- "", |
|
| 128 |
- ) |
|
| 129 |
- if err != nil {
|
|
| 130 |
- t.Fatal(err) |
|
| 131 |
- } |
|
| 132 |
- defer daemon.Rm(container) |
|
| 133 |
- |
|
| 134 |
- stdin := container.StdinPipe() |
|
| 135 |
- stdout := container.StdoutPipe() |
|
| 136 |
- if err := container.Start(); err != nil {
|
|
| 137 |
- t.Fatal(err) |
|
| 138 |
- } |
|
| 139 |
- defer stdin.Close() |
|
| 140 |
- defer stdout.Close() |
|
| 141 |
- if _, err := io.WriteString(stdin, "hello world"); err != nil {
|
|
| 142 |
- t.Fatal(err) |
|
| 143 |
- } |
|
| 144 |
- if err := stdin.Close(); err != nil {
|
|
| 145 |
- t.Fatal(err) |
|
| 146 |
- } |
|
| 147 |
- container.WaitStop(-1 * time.Second) |
|
| 148 |
- output, err := ioutil.ReadAll(stdout) |
|
| 149 |
- if err != nil {
|
|
| 150 |
- t.Fatal(err) |
|
| 151 |
- } |
|
| 152 |
- if string(output) != "hello world" {
|
|
| 153 |
- t.Fatalf("Unexpected output. Expected %s, received: %s", "hello world", string(output))
|
|
| 154 |
- } |
|
| 155 |
-} |
|
| 156 |
- |
|
| 157 |
-func BenchmarkRunSequential(b *testing.B) {
|
|
| 158 |
- daemon := mkDaemon(b) |
|
| 159 |
- defer nuke(daemon) |
|
| 160 |
- for i := 0; i < b.N; i++ {
|
|
| 161 |
- container, _, err := daemon.Create(&runconfig.Config{
|
|
| 162 |
- Image: GetTestImage(daemon).ID, |
|
| 163 |
- Cmd: runconfig.NewCommand("echo", "-n", "foo"),
|
|
| 164 |
- }, |
|
| 165 |
- &runconfig.HostConfig{},
|
|
| 166 |
- "", |
|
| 167 |
- ) |
|
| 168 |
- if err != nil {
|
|
| 169 |
- b.Fatal(err) |
|
| 170 |
- } |
|
| 171 |
- defer daemon.Rm(container) |
|
| 172 |
- output, err := container.Output() |
|
| 173 |
- if err != nil {
|
|
| 174 |
- b.Fatal(err) |
|
| 175 |
- } |
|
| 176 |
- if string(output) != "foo" {
|
|
| 177 |
- b.Fatalf("Unexpected output: %s", output)
|
|
| 178 |
- } |
|
| 179 |
- if err := daemon.Rm(container); err != nil {
|
|
| 180 |
- b.Fatal(err) |
|
| 181 |
- } |
|
| 182 |
- } |
|
| 183 |
-} |
|
| 184 |
- |
|
| 185 |
-func BenchmarkRunParallel(b *testing.B) {
|
|
| 186 |
- daemon := mkDaemon(b) |
|
| 187 |
- defer nuke(daemon) |
|
| 188 |
- |
|
| 189 |
- var tasks []chan error |
|
| 190 |
- |
|
| 191 |
- for i := 0; i < b.N; i++ {
|
|
| 192 |
- complete := make(chan error) |
|
| 193 |
- tasks = append(tasks, complete) |
|
| 194 |
- go func(i int, complete chan error) {
|
|
| 195 |
- container, _, err := daemon.Create(&runconfig.Config{
|
|
| 196 |
- Image: GetTestImage(daemon).ID, |
|
| 197 |
- Cmd: runconfig.NewCommand("echo", "-n", "foo"),
|
|
| 198 |
- }, |
|
| 199 |
- &runconfig.HostConfig{},
|
|
| 200 |
- "", |
|
| 201 |
- ) |
|
| 202 |
- if err != nil {
|
|
| 203 |
- complete <- err |
|
| 204 |
- return |
|
| 205 |
- } |
|
| 206 |
- defer daemon.Rm(container) |
|
| 207 |
- if err := container.Start(); err != nil {
|
|
| 208 |
- complete <- err |
|
| 209 |
- return |
|
| 210 |
- } |
|
| 211 |
- if _, err := container.WaitStop(15 * time.Second); err != nil {
|
|
| 212 |
- complete <- err |
|
| 213 |
- return |
|
| 214 |
- } |
|
| 215 |
- // if string(output) != "foo" {
|
|
| 216 |
- // complete <- fmt.Errorf("Unexpected output: %v", string(output))
|
|
| 217 |
- // } |
|
| 218 |
- if err := daemon.Rm(container); err != nil {
|
|
| 219 |
- complete <- err |
|
| 220 |
- return |
|
| 221 |
- } |
|
| 222 |
- complete <- nil |
|
| 223 |
- }(i, complete) |
|
| 224 |
- } |
|
| 225 |
- var errors []error |
|
| 226 |
- for _, task := range tasks {
|
|
| 227 |
- err := <-task |
|
| 228 |
- if err != nil {
|
|
| 229 |
- errors = append(errors, err) |
|
| 230 |
- } |
|
| 231 |
- } |
|
| 232 |
- if len(errors) > 0 {
|
|
| 233 |
- b.Fatal(errors) |
|
| 234 |
- } |
|
| 235 |
-} |
| 236 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,847 +0,0 @@ |
| 1 |
-package docker |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "bytes" |
|
| 5 |
- "fmt" |
|
| 6 |
- "io" |
|
| 7 |
- std_log "log" |
|
| 8 |
- "net" |
|
| 9 |
- "net/url" |
|
| 10 |
- "os" |
|
| 11 |
- "path/filepath" |
|
| 12 |
- "runtime" |
|
| 13 |
- "strconv" |
|
| 14 |
- "strings" |
|
| 15 |
- "syscall" |
|
| 16 |
- "testing" |
|
| 17 |
- "time" |
|
| 18 |
- |
|
| 19 |
- "github.com/Sirupsen/logrus" |
|
| 20 |
- apiserver "github.com/docker/docker/api/server" |
|
| 21 |
- "github.com/docker/docker/cliconfig" |
|
| 22 |
- "github.com/docker/docker/daemon" |
|
| 23 |
- "github.com/docker/docker/daemon/execdriver" |
|
| 24 |
- "github.com/docker/docker/engine" |
|
| 25 |
- "github.com/docker/docker/graph" |
|
| 26 |
- "github.com/docker/docker/image" |
|
| 27 |
- "github.com/docker/docker/nat" |
|
| 28 |
- "github.com/docker/docker/pkg/fileutils" |
|
| 29 |
- "github.com/docker/docker/pkg/ioutils" |
|
| 30 |
- "github.com/docker/docker/pkg/reexec" |
|
| 31 |
- "github.com/docker/docker/pkg/stringid" |
|
| 32 |
- "github.com/docker/docker/runconfig" |
|
| 33 |
- "github.com/docker/docker/utils" |
|
| 34 |
-) |
|
| 35 |
- |
|
| 36 |
-const ( |
|
| 37 |
- unitTestImageName = "docker-test-image" |
|
| 38 |
- unitTestImageID = "83599e29c455eb719f77d799bc7c51521b9551972f5a850d7ad265bc1b5292f6" // 1.0 |
|
| 39 |
- unitTestImageIDShort = "83599e29c455" |
|
| 40 |
- unitTestNetworkBridge = "testdockbr0" |
|
| 41 |
- unitTestStoreBase = "/var/lib/docker/unit-tests" |
|
| 42 |
- unitTestDockerTmpdir = "/var/lib/docker/tmp" |
|
| 43 |
- testDaemonAddr = "127.0.0.1:4270" |
|
| 44 |
- testDaemonProto = "tcp" |
|
| 45 |
- testDaemonHttpsProto = "tcp" |
|
| 46 |
- testDaemonHttpsAddr = "localhost:4271" |
|
| 47 |
- testDaemonRogueHttpsAddr = "localhost:4272" |
|
| 48 |
-) |
|
| 49 |
- |
|
| 50 |
-var ( |
|
| 51 |
- globalDaemon *daemon.Daemon |
|
| 52 |
- globalHttpsEngine *engine.Engine |
|
| 53 |
- globalRogueHttpsEngine *engine.Engine |
|
| 54 |
- startFds int |
|
| 55 |
- startGoroutines int |
|
| 56 |
-) |
|
| 57 |
- |
|
| 58 |
-// FIXME: nuke() is deprecated by Daemon.Nuke() |
|
| 59 |
-func nuke(daemon *daemon.Daemon) error {
|
|
| 60 |
- return daemon.Nuke() |
|
| 61 |
-} |
|
| 62 |
- |
|
| 63 |
-// FIXME: cleanup and nuke are redundant. |
|
| 64 |
-func cleanup(eng *engine.Engine, t *testing.T) error {
|
|
| 65 |
- daemon := mkDaemonFromEngine(eng, t) |
|
| 66 |
- for _, container := range daemon.List() {
|
|
| 67 |
- container.Kill() |
|
| 68 |
- daemon.Rm(container) |
|
| 69 |
- } |
|
| 70 |
- images, err := daemon.Repositories().Images(&graph.ImagesConfig{})
|
|
| 71 |
- if err != nil {
|
|
| 72 |
- t.Fatal(err) |
|
| 73 |
- } |
|
| 74 |
- for _, image := range images {
|
|
| 75 |
- if image.ID != unitTestImageID {
|
|
| 76 |
- eng.Job("image_delete", image.ID).Run()
|
|
| 77 |
- } |
|
| 78 |
- } |
|
| 79 |
- return nil |
|
| 80 |
-} |
|
| 81 |
- |
|
| 82 |
-func init() {
|
|
| 83 |
- // Always use the same driver (vfs) for all integration tests. |
|
| 84 |
- // To test other drivers, we need a dedicated driver validation suite. |
|
| 85 |
- os.Setenv("DOCKER_DRIVER", "vfs")
|
|
| 86 |
- os.Setenv("TEST", "1")
|
|
| 87 |
- os.Setenv("DOCKER_TMPDIR", unitTestDockerTmpdir)
|
|
| 88 |
- |
|
| 89 |
- // Hack to run sys init during unit testing |
|
| 90 |
- if reexec.Init() {
|
|
| 91 |
- return |
|
| 92 |
- } |
|
| 93 |
- |
|
| 94 |
- if uid := syscall.Geteuid(); uid != 0 {
|
|
| 95 |
- logrus.Fatalf("docker tests need to be run as root")
|
|
| 96 |
- } |
|
| 97 |
- |
|
| 98 |
- // Copy dockerinit into our current testing directory, if provided (so we can test a separate dockerinit binary) |
|
| 99 |
- if dockerinit := os.Getenv("TEST_DOCKERINIT_PATH"); dockerinit != "" {
|
|
| 100 |
- src, err := os.Open(dockerinit) |
|
| 101 |
- if err != nil {
|
|
| 102 |
- logrus.Fatalf("Unable to open TEST_DOCKERINIT_PATH: %s", err)
|
|
| 103 |
- } |
|
| 104 |
- defer src.Close() |
|
| 105 |
- dst, err := os.OpenFile(filepath.Join(filepath.Dir(utils.SelfPath()), "dockerinit"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0555) |
|
| 106 |
- if err != nil {
|
|
| 107 |
- logrus.Fatalf("Unable to create dockerinit in test directory: %s", err)
|
|
| 108 |
- } |
|
| 109 |
- defer dst.Close() |
|
| 110 |
- if _, err := io.Copy(dst, src); err != nil {
|
|
| 111 |
- logrus.Fatalf("Unable to copy dockerinit to TEST_DOCKERINIT_PATH: %s", err)
|
|
| 112 |
- } |
|
| 113 |
- dst.Close() |
|
| 114 |
- src.Close() |
|
| 115 |
- } |
|
| 116 |
- |
|
| 117 |
- // Setup the base daemon, which will be duplicated for each test. |
|
| 118 |
- // (no tests are run directly in the base) |
|
| 119 |
- setupBaseImage() |
|
| 120 |
- |
|
| 121 |
- // Create the "global daemon" with a long-running daemons for integration tests |
|
| 122 |
- spawnGlobalDaemon() |
|
| 123 |
- startFds, startGoroutines = fileutils.GetTotalUsedFds(), runtime.NumGoroutine() |
|
| 124 |
-} |
|
| 125 |
- |
|
| 126 |
-func setupBaseImage() {
|
|
| 127 |
- eng := newTestEngine(std_log.New(os.Stderr, "", 0), false, unitTestStoreBase) |
|
| 128 |
- d := getDaemon(eng) |
|
| 129 |
- |
|
| 130 |
- _, err := d.Repositories().Lookup(unitTestImageName) |
|
| 131 |
- // If the unit test is not found, try to download it. |
|
| 132 |
- if err != nil {
|
|
| 133 |
- // seems like we can just ignore the error here... |
|
| 134 |
- // there was a check of imgId from job stdout against unittestid but |
|
| 135 |
- // if there was an error how could the imgid from the job |
|
| 136 |
- // be compared?! it's obvious it's different, am I totally wrong? |
|
| 137 |
- |
|
| 138 |
- // Retrieve the Image |
|
| 139 |
- imagePullConfig := &graph.ImagePullConfig{
|
|
| 140 |
- Parallel: true, |
|
| 141 |
- OutStream: ioutils.NopWriteCloser(os.Stdout), |
|
| 142 |
- AuthConfig: &cliconfig.AuthConfig{},
|
|
| 143 |
- } |
|
| 144 |
- if err := d.Repositories().Pull(unitTestImageName, "", imagePullConfig); err != nil {
|
|
| 145 |
- logrus.Fatalf("Unable to pull the test image: %s", err)
|
|
| 146 |
- } |
|
| 147 |
- } |
|
| 148 |
-} |
|
| 149 |
- |
|
| 150 |
-func spawnGlobalDaemon() {
|
|
| 151 |
- if globalDaemon != nil {
|
|
| 152 |
- logrus.Debugf("Global daemon already exists. Skipping.")
|
|
| 153 |
- return |
|
| 154 |
- } |
|
| 155 |
- t := std_log.New(os.Stderr, "", 0) |
|
| 156 |
- eng := NewTestEngine(t) |
|
| 157 |
- globalDaemon = mkDaemonFromEngine(eng, t) |
|
| 158 |
- |
|
| 159 |
- serverConfig := &apiserver.ServerConfig{Logging: true}
|
|
| 160 |
- api := apiserver.New(serverConfig, eng) |
|
| 161 |
- // Spawn a Daemon |
|
| 162 |
- go func() {
|
|
| 163 |
- logrus.Debugf("Spawning global daemon for integration tests")
|
|
| 164 |
- listenURL := &url.URL{
|
|
| 165 |
- Scheme: testDaemonProto, |
|
| 166 |
- Host: testDaemonAddr, |
|
| 167 |
- } |
|
| 168 |
- |
|
| 169 |
- if err := api.ServeApi([]string{listenURL.String()}); err != nil {
|
|
| 170 |
- logrus.Fatalf("Unable to spawn the test daemon: %s", err)
|
|
| 171 |
- } |
|
| 172 |
- }() |
|
| 173 |
- |
|
| 174 |
- // Give some time to ListenAndServer to actually start |
|
| 175 |
- // FIXME: use inmem transports instead of tcp |
|
| 176 |
- time.Sleep(time.Second) |
|
| 177 |
- |
|
| 178 |
- api.AcceptConnections(getDaemon(eng)) |
|
| 179 |
-} |
|
| 180 |
- |
|
| 181 |
-// FIXME: test that ImagePull(json=true) send correct json output |
|
| 182 |
- |
|
| 183 |
-func GetTestImage(daemon *daemon.Daemon) *image.Image {
|
|
| 184 |
- imgs, err := daemon.Graph().Map() |
|
| 185 |
- if err != nil {
|
|
| 186 |
- logrus.Fatalf("Unable to get the test image: %s", err)
|
|
| 187 |
- } |
|
| 188 |
- for _, image := range imgs {
|
|
| 189 |
- if image.ID == unitTestImageID {
|
|
| 190 |
- return image |
|
| 191 |
- } |
|
| 192 |
- } |
|
| 193 |
- logrus.Fatalf("Test image %v not found in %s: %s", unitTestImageID, daemon.Graph().Root, imgs)
|
|
| 194 |
- return nil |
|
| 195 |
-} |
|
| 196 |
- |
|
| 197 |
-func TestDaemonCreate(t *testing.T) {
|
|
| 198 |
- daemon := mkDaemon(t) |
|
| 199 |
- defer nuke(daemon) |
|
| 200 |
- |
|
| 201 |
- // Make sure we start we 0 containers |
|
| 202 |
- if len(daemon.List()) != 0 {
|
|
| 203 |
- t.Errorf("Expected 0 containers, %v found", len(daemon.List()))
|
|
| 204 |
- } |
|
| 205 |
- |
|
| 206 |
- container, _, err := daemon.Create(&runconfig.Config{
|
|
| 207 |
- Image: GetTestImage(daemon).ID, |
|
| 208 |
- Cmd: runconfig.NewCommand("ls", "-al"),
|
|
| 209 |
- }, |
|
| 210 |
- &runconfig.HostConfig{},
|
|
| 211 |
- "", |
|
| 212 |
- ) |
|
| 213 |
- if err != nil {
|
|
| 214 |
- t.Fatal(err) |
|
| 215 |
- } |
|
| 216 |
- |
|
| 217 |
- defer func() {
|
|
| 218 |
- if err := daemon.Rm(container); err != nil {
|
|
| 219 |
- t.Error(err) |
|
| 220 |
- } |
|
| 221 |
- }() |
|
| 222 |
- |
|
| 223 |
- // Make sure we can find the newly created container with List() |
|
| 224 |
- if len(daemon.List()) != 1 {
|
|
| 225 |
- t.Errorf("Expected 1 container, %v found", len(daemon.List()))
|
|
| 226 |
- } |
|
| 227 |
- |
|
| 228 |
- // Make sure the container List() returns is the right one |
|
| 229 |
- if daemon.List()[0].ID != container.ID {
|
|
| 230 |
- t.Errorf("Unexpected container %v returned by List", daemon.List()[0])
|
|
| 231 |
- } |
|
| 232 |
- |
|
| 233 |
- // Make sure we can get the container with Get() |
|
| 234 |
- if _, err := daemon.Get(container.ID); err != nil {
|
|
| 235 |
- t.Errorf("Unable to get newly created container")
|
|
| 236 |
- } |
|
| 237 |
- |
|
| 238 |
- // Make sure it is the right container |
|
| 239 |
- if c, _ := daemon.Get(container.ID); c != container {
|
|
| 240 |
- t.Errorf("Get() returned the wrong container")
|
|
| 241 |
- } |
|
| 242 |
- |
|
| 243 |
- // Make sure Exists returns it as existing |
|
| 244 |
- if !daemon.Exists(container.ID) {
|
|
| 245 |
- t.Errorf("Exists() returned false for a newly created container")
|
|
| 246 |
- } |
|
| 247 |
- |
|
| 248 |
- // Test that conflict error displays correct details |
|
| 249 |
- cmd := runconfig.NewCommand("ls", "-al")
|
|
| 250 |
- testContainer, _, _ := daemon.Create( |
|
| 251 |
- &runconfig.Config{
|
|
| 252 |
- Image: GetTestImage(daemon).ID, |
|
| 253 |
- Cmd: cmd, |
|
| 254 |
- }, |
|
| 255 |
- &runconfig.HostConfig{},
|
|
| 256 |
- "conflictname", |
|
| 257 |
- ) |
|
| 258 |
- if _, _, err := daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID, Cmd: cmd}, &runconfig.HostConfig{}, testContainer.Name); err == nil || !strings.Contains(err.Error(), stringid.TruncateID(testContainer.ID)) {
|
|
| 259 |
- t.Fatalf("Name conflict error doesn't include the correct short id. Message was: %v", err)
|
|
| 260 |
- } |
|
| 261 |
- |
|
| 262 |
- // Make sure create with bad parameters returns an error |
|
| 263 |
- if _, _, err = daemon.Create(&runconfig.Config{Image: GetTestImage(daemon).ID}, &runconfig.HostConfig{}, ""); err == nil {
|
|
| 264 |
- t.Fatal("Builder.Create should throw an error when Cmd is missing")
|
|
| 265 |
- } |
|
| 266 |
- |
|
| 267 |
- if _, _, err := daemon.Create( |
|
| 268 |
- &runconfig.Config{
|
|
| 269 |
- Image: GetTestImage(daemon).ID, |
|
| 270 |
- Cmd: runconfig.NewCommand(), |
|
| 271 |
- }, |
|
| 272 |
- &runconfig.HostConfig{},
|
|
| 273 |
- "", |
|
| 274 |
- ); err == nil {
|
|
| 275 |
- t.Fatal("Builder.Create should throw an error when Cmd is empty")
|
|
| 276 |
- } |
|
| 277 |
- |
|
| 278 |
- config := &runconfig.Config{
|
|
| 279 |
- Image: GetTestImage(daemon).ID, |
|
| 280 |
- Cmd: runconfig.NewCommand("/bin/ls"),
|
|
| 281 |
- PortSpecs: []string{"80"},
|
|
| 282 |
- } |
|
| 283 |
- container, _, err = daemon.Create(config, &runconfig.HostConfig{}, "")
|
|
| 284 |
- |
|
| 285 |
- _, err = daemon.Commit(container, "testrepo", "testtag", "", "", true, config) |
|
| 286 |
- if err != nil {
|
|
| 287 |
- t.Error(err) |
|
| 288 |
- } |
|
| 289 |
- |
|
| 290 |
- // test expose 80:8000 |
|
| 291 |
- container, warnings, err := daemon.Create(&runconfig.Config{
|
|
| 292 |
- Image: GetTestImage(daemon).ID, |
|
| 293 |
- Cmd: runconfig.NewCommand("ls", "-al"),
|
|
| 294 |
- PortSpecs: []string{"80:8000"},
|
|
| 295 |
- }, |
|
| 296 |
- &runconfig.HostConfig{},
|
|
| 297 |
- "", |
|
| 298 |
- ) |
|
| 299 |
- if err != nil {
|
|
| 300 |
- t.Fatal(err) |
|
| 301 |
- } |
|
| 302 |
- if warnings == nil || len(warnings) != 1 {
|
|
| 303 |
- t.Error("Expected a warning, got none")
|
|
| 304 |
- } |
|
| 305 |
-} |
|
| 306 |
- |
|
| 307 |
-func TestDestroy(t *testing.T) {
|
|
| 308 |
- daemon := mkDaemon(t) |
|
| 309 |
- defer nuke(daemon) |
|
| 310 |
- |
|
| 311 |
- container, _, err := daemon.Create(&runconfig.Config{
|
|
| 312 |
- Image: GetTestImage(daemon).ID, |
|
| 313 |
- Cmd: runconfig.NewCommand("ls", "-al"),
|
|
| 314 |
- }, |
|
| 315 |
- &runconfig.HostConfig{},
|
|
| 316 |
- "") |
|
| 317 |
- if err != nil {
|
|
| 318 |
- t.Fatal(err) |
|
| 319 |
- } |
|
| 320 |
- // Destroy |
|
| 321 |
- if err := daemon.Rm(container); err != nil {
|
|
| 322 |
- t.Error(err) |
|
| 323 |
- } |
|
| 324 |
- |
|
| 325 |
- // Make sure daemon.Exists() behaves correctly |
|
| 326 |
- if daemon.Exists("test_destroy") {
|
|
| 327 |
- t.Errorf("Exists() returned true")
|
|
| 328 |
- } |
|
| 329 |
- |
|
| 330 |
- // Make sure daemon.List() doesn't list the destroyed container |
|
| 331 |
- if len(daemon.List()) != 0 {
|
|
| 332 |
- t.Errorf("Expected 0 container, %v found", len(daemon.List()))
|
|
| 333 |
- } |
|
| 334 |
- |
|
| 335 |
- // Make sure daemon.Get() refuses to return the unexisting container |
|
| 336 |
- if c, _ := daemon.Get(container.ID); c != nil {
|
|
| 337 |
- t.Errorf("Got a container that should not exist")
|
|
| 338 |
- } |
|
| 339 |
- |
|
| 340 |
- // Test double destroy |
|
| 341 |
- if err := daemon.Rm(container); err == nil {
|
|
| 342 |
- // It should have failed |
|
| 343 |
- t.Errorf("Double destroy did not fail")
|
|
| 344 |
- } |
|
| 345 |
-} |
|
| 346 |
- |
|
| 347 |
-func TestGet(t *testing.T) {
|
|
| 348 |
- daemon := mkDaemon(t) |
|
| 349 |
- defer nuke(daemon) |
|
| 350 |
- |
|
| 351 |
- container1, _, _ := mkContainer(daemon, []string{"_", "ls", "-al"}, t)
|
|
| 352 |
- defer daemon.Rm(container1) |
|
| 353 |
- |
|
| 354 |
- container2, _, _ := mkContainer(daemon, []string{"_", "ls", "-al"}, t)
|
|
| 355 |
- defer daemon.Rm(container2) |
|
| 356 |
- |
|
| 357 |
- container3, _, _ := mkContainer(daemon, []string{"_", "ls", "-al"}, t)
|
|
| 358 |
- defer daemon.Rm(container3) |
|
| 359 |
- |
|
| 360 |
- if c, _ := daemon.Get(container1.ID); c != container1 {
|
|
| 361 |
- t.Errorf("Get(test1) returned %v while expecting %v", c, container1)
|
|
| 362 |
- } |
|
| 363 |
- |
|
| 364 |
- if c, _ := daemon.Get(container2.ID); c != container2 {
|
|
| 365 |
- t.Errorf("Get(test2) returned %v while expecting %v", c, container2)
|
|
| 366 |
- } |
|
| 367 |
- |
|
| 368 |
- if c, _ := daemon.Get(container3.ID); c != container3 {
|
|
| 369 |
- t.Errorf("Get(test3) returned %v while expecting %v", c, container3)
|
|
| 370 |
- } |
|
| 371 |
- |
|
| 372 |
-} |
|
| 373 |
- |
|
| 374 |
-func startEchoServerContainer(t *testing.T, proto string) (*daemon.Daemon, *daemon.Container, string) {
|
|
| 375 |
- var ( |
|
| 376 |
- err error |
|
| 377 |
- id string |
|
| 378 |
- strPort string |
|
| 379 |
- eng = NewTestEngine(t) |
|
| 380 |
- daemon = mkDaemonFromEngine(eng, t) |
|
| 381 |
- port = 5554 |
|
| 382 |
- p nat.Port |
|
| 383 |
- ) |
|
| 384 |
- defer func() {
|
|
| 385 |
- if err != nil {
|
|
| 386 |
- daemon.Nuke() |
|
| 387 |
- } |
|
| 388 |
- }() |
|
| 389 |
- |
|
| 390 |
- for {
|
|
| 391 |
- port += 1 |
|
| 392 |
- strPort = strconv.Itoa(port) |
|
| 393 |
- var cmd string |
|
| 394 |
- if proto == "tcp" {
|
|
| 395 |
- cmd = "socat TCP-LISTEN:" + strPort + ",reuseaddr,fork EXEC:/bin/cat" |
|
| 396 |
- } else if proto == "udp" {
|
|
| 397 |
- cmd = "socat UDP-RECVFROM:" + strPort + ",fork EXEC:/bin/cat" |
|
| 398 |
- } else {
|
|
| 399 |
- t.Fatal(fmt.Errorf("Unknown protocol %v", proto))
|
|
| 400 |
- } |
|
| 401 |
- ep := make(map[nat.Port]struct{}, 1)
|
|
| 402 |
- p = nat.Port(fmt.Sprintf("%s/%s", strPort, proto))
|
|
| 403 |
- ep[p] = struct{}{}
|
|
| 404 |
- |
|
| 405 |
- c := &runconfig.Config{
|
|
| 406 |
- Image: unitTestImageID, |
|
| 407 |
- Cmd: runconfig.NewCommand("sh", "-c", cmd),
|
|
| 408 |
- PortSpecs: []string{fmt.Sprintf("%s/%s", strPort, proto)},
|
|
| 409 |
- ExposedPorts: ep, |
|
| 410 |
- } |
|
| 411 |
- |
|
| 412 |
- id, _, err = daemon.ContainerCreate(unitTestImageID, c, &runconfig.HostConfig{})
|
|
| 413 |
- // FIXME: this relies on the undocumented behavior of daemon.Create |
|
| 414 |
- // which will return a nil error AND container if the exposed ports |
|
| 415 |
- // are invalid. That behavior should be fixed! |
|
| 416 |
- if id != "" {
|
|
| 417 |
- break |
|
| 418 |
- } |
|
| 419 |
- t.Logf("Port %v already in use, trying another one", strPort)
|
|
| 420 |
- |
|
| 421 |
- } |
|
| 422 |
- |
|
| 423 |
- if err := daemon.ContainerStart(id, &runconfig.HostConfig{}); err != nil {
|
|
| 424 |
- t.Fatal(err) |
|
| 425 |
- } |
|
| 426 |
- |
|
| 427 |
- container, err := daemon.Get(id) |
|
| 428 |
- if err != nil {
|
|
| 429 |
- t.Fatal(err) |
|
| 430 |
- } |
|
| 431 |
- |
|
| 432 |
- setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
|
|
| 433 |
- for !container.IsRunning() {
|
|
| 434 |
- time.Sleep(10 * time.Millisecond) |
|
| 435 |
- } |
|
| 436 |
- }) |
|
| 437 |
- |
|
| 438 |
- // Even if the state is running, lets give some time to lxc to spawn the process |
|
| 439 |
- container.WaitStop(500 * time.Millisecond) |
|
| 440 |
- |
|
| 441 |
- strPort = container.NetworkSettings.Ports[p][0].HostPort |
|
| 442 |
- return daemon, container, strPort |
|
| 443 |
-} |
|
| 444 |
- |
|
| 445 |
-// Run a container with a TCP port allocated, and test that it can receive connections on localhost |
|
| 446 |
-func TestAllocateTCPPortLocalhost(t *testing.T) {
|
|
| 447 |
- daemon, container, port := startEchoServerContainer(t, "tcp") |
|
| 448 |
- defer nuke(daemon) |
|
| 449 |
- defer container.Kill() |
|
| 450 |
- |
|
| 451 |
- for i := 0; i != 10; i++ {
|
|
| 452 |
- conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%v", port))
|
|
| 453 |
- if err != nil {
|
|
| 454 |
- t.Fatal(err) |
|
| 455 |
- } |
|
| 456 |
- defer conn.Close() |
|
| 457 |
- |
|
| 458 |
- input := bytes.NewBufferString("well hello there\n")
|
|
| 459 |
- _, err = conn.Write(input.Bytes()) |
|
| 460 |
- if err != nil {
|
|
| 461 |
- t.Fatal(err) |
|
| 462 |
- } |
|
| 463 |
- buf := make([]byte, 16) |
|
| 464 |
- read := 0 |
|
| 465 |
- conn.SetReadDeadline(time.Now().Add(3 * time.Second)) |
|
| 466 |
- read, err = conn.Read(buf) |
|
| 467 |
- if err != nil {
|
|
| 468 |
- if err, ok := err.(*net.OpError); ok {
|
|
| 469 |
- if err.Err == syscall.ECONNRESET {
|
|
| 470 |
- t.Logf("Connection reset by the proxy, socat is probably not listening yet, trying again in a sec")
|
|
| 471 |
- conn.Close() |
|
| 472 |
- time.Sleep(time.Second) |
|
| 473 |
- continue |
|
| 474 |
- } |
|
| 475 |
- if err.Timeout() {
|
|
| 476 |
- t.Log("Timeout, trying again")
|
|
| 477 |
- conn.Close() |
|
| 478 |
- continue |
|
| 479 |
- } |
|
| 480 |
- } |
|
| 481 |
- t.Fatal(err) |
|
| 482 |
- } |
|
| 483 |
- output := string(buf[:read]) |
|
| 484 |
- if !strings.Contains(output, "well hello there") {
|
|
| 485 |
- t.Fatal(fmt.Errorf("[%v] doesn't contain [well hello there]", output))
|
|
| 486 |
- } else {
|
|
| 487 |
- return |
|
| 488 |
- } |
|
| 489 |
- } |
|
| 490 |
- |
|
| 491 |
- t.Fatal("No reply from the container")
|
|
| 492 |
-} |
|
| 493 |
- |
|
| 494 |
-// Run a container with an UDP port allocated, and test that it can receive connections on localhost |
|
| 495 |
-func TestAllocateUDPPortLocalhost(t *testing.T) {
|
|
| 496 |
- daemon, container, port := startEchoServerContainer(t, "udp") |
|
| 497 |
- defer nuke(daemon) |
|
| 498 |
- defer container.Kill() |
|
| 499 |
- |
|
| 500 |
- conn, err := net.Dial("udp", fmt.Sprintf("localhost:%v", port))
|
|
| 501 |
- if err != nil {
|
|
| 502 |
- t.Fatal(err) |
|
| 503 |
- } |
|
| 504 |
- defer conn.Close() |
|
| 505 |
- |
|
| 506 |
- input := bytes.NewBufferString("well hello there\n")
|
|
| 507 |
- buf := make([]byte, 16) |
|
| 508 |
- // Try for a minute, for some reason the select in socat may take ages |
|
| 509 |
- // to return even though everything on the path seems fine (i.e: the |
|
| 510 |
- // UDPProxy forwards the traffic correctly and you can see the packets |
|
| 511 |
- // on the interface from within the container). |
|
| 512 |
- for i := 0; i != 120; i++ {
|
|
| 513 |
- _, err := conn.Write(input.Bytes()) |
|
| 514 |
- if err != nil {
|
|
| 515 |
- t.Fatal(err) |
|
| 516 |
- } |
|
| 517 |
- conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) |
|
| 518 |
- read, err := conn.Read(buf) |
|
| 519 |
- if err == nil {
|
|
| 520 |
- output := string(buf[:read]) |
|
| 521 |
- if strings.Contains(output, "well hello there") {
|
|
| 522 |
- return |
|
| 523 |
- } |
|
| 524 |
- } |
|
| 525 |
- } |
|
| 526 |
- |
|
| 527 |
- t.Fatal("No reply from the container")
|
|
| 528 |
-} |
|
| 529 |
- |
|
| 530 |
-func TestRestore(t *testing.T) {
|
|
| 531 |
- eng := NewTestEngine(t) |
|
| 532 |
- daemon1 := mkDaemonFromEngine(eng, t) |
|
| 533 |
- defer daemon1.Nuke() |
|
| 534 |
- // Create a container with one instance of docker |
|
| 535 |
- container1, _, _ := mkContainer(daemon1, []string{"_", "ls", "-al"}, t)
|
|
| 536 |
- defer daemon1.Rm(container1) |
|
| 537 |
- |
|
| 538 |
- // Create a second container meant to be killed |
|
| 539 |
- container2, _, _ := mkContainer(daemon1, []string{"-i", "_", "/bin/cat"}, t)
|
|
| 540 |
- defer daemon1.Rm(container2) |
|
| 541 |
- |
|
| 542 |
- // Start the container non blocking |
|
| 543 |
- if err := container2.Start(); err != nil {
|
|
| 544 |
- t.Fatal(err) |
|
| 545 |
- } |
|
| 546 |
- |
|
| 547 |
- if !container2.IsRunning() {
|
|
| 548 |
- t.Fatalf("Container %v should appear as running but isn't", container2.ID)
|
|
| 549 |
- } |
|
| 550 |
- |
|
| 551 |
- // Simulate a crash/manual quit of dockerd: process dies, states stays 'Running' |
|
| 552 |
- cStdin := container2.StdinPipe() |
|
| 553 |
- cStdin.Close() |
|
| 554 |
- if _, err := container2.WaitStop(2 * time.Second); err != nil {
|
|
| 555 |
- t.Fatal(err) |
|
| 556 |
- } |
|
| 557 |
- container2.SetRunning(42) |
|
| 558 |
- container2.ToDisk() |
|
| 559 |
- |
|
| 560 |
- if len(daemon1.List()) != 2 {
|
|
| 561 |
- t.Errorf("Expected 2 container, %v found", len(daemon1.List()))
|
|
| 562 |
- } |
|
| 563 |
- if err := container1.Run(); err != nil {
|
|
| 564 |
- t.Fatal(err) |
|
| 565 |
- } |
|
| 566 |
- |
|
| 567 |
- if !container2.IsRunning() {
|
|
| 568 |
- t.Fatalf("Container %v should appear as running but isn't", container2.ID)
|
|
| 569 |
- } |
|
| 570 |
- |
|
| 571 |
- // Here are are simulating a docker restart - that is, reloading all containers |
|
| 572 |
- // from scratch |
|
| 573 |
- eng = newTestEngine(t, false, daemon1.Config().Root) |
|
| 574 |
- daemon2 := mkDaemonFromEngine(eng, t) |
|
| 575 |
- if len(daemon2.List()) != 2 {
|
|
| 576 |
- t.Errorf("Expected 2 container, %v found", len(daemon2.List()))
|
|
| 577 |
- } |
|
| 578 |
- runningCount := 0 |
|
| 579 |
- for _, c := range daemon2.List() {
|
|
| 580 |
- if c.IsRunning() {
|
|
| 581 |
- t.Errorf("Running container found: %v (%v)", c.ID, c.Path)
|
|
| 582 |
- runningCount++ |
|
| 583 |
- } |
|
| 584 |
- } |
|
| 585 |
- if runningCount != 0 {
|
|
| 586 |
- t.Fatalf("Expected 0 container alive, %d found", runningCount)
|
|
| 587 |
- } |
|
| 588 |
- container3, err := daemon2.Get(container1.ID) |
|
| 589 |
- if err != nil {
|
|
| 590 |
- t.Fatal("Unable to Get container")
|
|
| 591 |
- } |
|
| 592 |
- if err := container3.Run(); err != nil {
|
|
| 593 |
- t.Fatal(err) |
|
| 594 |
- } |
|
| 595 |
- container2.SetStopped(&execdriver.ExitStatus{ExitCode: 0})
|
|
| 596 |
-} |
|
| 597 |
- |
|
| 598 |
-func TestDefaultContainerName(t *testing.T) {
|
|
| 599 |
- eng := NewTestEngine(t) |
|
| 600 |
- daemon := mkDaemonFromEngine(eng, t) |
|
| 601 |
- defer nuke(daemon) |
|
| 602 |
- |
|
| 603 |
- config, _, _, err := parseRun([]string{unitTestImageID, "echo test"})
|
|
| 604 |
- if err != nil {
|
|
| 605 |
- t.Fatal(err) |
|
| 606 |
- } |
|
| 607 |
- |
|
| 608 |
- container, err := daemon.Get(createNamedTestContainer(eng, config, t, "some_name")) |
|
| 609 |
- if err != nil {
|
|
| 610 |
- t.Fatal(err) |
|
| 611 |
- } |
|
| 612 |
- containerID := container.ID |
|
| 613 |
- |
|
| 614 |
- if container.Name != "/some_name" {
|
|
| 615 |
- t.Fatalf("Expect /some_name got %s", container.Name)
|
|
| 616 |
- } |
|
| 617 |
- |
|
| 618 |
- c, err := daemon.Get("/some_name")
|
|
| 619 |
- if err != nil {
|
|
| 620 |
- t.Fatalf("Couldn't retrieve test container as /some_name")
|
|
| 621 |
- } |
|
| 622 |
- if c.ID != containerID {
|
|
| 623 |
- t.Fatalf("Container /some_name has ID %s instead of %s", c.ID, containerID)
|
|
| 624 |
- } |
|
| 625 |
-} |
|
| 626 |
- |
|
| 627 |
-func TestRandomContainerName(t *testing.T) {
|
|
| 628 |
- eng := NewTestEngine(t) |
|
| 629 |
- daemon := mkDaemonFromEngine(eng, t) |
|
| 630 |
- defer nuke(daemon) |
|
| 631 |
- |
|
| 632 |
- config, _, _, err := parseRun([]string{GetTestImage(daemon).ID, "echo test"})
|
|
| 633 |
- if err != nil {
|
|
| 634 |
- t.Fatal(err) |
|
| 635 |
- } |
|
| 636 |
- |
|
| 637 |
- container, err := daemon.Get(createTestContainer(eng, config, t)) |
|
| 638 |
- if err != nil {
|
|
| 639 |
- t.Fatal(err) |
|
| 640 |
- } |
|
| 641 |
- containerID := container.ID |
|
| 642 |
- |
|
| 643 |
- if container.Name == "" {
|
|
| 644 |
- t.Fatalf("Expected not empty container name")
|
|
| 645 |
- } |
|
| 646 |
- |
|
| 647 |
- if c, err := daemon.Get(container.Name); err != nil {
|
|
| 648 |
- logrus.Fatalf("Could not lookup container %s by its name", container.Name)
|
|
| 649 |
- } else if c.ID != containerID {
|
|
| 650 |
- logrus.Fatalf("Looking up container name %s returned id %s instead of %s", container.Name, c.ID, containerID)
|
|
| 651 |
- } |
|
| 652 |
-} |
|
| 653 |
- |
|
| 654 |
-func TestContainerNameValidation(t *testing.T) {
|
|
| 655 |
- eng := NewTestEngine(t) |
|
| 656 |
- daemon := mkDaemonFromEngine(eng, t) |
|
| 657 |
- defer nuke(daemon) |
|
| 658 |
- |
|
| 659 |
- for _, test := range []struct {
|
|
| 660 |
- Name string |
|
| 661 |
- Valid bool |
|
| 662 |
- }{
|
|
| 663 |
- {"abc-123_AAA.1", true},
|
|
| 664 |
- {"\000asdf", false},
|
|
| 665 |
- } {
|
|
| 666 |
- config, _, _, err := parseRun([]string{unitTestImageID, "echo test"})
|
|
| 667 |
- if err != nil {
|
|
| 668 |
- if !test.Valid {
|
|
| 669 |
- continue |
|
| 670 |
- } |
|
| 671 |
- t.Fatal(err) |
|
| 672 |
- } |
|
| 673 |
- |
|
| 674 |
- containerId, _, err := daemon.ContainerCreate(test.Name, config, &runconfig.HostConfig{})
|
|
| 675 |
- if err != nil {
|
|
| 676 |
- if !test.Valid {
|
|
| 677 |
- continue |
|
| 678 |
- } |
|
| 679 |
- t.Fatal(err) |
|
| 680 |
- } |
|
| 681 |
- |
|
| 682 |
- container, err := daemon.Get(containerId) |
|
| 683 |
- if err != nil {
|
|
| 684 |
- t.Fatal(err) |
|
| 685 |
- } |
|
| 686 |
- |
|
| 687 |
- if container.Name != "/"+test.Name {
|
|
| 688 |
- t.Fatalf("Expect /%s got %s", test.Name, container.Name)
|
|
| 689 |
- } |
|
| 690 |
- |
|
| 691 |
- if c, err := daemon.Get("/" + test.Name); err != nil {
|
|
| 692 |
- t.Fatalf("Couldn't retrieve test container as /%s", test.Name)
|
|
| 693 |
- } else if c.ID != container.ID {
|
|
| 694 |
- t.Fatalf("Container /%s has ID %s instead of %s", test.Name, c.ID, container.ID)
|
|
| 695 |
- } |
|
| 696 |
- } |
|
| 697 |
-} |
|
| 698 |
- |
|
| 699 |
-func TestLinkChildContainer(t *testing.T) {
|
|
| 700 |
- eng := NewTestEngine(t) |
|
| 701 |
- daemon := mkDaemonFromEngine(eng, t) |
|
| 702 |
- defer nuke(daemon) |
|
| 703 |
- |
|
| 704 |
- config, _, _, err := parseRun([]string{unitTestImageID, "echo test"})
|
|
| 705 |
- if err != nil {
|
|
| 706 |
- t.Fatal(err) |
|
| 707 |
- } |
|
| 708 |
- |
|
| 709 |
- container, err := daemon.Get(createNamedTestContainer(eng, config, t, "/webapp")) |
|
| 710 |
- if err != nil {
|
|
| 711 |
- t.Fatal(err) |
|
| 712 |
- } |
|
| 713 |
- |
|
| 714 |
- webapp, err := daemon.GetByName("/webapp")
|
|
| 715 |
- if err != nil {
|
|
| 716 |
- t.Fatal(err) |
|
| 717 |
- } |
|
| 718 |
- |
|
| 719 |
- if webapp.ID != container.ID {
|
|
| 720 |
- t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
|
|
| 721 |
- } |
|
| 722 |
- |
|
| 723 |
- config, _, _, err = parseRun([]string{GetTestImage(daemon).ID, "echo test"})
|
|
| 724 |
- if err != nil {
|
|
| 725 |
- t.Fatal(err) |
|
| 726 |
- } |
|
| 727 |
- |
|
| 728 |
- childContainer, err := daemon.Get(createTestContainer(eng, config, t)) |
|
| 729 |
- if err != nil {
|
|
| 730 |
- t.Fatal(err) |
|
| 731 |
- } |
|
| 732 |
- |
|
| 733 |
- if err := daemon.RegisterLink(webapp, childContainer, "db"); err != nil {
|
|
| 734 |
- t.Fatal(err) |
|
| 735 |
- } |
|
| 736 |
- |
|
| 737 |
- // Get the child by it's new name |
|
| 738 |
- db, err := daemon.GetByName("/webapp/db")
|
|
| 739 |
- if err != nil {
|
|
| 740 |
- t.Fatal(err) |
|
| 741 |
- } |
|
| 742 |
- if db.ID != childContainer.ID {
|
|
| 743 |
- t.Fatalf("Expect db id to match container id: %s != %s", db.ID, childContainer.ID)
|
|
| 744 |
- } |
|
| 745 |
-} |
|
| 746 |
- |
|
| 747 |
-func TestGetAllChildren(t *testing.T) {
|
|
| 748 |
- eng := NewTestEngine(t) |
|
| 749 |
- daemon := mkDaemonFromEngine(eng, t) |
|
| 750 |
- defer nuke(daemon) |
|
| 751 |
- |
|
| 752 |
- config, _, _, err := parseRun([]string{unitTestImageID, "echo test"})
|
|
| 753 |
- if err != nil {
|
|
| 754 |
- t.Fatal(err) |
|
| 755 |
- } |
|
| 756 |
- |
|
| 757 |
- container, err := daemon.Get(createNamedTestContainer(eng, config, t, "/webapp")) |
|
| 758 |
- if err != nil {
|
|
| 759 |
- t.Fatal(err) |
|
| 760 |
- } |
|
| 761 |
- |
|
| 762 |
- webapp, err := daemon.GetByName("/webapp")
|
|
| 763 |
- if err != nil {
|
|
| 764 |
- t.Fatal(err) |
|
| 765 |
- } |
|
| 766 |
- |
|
| 767 |
- if webapp.ID != container.ID {
|
|
| 768 |
- t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
|
|
| 769 |
- } |
|
| 770 |
- |
|
| 771 |
- config, _, _, err = parseRun([]string{unitTestImageID, "echo test"})
|
|
| 772 |
- if err != nil {
|
|
| 773 |
- t.Fatal(err) |
|
| 774 |
- } |
|
| 775 |
- |
|
| 776 |
- childContainer, err := daemon.Get(createTestContainer(eng, config, t)) |
|
| 777 |
- if err != nil {
|
|
| 778 |
- t.Fatal(err) |
|
| 779 |
- } |
|
| 780 |
- |
|
| 781 |
- if err := daemon.RegisterLink(webapp, childContainer, "db"); err != nil {
|
|
| 782 |
- t.Fatal(err) |
|
| 783 |
- } |
|
| 784 |
- |
|
| 785 |
- children, err := daemon.Children("/webapp")
|
|
| 786 |
- if err != nil {
|
|
| 787 |
- t.Fatal(err) |
|
| 788 |
- } |
|
| 789 |
- |
|
| 790 |
- if children == nil {
|
|
| 791 |
- t.Fatal("Children should not be nil")
|
|
| 792 |
- } |
|
| 793 |
- if len(children) == 0 {
|
|
| 794 |
- t.Fatal("Children should not be empty")
|
|
| 795 |
- } |
|
| 796 |
- |
|
| 797 |
- for key, value := range children {
|
|
| 798 |
- if key != "/webapp/db" {
|
|
| 799 |
- t.Fatalf("Expected /webapp/db got %s", key)
|
|
| 800 |
- } |
|
| 801 |
- if value.ID != childContainer.ID {
|
|
| 802 |
- t.Fatalf("Expected id %s got %s", childContainer.ID, value.ID)
|
|
| 803 |
- } |
|
| 804 |
- } |
|
| 805 |
-} |
|
| 806 |
- |
|
| 807 |
-func TestDestroyWithInitLayer(t *testing.T) {
|
|
| 808 |
- daemon := mkDaemon(t) |
|
| 809 |
- defer nuke(daemon) |
|
| 810 |
- |
|
| 811 |
- container, _, err := daemon.Create(&runconfig.Config{
|
|
| 812 |
- Image: GetTestImage(daemon).ID, |
|
| 813 |
- Cmd: runconfig.NewCommand("ls", "-al"),
|
|
| 814 |
- }, |
|
| 815 |
- &runconfig.HostConfig{},
|
|
| 816 |
- "") |
|
| 817 |
- |
|
| 818 |
- if err != nil {
|
|
| 819 |
- t.Fatal(err) |
|
| 820 |
- } |
|
| 821 |
- // Destroy |
|
| 822 |
- if err := daemon.Rm(container); err != nil {
|
|
| 823 |
- t.Fatal(err) |
|
| 824 |
- } |
|
| 825 |
- |
|
| 826 |
- // Make sure daemon.Exists() behaves correctly |
|
| 827 |
- if daemon.Exists("test_destroy") {
|
|
| 828 |
- t.Fatalf("Exists() returned true")
|
|
| 829 |
- } |
|
| 830 |
- |
|
| 831 |
- // Make sure daemon.List() doesn't list the destroyed container |
|
| 832 |
- if len(daemon.List()) != 0 {
|
|
| 833 |
- t.Fatalf("Expected 0 container, %v found", len(daemon.List()))
|
|
| 834 |
- } |
|
| 835 |
- |
|
| 836 |
- driver := daemon.Graph().Driver() |
|
| 837 |
- |
|
| 838 |
- // Make sure that the container does not exist in the driver |
|
| 839 |
- if _, err := driver.Get(container.ID, ""); err == nil {
|
|
| 840 |
- t.Fatal("Container should not exist in the driver")
|
|
| 841 |
- } |
|
| 842 |
- |
|
| 843 |
- // Make sure that the init layer is removed from the driver |
|
| 844 |
- if _, err := driver.Get(fmt.Sprintf("%s-init", container.ID), ""); err == nil {
|
|
| 845 |
- t.Fatal("Container's init layer should not exist in the driver")
|
|
| 846 |
- } |
|
| 847 |
-} |
| 848 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,88 +0,0 @@ |
| 1 |
-package docker |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "bufio" |
|
| 5 |
- "fmt" |
|
| 6 |
- "io" |
|
| 7 |
- "strings" |
|
| 8 |
- "testing" |
|
| 9 |
- "time" |
|
| 10 |
- |
|
| 11 |
- "github.com/docker/docker/daemon" |
|
| 12 |
-) |
|
| 13 |
- |
|
| 14 |
-func closeWrap(args ...io.Closer) error {
|
|
| 15 |
- e := false |
|
| 16 |
- ret := fmt.Errorf("Error closing elements")
|
|
| 17 |
- for _, c := range args {
|
|
| 18 |
- if err := c.Close(); err != nil {
|
|
| 19 |
- e = true |
|
| 20 |
- ret = fmt.Errorf("%s\n%s", ret, err)
|
|
| 21 |
- } |
|
| 22 |
- } |
|
| 23 |
- if e {
|
|
| 24 |
- return ret |
|
| 25 |
- } |
|
| 26 |
- return nil |
|
| 27 |
-} |
|
| 28 |
- |
|
| 29 |
-func waitContainerStart(t *testing.T, timeout time.Duration) *daemon.Container {
|
|
| 30 |
- var container *daemon.Container |
|
| 31 |
- |
|
| 32 |
- setTimeout(t, "Waiting for the container to be started timed out", timeout, func() {
|
|
| 33 |
- for {
|
|
| 34 |
- l := globalDaemon.List() |
|
| 35 |
- if len(l) == 1 && l[0].IsRunning() {
|
|
| 36 |
- container = l[0] |
|
| 37 |
- break |
|
| 38 |
- } |
|
| 39 |
- time.Sleep(10 * time.Millisecond) |
|
| 40 |
- } |
|
| 41 |
- }) |
|
| 42 |
- |
|
| 43 |
- if container == nil {
|
|
| 44 |
- t.Fatal("An error occurred while waiting for the container to start")
|
|
| 45 |
- } |
|
| 46 |
- |
|
| 47 |
- return container |
|
| 48 |
-} |
|
| 49 |
- |
|
| 50 |
-func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
|
|
| 51 |
- c := make(chan bool) |
|
| 52 |
- |
|
| 53 |
- // Make sure we are not too long |
|
| 54 |
- go func() {
|
|
| 55 |
- time.Sleep(d) |
|
| 56 |
- c <- true |
|
| 57 |
- }() |
|
| 58 |
- go func() {
|
|
| 59 |
- f() |
|
| 60 |
- c <- false |
|
| 61 |
- }() |
|
| 62 |
- if <-c && msg != "" {
|
|
| 63 |
- t.Fatal(msg) |
|
| 64 |
- } |
|
| 65 |
-} |
|
| 66 |
- |
|
| 67 |
-func expectPipe(expected string, r io.Reader) error {
|
|
| 68 |
- o, err := bufio.NewReader(r).ReadString('\n')
|
|
| 69 |
- if err != nil {
|
|
| 70 |
- return err |
|
| 71 |
- } |
|
| 72 |
- if strings.Trim(o, " \r\n") != expected {
|
|
| 73 |
- return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", expected, o)
|
|
| 74 |
- } |
|
| 75 |
- return nil |
|
| 76 |
-} |
|
| 77 |
- |
|
| 78 |
-func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
|
|
| 79 |
- for i := 0; i < count; i++ {
|
|
| 80 |
- if _, err := w.Write([]byte(input)); err != nil {
|
|
| 81 |
- return err |
|
| 82 |
- } |
|
| 83 |
- if err := expectPipe(output, r); err != nil {
|
|
| 84 |
- return err |
|
| 85 |
- } |
|
| 86 |
- } |
|
| 87 |
- return nil |
|
| 88 |
-} |
| 89 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,348 +0,0 @@ |
| 1 |
-package docker |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "bytes" |
|
| 5 |
- "fmt" |
|
| 6 |
- "io" |
|
| 7 |
- "io/ioutil" |
|
| 8 |
- "net/http" |
|
| 9 |
- "net/http/httptest" |
|
| 10 |
- "os" |
|
| 11 |
- "path" |
|
| 12 |
- "path/filepath" |
|
| 13 |
- "strings" |
|
| 14 |
- "testing" |
|
| 15 |
- "time" |
|
| 16 |
- |
|
| 17 |
- "github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar" |
|
| 18 |
- |
|
| 19 |
- "github.com/docker/docker/api/types" |
|
| 20 |
- "github.com/docker/docker/daemon" |
|
| 21 |
- "github.com/docker/docker/daemon/networkdriver/bridge" |
|
| 22 |
- "github.com/docker/docker/engine" |
|
| 23 |
- "github.com/docker/docker/graph" |
|
| 24 |
- flag "github.com/docker/docker/pkg/mflag" |
|
| 25 |
- "github.com/docker/docker/registry" |
|
| 26 |
- "github.com/docker/docker/runconfig" |
|
| 27 |
- "github.com/docker/docker/utils" |
|
| 28 |
-) |
|
| 29 |
- |
|
| 30 |
-type Fataler interface {
|
|
| 31 |
- Fatal(...interface{})
|
|
| 32 |
-} |
|
| 33 |
- |
|
| 34 |
-// This file contains utility functions for docker's unit test suite. |
|
| 35 |
-// It has to be named XXX_test.go, apparently, in other to access private functions |
|
| 36 |
-// from other XXX_test.go functions. |
|
| 37 |
- |
|
| 38 |
-// Create a temporary daemon suitable for unit testing. |
|
| 39 |
-// Call t.Fatal() at the first error. |
|
| 40 |
-func mkDaemon(f Fataler) *daemon.Daemon {
|
|
| 41 |
- eng := newTestEngine(f, false, "") |
|
| 42 |
- return mkDaemonFromEngine(eng, f) |
|
| 43 |
-} |
|
| 44 |
- |
|
| 45 |
-func createNamedTestContainer(eng *engine.Engine, config *runconfig.Config, f Fataler, name string) (shortId string) {
|
|
| 46 |
- containerId, _, err := getDaemon(eng).ContainerCreate(name, config, &runconfig.HostConfig{})
|
|
| 47 |
- if err != nil {
|
|
| 48 |
- f.Fatal(err) |
|
| 49 |
- } |
|
| 50 |
- return containerId |
|
| 51 |
-} |
|
| 52 |
- |
|
| 53 |
-func createTestContainer(eng *engine.Engine, config *runconfig.Config, f Fataler) (shortId string) {
|
|
| 54 |
- return createNamedTestContainer(eng, config, f, "") |
|
| 55 |
-} |
|
| 56 |
- |
|
| 57 |
-func startContainer(eng *engine.Engine, id string, t Fataler) {
|
|
| 58 |
- if err := getDaemon(eng).ContainerStart(id, &runconfig.HostConfig{}); err != nil {
|
|
| 59 |
- t.Fatal(err) |
|
| 60 |
- } |
|
| 61 |
-} |
|
| 62 |
- |
|
| 63 |
-func containerRun(eng *engine.Engine, id string, t Fataler) {
|
|
| 64 |
- startContainer(eng, id, t) |
|
| 65 |
- containerWait(eng, id, t) |
|
| 66 |
-} |
|
| 67 |
- |
|
| 68 |
-func containerFileExists(eng *engine.Engine, id, dir string, t Fataler) bool {
|
|
| 69 |
- c := getContainer(eng, id, t) |
|
| 70 |
- if err := c.Mount(); err != nil {
|
|
| 71 |
- t.Fatal(err) |
|
| 72 |
- } |
|
| 73 |
- defer c.Unmount() |
|
| 74 |
- if _, err := os.Stat(path.Join(c.RootfsPath(), dir)); err != nil {
|
|
| 75 |
- if os.IsNotExist(err) {
|
|
| 76 |
- return false |
|
| 77 |
- } |
|
| 78 |
- t.Fatal(err) |
|
| 79 |
- } |
|
| 80 |
- return true |
|
| 81 |
-} |
|
| 82 |
- |
|
| 83 |
-func containerAttach(eng *engine.Engine, id string, t Fataler) (io.WriteCloser, io.ReadCloser) {
|
|
| 84 |
- c := getContainer(eng, id, t) |
|
| 85 |
- i := c.StdinPipe() |
|
| 86 |
- o := c.StdoutPipe() |
|
| 87 |
- return i, o |
|
| 88 |
-} |
|
| 89 |
- |
|
| 90 |
-func containerWait(eng *engine.Engine, id string, t Fataler) int {
|
|
| 91 |
- ex, _ := getContainer(eng, id, t).WaitStop(-1 * time.Second) |
|
| 92 |
- return ex |
|
| 93 |
-} |
|
| 94 |
- |
|
| 95 |
-func containerWaitTimeout(eng *engine.Engine, id string, t Fataler) error {
|
|
| 96 |
- _, err := getContainer(eng, id, t).WaitStop(500 * time.Millisecond) |
|
| 97 |
- return err |
|
| 98 |
-} |
|
| 99 |
- |
|
| 100 |
-func containerKill(eng *engine.Engine, id string, t Fataler) {
|
|
| 101 |
- if err := getDaemon(eng).ContainerKill(id, 0); err != nil {
|
|
| 102 |
- t.Fatal(err) |
|
| 103 |
- } |
|
| 104 |
-} |
|
| 105 |
- |
|
| 106 |
-func containerRunning(eng *engine.Engine, id string, t Fataler) bool {
|
|
| 107 |
- return getContainer(eng, id, t).IsRunning() |
|
| 108 |
-} |
|
| 109 |
- |
|
| 110 |
-func containerAssertExists(eng *engine.Engine, id string, t Fataler) {
|
|
| 111 |
- getContainer(eng, id, t) |
|
| 112 |
-} |
|
| 113 |
- |
|
| 114 |
-func containerAssertNotExists(eng *engine.Engine, id string, t Fataler) {
|
|
| 115 |
- daemon := mkDaemonFromEngine(eng, t) |
|
| 116 |
- if c, _ := daemon.Get(id); c != nil {
|
|
| 117 |
- t.Fatal(fmt.Errorf("Container %s should not exist", id))
|
|
| 118 |
- } |
|
| 119 |
-} |
|
| 120 |
- |
|
| 121 |
-// assertHttpNotError expect the given response to not have an error. |
|
| 122 |
-// Otherwise the it causes the test to fail. |
|
| 123 |
-func assertHttpNotError(r *httptest.ResponseRecorder, t Fataler) {
|
|
| 124 |
- // Non-error http status are [200, 400) |
|
| 125 |
- if r.Code < http.StatusOK || r.Code >= http.StatusBadRequest {
|
|
| 126 |
- t.Fatal(fmt.Errorf("Unexpected http error: %v", r.Code))
|
|
| 127 |
- } |
|
| 128 |
-} |
|
| 129 |
- |
|
| 130 |
-// assertHttpError expect the given response to have an error. |
|
| 131 |
-// Otherwise the it causes the test to fail. |
|
| 132 |
-func assertHttpError(r *httptest.ResponseRecorder, t Fataler) {
|
|
| 133 |
- // Non-error http status are [200, 400) |
|
| 134 |
- if !(r.Code < http.StatusOK || r.Code >= http.StatusBadRequest) {
|
|
| 135 |
- t.Fatal(fmt.Errorf("Unexpected http success code: %v", r.Code))
|
|
| 136 |
- } |
|
| 137 |
-} |
|
| 138 |
- |
|
| 139 |
-func getContainer(eng *engine.Engine, id string, t Fataler) *daemon.Container {
|
|
| 140 |
- daemon := mkDaemonFromEngine(eng, t) |
|
| 141 |
- c, err := daemon.Get(id) |
|
| 142 |
- if err != nil {
|
|
| 143 |
- t.Fatal(err) |
|
| 144 |
- } |
|
| 145 |
- return c |
|
| 146 |
-} |
|
| 147 |
- |
|
| 148 |
-func mkDaemonFromEngine(eng *engine.Engine, t Fataler) *daemon.Daemon {
|
|
| 149 |
- iDaemon := eng.HackGetGlobalVar("httpapi.daemon")
|
|
| 150 |
- if iDaemon == nil {
|
|
| 151 |
- panic("Legacy daemon field not set in engine")
|
|
| 152 |
- } |
|
| 153 |
- daemon, ok := iDaemon.(*daemon.Daemon) |
|
| 154 |
- if !ok {
|
|
| 155 |
- panic("Legacy daemon field in engine does not cast to *daemon.Daemon")
|
|
| 156 |
- } |
|
| 157 |
- return daemon |
|
| 158 |
-} |
|
| 159 |
- |
|
| 160 |
-func newTestEngine(t Fataler, autorestart bool, root string) *engine.Engine {
|
|
| 161 |
- if root == "" {
|
|
| 162 |
- if dir, err := newTestDirectory(unitTestStoreBase); err != nil {
|
|
| 163 |
- t.Fatal(err) |
|
| 164 |
- } else {
|
|
| 165 |
- root = dir |
|
| 166 |
- } |
|
| 167 |
- } |
|
| 168 |
- os.MkdirAll(root, 0700) |
|
| 169 |
- |
|
| 170 |
- eng := engine.New() |
|
| 171 |
- eng.Logging = false |
|
| 172 |
- |
|
| 173 |
- // (This is manually copied and modified from main() until we have a more generic plugin system) |
|
| 174 |
- cfg := &daemon.Config{
|
|
| 175 |
- Root: root, |
|
| 176 |
- AutoRestart: autorestart, |
|
| 177 |
- ExecDriver: "native", |
|
| 178 |
- // Either InterContainerCommunication or EnableIptables must be set, |
|
| 179 |
- // otherwise NewDaemon will fail because of conflicting settings. |
|
| 180 |
- Bridge: bridge.Config{
|
|
| 181 |
- InterContainerCommunication: true, |
|
| 182 |
- }, |
|
| 183 |
- TrustKeyPath: filepath.Join(root, "key.json"), |
|
| 184 |
- LogConfig: runconfig.LogConfig{Type: "json-file"},
|
|
| 185 |
- } |
|
| 186 |
- d, err := daemon.NewDaemon(cfg, eng, registry.NewService(nil)) |
|
| 187 |
- if err != nil {
|
|
| 188 |
- t.Fatal(err) |
|
| 189 |
- } |
|
| 190 |
- if err := d.Install(eng); err != nil {
|
|
| 191 |
- t.Fatal(err) |
|
| 192 |
- } |
|
| 193 |
- return eng |
|
| 194 |
-} |
|
| 195 |
- |
|
| 196 |
-func NewTestEngine(t Fataler) *engine.Engine {
|
|
| 197 |
- return newTestEngine(t, false, "") |
|
| 198 |
-} |
|
| 199 |
- |
|
| 200 |
-func newTestDirectory(templateDir string) (dir string, err error) {
|
|
| 201 |
- return utils.TestDirectory(templateDir) |
|
| 202 |
-} |
|
| 203 |
- |
|
| 204 |
-func getCallerName(depth int) string {
|
|
| 205 |
- return utils.GetCallerName(depth) |
|
| 206 |
-} |
|
| 207 |
- |
|
| 208 |
-// Write `content` to the file at path `dst`, creating it if necessary, |
|
| 209 |
-// as well as any missing directories. |
|
| 210 |
-// The file is truncated if it already exists. |
|
| 211 |
-// Call t.Fatal() at the first error. |
|
| 212 |
-func writeFile(dst, content string, t *testing.T) {
|
|
| 213 |
- // Create subdirectories if necessary |
|
| 214 |
- if err := os.MkdirAll(path.Dir(dst), 0700); err != nil && !os.IsExist(err) {
|
|
| 215 |
- t.Fatal(err) |
|
| 216 |
- } |
|
| 217 |
- f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700) |
|
| 218 |
- if err != nil {
|
|
| 219 |
- t.Fatal(err) |
|
| 220 |
- } |
|
| 221 |
- // Write content (truncate if it exists) |
|
| 222 |
- if _, err := io.Copy(f, strings.NewReader(content)); err != nil {
|
|
| 223 |
- t.Fatal(err) |
|
| 224 |
- } |
|
| 225 |
-} |
|
| 226 |
- |
|
| 227 |
-// Return the contents of file at path `src`. |
|
| 228 |
-// Call t.Fatal() at the first error (including if the file doesn't exist) |
|
| 229 |
-func readFile(src string, t *testing.T) (content string) {
|
|
| 230 |
- f, err := os.Open(src) |
|
| 231 |
- if err != nil {
|
|
| 232 |
- t.Fatal(err) |
|
| 233 |
- } |
|
| 234 |
- data, err := ioutil.ReadAll(f) |
|
| 235 |
- if err != nil {
|
|
| 236 |
- t.Fatal(err) |
|
| 237 |
- } |
|
| 238 |
- return string(data) |
|
| 239 |
-} |
|
| 240 |
- |
|
| 241 |
-// Create a test container from the given daemon `r` and run arguments `args`. |
|
| 242 |
-// If the image name is "_", (eg. []string{"-i", "-t", "_", "bash"}, it is
|
|
| 243 |
-// dynamically replaced by the current test image. |
|
| 244 |
-// The caller is responsible for destroying the container. |
|
| 245 |
-// Call t.Fatal() at the first error. |
|
| 246 |
-func mkContainer(r *daemon.Daemon, args []string, t *testing.T) (*daemon.Container, *runconfig.HostConfig, error) {
|
|
| 247 |
- config, hc, _, err := parseRun(args) |
|
| 248 |
- defer func() {
|
|
| 249 |
- if err != nil && t != nil {
|
|
| 250 |
- t.Fatal(err) |
|
| 251 |
- } |
|
| 252 |
- }() |
|
| 253 |
- if err != nil {
|
|
| 254 |
- return nil, nil, err |
|
| 255 |
- } |
|
| 256 |
- if config.Image == "_" {
|
|
| 257 |
- config.Image = GetTestImage(r).ID |
|
| 258 |
- } |
|
| 259 |
- c, _, err := r.Create(config, nil, "") |
|
| 260 |
- if err != nil {
|
|
| 261 |
- return nil, nil, err |
|
| 262 |
- } |
|
| 263 |
- // NOTE: hostConfig is ignored. |
|
| 264 |
- // If `args` specify privileged mode, custom lxc conf, external mount binds, |
|
| 265 |
- // port redirects etc. they will be ignored. |
|
| 266 |
- // This is because the correct way to set these things is to pass environment |
|
| 267 |
- // to the `start` job. |
|
| 268 |
- // FIXME: this helper function should be deprecated in favor of calling |
|
| 269 |
- // `create` and `start` jobs directly. |
|
| 270 |
- return c, hc, nil |
|
| 271 |
-} |
|
| 272 |
- |
|
| 273 |
-// Create a test container, start it, wait for it to complete, destroy it, |
|
| 274 |
-// and return its standard output as a string. |
|
| 275 |
-// The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
|
|
| 276 |
-// If t is not nil, call t.Fatal() at the first error. Otherwise return errors normally. |
|
| 277 |
-func runContainer(eng *engine.Engine, r *daemon.Daemon, args []string, t *testing.T) (output string, err error) {
|
|
| 278 |
- defer func() {
|
|
| 279 |
- if err != nil && t != nil {
|
|
| 280 |
- t.Fatal(err) |
|
| 281 |
- } |
|
| 282 |
- }() |
|
| 283 |
- container, hc, err := mkContainer(r, args, t) |
|
| 284 |
- if err != nil {
|
|
| 285 |
- return "", err |
|
| 286 |
- } |
|
| 287 |
- defer r.Rm(container) |
|
| 288 |
- stdout := container.StdoutPipe() |
|
| 289 |
- defer stdout.Close() |
|
| 290 |
- |
|
| 291 |
- job := eng.Job("start", container.ID)
|
|
| 292 |
- if err := job.ImportEnv(hc); err != nil {
|
|
| 293 |
- return "", err |
|
| 294 |
- } |
|
| 295 |
- if err := job.Run(); err != nil {
|
|
| 296 |
- return "", err |
|
| 297 |
- } |
|
| 298 |
- |
|
| 299 |
- container.WaitStop(-1 * time.Second) |
|
| 300 |
- data, err := ioutil.ReadAll(stdout) |
|
| 301 |
- if err != nil {
|
|
| 302 |
- return "", err |
|
| 303 |
- } |
|
| 304 |
- output = string(data) |
|
| 305 |
- return |
|
| 306 |
-} |
|
| 307 |
- |
|
| 308 |
-// FIXME: this is duplicated from graph_test.go in the docker package. |
|
| 309 |
-func fakeTar() (io.ReadCloser, error) {
|
|
| 310 |
- content := []byte("Hello world!\n")
|
|
| 311 |
- buf := new(bytes.Buffer) |
|
| 312 |
- tw := tar.NewWriter(buf) |
|
| 313 |
- for _, name := range []string{"/etc/postgres/postgres.conf", "/etc/passwd", "/var/log/postgres/postgres.conf"} {
|
|
| 314 |
- hdr := new(tar.Header) |
|
| 315 |
- hdr.Size = int64(len(content)) |
|
| 316 |
- hdr.Name = name |
|
| 317 |
- if err := tw.WriteHeader(hdr); err != nil {
|
|
| 318 |
- return nil, err |
|
| 319 |
- } |
|
| 320 |
- tw.Write([]byte(content)) |
|
| 321 |
- } |
|
| 322 |
- tw.Close() |
|
| 323 |
- return ioutil.NopCloser(buf), nil |
|
| 324 |
-} |
|
| 325 |
- |
|
| 326 |
-func getImages(eng *engine.Engine, t *testing.T, all bool, filter string) []*types.Image {
|
|
| 327 |
- config := graph.ImagesConfig{
|
|
| 328 |
- Filter: filter, |
|
| 329 |
- All: all, |
|
| 330 |
- } |
|
| 331 |
- images, err := getDaemon(eng).Repositories().Images(&config) |
|
| 332 |
- if err != nil {
|
|
| 333 |
- t.Fatal(err) |
|
| 334 |
- } |
|
| 335 |
- |
|
| 336 |
- return images |
|
| 337 |
-} |
|
| 338 |
- |
|
| 339 |
-func parseRun(args []string) (*runconfig.Config, *runconfig.HostConfig, *flag.FlagSet, error) {
|
|
| 340 |
- cmd := flag.NewFlagSet("run", flag.ContinueOnError)
|
|
| 341 |
- cmd.SetOutput(ioutil.Discard) |
|
| 342 |
- cmd.Usage = nil |
|
| 343 |
- return runconfig.Parse(cmd, args) |
|
| 344 |
-} |
|
| 345 |
- |
|
| 346 |
-func getDaemon(eng *engine.Engine) *daemon.Daemon {
|
|
| 347 |
- return eng.HackGetGlobalVar("httpapi.daemon").(*daemon.Daemon)
|
|
| 348 |
-} |
| 349 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,18 +0,0 @@ |
| 1 |
-package docker |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "runtime" |
|
| 5 |
- "testing" |
|
| 6 |
- |
|
| 7 |
- "github.com/docker/docker/pkg/fileutils" |
|
| 8 |
-) |
|
| 9 |
- |
|
| 10 |
-func displayFdGoroutines(t *testing.T) {
|
|
| 11 |
- t.Logf("File Descriptors: %d, Goroutines: %d", fileutils.GetTotalUsedFds(), runtime.NumGoroutine())
|
|
| 12 |
-} |
|
| 13 |
- |
|
| 14 |
-func TestFinal(t *testing.T) {
|
|
| 15 |
- nuke(globalDaemon) |
|
| 16 |
- t.Logf("Start File Descriptors: %d, Start Goroutines: %d", startFds, startGoroutines)
|
|
| 17 |
- displayFdGoroutines(t) |
|
| 18 |
-} |