Signed-off-by: Vincent Demeester <vincent@sbr.pm>
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,118 @@ |
| 0 |
+package runconfig |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "testing" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/docker/docker/pkg/nat" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func TestCompare(t *testing.T) {
|
|
| 9 |
+ ports1 := make(nat.PortSet) |
|
| 10 |
+ ports1[nat.Port("1111/tcp")] = struct{}{}
|
|
| 11 |
+ ports1[nat.Port("2222/tcp")] = struct{}{}
|
|
| 12 |
+ ports2 := make(nat.PortSet) |
|
| 13 |
+ ports2[nat.Port("3333/tcp")] = struct{}{}
|
|
| 14 |
+ ports2[nat.Port("4444/tcp")] = struct{}{}
|
|
| 15 |
+ ports3 := make(nat.PortSet) |
|
| 16 |
+ ports3[nat.Port("1111/tcp")] = struct{}{}
|
|
| 17 |
+ ports3[nat.Port("2222/tcp")] = struct{}{}
|
|
| 18 |
+ ports3[nat.Port("5555/tcp")] = struct{}{}
|
|
| 19 |
+ volumes1 := make(map[string]struct{})
|
|
| 20 |
+ volumes1["/test1"] = struct{}{}
|
|
| 21 |
+ volumes2 := make(map[string]struct{})
|
|
| 22 |
+ volumes2["/test2"] = struct{}{}
|
|
| 23 |
+ volumes3 := make(map[string]struct{})
|
|
| 24 |
+ volumes3["/test1"] = struct{}{}
|
|
| 25 |
+ volumes3["/test3"] = struct{}{}
|
|
| 26 |
+ envs1 := []string{"ENV1=value1", "ENV2=value2"}
|
|
| 27 |
+ envs2 := []string{"ENV1=value1", "ENV3=value3"}
|
|
| 28 |
+ entrypoint1 := &Entrypoint{parts: []string{"/bin/sh", "-c"}}
|
|
| 29 |
+ entrypoint2 := &Entrypoint{parts: []string{"/bin/sh", "-d"}}
|
|
| 30 |
+ entrypoint3 := &Entrypoint{parts: []string{"/bin/sh", "-c", "echo"}}
|
|
| 31 |
+ cmd1 := &Command{parts: []string{"/bin/sh", "-c"}}
|
|
| 32 |
+ cmd2 := &Command{parts: []string{"/bin/sh", "-d"}}
|
|
| 33 |
+ cmd3 := &Command{parts: []string{"/bin/sh", "-c", "echo"}}
|
|
| 34 |
+ labels1 := map[string]string{"LABEL1": "value1", "LABEL2": "value2"}
|
|
| 35 |
+ labels2 := map[string]string{"LABEL1": "value1", "LABEL2": "value3"}
|
|
| 36 |
+ labels3 := map[string]string{"LABEL1": "value1", "LABEL2": "value2", "LABEL3": "value3"}
|
|
| 37 |
+ |
|
| 38 |
+ sameConfigs := map[*Config]*Config{
|
|
| 39 |
+ // Empty config |
|
| 40 |
+ &Config{}: {},
|
|
| 41 |
+ // Does not compare hostname, domainname & image |
|
| 42 |
+ &Config{
|
|
| 43 |
+ Hostname: "host1", |
|
| 44 |
+ Domainname: "domain1", |
|
| 45 |
+ Image: "image1", |
|
| 46 |
+ User: "user", |
|
| 47 |
+ }: {
|
|
| 48 |
+ Hostname: "host2", |
|
| 49 |
+ Domainname: "domain2", |
|
| 50 |
+ Image: "image2", |
|
| 51 |
+ User: "user", |
|
| 52 |
+ }, |
|
| 53 |
+ // only OpenStdin |
|
| 54 |
+ &Config{OpenStdin: false}: {OpenStdin: false},
|
|
| 55 |
+ // only env |
|
| 56 |
+ &Config{Env: envs1}: {Env: envs1},
|
|
| 57 |
+ // only cmd |
|
| 58 |
+ &Config{Cmd: cmd1}: {Cmd: cmd1},
|
|
| 59 |
+ // only labels |
|
| 60 |
+ &Config{Labels: labels1}: {Labels: labels1},
|
|
| 61 |
+ // only exposedPorts |
|
| 62 |
+ &Config{ExposedPorts: ports1}: {ExposedPorts: ports1},
|
|
| 63 |
+ // only entrypoints |
|
| 64 |
+ &Config{Entrypoint: entrypoint1}: {Entrypoint: entrypoint1},
|
|
| 65 |
+ // only volumes |
|
| 66 |
+ &Config{Volumes: volumes1}: {Volumes: volumes1},
|
|
| 67 |
+ } |
|
| 68 |
+ differentConfigs := map[*Config]*Config{
|
|
| 69 |
+ nil: nil, |
|
| 70 |
+ &Config{
|
|
| 71 |
+ Hostname: "host1", |
|
| 72 |
+ Domainname: "domain1", |
|
| 73 |
+ Image: "image1", |
|
| 74 |
+ User: "user1", |
|
| 75 |
+ }: {
|
|
| 76 |
+ Hostname: "host1", |
|
| 77 |
+ Domainname: "domain1", |
|
| 78 |
+ Image: "image1", |
|
| 79 |
+ User: "user2", |
|
| 80 |
+ }, |
|
| 81 |
+ // only OpenStdin |
|
| 82 |
+ &Config{OpenStdin: false}: {OpenStdin: true},
|
|
| 83 |
+ &Config{OpenStdin: true}: {OpenStdin: false},
|
|
| 84 |
+ // only env |
|
| 85 |
+ &Config{Env: envs1}: {Env: envs2},
|
|
| 86 |
+ // only cmd |
|
| 87 |
+ &Config{Cmd: cmd1}: {Cmd: cmd2},
|
|
| 88 |
+ // not the same number of parts |
|
| 89 |
+ &Config{Cmd: cmd1}: {Cmd: cmd3},
|
|
| 90 |
+ // only labels |
|
| 91 |
+ &Config{Labels: labels1}: {Labels: labels2},
|
|
| 92 |
+ // not the same number of labels |
|
| 93 |
+ &Config{Labels: labels1}: {Labels: labels3},
|
|
| 94 |
+ // only exposedPorts |
|
| 95 |
+ &Config{ExposedPorts: ports1}: {ExposedPorts: ports2},
|
|
| 96 |
+ // not the same number of ports |
|
| 97 |
+ &Config{ExposedPorts: ports1}: {ExposedPorts: ports3},
|
|
| 98 |
+ // only entrypoints |
|
| 99 |
+ &Config{Entrypoint: entrypoint1}: {Entrypoint: entrypoint2},
|
|
| 100 |
+ // not the same number of parts |
|
| 101 |
+ &Config{Entrypoint: entrypoint1}: {Entrypoint: entrypoint3},
|
|
| 102 |
+ // only volumes |
|
| 103 |
+ &Config{Volumes: volumes1}: {Volumes: volumes2},
|
|
| 104 |
+ // not the same number of labels |
|
| 105 |
+ &Config{Volumes: volumes1}: {Volumes: volumes3},
|
|
| 106 |
+ } |
|
| 107 |
+ for config1, config2 := range sameConfigs {
|
|
| 108 |
+ if !Compare(config1, config2) {
|
|
| 109 |
+ t.Fatalf("Compare should be true for [%v] and [%v]", config1, config2)
|
|
| 110 |
+ } |
|
| 111 |
+ } |
|
| 112 |
+ for config1, config2 := range differentConfigs {
|
|
| 113 |
+ if Compare(config1, config2) {
|
|
| 114 |
+ t.Fatalf("Compare should be false for [%v] and [%v]", config1, config2)
|
|
| 115 |
+ } |
|
| 116 |
+ } |
|
| 117 |
+} |
| ... | ... |
@@ -5,274 +5,109 @@ import ( |
| 5 | 5 |
"encoding/json" |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"io/ioutil" |
| 8 |
- "strings" |
|
| 9 | 8 |
"testing" |
| 10 |
- |
|
| 11 |
- "github.com/docker/docker/pkg/nat" |
|
| 12 | 9 |
) |
| 13 | 10 |
|
| 14 |
-func parse(t *testing.T, args string) (*Config, *HostConfig, error) {
|
|
| 15 |
- config, hostConfig, _, err := parseRun(strings.Split(args+" ubuntu bash", " ")) |
|
| 16 |
- return config, hostConfig, err |
|
| 17 |
-} |
|
| 18 |
- |
|
| 19 |
-func mustParse(t *testing.T, args string) (*Config, *HostConfig) {
|
|
| 20 |
- config, hostConfig, err := parse(t, args) |
|
| 21 |
- if err != nil {
|
|
| 22 |
- t.Fatal(err) |
|
| 11 |
+func TestEntrypointMarshalJSON(t *testing.T) {
|
|
| 12 |
+ entrypoints := map[*Entrypoint]string{
|
|
| 13 |
+ nil: "", |
|
| 14 |
+ &Entrypoint{}: "null",
|
|
| 15 |
+ &Entrypoint{[]string{"/bin/sh", "-c", "echo"}}: `["/bin/sh","-c","echo"]`,
|
|
| 23 | 16 |
} |
| 24 |
- return config, hostConfig |
|
| 25 |
-} |
|
| 26 | 17 |
|
| 27 |
-// check if (a == c && b == d) || (a == d && b == c) |
|
| 28 |
-// because maps are randomized |
|
| 29 |
-func compareRandomizedStrings(a, b, c, d string) error {
|
|
| 30 |
- if a == c && b == d {
|
|
| 31 |
- return nil |
|
| 32 |
- } |
|
| 33 |
- if a == d && b == c {
|
|
| 34 |
- return nil |
|
| 35 |
- } |
|
| 36 |
- return fmt.Errorf("strings don't match")
|
|
| 37 |
-} |
|
| 38 |
- |
|
| 39 |
-func TestParseRunLinks(t *testing.T) {
|
|
| 40 |
- if _, hostConfig := mustParse(t, "--link a:b"); len(hostConfig.Links) == 0 || hostConfig.Links[0] != "a:b" {
|
|
| 41 |
- t.Fatalf("Error parsing links. Expected []string{\"a:b\"}, received: %v", hostConfig.Links)
|
|
| 42 |
- } |
|
| 43 |
- if _, hostConfig := mustParse(t, "--link a:b --link c:d"); len(hostConfig.Links) < 2 || hostConfig.Links[0] != "a:b" || hostConfig.Links[1] != "c:d" {
|
|
| 44 |
- t.Fatalf("Error parsing links. Expected []string{\"a:b\", \"c:d\"}, received: %v", hostConfig.Links)
|
|
| 45 |
- } |
|
| 46 |
- if _, hostConfig := mustParse(t, ""); len(hostConfig.Links) != 0 {
|
|
| 47 |
- t.Fatalf("Error parsing links. No link expected, received: %v", hostConfig.Links)
|
|
| 18 |
+ for entrypoint, expected := range entrypoints {
|
|
| 19 |
+ data, err := entrypoint.MarshalJSON() |
|
| 20 |
+ if err != nil {
|
|
| 21 |
+ t.Fatal(err) |
|
| 22 |
+ } |
|
| 23 |
+ if string(data) != expected {
|
|
| 24 |
+ t.Fatalf("Expected %v, got %v", expected, string(data))
|
|
| 25 |
+ } |
|
| 48 | 26 |
} |
| 49 | 27 |
} |
| 50 | 28 |
|
| 51 |
-func TestParseRunAttach(t *testing.T) {
|
|
| 52 |
- if config, _ := mustParse(t, "-a stdin"); !config.AttachStdin || config.AttachStdout || config.AttachStderr {
|
|
| 53 |
- t.Fatalf("Error parsing attach flags. Expect only Stdin enabled. Received: in: %v, out: %v, err: %v", config.AttachStdin, config.AttachStdout, config.AttachStderr)
|
|
| 54 |
- } |
|
| 55 |
- if config, _ := mustParse(t, "-a stdin -a stdout"); !config.AttachStdin || !config.AttachStdout || config.AttachStderr {
|
|
| 56 |
- t.Fatalf("Error parsing attach flags. Expect only Stdin and Stdout enabled. Received: in: %v, out: %v, err: %v", config.AttachStdin, config.AttachStdout, config.AttachStderr)
|
|
| 57 |
- } |
|
| 58 |
- if config, _ := mustParse(t, "-a stdin -a stdout -a stderr"); !config.AttachStdin || !config.AttachStdout || !config.AttachStderr {
|
|
| 59 |
- t.Fatalf("Error parsing attach flags. Expect all attach enabled. Received: in: %v, out: %v, err: %v", config.AttachStdin, config.AttachStdout, config.AttachStderr)
|
|
| 60 |
- } |
|
| 61 |
- if config, _ := mustParse(t, ""); config.AttachStdin || !config.AttachStdout || !config.AttachStderr {
|
|
| 62 |
- t.Fatalf("Error parsing attach flags. Expect Stdin disabled. Received: in: %v, out: %v, err: %v", config.AttachStdin, config.AttachStdout, config.AttachStderr)
|
|
| 29 |
+func TestEntrypointUnmarshalJSON(t *testing.T) {
|
|
| 30 |
+ parts := map[string][]string{
|
|
| 31 |
+ "": {"default", "values"},
|
|
| 32 |
+ "[]": {},
|
|
| 33 |
+ `["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"},
|
|
| 63 | 34 |
} |
| 35 |
+ for json, expectedParts := range parts {
|
|
| 36 |
+ entrypoint := &Entrypoint{
|
|
| 37 |
+ []string{"default", "values"},
|
|
| 38 |
+ } |
|
| 39 |
+ if err := entrypoint.UnmarshalJSON([]byte(json)); err != nil {
|
|
| 40 |
+ t.Fatal(err) |
|
| 41 |
+ } |
|
| 64 | 42 |
|
| 65 |
- if _, _, err := parse(t, "-a"); err == nil {
|
|
| 66 |
- t.Fatalf("Error parsing attach flags, `-a` should be an error but is not")
|
|
| 67 |
- } |
|
| 68 |
- if _, _, err := parse(t, "-a invalid"); err == nil {
|
|
| 69 |
- t.Fatalf("Error parsing attach flags, `-a invalid` should be an error but is not")
|
|
| 70 |
- } |
|
| 71 |
- if _, _, err := parse(t, "-a invalid -a stdout"); err == nil {
|
|
| 72 |
- t.Fatalf("Error parsing attach flags, `-a stdout -a invalid` should be an error but is not")
|
|
| 73 |
- } |
|
| 74 |
- if _, _, err := parse(t, "-a stdout -a stderr -d"); err == nil {
|
|
| 75 |
- t.Fatalf("Error parsing attach flags, `-a stdout -a stderr -d` should be an error but is not")
|
|
| 76 |
- } |
|
| 77 |
- if _, _, err := parse(t, "-a stdin -d"); err == nil {
|
|
| 78 |
- t.Fatalf("Error parsing attach flags, `-a stdin -d` should be an error but is not")
|
|
| 79 |
- } |
|
| 80 |
- if _, _, err := parse(t, "-a stdout -d"); err == nil {
|
|
| 81 |
- t.Fatalf("Error parsing attach flags, `-a stdout -d` should be an error but is not")
|
|
| 82 |
- } |
|
| 83 |
- if _, _, err := parse(t, "-a stderr -d"); err == nil {
|
|
| 84 |
- t.Fatalf("Error parsing attach flags, `-a stderr -d` should be an error but is not")
|
|
| 85 |
- } |
|
| 86 |
- if _, _, err := parse(t, "-d --rm"); err == nil {
|
|
| 87 |
- t.Fatalf("Error parsing attach flags, `-d --rm` should be an error but is not")
|
|
| 43 |
+ actualParts := entrypoint.Slice() |
|
| 44 |
+ if len(actualParts) != len(expectedParts) {
|
|
| 45 |
+ t.Fatalf("Expected %v parts, got %v (%v)", len(expectedParts), len(actualParts), expectedParts)
|
|
| 46 |
+ } |
|
| 47 |
+ for index, part := range actualParts {
|
|
| 48 |
+ if part != expectedParts[index] {
|
|
| 49 |
+ t.Fatalf("Expected %v, got %v", expectedParts, actualParts)
|
|
| 50 |
+ break |
|
| 51 |
+ } |
|
| 52 |
+ } |
|
| 88 | 53 |
} |
| 89 | 54 |
} |
| 90 | 55 |
|
| 91 |
-func TestParseRunVolumes(t *testing.T) {
|
|
| 92 |
- if config, hostConfig := mustParse(t, "-v /tmp"); hostConfig.Binds != nil {
|
|
| 93 |
- t.Fatalf("Error parsing volume flags, `-v /tmp` should not mount-bind anything. Received %v", hostConfig.Binds)
|
|
| 94 |
- } else if _, exists := config.Volumes["/tmp"]; !exists {
|
|
| 95 |
- t.Fatalf("Error parsing volume flags, `-v /tmp` is missing from volumes. Received %v", config.Volumes)
|
|
| 96 |
- } |
|
| 97 |
- |
|
| 98 |
- if config, hostConfig := mustParse(t, "-v /tmp -v /var"); hostConfig.Binds != nil {
|
|
| 99 |
- t.Fatalf("Error parsing volume flags, `-v /tmp -v /var` should not mount-bind anything. Received %v", hostConfig.Binds)
|
|
| 100 |
- } else if _, exists := config.Volumes["/tmp"]; !exists {
|
|
| 101 |
- t.Fatalf("Error parsing volume flags, `-v /tmp` is missing from volumes. Received %v", config.Volumes)
|
|
| 102 |
- } else if _, exists := config.Volumes["/var"]; !exists {
|
|
| 103 |
- t.Fatalf("Error parsing volume flags, `-v /var` is missing from volumes. Received %v", config.Volumes)
|
|
| 104 |
- } |
|
| 105 |
- |
|
| 106 |
- if _, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp"); hostConfig.Binds == nil || hostConfig.Binds[0] != "/hostTmp:/containerTmp" {
|
|
| 107 |
- t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp` should mount-bind /hostTmp into /containeTmp. Received %v", hostConfig.Binds)
|
|
| 108 |
- } |
|
| 109 |
- |
|
| 110 |
- if _, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp -v /hostVar:/containerVar"); hostConfig.Binds == nil || compareRandomizedStrings(hostConfig.Binds[0], hostConfig.Binds[1], "/hostTmp:/containerTmp", "/hostVar:/containerVar") != nil {
|
|
| 111 |
- t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp -v /hostVar:/containerVar` should mount-bind /hostTmp into /containeTmp and /hostVar into /hostContainer. Received %v", hostConfig.Binds)
|
|
| 112 |
- } |
|
| 113 |
- |
|
| 114 |
- if _, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp:ro -v /hostVar:/containerVar:rw"); hostConfig.Binds == nil || compareRandomizedStrings(hostConfig.Binds[0], hostConfig.Binds[1], "/hostTmp:/containerTmp:ro", "/hostVar:/containerVar:rw") != nil {
|
|
| 115 |
- t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp:ro -v /hostVar:/containerVar:rw` should mount-bind /hostTmp into /containeTmp and /hostVar into /hostContainer. Received %v", hostConfig.Binds)
|
|
| 116 |
- } |
|
| 117 |
- |
|
| 118 |
- if _, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp:roZ -v /hostVar:/containerVar:rwZ"); hostConfig.Binds == nil || compareRandomizedStrings(hostConfig.Binds[0], hostConfig.Binds[1], "/hostTmp:/containerTmp:roZ", "/hostVar:/containerVar:rwZ") != nil {
|
|
| 119 |
- t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp:roZ -v /hostVar:/containerVar:rwZ` should mount-bind /hostTmp into /containeTmp and /hostVar into /hostContainer. Received %v", hostConfig.Binds)
|
|
| 120 |
- } |
|
| 121 |
- |
|
| 122 |
- if _, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp:Z -v /hostVar:/containerVar:z"); hostConfig.Binds == nil || compareRandomizedStrings(hostConfig.Binds[0], hostConfig.Binds[1], "/hostTmp:/containerTmp:Z", "/hostVar:/containerVar:z") != nil {
|
|
| 123 |
- t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp:Z -v /hostVar:/containerVar:z` should mount-bind /hostTmp into /containeTmp and /hostVar into /hostContainer. Received %v", hostConfig.Binds)
|
|
| 56 |
+func TestCommandToString(t *testing.T) {
|
|
| 57 |
+ commands := map[*Command]string{
|
|
| 58 |
+ &Command{[]string{""}}: "",
|
|
| 59 |
+ &Command{[]string{"one"}}: "one",
|
|
| 60 |
+ &Command{[]string{"one", "two"}}: "one two",
|
|
| 124 | 61 |
} |
| 125 |
- |
|
| 126 |
- if config, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp -v /containerVar"); hostConfig.Binds == nil || len(hostConfig.Binds) > 1 || hostConfig.Binds[0] != "/hostTmp:/containerTmp" {
|
|
| 127 |
- t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp -v /containerVar` should mount-bind only /hostTmp into /containeTmp. Received %v", hostConfig.Binds)
|
|
| 128 |
- } else if _, exists := config.Volumes["/containerVar"]; !exists {
|
|
| 129 |
- t.Fatalf("Error parsing volume flags, `-v /containerVar` is missing from volumes. Received %v", config.Volumes)
|
|
| 130 |
- } |
|
| 131 |
- |
|
| 132 |
- if config, hostConfig := mustParse(t, ""); hostConfig.Binds != nil {
|
|
| 133 |
- t.Fatalf("Error parsing volume flags, without volume, nothing should be mount-binded. Received %v", hostConfig.Binds)
|
|
| 134 |
- } else if len(config.Volumes) != 0 {
|
|
| 135 |
- t.Fatalf("Error parsing volume flags, without volume, no volume should be present. Received %v", config.Volumes)
|
|
| 136 |
- } |
|
| 137 |
- |
|
| 138 |
- if _, _, err := parse(t, "-v /"); err == nil {
|
|
| 139 |
- t.Fatalf("Expected error, but got none")
|
|
| 140 |
- } |
|
| 141 |
- |
|
| 142 |
- if _, _, err := parse(t, "-v /:/"); err == nil {
|
|
| 143 |
- t.Fatalf("Error parsing volume flags, `-v /:/` should fail but didn't")
|
|
| 144 |
- } |
|
| 145 |
- if _, _, err := parse(t, "-v"); err == nil {
|
|
| 146 |
- t.Fatalf("Error parsing volume flags, `-v` should fail but didn't")
|
|
| 147 |
- } |
|
| 148 |
- if _, _, err := parse(t, "-v /tmp:"); err == nil {
|
|
| 149 |
- t.Fatalf("Error parsing volume flags, `-v /tmp:` should fail but didn't")
|
|
| 150 |
- } |
|
| 151 |
- if _, _, err := parse(t, "-v /tmp:ro"); err == nil {
|
|
| 152 |
- t.Fatalf("Error parsing volume flags, `-v /tmp:ro` should fail but didn't")
|
|
| 153 |
- } |
|
| 154 |
- if _, _, err := parse(t, "-v /tmp::"); err == nil {
|
|
| 155 |
- t.Fatalf("Error parsing volume flags, `-v /tmp::` should fail but didn't")
|
|
| 156 |
- } |
|
| 157 |
- if _, _, err := parse(t, "-v :"); err == nil {
|
|
| 158 |
- t.Fatalf("Error parsing volume flags, `-v :` should fail but didn't")
|
|
| 159 |
- } |
|
| 160 |
- if _, _, err := parse(t, "-v ::"); err == nil {
|
|
| 161 |
- t.Fatalf("Error parsing volume flags, `-v ::` should fail but didn't")
|
|
| 162 |
- } |
|
| 163 |
- if _, _, err := parse(t, "-v /tmp:/tmp:/tmp:/tmp"); err == nil {
|
|
| 164 |
- t.Fatalf("Error parsing volume flags, `-v /tmp:/tmp:/tmp:/tmp` should fail but didn't")
|
|
| 62 |
+ for command, expected := range commands {
|
|
| 63 |
+ toString := command.ToString() |
|
| 64 |
+ if toString != expected {
|
|
| 65 |
+ t.Fatalf("Expected %v, got %v", expected, toString)
|
|
| 66 |
+ } |
|
| 165 | 67 |
} |
| 166 | 68 |
} |
| 167 | 69 |
|
| 168 |
-func TestCompare(t *testing.T) {
|
|
| 169 |
- volumes1 := make(map[string]struct{})
|
|
| 170 |
- volumes1["/test1"] = struct{}{}
|
|
| 171 |
- ports1 := make(nat.PortSet) |
|
| 172 |
- ports1[nat.Port("1111/tcp")] = struct{}{}
|
|
| 173 |
- ports1[nat.Port("2222/tcp")] = struct{}{}
|
|
| 174 |
- config1 := Config{
|
|
| 175 |
- ExposedPorts: ports1, |
|
| 176 |
- Env: []string{"VAR1=1", "VAR2=2"},
|
|
| 177 |
- Volumes: volumes1, |
|
| 178 |
- } |
|
| 179 |
- ports3 := make(nat.PortSet) |
|
| 180 |
- ports3[nat.Port("0000/tcp")] = struct{}{}
|
|
| 181 |
- ports3[nat.Port("2222/tcp")] = struct{}{}
|
|
| 182 |
- config3 := Config{
|
|
| 183 |
- ExposedPorts: ports3, |
|
| 184 |
- Volumes: volumes1, |
|
| 185 |
- } |
|
| 186 |
- volumes2 := make(map[string]struct{})
|
|
| 187 |
- volumes2["/test2"] = struct{}{}
|
|
| 188 |
- config5 := Config{
|
|
| 189 |
- Env: []string{"VAR1=1", "VAR2=2"},
|
|
| 190 |
- Volumes: volumes2, |
|
| 70 |
+func TestCommandMarshalJSON(t *testing.T) {
|
|
| 71 |
+ commands := map[*Command]string{
|
|
| 72 |
+ nil: "", |
|
| 73 |
+ &Command{}: "null",
|
|
| 74 |
+ &Command{[]string{"/bin/sh", "-c", "echo"}}: `["/bin/sh","-c","echo"]`,
|
|
| 191 | 75 |
} |
| 192 | 76 |
|
| 193 |
- if Compare(&config1, &config3) {
|
|
| 194 |
- t.Fatalf("Compare should return false, ExposedPorts are different")
|
|
| 195 |
- } |
|
| 196 |
- if Compare(&config1, &config5) {
|
|
| 197 |
- t.Fatalf("Compare should return false, Volumes are different")
|
|
| 198 |
- } |
|
| 199 |
- if !Compare(&config1, &config1) {
|
|
| 200 |
- t.Fatalf("Compare should return true")
|
|
| 77 |
+ for command, expected := range commands {
|
|
| 78 |
+ data, err := command.MarshalJSON() |
|
| 79 |
+ if err != nil {
|
|
| 80 |
+ t.Fatal(err) |
|
| 81 |
+ } |
|
| 82 |
+ if string(data) != expected {
|
|
| 83 |
+ t.Fatalf("Expected %v, got %v", expected, string(data))
|
|
| 84 |
+ } |
|
| 201 | 85 |
} |
| 202 | 86 |
} |
| 203 | 87 |
|
| 204 |
-func TestMerge(t *testing.T) {
|
|
| 205 |
- volumesImage := make(map[string]struct{})
|
|
| 206 |
- volumesImage["/test1"] = struct{}{}
|
|
| 207 |
- volumesImage["/test2"] = struct{}{}
|
|
| 208 |
- portsImage := make(nat.PortSet) |
|
| 209 |
- portsImage[nat.Port("1111/tcp")] = struct{}{}
|
|
| 210 |
- portsImage[nat.Port("2222/tcp")] = struct{}{}
|
|
| 211 |
- configImage := &Config{
|
|
| 212 |
- ExposedPorts: portsImage, |
|
| 213 |
- Env: []string{"VAR1=1", "VAR2=2"},
|
|
| 214 |
- Volumes: volumesImage, |
|
| 215 |
- } |
|
| 216 |
- |
|
| 217 |
- portsUser := make(nat.PortSet) |
|
| 218 |
- portsUser[nat.Port("2222/tcp")] = struct{}{}
|
|
| 219 |
- portsUser[nat.Port("3333/tcp")] = struct{}{}
|
|
| 220 |
- volumesUser := make(map[string]struct{})
|
|
| 221 |
- volumesUser["/test3"] = struct{}{}
|
|
| 222 |
- configUser := &Config{
|
|
| 223 |
- ExposedPorts: portsUser, |
|
| 224 |
- Env: []string{"VAR2=3", "VAR3=3"},
|
|
| 225 |
- Volumes: volumesUser, |
|
| 88 |
+func TestCommandUnmarshalJSON(t *testing.T) {
|
|
| 89 |
+ parts := map[string][]string{
|
|
| 90 |
+ "": {"default", "values"},
|
|
| 91 |
+ "[]": {},
|
|
| 92 |
+ `["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"},
|
|
| 226 | 93 |
} |
| 227 |
- |
|
| 228 |
- if err := Merge(configUser, configImage); err != nil {
|
|
| 229 |
- t.Error(err) |
|
| 230 |
- } |
|
| 231 |
- |
|
| 232 |
- if len(configUser.ExposedPorts) != 3 {
|
|
| 233 |
- t.Fatalf("Expected 3 ExposedPorts, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
|
|
| 234 |
- } |
|
| 235 |
- for portSpecs := range configUser.ExposedPorts {
|
|
| 236 |
- if portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
|
|
| 237 |
- t.Fatalf("Expected 1111 or 2222 or 3333, found %s", portSpecs)
|
|
| 94 |
+ for json, expectedParts := range parts {
|
|
| 95 |
+ command := &Command{
|
|
| 96 |
+ []string{"default", "values"},
|
|
| 238 | 97 |
} |
| 239 |
- } |
|
| 240 |
- if len(configUser.Env) != 3 {
|
|
| 241 |
- t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
|
|
| 242 |
- } |
|
| 243 |
- for _, env := range configUser.Env {
|
|
| 244 |
- if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
|
|
| 245 |
- t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
|
|
| 98 |
+ if err := command.UnmarshalJSON([]byte(json)); err != nil {
|
|
| 99 |
+ t.Fatal(err) |
|
| 246 | 100 |
} |
| 247 |
- } |
|
| 248 | 101 |
|
| 249 |
- if len(configUser.Volumes) != 3 {
|
|
| 250 |
- t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
|
|
| 251 |
- } |
|
| 252 |
- for v := range configUser.Volumes {
|
|
| 253 |
- if v != "/test1" && v != "/test2" && v != "/test3" {
|
|
| 254 |
- t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
|
|
| 102 |
+ actualParts := command.Slice() |
|
| 103 |
+ if len(actualParts) != len(expectedParts) {
|
|
| 104 |
+ t.Fatalf("Expected %v parts, got %v (%v)", len(expectedParts), len(actualParts), expectedParts)
|
|
| 255 | 105 |
} |
| 256 |
- } |
|
| 257 |
- |
|
| 258 |
- ports, _, err := nat.ParsePortSpecs([]string{"0000"})
|
|
| 259 |
- if err != nil {
|
|
| 260 |
- t.Error(err) |
|
| 261 |
- } |
|
| 262 |
- configImage2 := &Config{
|
|
| 263 |
- ExposedPorts: ports, |
|
| 264 |
- } |
|
| 265 |
- |
|
| 266 |
- if err := Merge(configUser, configImage2); err != nil {
|
|
| 267 |
- t.Error(err) |
|
| 268 |
- } |
|
| 269 |
- |
|
| 270 |
- if len(configUser.ExposedPorts) != 4 {
|
|
| 271 |
- t.Fatalf("Expected 4 ExposedPorts, 0000, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
|
|
| 272 |
- } |
|
| 273 |
- for portSpecs := range configUser.ExposedPorts {
|
|
| 274 |
- if portSpecs.Port() != "0" && portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
|
|
| 275 |
- t.Fatalf("Expected %q or %q or %q or %q, found %s", 0, 1111, 2222, 3333, portSpecs)
|
|
| 106 |
+ for index, part := range actualParts {
|
|
| 107 |
+ if part != expectedParts[index] {
|
|
| 108 |
+ t.Fatalf("Expected %v, got %v", expectedParts, actualParts)
|
|
| 109 |
+ break |
|
| 110 |
+ } |
|
| 276 | 111 |
} |
| 277 | 112 |
} |
| 278 | 113 |
} |
| 279 | 114 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,129 @@ |
| 0 |
+package runconfig |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ flag "github.com/docker/docker/pkg/mflag" |
|
| 5 |
+ "io/ioutil" |
|
| 6 |
+ "testing" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+type arguments struct {
|
|
| 10 |
+ args []string |
|
| 11 |
+} |
|
| 12 |
+ |
|
| 13 |
+func TestParseExec(t *testing.T) {
|
|
| 14 |
+ invalids := map[*arguments]error{
|
|
| 15 |
+ &arguments{[]string{"-unknown"}}: fmt.Errorf("flag provided but not defined: -unknown"),
|
|
| 16 |
+ &arguments{[]string{"-u"}}: fmt.Errorf("flag needs an argument: -u"),
|
|
| 17 |
+ &arguments{[]string{"--user"}}: fmt.Errorf("flag needs an argument: --user"),
|
|
| 18 |
+ } |
|
| 19 |
+ valids := map[*arguments]*ExecConfig{
|
|
| 20 |
+ &arguments{
|
|
| 21 |
+ []string{"container", "command"},
|
|
| 22 |
+ }: {
|
|
| 23 |
+ Container: "container", |
|
| 24 |
+ Cmd: []string{"command"},
|
|
| 25 |
+ AttachStdout: true, |
|
| 26 |
+ AttachStderr: true, |
|
| 27 |
+ }, |
|
| 28 |
+ &arguments{
|
|
| 29 |
+ []string{"container", "command1", "command2"},
|
|
| 30 |
+ }: {
|
|
| 31 |
+ Container: "container", |
|
| 32 |
+ Cmd: []string{"command1", "command2"},
|
|
| 33 |
+ AttachStdout: true, |
|
| 34 |
+ AttachStderr: true, |
|
| 35 |
+ }, |
|
| 36 |
+ &arguments{
|
|
| 37 |
+ []string{"-i", "-t", "-u", "uid", "container", "command"},
|
|
| 38 |
+ }: {
|
|
| 39 |
+ User: "uid", |
|
| 40 |
+ AttachStdin: true, |
|
| 41 |
+ AttachStdout: true, |
|
| 42 |
+ AttachStderr: true, |
|
| 43 |
+ Tty: true, |
|
| 44 |
+ Container: "container", |
|
| 45 |
+ Cmd: []string{"command"},
|
|
| 46 |
+ }, |
|
| 47 |
+ &arguments{
|
|
| 48 |
+ []string{"-d", "container", "command"},
|
|
| 49 |
+ }: {
|
|
| 50 |
+ AttachStdin: false, |
|
| 51 |
+ AttachStdout: false, |
|
| 52 |
+ AttachStderr: false, |
|
| 53 |
+ Detach: true, |
|
| 54 |
+ Container: "container", |
|
| 55 |
+ Cmd: []string{"command"},
|
|
| 56 |
+ }, |
|
| 57 |
+ &arguments{
|
|
| 58 |
+ []string{"-t", "-i", "-d", "container", "command"},
|
|
| 59 |
+ }: {
|
|
| 60 |
+ AttachStdin: false, |
|
| 61 |
+ AttachStdout: false, |
|
| 62 |
+ AttachStderr: false, |
|
| 63 |
+ Detach: true, |
|
| 64 |
+ Tty: true, |
|
| 65 |
+ Container: "container", |
|
| 66 |
+ Cmd: []string{"command"},
|
|
| 67 |
+ }, |
|
| 68 |
+ } |
|
| 69 |
+ for invalid, expectedError := range invalids {
|
|
| 70 |
+ cmd := flag.NewFlagSet("exec", flag.ContinueOnError)
|
|
| 71 |
+ cmd.ShortUsage = func() {}
|
|
| 72 |
+ cmd.SetOutput(ioutil.Discard) |
|
| 73 |
+ _, err := ParseExec(cmd, invalid.args) |
|
| 74 |
+ if err == nil || err.Error() != expectedError.Error() {
|
|
| 75 |
+ t.Fatalf("Expected an error [%v] for %v, got %v", expectedError, invalid, err)
|
|
| 76 |
+ } |
|
| 77 |
+ |
|
| 78 |
+ } |
|
| 79 |
+ for valid, expectedExecConfig := range valids {
|
|
| 80 |
+ cmd := flag.NewFlagSet("exec", flag.ContinueOnError)
|
|
| 81 |
+ cmd.ShortUsage = func() {}
|
|
| 82 |
+ cmd.SetOutput(ioutil.Discard) |
|
| 83 |
+ execConfig, err := ParseExec(cmd, valid.args) |
|
| 84 |
+ if err != nil {
|
|
| 85 |
+ t.Fatal(err) |
|
| 86 |
+ } |
|
| 87 |
+ if !compareExecConfig(expectedExecConfig, execConfig) {
|
|
| 88 |
+ t.Fatalf("Expected [%v] for %v, got [%v]", expectedExecConfig, valid, execConfig)
|
|
| 89 |
+ } |
|
| 90 |
+ } |
|
| 91 |
+} |
|
| 92 |
+ |
|
| 93 |
+func compareExecConfig(config1 *ExecConfig, config2 *ExecConfig) bool {
|
|
| 94 |
+ if config1.AttachStderr != config2.AttachStderr {
|
|
| 95 |
+ return false |
|
| 96 |
+ } |
|
| 97 |
+ if config1.AttachStdin != config2.AttachStdin {
|
|
| 98 |
+ return false |
|
| 99 |
+ } |
|
| 100 |
+ if config1.AttachStdout != config2.AttachStdout {
|
|
| 101 |
+ return false |
|
| 102 |
+ } |
|
| 103 |
+ if config1.Container != config2.Container {
|
|
| 104 |
+ return false |
|
| 105 |
+ } |
|
| 106 |
+ if config1.Detach != config2.Detach {
|
|
| 107 |
+ return false |
|
| 108 |
+ } |
|
| 109 |
+ if config1.Privileged != config2.Privileged {
|
|
| 110 |
+ return false |
|
| 111 |
+ } |
|
| 112 |
+ if config1.Tty != config2.Tty {
|
|
| 113 |
+ return false |
|
| 114 |
+ } |
|
| 115 |
+ if config1.User != config2.User {
|
|
| 116 |
+ return false |
|
| 117 |
+ } |
|
| 118 |
+ if len(config1.Cmd) != len(config2.Cmd) {
|
|
| 119 |
+ return false |
|
| 120 |
+ } else {
|
|
| 121 |
+ for index, value := range config1.Cmd {
|
|
| 122 |
+ if value != config2.Cmd[index] {
|
|
| 123 |
+ return false |
|
| 124 |
+ } |
|
| 125 |
+ } |
|
| 126 |
+ } |
|
| 127 |
+ return true |
|
| 128 |
+} |
| 0 | 129 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,18 @@ |
| 0 |
+{
|
|
| 1 |
+ "Binds": ["/tmp:/tmp"], |
|
| 2 |
+ "ContainerIDFile": "", |
|
| 3 |
+ "LxcConf": [], |
|
| 4 |
+ "Privileged": false, |
|
| 5 |
+ "PortBindings": {
|
|
| 6 |
+ "80/tcp": [ |
|
| 7 |
+ {
|
|
| 8 |
+ "HostIp": "0.0.0.0", |
|
| 9 |
+ "HostPort": "49153" |
|
| 10 |
+ } |
|
| 11 |
+ ] |
|
| 12 |
+ }, |
|
| 13 |
+ "Links": ["/name:alias"], |
|
| 14 |
+ "PublishAllPorts": false, |
|
| 15 |
+ "CapAdd": ["NET_ADMIN"], |
|
| 16 |
+ "CapDrop": ["MKNOD"] |
|
| 17 |
+} |
| 0 | 18 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,30 @@ |
| 0 |
+{
|
|
| 1 |
+ "Binds": ["/tmp:/tmp"], |
|
| 2 |
+ "Links": ["redis3:redis"], |
|
| 3 |
+ "LxcConf": {"lxc.utsname":"docker"},
|
|
| 4 |
+ "Memory": 0, |
|
| 5 |
+ "MemorySwap": 0, |
|
| 6 |
+ "CpuShares": 512, |
|
| 7 |
+ "CpuPeriod": 100000, |
|
| 8 |
+ "CpusetCpus": "0,1", |
|
| 9 |
+ "CpusetMems": "0,1", |
|
| 10 |
+ "BlkioWeight": 300, |
|
| 11 |
+ "OomKillDisable": false, |
|
| 12 |
+ "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
|
|
| 13 |
+ "PublishAllPorts": false, |
|
| 14 |
+ "Privileged": false, |
|
| 15 |
+ "ReadonlyRootfs": false, |
|
| 16 |
+ "Dns": ["8.8.8.8"], |
|
| 17 |
+ "DnsSearch": [""], |
|
| 18 |
+ "ExtraHosts": null, |
|
| 19 |
+ "VolumesFrom": ["parent", "other:ro"], |
|
| 20 |
+ "CapAdd": ["NET_ADMIN"], |
|
| 21 |
+ "CapDrop": ["MKNOD"], |
|
| 22 |
+ "RestartPolicy": { "Name": "", "MaximumRetryCount": 0 },
|
|
| 23 |
+ "NetworkMode": "bridge", |
|
| 24 |
+ "Devices": [], |
|
| 25 |
+ "Ulimits": [{}],
|
|
| 26 |
+ "LogConfig": { "Type": "json-file", "Config": {} },
|
|
| 27 |
+ "SecurityOpt": [""], |
|
| 28 |
+ "CgroupParent": "" |
|
| 29 |
+} |
| 0 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,265 @@ |
| 0 |
+package runconfig |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bytes" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "io/ioutil" |
|
| 6 |
+ "testing" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+func TestNetworkModeTest(t *testing.T) {
|
|
| 10 |
+ networkModes := map[NetworkMode][]bool{
|
|
| 11 |
+ // private, bridge, host, container, none, default |
|
| 12 |
+ "": {true, false, false, false, false, false},
|
|
| 13 |
+ "something:weird": {true, false, false, false, false, false},
|
|
| 14 |
+ "bridge": {true, true, false, false, false, false},
|
|
| 15 |
+ DefaultDaemonNetworkMode(): {true, true, false, false, false, false},
|
|
| 16 |
+ "host": {false, false, true, false, false, false},
|
|
| 17 |
+ "container:name": {false, false, false, true, false, false},
|
|
| 18 |
+ "none": {true, false, false, false, true, false},
|
|
| 19 |
+ "default": {true, false, false, false, false, true},
|
|
| 20 |
+ } |
|
| 21 |
+ networkModeNames := map[NetworkMode]string{
|
|
| 22 |
+ "": "", |
|
| 23 |
+ "something:weird": "", |
|
| 24 |
+ "bridge": "bridge", |
|
| 25 |
+ DefaultDaemonNetworkMode(): "bridge", |
|
| 26 |
+ "host": "host", |
|
| 27 |
+ "container:name": "container", |
|
| 28 |
+ "none": "none", |
|
| 29 |
+ "default": "default", |
|
| 30 |
+ } |
|
| 31 |
+ for networkMode, state := range networkModes {
|
|
| 32 |
+ if networkMode.IsPrivate() != state[0] {
|
|
| 33 |
+ t.Fatalf("NetworkMode.IsPrivate for %v should have been %v but was %v", networkMode, state[0], networkMode.IsPrivate())
|
|
| 34 |
+ } |
|
| 35 |
+ if networkMode.IsBridge() != state[1] {
|
|
| 36 |
+ t.Fatalf("NetworkMode.IsBridge for %v should have been %v but was %v", networkMode, state[1], networkMode.IsBridge())
|
|
| 37 |
+ } |
|
| 38 |
+ if networkMode.IsHost() != state[2] {
|
|
| 39 |
+ t.Fatalf("NetworkMode.IsHost for %v should have been %v but was %v", networkMode, state[2], networkMode.IsHost())
|
|
| 40 |
+ } |
|
| 41 |
+ if networkMode.IsContainer() != state[3] {
|
|
| 42 |
+ t.Fatalf("NetworkMode.IsContainer for %v should have been %v but was %v", networkMode, state[3], networkMode.IsContainer())
|
|
| 43 |
+ } |
|
| 44 |
+ if networkMode.IsNone() != state[4] {
|
|
| 45 |
+ t.Fatalf("NetworkMode.IsNone for %v should have been %v but was %v", networkMode, state[4], networkMode.IsNone())
|
|
| 46 |
+ } |
|
| 47 |
+ if networkMode.IsDefault() != state[5] {
|
|
| 48 |
+ t.Fatalf("NetworkMode.IsDefault for %v should have been %v but was %v", networkMode, state[5], networkMode.IsDefault())
|
|
| 49 |
+ } |
|
| 50 |
+ if networkMode.NetworkName() != networkModeNames[networkMode] {
|
|
| 51 |
+ t.Fatalf("Expected name %v, got %v", networkModeNames[networkMode], networkMode.NetworkName())
|
|
| 52 |
+ } |
|
| 53 |
+ } |
|
| 54 |
+} |
|
| 55 |
+ |
|
| 56 |
+func TestIpcModeTest(t *testing.T) {
|
|
| 57 |
+ ipcModes := map[IpcMode][]bool{
|
|
| 58 |
+ // private, host, container, valid |
|
| 59 |
+ "": {true, false, false, true},
|
|
| 60 |
+ "something:weird": {true, false, false, false},
|
|
| 61 |
+ ":weird": {true, false, false, true},
|
|
| 62 |
+ "host": {false, true, false, true},
|
|
| 63 |
+ "container:name": {false, false, true, true},
|
|
| 64 |
+ "container:name:something": {false, false, true, false},
|
|
| 65 |
+ "container:": {false, false, true, false},
|
|
| 66 |
+ } |
|
| 67 |
+ for ipcMode, state := range ipcModes {
|
|
| 68 |
+ if ipcMode.IsPrivate() != state[0] {
|
|
| 69 |
+ t.Fatalf("IpcMode.IsPrivate for %v should have been %v but was %v", ipcMode, state[0], ipcMode.IsPrivate())
|
|
| 70 |
+ } |
|
| 71 |
+ if ipcMode.IsHost() != state[1] {
|
|
| 72 |
+ t.Fatalf("IpcMode.IsHost for %v should have been %v but was %v", ipcMode, state[1], ipcMode.IsHost())
|
|
| 73 |
+ } |
|
| 74 |
+ if ipcMode.IsContainer() != state[2] {
|
|
| 75 |
+ t.Fatalf("IpcMode.IsContainer for %v should have been %v but was %v", ipcMode, state[2], ipcMode.IsContainer())
|
|
| 76 |
+ } |
|
| 77 |
+ if ipcMode.Valid() != state[3] {
|
|
| 78 |
+ t.Fatalf("IpcMode.Valid for %v should have been %v but was %v", ipcMode, state[3], ipcMode.Valid())
|
|
| 79 |
+ } |
|
| 80 |
+ } |
|
| 81 |
+ containerIpcModes := map[IpcMode]string{
|
|
| 82 |
+ "": "", |
|
| 83 |
+ "something": "", |
|
| 84 |
+ "something:weird": "weird", |
|
| 85 |
+ "container": "", |
|
| 86 |
+ "container:": "", |
|
| 87 |
+ "container:name": "name", |
|
| 88 |
+ "container:name1:name2": "name1:name2", |
|
| 89 |
+ } |
|
| 90 |
+ for ipcMode, container := range containerIpcModes {
|
|
| 91 |
+ if ipcMode.Container() != container {
|
|
| 92 |
+ t.Fatalf("Expected %v for %v but was %v", container, ipcMode, ipcMode.Container())
|
|
| 93 |
+ } |
|
| 94 |
+ } |
|
| 95 |
+} |
|
| 96 |
+ |
|
| 97 |
+func TestUTSModeTest(t *testing.T) {
|
|
| 98 |
+ utsModes := map[UTSMode][]bool{
|
|
| 99 |
+ // private, host, valid |
|
| 100 |
+ "": {true, false, true},
|
|
| 101 |
+ "something:weird": {true, false, false},
|
|
| 102 |
+ "host": {false, true, true},
|
|
| 103 |
+ "host:name": {true, false, true},
|
|
| 104 |
+ } |
|
| 105 |
+ for utsMode, state := range utsModes {
|
|
| 106 |
+ if utsMode.IsPrivate() != state[0] {
|
|
| 107 |
+ t.Fatalf("UtsMode.IsPrivate for %v should have been %v but was %v", utsMode, state[0], utsMode.IsPrivate())
|
|
| 108 |
+ } |
|
| 109 |
+ if utsMode.IsHost() != state[1] {
|
|
| 110 |
+ t.Fatalf("UtsMode.IsHost for %v should have been %v but was %v", utsMode, state[1], utsMode.IsHost())
|
|
| 111 |
+ } |
|
| 112 |
+ if utsMode.Valid() != state[2] {
|
|
| 113 |
+ t.Fatalf("UtsMode.Valid for %v should have been %v but was %v", utsMode, state[2], utsMode.Valid())
|
|
| 114 |
+ } |
|
| 115 |
+ } |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 118 |
+func TestPidModeTest(t *testing.T) {
|
|
| 119 |
+ pidModes := map[PidMode][]bool{
|
|
| 120 |
+ // private, host, valid |
|
| 121 |
+ "": {true, false, true},
|
|
| 122 |
+ "something:weird": {true, false, false},
|
|
| 123 |
+ "host": {false, true, true},
|
|
| 124 |
+ "host:name": {true, false, true},
|
|
| 125 |
+ } |
|
| 126 |
+ for pidMode, state := range pidModes {
|
|
| 127 |
+ if pidMode.IsPrivate() != state[0] {
|
|
| 128 |
+ t.Fatalf("PidMode.IsPrivate for %v should have been %v but was %v", pidMode, state[0], pidMode.IsPrivate())
|
|
| 129 |
+ } |
|
| 130 |
+ if pidMode.IsHost() != state[1] {
|
|
| 131 |
+ t.Fatalf("PidMode.IsHost for %v should have been %v but was %v", pidMode, state[1], pidMode.IsHost())
|
|
| 132 |
+ } |
|
| 133 |
+ if pidMode.Valid() != state[2] {
|
|
| 134 |
+ t.Fatalf("PidMode.Valid for %v should have been %v but was %v", pidMode, state[2], pidMode.Valid())
|
|
| 135 |
+ } |
|
| 136 |
+ } |
|
| 137 |
+} |
|
| 138 |
+ |
|
| 139 |
+func TestRestartPolicy(t *testing.T) {
|
|
| 140 |
+ restartPolicies := map[RestartPolicy][]bool{
|
|
| 141 |
+ // none, always, failure |
|
| 142 |
+ RestartPolicy{}: {false, false, false},
|
|
| 143 |
+ RestartPolicy{"something", 0}: {false, false, false},
|
|
| 144 |
+ RestartPolicy{"no", 0}: {true, false, false},
|
|
| 145 |
+ RestartPolicy{"always", 0}: {false, true, false},
|
|
| 146 |
+ RestartPolicy{"on-failure", 0}: {false, false, true},
|
|
| 147 |
+ } |
|
| 148 |
+ for restartPolicy, state := range restartPolicies {
|
|
| 149 |
+ if restartPolicy.IsNone() != state[0] {
|
|
| 150 |
+ t.Fatalf("RestartPolicy.IsNone for %v should have been %v but was %v", restartPolicy, state[0], restartPolicy.IsNone())
|
|
| 151 |
+ } |
|
| 152 |
+ if restartPolicy.IsAlways() != state[1] {
|
|
| 153 |
+ t.Fatalf("RestartPolicy.IsAlways for %v should have been %v but was %v", restartPolicy, state[1], restartPolicy.IsAlways())
|
|
| 154 |
+ } |
|
| 155 |
+ if restartPolicy.IsOnFailure() != state[2] {
|
|
| 156 |
+ t.Fatalf("RestartPolicy.IsOnFailure for %v should have been %v but was %v", restartPolicy, state[2], restartPolicy.IsOnFailure())
|
|
| 157 |
+ } |
|
| 158 |
+ } |
|
| 159 |
+} |
|
| 160 |
+ |
|
| 161 |
+func TestLxcConfigMarshalJSON(t *testing.T) {
|
|
| 162 |
+ lxcConfigs := map[*LxcConfig]string{
|
|
| 163 |
+ nil: "", |
|
| 164 |
+ &LxcConfig{}: "null",
|
|
| 165 |
+ &LxcConfig{
|
|
| 166 |
+ []KeyValuePair{{"key1", "value1"}},
|
|
| 167 |
+ }: `[{"Key":"key1","Value":"value1"}]`,
|
|
| 168 |
+ } |
|
| 169 |
+ |
|
| 170 |
+ for lxcconfig, expected := range lxcConfigs {
|
|
| 171 |
+ data, err := lxcconfig.MarshalJSON() |
|
| 172 |
+ if err != nil {
|
|
| 173 |
+ t.Fatal(err) |
|
| 174 |
+ } |
|
| 175 |
+ if string(data) != expected {
|
|
| 176 |
+ t.Fatalf("Expected %v, got %v", expected, string(data))
|
|
| 177 |
+ } |
|
| 178 |
+ } |
|
| 179 |
+} |
|
| 180 |
+ |
|
| 181 |
+func TestLxcConfigUnmarshalJSON(t *testing.T) {
|
|
| 182 |
+ keyvaluePairs := map[string][]KeyValuePair{
|
|
| 183 |
+ "": {{"key1", "value1"}},
|
|
| 184 |
+ "[]": {},
|
|
| 185 |
+ `[{"Key":"key2","Value":"value2"}]`: {{"key2", "value2"}},
|
|
| 186 |
+ } |
|
| 187 |
+ for json, expectedParts := range keyvaluePairs {
|
|
| 188 |
+ lxcConfig := &LxcConfig{
|
|
| 189 |
+ []KeyValuePair{{"key1", "value1"}},
|
|
| 190 |
+ } |
|
| 191 |
+ if err := lxcConfig.UnmarshalJSON([]byte(json)); err != nil {
|
|
| 192 |
+ t.Fatal(err) |
|
| 193 |
+ } |
|
| 194 |
+ |
|
| 195 |
+ actualParts := lxcConfig.Slice() |
|
| 196 |
+ if len(actualParts) != len(expectedParts) {
|
|
| 197 |
+ t.Fatalf("Expected %v keyvaluePairs, got %v (%v)", len(expectedParts), len(actualParts), expectedParts)
|
|
| 198 |
+ } |
|
| 199 |
+ for index, part := range actualParts {
|
|
| 200 |
+ if part != expectedParts[index] {
|
|
| 201 |
+ t.Fatalf("Expected %v, got %v", expectedParts, actualParts)
|
|
| 202 |
+ break |
|
| 203 |
+ } |
|
| 204 |
+ } |
|
| 205 |
+ } |
|
| 206 |
+} |
|
| 207 |
+ |
|
| 208 |
+func TestMergeConfigs(t *testing.T) {
|
|
| 209 |
+ expectedHostname := "hostname" |
|
| 210 |
+ expectedContainerIDFile := "containerIdFile" |
|
| 211 |
+ config := &Config{
|
|
| 212 |
+ Hostname: expectedHostname, |
|
| 213 |
+ } |
|
| 214 |
+ hostConfig := &HostConfig{
|
|
| 215 |
+ ContainerIDFile: expectedContainerIDFile, |
|
| 216 |
+ } |
|
| 217 |
+ containerConfigWrapper := MergeConfigs(config, hostConfig) |
|
| 218 |
+ if containerConfigWrapper.Config.Hostname != expectedHostname {
|
|
| 219 |
+ t.Fatalf("containerConfigWrapper config hostname expected %v got %v", expectedHostname, containerConfigWrapper.Config.Hostname)
|
|
| 220 |
+ } |
|
| 221 |
+ if containerConfigWrapper.InnerHostConfig.ContainerIDFile != expectedContainerIDFile {
|
|
| 222 |
+ t.Fatalf("containerConfigWrapper hostconfig containerIdfile expected %v got %v", expectedContainerIDFile, containerConfigWrapper.InnerHostConfig.ContainerIDFile)
|
|
| 223 |
+ } |
|
| 224 |
+ if containerConfigWrapper.Cpuset != "" {
|
|
| 225 |
+ t.Fatalf("Expected empty Cpuset, got %v", containerConfigWrapper.Cpuset)
|
|
| 226 |
+ } |
|
| 227 |
+} |
|
| 228 |
+ |
|
| 229 |
+func TestDecodeHostConfig(t *testing.T) {
|
|
| 230 |
+ fixtures := []struct {
|
|
| 231 |
+ file string |
|
| 232 |
+ }{
|
|
| 233 |
+ {"fixtures/container_hostconfig_1_14.json"},
|
|
| 234 |
+ {"fixtures/container_hostconfig_1_19.json"},
|
|
| 235 |
+ } |
|
| 236 |
+ |
|
| 237 |
+ for _, f := range fixtures {
|
|
| 238 |
+ b, err := ioutil.ReadFile(f.file) |
|
| 239 |
+ if err != nil {
|
|
| 240 |
+ t.Fatal(err) |
|
| 241 |
+ } |
|
| 242 |
+ |
|
| 243 |
+ c, err := DecodeHostConfig(bytes.NewReader(b)) |
|
| 244 |
+ if err != nil {
|
|
| 245 |
+ t.Fatal(fmt.Errorf("Error parsing %s: %v", f, err))
|
|
| 246 |
+ } |
|
| 247 |
+ |
|
| 248 |
+ if c.Privileged != false {
|
|
| 249 |
+ t.Fatalf("Expected privileged false, found %s\n", c.Privileged)
|
|
| 250 |
+ } |
|
| 251 |
+ |
|
| 252 |
+ if len(c.Binds) != 1 {
|
|
| 253 |
+ t.Fatalf("Expected 1 bind, found %v\n", c.Binds)
|
|
| 254 |
+ } |
|
| 255 |
+ |
|
| 256 |
+ if len(c.CapAdd) != 1 && c.CapAdd[0] != "NET_ADMIN" {
|
|
| 257 |
+ t.Fatalf("Expected CapAdd NET_ADMIN, got %v", c.CapAdd)
|
|
| 258 |
+ } |
|
| 259 |
+ |
|
| 260 |
+ if len(c.CapDrop) != 1 && c.CapDrop[0] != "NET_ADMIN" {
|
|
| 261 |
+ t.Fatalf("Expected CapDrop MKNOD, got %v", c.CapDrop)
|
|
| 262 |
+ } |
|
| 263 |
+ } |
|
| 264 |
+} |
| 0 | 265 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,83 @@ |
| 0 |
+package runconfig |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "testing" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/docker/docker/pkg/nat" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func TestMerge(t *testing.T) {
|
|
| 9 |
+ volumesImage := make(map[string]struct{})
|
|
| 10 |
+ volumesImage["/test1"] = struct{}{}
|
|
| 11 |
+ volumesImage["/test2"] = struct{}{}
|
|
| 12 |
+ portsImage := make(nat.PortSet) |
|
| 13 |
+ portsImage[nat.Port("1111/tcp")] = struct{}{}
|
|
| 14 |
+ portsImage[nat.Port("2222/tcp")] = struct{}{}
|
|
| 15 |
+ configImage := &Config{
|
|
| 16 |
+ ExposedPorts: portsImage, |
|
| 17 |
+ Env: []string{"VAR1=1", "VAR2=2"},
|
|
| 18 |
+ Volumes: volumesImage, |
|
| 19 |
+ } |
|
| 20 |
+ |
|
| 21 |
+ portsUser := make(nat.PortSet) |
|
| 22 |
+ portsUser[nat.Port("2222/tcp")] = struct{}{}
|
|
| 23 |
+ portsUser[nat.Port("3333/tcp")] = struct{}{}
|
|
| 24 |
+ volumesUser := make(map[string]struct{})
|
|
| 25 |
+ volumesUser["/test3"] = struct{}{}
|
|
| 26 |
+ configUser := &Config{
|
|
| 27 |
+ ExposedPorts: portsUser, |
|
| 28 |
+ Env: []string{"VAR2=3", "VAR3=3"},
|
|
| 29 |
+ Volumes: volumesUser, |
|
| 30 |
+ } |
|
| 31 |
+ |
|
| 32 |
+ if err := Merge(configUser, configImage); err != nil {
|
|
| 33 |
+ t.Error(err) |
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ if len(configUser.ExposedPorts) != 3 {
|
|
| 37 |
+ t.Fatalf("Expected 3 ExposedPorts, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
|
|
| 38 |
+ } |
|
| 39 |
+ for portSpecs := range configUser.ExposedPorts {
|
|
| 40 |
+ if portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
|
|
| 41 |
+ t.Fatalf("Expected 1111 or 2222 or 3333, found %s", portSpecs)
|
|
| 42 |
+ } |
|
| 43 |
+ } |
|
| 44 |
+ if len(configUser.Env) != 3 {
|
|
| 45 |
+ t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
|
|
| 46 |
+ } |
|
| 47 |
+ for _, env := range configUser.Env {
|
|
| 48 |
+ if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
|
|
| 49 |
+ t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
|
|
| 50 |
+ } |
|
| 51 |
+ } |
|
| 52 |
+ |
|
| 53 |
+ if len(configUser.Volumes) != 3 {
|
|
| 54 |
+ t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
|
|
| 55 |
+ } |
|
| 56 |
+ for v := range configUser.Volumes {
|
|
| 57 |
+ if v != "/test1" && v != "/test2" && v != "/test3" {
|
|
| 58 |
+ t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
|
|
| 59 |
+ } |
|
| 60 |
+ } |
|
| 61 |
+ |
|
| 62 |
+ ports, _, err := nat.ParsePortSpecs([]string{"0000"})
|
|
| 63 |
+ if err != nil {
|
|
| 64 |
+ t.Error(err) |
|
| 65 |
+ } |
|
| 66 |
+ configImage2 := &Config{
|
|
| 67 |
+ ExposedPorts: ports, |
|
| 68 |
+ } |
|
| 69 |
+ |
|
| 70 |
+ if err := Merge(configUser, configImage2); err != nil {
|
|
| 71 |
+ t.Error(err) |
|
| 72 |
+ } |
|
| 73 |
+ |
|
| 74 |
+ if len(configUser.ExposedPorts) != 4 {
|
|
| 75 |
+ t.Fatalf("Expected 4 ExposedPorts, 0000, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
|
|
| 76 |
+ } |
|
| 77 |
+ for portSpecs := range configUser.ExposedPorts {
|
|
| 78 |
+ if portSpecs.Port() != "0" && portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
|
|
| 79 |
+ t.Fatalf("Expected %q or %q or %q or %q, found %s", 0, 1111, 2222, 3333, portSpecs)
|
|
| 80 |
+ } |
|
| 81 |
+ } |
|
| 82 |
+} |
| ... | ... |
@@ -1,10 +1,13 @@ |
| 1 | 1 |
package runconfig |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "fmt" |
|
| 4 | 5 |
"io/ioutil" |
| 6 |
+ "strings" |
|
| 5 | 7 |
"testing" |
| 6 | 8 |
|
| 7 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 10 |
+ "github.com/docker/docker/pkg/nat" |
|
| 8 | 11 |
"github.com/docker/docker/pkg/parsers" |
| 9 | 12 |
) |
| 10 | 13 |
|
| ... | ... |
@@ -15,6 +18,162 @@ func parseRun(args []string) (*Config, *HostConfig, *flag.FlagSet, error) {
|
| 15 | 15 |
return Parse(cmd, args) |
| 16 | 16 |
} |
| 17 | 17 |
|
| 18 |
+func parse(t *testing.T, args string) (*Config, *HostConfig, error) {
|
|
| 19 |
+ config, hostConfig, _, err := parseRun(strings.Split(args+" ubuntu bash", " ")) |
|
| 20 |
+ return config, hostConfig, err |
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+func mustParse(t *testing.T, args string) (*Config, *HostConfig) {
|
|
| 24 |
+ config, hostConfig, err := parse(t, args) |
|
| 25 |
+ if err != nil {
|
|
| 26 |
+ t.Fatal(err) |
|
| 27 |
+ } |
|
| 28 |
+ return config, hostConfig |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+// check if (a == c && b == d) || (a == d && b == c) |
|
| 32 |
+// because maps are randomized |
|
| 33 |
+func compareRandomizedStrings(a, b, c, d string) error {
|
|
| 34 |
+ if a == c && b == d {
|
|
| 35 |
+ return nil |
|
| 36 |
+ } |
|
| 37 |
+ if a == d && b == c {
|
|
| 38 |
+ return nil |
|
| 39 |
+ } |
|
| 40 |
+ return fmt.Errorf("strings don't match")
|
|
| 41 |
+} |
|
| 42 |
+func TestParseRunLinks(t *testing.T) {
|
|
| 43 |
+ if _, hostConfig := mustParse(t, "--link a:b"); len(hostConfig.Links) == 0 || hostConfig.Links[0] != "a:b" {
|
|
| 44 |
+ t.Fatalf("Error parsing links. Expected []string{\"a:b\"}, received: %v", hostConfig.Links)
|
|
| 45 |
+ } |
|
| 46 |
+ if _, hostConfig := mustParse(t, "--link a:b --link c:d"); len(hostConfig.Links) < 2 || hostConfig.Links[0] != "a:b" || hostConfig.Links[1] != "c:d" {
|
|
| 47 |
+ t.Fatalf("Error parsing links. Expected []string{\"a:b\", \"c:d\"}, received: %v", hostConfig.Links)
|
|
| 48 |
+ } |
|
| 49 |
+ if _, hostConfig := mustParse(t, ""); len(hostConfig.Links) != 0 {
|
|
| 50 |
+ t.Fatalf("Error parsing links. No link expected, received: %v", hostConfig.Links)
|
|
| 51 |
+ } |
|
| 52 |
+} |
|
| 53 |
+ |
|
| 54 |
+func TestParseRunAttach(t *testing.T) {
|
|
| 55 |
+ if config, _ := mustParse(t, "-a stdin"); !config.AttachStdin || config.AttachStdout || config.AttachStderr {
|
|
| 56 |
+ t.Fatalf("Error parsing attach flags. Expect only Stdin enabled. Received: in: %v, out: %v, err: %v", config.AttachStdin, config.AttachStdout, config.AttachStderr)
|
|
| 57 |
+ } |
|
| 58 |
+ if config, _ := mustParse(t, "-a stdin -a stdout"); !config.AttachStdin || !config.AttachStdout || config.AttachStderr {
|
|
| 59 |
+ t.Fatalf("Error parsing attach flags. Expect only Stdin and Stdout enabled. Received: in: %v, out: %v, err: %v", config.AttachStdin, config.AttachStdout, config.AttachStderr)
|
|
| 60 |
+ } |
|
| 61 |
+ if config, _ := mustParse(t, "-a stdin -a stdout -a stderr"); !config.AttachStdin || !config.AttachStdout || !config.AttachStderr {
|
|
| 62 |
+ t.Fatalf("Error parsing attach flags. Expect all attach enabled. Received: in: %v, out: %v, err: %v", config.AttachStdin, config.AttachStdout, config.AttachStderr)
|
|
| 63 |
+ } |
|
| 64 |
+ if config, _ := mustParse(t, ""); config.AttachStdin || !config.AttachStdout || !config.AttachStderr {
|
|
| 65 |
+ t.Fatalf("Error parsing attach flags. Expect Stdin disabled. Received: in: %v, out: %v, err: %v", config.AttachStdin, config.AttachStdout, config.AttachStderr)
|
|
| 66 |
+ } |
|
| 67 |
+ if config, _ := mustParse(t, "-i"); !config.AttachStdin || !config.AttachStdout || !config.AttachStderr {
|
|
| 68 |
+ t.Fatalf("Error parsing attach flags. Expect Stdin enabled. Received: in: %v, out: %v, err: %v", config.AttachStdin, config.AttachStdout, config.AttachStderr)
|
|
| 69 |
+ } |
|
| 70 |
+ |
|
| 71 |
+ if _, _, err := parse(t, "-a"); err == nil {
|
|
| 72 |
+ t.Fatalf("Error parsing attach flags, `-a` should be an error but is not")
|
|
| 73 |
+ } |
|
| 74 |
+ if _, _, err := parse(t, "-a invalid"); err == nil {
|
|
| 75 |
+ t.Fatalf("Error parsing attach flags, `-a invalid` should be an error but is not")
|
|
| 76 |
+ } |
|
| 77 |
+ if _, _, err := parse(t, "-a invalid -a stdout"); err == nil {
|
|
| 78 |
+ t.Fatalf("Error parsing attach flags, `-a stdout -a invalid` should be an error but is not")
|
|
| 79 |
+ } |
|
| 80 |
+ if _, _, err := parse(t, "-a stdout -a stderr -d"); err == nil {
|
|
| 81 |
+ t.Fatalf("Error parsing attach flags, `-a stdout -a stderr -d` should be an error but is not")
|
|
| 82 |
+ } |
|
| 83 |
+ if _, _, err := parse(t, "-a stdin -d"); err == nil {
|
|
| 84 |
+ t.Fatalf("Error parsing attach flags, `-a stdin -d` should be an error but is not")
|
|
| 85 |
+ } |
|
| 86 |
+ if _, _, err := parse(t, "-a stdout -d"); err == nil {
|
|
| 87 |
+ t.Fatalf("Error parsing attach flags, `-a stdout -d` should be an error but is not")
|
|
| 88 |
+ } |
|
| 89 |
+ if _, _, err := parse(t, "-a stderr -d"); err == nil {
|
|
| 90 |
+ t.Fatalf("Error parsing attach flags, `-a stderr -d` should be an error but is not")
|
|
| 91 |
+ } |
|
| 92 |
+ if _, _, err := parse(t, "-d --rm"); err == nil {
|
|
| 93 |
+ t.Fatalf("Error parsing attach flags, `-d --rm` should be an error but is not")
|
|
| 94 |
+ } |
|
| 95 |
+} |
|
| 96 |
+ |
|
| 97 |
+func TestParseRunVolumes(t *testing.T) {
|
|
| 98 |
+ if config, hostConfig := mustParse(t, "-v /tmp"); hostConfig.Binds != nil {
|
|
| 99 |
+ t.Fatalf("Error parsing volume flags, `-v /tmp` should not mount-bind anything. Received %v", hostConfig.Binds)
|
|
| 100 |
+ } else if _, exists := config.Volumes["/tmp"]; !exists {
|
|
| 101 |
+ t.Fatalf("Error parsing volume flags, `-v /tmp` is missing from volumes. Received %v", config.Volumes)
|
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 104 |
+ if config, hostConfig := mustParse(t, "-v /tmp -v /var"); hostConfig.Binds != nil {
|
|
| 105 |
+ t.Fatalf("Error parsing volume flags, `-v /tmp -v /var` should not mount-bind anything. Received %v", hostConfig.Binds)
|
|
| 106 |
+ } else if _, exists := config.Volumes["/tmp"]; !exists {
|
|
| 107 |
+ t.Fatalf("Error parsing volume flags, `-v /tmp` is missing from volumes. Received %v", config.Volumes)
|
|
| 108 |
+ } else if _, exists := config.Volumes["/var"]; !exists {
|
|
| 109 |
+ t.Fatalf("Error parsing volume flags, `-v /var` is missing from volumes. Received %v", config.Volumes)
|
|
| 110 |
+ } |
|
| 111 |
+ |
|
| 112 |
+ if _, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp"); hostConfig.Binds == nil || hostConfig.Binds[0] != "/hostTmp:/containerTmp" {
|
|
| 113 |
+ t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp` should mount-bind /hostTmp into /containeTmp. Received %v", hostConfig.Binds)
|
|
| 114 |
+ } |
|
| 115 |
+ |
|
| 116 |
+ if _, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp -v /hostVar:/containerVar"); hostConfig.Binds == nil || compareRandomizedStrings(hostConfig.Binds[0], hostConfig.Binds[1], "/hostTmp:/containerTmp", "/hostVar:/containerVar") != nil {
|
|
| 117 |
+ t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp -v /hostVar:/containerVar` should mount-bind /hostTmp into /containeTmp and /hostVar into /hostContainer. Received %v", hostConfig.Binds)
|
|
| 118 |
+ } |
|
| 119 |
+ |
|
| 120 |
+ if _, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp:ro -v /hostVar:/containerVar:rw"); hostConfig.Binds == nil || compareRandomizedStrings(hostConfig.Binds[0], hostConfig.Binds[1], "/hostTmp:/containerTmp:ro", "/hostVar:/containerVar:rw") != nil {
|
|
| 121 |
+ t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp:ro -v /hostVar:/containerVar:rw` should mount-bind /hostTmp into /containeTmp and /hostVar into /hostContainer. Received %v", hostConfig.Binds)
|
|
| 122 |
+ } |
|
| 123 |
+ |
|
| 124 |
+ if _, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp:roZ -v /hostVar:/containerVar:rwZ"); hostConfig.Binds == nil || compareRandomizedStrings(hostConfig.Binds[0], hostConfig.Binds[1], "/hostTmp:/containerTmp:roZ", "/hostVar:/containerVar:rwZ") != nil {
|
|
| 125 |
+ t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp:roZ -v /hostVar:/containerVar:rwZ` should mount-bind /hostTmp into /containeTmp and /hostVar into /hostContainer. Received %v", hostConfig.Binds)
|
|
| 126 |
+ } |
|
| 127 |
+ |
|
| 128 |
+ if _, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp:Z -v /hostVar:/containerVar:z"); hostConfig.Binds == nil || compareRandomizedStrings(hostConfig.Binds[0], hostConfig.Binds[1], "/hostTmp:/containerTmp:Z", "/hostVar:/containerVar:z") != nil {
|
|
| 129 |
+ t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp:Z -v /hostVar:/containerVar:z` should mount-bind /hostTmp into /containeTmp and /hostVar into /hostContainer. Received %v", hostConfig.Binds)
|
|
| 130 |
+ } |
|
| 131 |
+ |
|
| 132 |
+ if config, hostConfig := mustParse(t, "-v /hostTmp:/containerTmp -v /containerVar"); hostConfig.Binds == nil || len(hostConfig.Binds) > 1 || hostConfig.Binds[0] != "/hostTmp:/containerTmp" {
|
|
| 133 |
+ t.Fatalf("Error parsing volume flags, `-v /hostTmp:/containerTmp -v /containerVar` should mount-bind only /hostTmp into /containeTmp. Received %v", hostConfig.Binds)
|
|
| 134 |
+ } else if _, exists := config.Volumes["/containerVar"]; !exists {
|
|
| 135 |
+ t.Fatalf("Error parsing volume flags, `-v /containerVar` is missing from volumes. Received %v", config.Volumes)
|
|
| 136 |
+ } |
|
| 137 |
+ |
|
| 138 |
+ if config, hostConfig := mustParse(t, ""); hostConfig.Binds != nil {
|
|
| 139 |
+ t.Fatalf("Error parsing volume flags, without volume, nothing should be mount-binded. Received %v", hostConfig.Binds)
|
|
| 140 |
+ } else if len(config.Volumes) != 0 {
|
|
| 141 |
+ t.Fatalf("Error parsing volume flags, without volume, no volume should be present. Received %v", config.Volumes)
|
|
| 142 |
+ } |
|
| 143 |
+ |
|
| 144 |
+ if _, _, err := parse(t, "-v /"); err == nil {
|
|
| 145 |
+ t.Fatalf("Expected error, but got none")
|
|
| 146 |
+ } |
|
| 147 |
+ |
|
| 148 |
+ if _, _, err := parse(t, "-v /:/"); err == nil {
|
|
| 149 |
+ t.Fatalf("Error parsing volume flags, `-v /:/` should fail but didn't")
|
|
| 150 |
+ } |
|
| 151 |
+ if _, _, err := parse(t, "-v"); err == nil {
|
|
| 152 |
+ t.Fatalf("Error parsing volume flags, `-v` should fail but didn't")
|
|
| 153 |
+ } |
|
| 154 |
+ if _, _, err := parse(t, "-v /tmp:"); err == nil {
|
|
| 155 |
+ t.Fatalf("Error parsing volume flags, `-v /tmp:` should fail but didn't")
|
|
| 156 |
+ } |
|
| 157 |
+ if _, _, err := parse(t, "-v /tmp:ro"); err == nil {
|
|
| 158 |
+ t.Fatalf("Error parsing volume flags, `-v /tmp:ro` should fail but didn't")
|
|
| 159 |
+ } |
|
| 160 |
+ if _, _, err := parse(t, "-v /tmp::"); err == nil {
|
|
| 161 |
+ t.Fatalf("Error parsing volume flags, `-v /tmp::` should fail but didn't")
|
|
| 162 |
+ } |
|
| 163 |
+ if _, _, err := parse(t, "-v :"); err == nil {
|
|
| 164 |
+ t.Fatalf("Error parsing volume flags, `-v :` should fail but didn't")
|
|
| 165 |
+ } |
|
| 166 |
+ if _, _, err := parse(t, "-v ::"); err == nil {
|
|
| 167 |
+ t.Fatalf("Error parsing volume flags, `-v ::` should fail but didn't")
|
|
| 168 |
+ } |
|
| 169 |
+ if _, _, err := parse(t, "-v /tmp:/tmp:/tmp:/tmp"); err == nil {
|
|
| 170 |
+ t.Fatalf("Error parsing volume flags, `-v /tmp:/tmp:/tmp:/tmp` should fail but didn't")
|
|
| 171 |
+ } |
|
| 172 |
+} |
|
| 173 |
+ |
|
| 18 | 174 |
func TestParseLxcConfOpt(t *testing.T) {
|
| 19 | 175 |
opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
|
| 20 | 176 |
|
| ... | ... |
@@ -30,6 +189,18 @@ func TestParseLxcConfOpt(t *testing.T) {
|
| 30 | 30 |
t.Fail() |
| 31 | 31 |
} |
| 32 | 32 |
} |
| 33 |
+ |
|
| 34 |
+ // With parseRun too |
|
| 35 |
+ _, hostconfig, _, err := parseRun([]string{"lxc.utsname=docker", "lxc.utsname = docker ", "img", "cmd"})
|
|
| 36 |
+ if err != nil {
|
|
| 37 |
+ t.Fatal(err) |
|
| 38 |
+ } |
|
| 39 |
+ for _, lxcConf := range hostconfig.LxcConf.Slice() {
|
|
| 40 |
+ if lxcConf.Key != "lxc.utsname" || lxcConf.Value != "docker" {
|
|
| 41 |
+ t.Fail() |
|
| 42 |
+ } |
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 33 | 45 |
} |
| 34 | 46 |
|
| 35 | 47 |
func TestNetHostname(t *testing.T) {
|
| ... | ... |
@@ -56,10 +227,335 @@ func TestNetHostname(t *testing.T) {
|
| 56 | 56 |
if _, _, _, err := parseRun([]string{"-h=name", "--net=container:other", "img", "cmd"}); err != ErrConflictNetworkHostname {
|
| 57 | 57 |
t.Fatalf("Expected error ErrConflictNetworkHostname, got: %s", err)
|
| 58 | 58 |
} |
| 59 |
+ if _, _, _, err := parseRun([]string{"--net=container", "img", "cmd"}); err == nil || err.Error() != "--net: invalid net mode: invalid container format container:<name|id>" {
|
|
| 60 |
+ t.Fatalf("Expected error with --net=container, got : %v", err)
|
|
| 61 |
+ } |
|
| 62 |
+ if _, _, _, err := parseRun([]string{"--net=weird", "img", "cmd"}); err == nil || err.Error() != "--net: invalid net mode: invalid --net: weird" {
|
|
| 63 |
+ t.Fatalf("Expected error with --net=weird, got: %s", err)
|
|
| 64 |
+ } |
|
| 59 | 65 |
} |
| 60 | 66 |
|
| 61 | 67 |
func TestConflictContainerNetworkAndLinks(t *testing.T) {
|
| 62 | 68 |
if _, _, _, err := parseRun([]string{"--net=container:other", "--link=zip:zap", "img", "cmd"}); err != ErrConflictContainerNetworkAndLinks {
|
| 63 | 69 |
t.Fatalf("Expected error ErrConflictContainerNetworkAndLinks, got: %s", err)
|
| 64 | 70 |
} |
| 71 |
+ if _, _, _, err := parseRun([]string{"--net=host", "--link=zip:zap", "img", "cmd"}); err != ErrConflictHostNetworkAndLinks {
|
|
| 72 |
+ t.Fatalf("Expected error ErrConflictHostNetworkAndLinks, got: %s", err)
|
|
| 73 |
+ } |
|
| 74 |
+} |
|
| 75 |
+ |
|
| 76 |
+func TestConflictNetworkModeAndOptions(t *testing.T) {
|
|
| 77 |
+ if _, _, _, err := parseRun([]string{"--net=host", "--dns=8.8.8.8", "img", "cmd"}); err != ErrConflictNetworkAndDns {
|
|
| 78 |
+ t.Fatalf("Expected error ErrConflictNetworkAndDns, got %s", err)
|
|
| 79 |
+ } |
|
| 80 |
+ if _, _, _, err := parseRun([]string{"--net=container:other", "--dns=8.8.8.8", "img", "cmd"}); err != ErrConflictNetworkAndDns {
|
|
| 81 |
+ t.Fatalf("Expected error ErrConflictNetworkAndDns, got %s", err)
|
|
| 82 |
+ } |
|
| 83 |
+ if _, _, _, err := parseRun([]string{"--net=host", "--add-host=name:8.8.8.8", "img", "cmd"}); err != ErrConflictNetworkHosts {
|
|
| 84 |
+ t.Fatalf("Expected error ErrConflictNetworkAndDns, got %s", err)
|
|
| 85 |
+ } |
|
| 86 |
+ if _, _, _, err := parseRun([]string{"--net=container:other", "--add-host=name:8.8.8.8", "img", "cmd"}); err != ErrConflictNetworkHosts {
|
|
| 87 |
+ t.Fatalf("Expected error ErrConflictNetworkAndDns, got %s", err)
|
|
| 88 |
+ } |
|
| 89 |
+ if _, _, _, err := parseRun([]string{"--net=host", "--mac-address=92:d0:c6:0a:29:33", "img", "cmd"}); err != ErrConflictContainerNetworkAndMac {
|
|
| 90 |
+ t.Fatalf("Expected error ErrConflictContainerNetworkAndMac, got %s", err)
|
|
| 91 |
+ } |
|
| 92 |
+ if _, _, _, err := parseRun([]string{"--net=container:other", "--mac-address=92:d0:c6:0a:29:33", "img", "cmd"}); err != ErrConflictContainerNetworkAndMac {
|
|
| 93 |
+ t.Fatalf("Expected error ErrConflictContainerNetworkAndMac, got %s", err)
|
|
| 94 |
+ } |
|
| 95 |
+ if _, _, _, err := parseRun([]string{"--net=container:other", "-P", "img", "cmd"}); err != ErrConflictNetworkPublishPorts {
|
|
| 96 |
+ t.Fatalf("Expected error ErrConflictNetworkPublishPorts, got %s", err)
|
|
| 97 |
+ } |
|
| 98 |
+ if _, _, _, err := parseRun([]string{"--net=container:other", "-p", "8080", "img", "cmd"}); err != ErrConflictNetworkPublishPorts {
|
|
| 99 |
+ t.Fatalf("Expected error ErrConflictNetworkPublishPorts, got %s", err)
|
|
| 100 |
+ } |
|
| 101 |
+ if _, _, _, err := parseRun([]string{"--net=container:other", "--expose", "8000-9000", "img", "cmd"}); err != ErrConflictNetworkExposePorts {
|
|
| 102 |
+ t.Fatalf("Expected error ErrConflictNetworkExposePorts, got %s", err)
|
|
| 103 |
+ } |
|
| 104 |
+} |
|
| 105 |
+ |
|
| 106 |
+// Simple parse with MacAddress validatation |
|
| 107 |
+func TestParseWithMacAddress(t *testing.T) {
|
|
| 108 |
+ invalidMacAddress := "--mac-address=invalidMacAddress" |
|
| 109 |
+ validMacAddress := "--mac-address=92:d0:c6:0a:29:33" |
|
| 110 |
+ if _, _, _, err := parseRun([]string{invalidMacAddress, "img", "cmd"}); err != nil && err.Error() != "invalidMacAddress is not a valid mac address" {
|
|
| 111 |
+ t.Fatalf("Expected an error with %v mac-address, got %v", invalidMacAddress, err)
|
|
| 112 |
+ } |
|
| 113 |
+ if config, _ := mustParse(t, validMacAddress); config.MacAddress != "92:d0:c6:0a:29:33" {
|
|
| 114 |
+ t.Fatalf("Expected the config to have '92:d0:c6:0a:29:33' as MacAddress, got '%v'", config.MacAddress)
|
|
| 115 |
+ } |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 118 |
+func TestParseWithMemory(t *testing.T) {
|
|
| 119 |
+ invalidMemory := "--memory=invalid" |
|
| 120 |
+ validMemory := "--memory=1G" |
|
| 121 |
+ if _, _, _, err := parseRun([]string{invalidMemory, "img", "cmd"}); err != nil && err.Error() != "invalid size: 'invalid'" {
|
|
| 122 |
+ t.Fatalf("Expected an error with '%v' Memory, got '%v'", invalidMemory, err)
|
|
| 123 |
+ } |
|
| 124 |
+ if _, hostconfig := mustParse(t, validMemory); hostconfig.Memory != 1073741824 {
|
|
| 125 |
+ t.Fatalf("Expected the config to have '1G' as Memory, got '%v'", hostconfig.Memory)
|
|
| 126 |
+ } |
|
| 127 |
+} |
|
| 128 |
+ |
|
| 129 |
+func TestParseWithMemorySwap(t *testing.T) {
|
|
| 130 |
+ invalidMemory := "--memory-swap=invalid" |
|
| 131 |
+ validMemory := "--memory-swap=1G" |
|
| 132 |
+ anotherValidMemory := "--memory-swap=-1" |
|
| 133 |
+ if _, _, _, err := parseRun([]string{invalidMemory, "img", "cmd"}); err == nil || err.Error() != "invalid size: 'invalid'" {
|
|
| 134 |
+ t.Fatalf("Expected an error with '%v' MemorySwap, got '%v'", invalidMemory, err)
|
|
| 135 |
+ } |
|
| 136 |
+ if _, hostconfig := mustParse(t, validMemory); hostconfig.MemorySwap != 1073741824 {
|
|
| 137 |
+ t.Fatalf("Expected the config to have '1073741824' as MemorySwap, got '%v'", hostconfig.MemorySwap)
|
|
| 138 |
+ } |
|
| 139 |
+ if _, hostconfig := mustParse(t, anotherValidMemory); hostconfig.MemorySwap != -1 {
|
|
| 140 |
+ t.Fatalf("Expected the config to have '-1' as MemorySwap, got '%v'", hostconfig.MemorySwap)
|
|
| 141 |
+ } |
|
| 142 |
+} |
|
| 143 |
+ |
|
| 144 |
+func TestParseHostname(t *testing.T) {
|
|
| 145 |
+ hostname := "--hostname=hostname" |
|
| 146 |
+ hostnameWithDomain := "--hostname=hostname.domainname" |
|
| 147 |
+ hostnameWithDomainTld := "--hostname=hostname.domainname.tld" |
|
| 148 |
+ if config, _ := mustParse(t, hostname); config.Hostname != "hostname" && config.Domainname != "" {
|
|
| 149 |
+ t.Fatalf("Expected the config to have 'hostname' as hostname, got '%v'", config.Hostname)
|
|
| 150 |
+ } |
|
| 151 |
+ if config, _ := mustParse(t, hostnameWithDomain); config.Hostname != "hostname" && config.Domainname != "domainname" {
|
|
| 152 |
+ t.Fatalf("Expected the config to have 'hostname' as hostname, got '%v'", config.Hostname)
|
|
| 153 |
+ } |
|
| 154 |
+ if config, _ := mustParse(t, hostnameWithDomainTld); config.Hostname != "hostname" && config.Domainname != "domainname.tld" {
|
|
| 155 |
+ t.Fatalf("Expected the config to have 'hostname' as hostname, got '%v'", config.Hostname)
|
|
| 156 |
+ } |
|
| 157 |
+} |
|
| 158 |
+ |
|
| 159 |
+func TestParseWithExpose(t *testing.T) {
|
|
| 160 |
+ invalids := map[string]string{
|
|
| 161 |
+ ":": "Invalid port format for --expose: :", |
|
| 162 |
+ "8080:9090": "Invalid port format for --expose: 8080:9090", |
|
| 163 |
+ "/tcp": "Invalid range format for --expose: /tcp, error: Empty string specified for ports.", |
|
| 164 |
+ "/udp": "Invalid range format for --expose: /udp, error: Empty string specified for ports.", |
|
| 165 |
+ "NaN/tcp": `Invalid range format for --expose: NaN/tcp, error: strconv.ParseUint: parsing "NaN": invalid syntax`, |
|
| 166 |
+ "NaN-NaN/tcp": `Invalid range format for --expose: NaN-NaN/tcp, error: strconv.ParseUint: parsing "NaN": invalid syntax`, |
|
| 167 |
+ "8080-NaN/tcp": `Invalid range format for --expose: 8080-NaN/tcp, error: strconv.ParseUint: parsing "NaN": invalid syntax`, |
|
| 168 |
+ "1234567890-8080/tcp": `Invalid range format for --expose: 1234567890-8080/tcp, error: strconv.ParseUint: parsing "1234567890": value out of range`, |
|
| 169 |
+ } |
|
| 170 |
+ valids := map[string][]nat.Port{
|
|
| 171 |
+ "8080/tcp": {"8080/tcp"},
|
|
| 172 |
+ "8080/udp": {"8080/udp"},
|
|
| 173 |
+ "8080/ncp": {"8080/ncp"},
|
|
| 174 |
+ "8080-8080/udp": {"8080/udp"},
|
|
| 175 |
+ "8080-8082/tcp": {"8080/tcp", "8081/tcp", "8082/tcp"},
|
|
| 176 |
+ } |
|
| 177 |
+ for expose, expectedError := range invalids {
|
|
| 178 |
+ if _, _, _, err := parseRun([]string{fmt.Sprintf("--expose=%v", expose), "img", "cmd"}); err == nil || err.Error() != expectedError {
|
|
| 179 |
+ t.Fatalf("Expected error '%v' with '--expose=%v', got '%v'", expectedError, expose, err)
|
|
| 180 |
+ } |
|
| 181 |
+ } |
|
| 182 |
+ for expose, exposedPorts := range valids {
|
|
| 183 |
+ config, _, _, err := parseRun([]string{fmt.Sprintf("--expose=%v", expose), "img", "cmd"})
|
|
| 184 |
+ if err != nil {
|
|
| 185 |
+ t.Fatal(err) |
|
| 186 |
+ } |
|
| 187 |
+ if len(config.ExposedPorts) != len(exposedPorts) {
|
|
| 188 |
+ t.Fatalf("Expected %v exposed port, got %v", len(exposedPorts), len(config.ExposedPorts))
|
|
| 189 |
+ } |
|
| 190 |
+ for _, port := range exposedPorts {
|
|
| 191 |
+ if _, ok := config.ExposedPorts[port]; !ok {
|
|
| 192 |
+ t.Fatalf("Expected %v, got %v", exposedPorts, config.ExposedPorts)
|
|
| 193 |
+ } |
|
| 194 |
+ } |
|
| 195 |
+ } |
|
| 196 |
+ // Merge with actual published port |
|
| 197 |
+ config, _, _, err := parseRun([]string{"--publish=80", "--expose=80-81/tcp", "img", "cmd"})
|
|
| 198 |
+ if err != nil {
|
|
| 199 |
+ t.Fatal(err) |
|
| 200 |
+ } |
|
| 201 |
+ if len(config.ExposedPorts) != 2 {
|
|
| 202 |
+ t.Fatalf("Expected 2 exposed ports, got %v", config.ExposedPorts)
|
|
| 203 |
+ } |
|
| 204 |
+ ports := []nat.Port{"80/tcp", "81/tcp"}
|
|
| 205 |
+ for _, port := range ports {
|
|
| 206 |
+ if _, ok := config.ExposedPorts[port]; !ok {
|
|
| 207 |
+ t.Fatalf("Expected %v, got %v", ports, config.ExposedPorts)
|
|
| 208 |
+ } |
|
| 209 |
+ } |
|
| 210 |
+} |
|
| 211 |
+ |
|
| 212 |
+func TestParseDevice(t *testing.T) {
|
|
| 213 |
+ valids := map[string]DeviceMapping{
|
|
| 214 |
+ "/dev/snd": {
|
|
| 215 |
+ PathOnHost: "/dev/snd", |
|
| 216 |
+ PathInContainer: "/dev/snd", |
|
| 217 |
+ CgroupPermissions: "rwm", |
|
| 218 |
+ }, |
|
| 219 |
+ "/dev/snd:/something": {
|
|
| 220 |
+ PathOnHost: "/dev/snd", |
|
| 221 |
+ PathInContainer: "/something", |
|
| 222 |
+ CgroupPermissions: "rwm", |
|
| 223 |
+ }, |
|
| 224 |
+ "/dev/snd:/something:ro": {
|
|
| 225 |
+ PathOnHost: "/dev/snd", |
|
| 226 |
+ PathInContainer: "/something", |
|
| 227 |
+ CgroupPermissions: "ro", |
|
| 228 |
+ }, |
|
| 229 |
+ } |
|
| 230 |
+ for device, deviceMapping := range valids {
|
|
| 231 |
+ _, hostconfig, _, err := parseRun([]string{fmt.Sprintf("--device=%v", device), "img", "cmd"})
|
|
| 232 |
+ if err != nil {
|
|
| 233 |
+ t.Fatal(err) |
|
| 234 |
+ } |
|
| 235 |
+ if len(hostconfig.Devices) != 1 {
|
|
| 236 |
+ t.Fatalf("Expected 1 devices, got %v", hostconfig.Devices)
|
|
| 237 |
+ } |
|
| 238 |
+ if hostconfig.Devices[0] != deviceMapping {
|
|
| 239 |
+ t.Fatalf("Expected %v, got %v", deviceMapping, hostconfig.Devices)
|
|
| 240 |
+ } |
|
| 241 |
+ } |
|
| 242 |
+ |
|
| 243 |
+} |
|
| 244 |
+ |
|
| 245 |
+func TestParseModes(t *testing.T) {
|
|
| 246 |
+ // ipc ko |
|
| 247 |
+ if _, _, _, err := parseRun([]string{"--ipc=container:", "img", "cmd"}); err == nil || err.Error() != "--ipc: invalid IPC mode" {
|
|
| 248 |
+ t.Fatalf("Expected an error with message '--ipc: invalid IPC mode', got %v", err)
|
|
| 249 |
+ } |
|
| 250 |
+ // ipc ok |
|
| 251 |
+ _, hostconfig, _, err := parseRun([]string{"--ipc=host", "img", "cmd"})
|
|
| 252 |
+ if err != nil {
|
|
| 253 |
+ t.Fatal(err) |
|
| 254 |
+ } |
|
| 255 |
+ if !hostconfig.IpcMode.Valid() {
|
|
| 256 |
+ t.Fatalf("Expected a valid IpcMode, got %v", hostconfig.IpcMode)
|
|
| 257 |
+ } |
|
| 258 |
+ // pid ko |
|
| 259 |
+ if _, _, _, err := parseRun([]string{"--pid=container:", "img", "cmd"}); err == nil || err.Error() != "--pid: invalid PID mode" {
|
|
| 260 |
+ t.Fatalf("Expected an error with message '--pid: invalid PID mode', got %v", err)
|
|
| 261 |
+ } |
|
| 262 |
+ // pid ok |
|
| 263 |
+ _, hostconfig, _, err = parseRun([]string{"--pid=host", "img", "cmd"})
|
|
| 264 |
+ if err != nil {
|
|
| 265 |
+ t.Fatal(err) |
|
| 266 |
+ } |
|
| 267 |
+ if !hostconfig.PidMode.Valid() {
|
|
| 268 |
+ t.Fatalf("Expected a valid PidMode, got %v", hostconfig.PidMode)
|
|
| 269 |
+ } |
|
| 270 |
+ // uts ko |
|
| 271 |
+ if _, _, _, err := parseRun([]string{"--uts=container:", "img", "cmd"}); err == nil || err.Error() != "--uts: invalid UTS mode" {
|
|
| 272 |
+ t.Fatalf("Expected an error with message '--uts: invalid UTS mode', got %v", err)
|
|
| 273 |
+ } |
|
| 274 |
+ // uts ok |
|
| 275 |
+ _, hostconfig, _, err = parseRun([]string{"--uts=host", "img", "cmd"})
|
|
| 276 |
+ if err != nil {
|
|
| 277 |
+ t.Fatal(err) |
|
| 278 |
+ } |
|
| 279 |
+ if !hostconfig.UTSMode.Valid() {
|
|
| 280 |
+ t.Fatalf("Expected a valid UTSMode, got %v", hostconfig.UTSMode)
|
|
| 281 |
+ } |
|
| 282 |
+} |
|
| 283 |
+ |
|
| 284 |
+func TestParseRestartPolicy(t *testing.T) {
|
|
| 285 |
+ invalids := map[string]string{
|
|
| 286 |
+ "something": "invalid restart policy something", |
|
| 287 |
+ "always:2": "maximum restart count not valid with restart policy of \"always\"", |
|
| 288 |
+ "on-failure:invalid": `strconv.ParseInt: parsing "invalid": invalid syntax`, |
|
| 289 |
+ } |
|
| 290 |
+ valids := map[string]RestartPolicy{
|
|
| 291 |
+ "": {},
|
|
| 292 |
+ // FIXME This feels not right |
|
| 293 |
+ "always:1:2": {
|
|
| 294 |
+ Name: "always", |
|
| 295 |
+ MaximumRetryCount: 0, |
|
| 296 |
+ }, |
|
| 297 |
+ "on-failure:1": {
|
|
| 298 |
+ Name: "on-failure", |
|
| 299 |
+ MaximumRetryCount: 1, |
|
| 300 |
+ }, |
|
| 301 |
+ // FIXME This doesn't feel right |
|
| 302 |
+ "on-failure:1:2": {
|
|
| 303 |
+ Name: "on-failure", |
|
| 304 |
+ MaximumRetryCount: 0, |
|
| 305 |
+ }, |
|
| 306 |
+ } |
|
| 307 |
+ for restart, expectedError := range invalids {
|
|
| 308 |
+ if _, _, _, err := parseRun([]string{fmt.Sprintf("--restart=%s", restart), "img", "cmd"}); err == nil || err.Error() != expectedError {
|
|
| 309 |
+ t.Fatalf("Expected an error with message '%v' for %v, got %v", expectedError, restart, err)
|
|
| 310 |
+ } |
|
| 311 |
+ } |
|
| 312 |
+ for restart, expected := range valids {
|
|
| 313 |
+ _, hostconfig, _, err := parseRun([]string{fmt.Sprintf("--restart=%v", restart), "img", "cmd"})
|
|
| 314 |
+ if err != nil {
|
|
| 315 |
+ t.Fatal(err) |
|
| 316 |
+ } |
|
| 317 |
+ if hostconfig.RestartPolicy != expected {
|
|
| 318 |
+ t.Fatalf("Expected %v, got %v", expected, hostconfig.RestartPolicy)
|
|
| 319 |
+ } |
|
| 320 |
+ } |
|
| 321 |
+} |
|
| 322 |
+ |
|
| 323 |
+func TestParseLoggingOpts(t *testing.T) {
|
|
| 324 |
+ // logging opts ko |
|
| 325 |
+ if _, _, _, err := parseRun([]string{"--log-driver=none", "--log-opt=anything", "img", "cmd"}); err == nil || err.Error() != "Invalid logging opts for driver none" {
|
|
| 326 |
+ t.Fatalf("Expected an error with message 'Invalid logging opts for driver none', got %v", err)
|
|
| 327 |
+ } |
|
| 328 |
+ // logging opts ok |
|
| 329 |
+ _, hostconfig, _, err := parseRun([]string{"--log-driver=syslog", "--log-opt=something", "img", "cmd"})
|
|
| 330 |
+ if err != nil {
|
|
| 331 |
+ t.Fatal(err) |
|
| 332 |
+ } |
|
| 333 |
+ if hostconfig.LogConfig.Type != "syslog" || len(hostconfig.LogConfig.Config) != 1 {
|
|
| 334 |
+ t.Fatalf("Expected a 'syslog' LogConfig with one config, got %v", hostconfig.RestartPolicy)
|
|
| 335 |
+ } |
|
| 336 |
+} |
|
| 337 |
+ |
|
| 338 |
+func TestParseEnvfileVariables(t *testing.T) {
|
|
| 339 |
+ // env ko |
|
| 340 |
+ if _, _, _, err := parseRun([]string{"--env-file=nonexistent", "img", "cmd"}); err == nil || err.Error() != "open nonexistent: no such file or directory" {
|
|
| 341 |
+ t.Fatalf("Expected an error with message 'open nonexistent: no such file or directory', got %v", err)
|
|
| 342 |
+ } |
|
| 343 |
+ // env ok |
|
| 344 |
+ config, _, _, err := parseRun([]string{"--env-file=fixtures/valid.env", "img", "cmd"})
|
|
| 345 |
+ if err != nil {
|
|
| 346 |
+ t.Fatal(err) |
|
| 347 |
+ } |
|
| 348 |
+ if len(config.Env) != 1 || config.Env[0] != "ENV1=value1" {
|
|
| 349 |
+ t.Fatalf("Expected a a config with [ENV1=value1], got %v", config.Env)
|
|
| 350 |
+ } |
|
| 351 |
+ config, _, _, err = parseRun([]string{"--env-file=fixtures/valid.env", "--env=ENV2=value2", "img", "cmd"})
|
|
| 352 |
+ if err != nil {
|
|
| 353 |
+ t.Fatal(err) |
|
| 354 |
+ } |
|
| 355 |
+ if len(config.Env) != 2 || config.Env[0] != "ENV1=value1" || config.Env[1] != "ENV2=value2" {
|
|
| 356 |
+ t.Fatalf("Expected a a config with [ENV1=value1 ENV2=value2], got %v", config.Env)
|
|
| 357 |
+ } |
|
| 358 |
+} |
|
| 359 |
+ |
|
| 360 |
+func TestParseLabelfileVariables(t *testing.T) {
|
|
| 361 |
+ // label ko |
|
| 362 |
+ if _, _, _, err := parseRun([]string{"--label-file=nonexistent", "img", "cmd"}); err == nil || err.Error() != "open nonexistent: no such file or directory" {
|
|
| 363 |
+ t.Fatalf("Expected an error with message 'open nonexistent: no such file or directory', got %v", err)
|
|
| 364 |
+ } |
|
| 365 |
+ // label ok |
|
| 366 |
+ config, _, _, err := parseRun([]string{"--label-file=fixtures/valid.label", "img", "cmd"})
|
|
| 367 |
+ if err != nil {
|
|
| 368 |
+ t.Fatal(err) |
|
| 369 |
+ } |
|
| 370 |
+ if len(config.Labels) != 1 || config.Labels["LABEL1"] != "value1" {
|
|
| 371 |
+ t.Fatalf("Expected a a config with [LABEL1:value1], got %v", config.Labels)
|
|
| 372 |
+ } |
|
| 373 |
+ config, _, _, err = parseRun([]string{"--label-file=fixtures/valid.label", "--label=LABEL2=value2", "img", "cmd"})
|
|
| 374 |
+ if err != nil {
|
|
| 375 |
+ t.Fatal(err) |
|
| 376 |
+ } |
|
| 377 |
+ if len(config.Labels) != 2 || config.Labels["LABEL1"] != "value1" || config.Labels["LABEL2"] != "value2" {
|
|
| 378 |
+ t.Fatalf("Expected a a config with [LABEL1:value1 LABEL2:value2], got %v", config.Labels)
|
|
| 379 |
+ } |
|
| 380 |
+} |
|
| 381 |
+ |
|
| 382 |
+func TestParseEntryPoint(t *testing.T) {
|
|
| 383 |
+ config, _, _, err := parseRun([]string{"--entrypoint=anything", "cmd", "img"})
|
|
| 384 |
+ if err != nil {
|
|
| 385 |
+ t.Fatal(err) |
|
| 386 |
+ } |
|
| 387 |
+ if config.Entrypoint.Len() != 1 && config.Entrypoint.parts[0] != "anything" {
|
|
| 388 |
+ t.Fatalf("Expected entrypoint 'anything', got %v", config.Entrypoint)
|
|
| 389 |
+ } |
|
| 65 | 390 |
} |