1// +build !windows 2 3package runconfig // import "github.com/docker/docker/runconfig" 4 5import ( 6 "bytes" 7 "fmt" 8 "io/ioutil" 9 "testing" 10 11 "github.com/docker/docker/api/types/container" 12 "github.com/docker/docker/pkg/sysinfo" 13 "gotest.tools/assert" 14 is "gotest.tools/assert/cmp" 15) 16 17// TODO Windows: This will need addressing for a Windows daemon. 18func TestNetworkModeTest(t *testing.T) { 19 networkModes := map[container.NetworkMode][]bool{ 20 // private, bridge, host, container, none, default 21 "": {true, false, false, false, false, false}, 22 "something:weird": {true, false, false, false, false, false}, 23 "bridge": {true, true, false, false, false, false}, 24 DefaultDaemonNetworkMode(): {true, true, false, false, false, false}, 25 "host": {false, false, true, false, false, false}, 26 "container:name": {false, false, false, true, false, false}, 27 "none": {true, false, false, false, true, false}, 28 "default": {true, false, false, false, false, true}, 29 } 30 networkModeNames := map[container.NetworkMode]string{ 31 "": "", 32 "something:weird": "something:weird", 33 "bridge": "bridge", 34 DefaultDaemonNetworkMode(): "bridge", 35 "host": "host", 36 "container:name": "container", 37 "none": "none", 38 "default": "default", 39 } 40 for networkMode, state := range networkModes { 41 if networkMode.IsPrivate() != state[0] { 42 t.Fatalf("NetworkMode.IsPrivate for %v should have been %v but was %v", networkMode, state[0], networkMode.IsPrivate()) 43 } 44 if networkMode.IsBridge() != state[1] { 45 t.Fatalf("NetworkMode.IsBridge for %v should have been %v but was %v", networkMode, state[1], networkMode.IsBridge()) 46 } 47 if networkMode.IsHost() != state[2] { 48 t.Fatalf("NetworkMode.IsHost for %v should have been %v but was %v", networkMode, state[2], networkMode.IsHost()) 49 } 50 if networkMode.IsContainer() != state[3] { 51 t.Fatalf("NetworkMode.IsContainer for %v should have been %v but was %v", networkMode, state[3], networkMode.IsContainer()) 52 } 53 if networkMode.IsNone() != state[4] { 54 t.Fatalf("NetworkMode.IsNone for %v should have been %v but was %v", networkMode, state[4], networkMode.IsNone()) 55 } 56 if networkMode.IsDefault() != state[5] { 57 t.Fatalf("NetworkMode.IsDefault for %v should have been %v but was %v", networkMode, state[5], networkMode.IsDefault()) 58 } 59 if networkMode.NetworkName() != networkModeNames[networkMode] { 60 t.Fatalf("Expected name %v, got %v", networkModeNames[networkMode], networkMode.NetworkName()) 61 } 62 } 63} 64 65func TestIpcModeTest(t *testing.T) { 66 ipcModes := map[container.IpcMode]struct { 67 private bool 68 host bool 69 container bool 70 shareable bool 71 valid bool 72 ctrName string 73 }{ 74 "": {valid: true}, 75 "private": {private: true, valid: true}, 76 "something:weird": {}, 77 ":weird": {}, 78 "host": {host: true, valid: true}, 79 "container": {}, 80 "container:": {container: true, valid: true, ctrName: ""}, 81 "container:name": {container: true, valid: true, ctrName: "name"}, 82 "container:name1:name2": {container: true, valid: true, ctrName: "name1:name2"}, 83 "shareable": {shareable: true, valid: true}, 84 } 85 86 for ipcMode, state := range ipcModes { 87 assert.Check(t, is.Equal(state.private, ipcMode.IsPrivate()), "IpcMode.IsPrivate() parsing failed for %q", ipcMode) 88 assert.Check(t, is.Equal(state.host, ipcMode.IsHost()), "IpcMode.IsHost() parsing failed for %q", ipcMode) 89 assert.Check(t, is.Equal(state.container, ipcMode.IsContainer()), "IpcMode.IsContainer() parsing failed for %q", ipcMode) 90 assert.Check(t, is.Equal(state.shareable, ipcMode.IsShareable()), "IpcMode.IsShareable() parsing failed for %q", ipcMode) 91 assert.Check(t, is.Equal(state.valid, ipcMode.Valid()), "IpcMode.Valid() parsing failed for %q", ipcMode) 92 assert.Check(t, is.Equal(state.ctrName, ipcMode.Container()), "IpcMode.Container() parsing failed for %q", ipcMode) 93 } 94} 95 96func TestUTSModeTest(t *testing.T) { 97 utsModes := map[container.UTSMode][]bool{ 98 // private, host, valid 99 "": {true, false, true}, 100 "something:weird": {true, false, false}, 101 "host": {false, true, true}, 102 "host:name": {true, false, true}, 103 } 104 for utsMode, state := range utsModes { 105 if utsMode.IsPrivate() != state[0] { 106 t.Fatalf("UtsMode.IsPrivate for %v should have been %v but was %v", utsMode, state[0], utsMode.IsPrivate()) 107 } 108 if utsMode.IsHost() != state[1] { 109 t.Fatalf("UtsMode.IsHost for %v should have been %v but was %v", utsMode, state[1], utsMode.IsHost()) 110 } 111 if utsMode.Valid() != state[2] { 112 t.Fatalf("UtsMode.Valid for %v should have been %v but was %v", utsMode, state[2], utsMode.Valid()) 113 } 114 } 115} 116 117func TestUsernsModeTest(t *testing.T) { 118 usrensMode := map[container.UsernsMode][]bool{ 119 // private, host, valid 120 "": {true, false, true}, 121 "something:weird": {true, false, false}, 122 "host": {false, true, true}, 123 "host:name": {true, false, true}, 124 } 125 for usernsMode, state := range usrensMode { 126 if usernsMode.IsPrivate() != state[0] { 127 t.Fatalf("UsernsMode.IsPrivate for %v should have been %v but was %v", usernsMode, state[0], usernsMode.IsPrivate()) 128 } 129 if usernsMode.IsHost() != state[1] { 130 t.Fatalf("UsernsMode.IsHost for %v should have been %v but was %v", usernsMode, state[1], usernsMode.IsHost()) 131 } 132 if usernsMode.Valid() != state[2] { 133 t.Fatalf("UsernsMode.Valid for %v should have been %v but was %v", usernsMode, state[2], usernsMode.Valid()) 134 } 135 } 136} 137 138func TestPidModeTest(t *testing.T) { 139 pidModes := map[container.PidMode][]bool{ 140 // private, host, valid 141 "": {true, false, true}, 142 "something:weird": {true, false, false}, 143 "host": {false, true, true}, 144 "host:name": {true, false, true}, 145 } 146 for pidMode, state := range pidModes { 147 if pidMode.IsPrivate() != state[0] { 148 t.Fatalf("PidMode.IsPrivate for %v should have been %v but was %v", pidMode, state[0], pidMode.IsPrivate()) 149 } 150 if pidMode.IsHost() != state[1] { 151 t.Fatalf("PidMode.IsHost for %v should have been %v but was %v", pidMode, state[1], pidMode.IsHost()) 152 } 153 if pidMode.Valid() != state[2] { 154 t.Fatalf("PidMode.Valid for %v should have been %v but was %v", pidMode, state[2], pidMode.Valid()) 155 } 156 } 157} 158 159func TestRestartPolicy(t *testing.T) { 160 restartPolicies := map[container.RestartPolicy][]bool{ 161 // none, always, failure 162 {}: {true, false, false}, 163 {Name: "something", MaximumRetryCount: 0}: {false, false, false}, 164 {Name: "no", MaximumRetryCount: 0}: {true, false, false}, 165 {Name: "always", MaximumRetryCount: 0}: {false, true, false}, 166 {Name: "on-failure", MaximumRetryCount: 0}: {false, false, true}, 167 } 168 for restartPolicy, state := range restartPolicies { 169 if restartPolicy.IsNone() != state[0] { 170 t.Fatalf("RestartPolicy.IsNone for %v should have been %v but was %v", restartPolicy, state[0], restartPolicy.IsNone()) 171 } 172 if restartPolicy.IsAlways() != state[1] { 173 t.Fatalf("RestartPolicy.IsAlways for %v should have been %v but was %v", restartPolicy, state[1], restartPolicy.IsAlways()) 174 } 175 if restartPolicy.IsOnFailure() != state[2] { 176 t.Fatalf("RestartPolicy.IsOnFailure for %v should have been %v but was %v", restartPolicy, state[2], restartPolicy.IsOnFailure()) 177 } 178 } 179} 180func TestDecodeHostConfig(t *testing.T) { 181 fixtures := []struct { 182 file string 183 }{ 184 {"fixtures/unix/container_hostconfig_1_14.json"}, 185 {"fixtures/unix/container_hostconfig_1_19.json"}, 186 } 187 188 for _, f := range fixtures { 189 b, err := ioutil.ReadFile(f.file) 190 if err != nil { 191 t.Fatal(err) 192 } 193 194 c, err := decodeHostConfig(bytes.NewReader(b)) 195 if err != nil { 196 t.Fatal(fmt.Errorf("Error parsing %s: %v", f, err)) 197 } 198 199 assert.Check(t, !c.Privileged) 200 201 if l := len(c.Binds); l != 1 { 202 t.Fatalf("Expected 1 bind, found %d\n", l) 203 } 204 205 if len(c.CapAdd) != 1 && c.CapAdd[0] != "NET_ADMIN" { 206 t.Fatalf("Expected CapAdd NET_ADMIN, got %v", c.CapAdd) 207 } 208 209 if len(c.CapDrop) != 1 && c.CapDrop[0] != "NET_ADMIN" { 210 t.Fatalf("Expected CapDrop NET_ADMIN, got %v", c.CapDrop) 211 } 212 } 213} 214 215func TestValidateResources(t *testing.T) { 216 type resourceTest struct { 217 ConfigCPURealtimePeriod int64 218 ConfigCPURealtimeRuntime int64 219 SysInfoCPURealtimePeriod bool 220 SysInfoCPURealtimeRuntime bool 221 ErrorExpected bool 222 FailureMsg string 223 } 224 225 tests := []resourceTest{ 226 { 227 ConfigCPURealtimePeriod: 1000, 228 ConfigCPURealtimeRuntime: 1000, 229 SysInfoCPURealtimePeriod: true, 230 SysInfoCPURealtimeRuntime: true, 231 ErrorExpected: false, 232 FailureMsg: "Expected valid configuration", 233 }, 234 { 235 ConfigCPURealtimePeriod: 5000, 236 ConfigCPURealtimeRuntime: 5000, 237 SysInfoCPURealtimePeriod: false, 238 SysInfoCPURealtimeRuntime: true, 239 ErrorExpected: true, 240 FailureMsg: "Expected failure when cpu-rt-period is set but kernel doesn't support it", 241 }, 242 { 243 ConfigCPURealtimePeriod: 5000, 244 ConfigCPURealtimeRuntime: 5000, 245 SysInfoCPURealtimePeriod: true, 246 SysInfoCPURealtimeRuntime: false, 247 ErrorExpected: true, 248 FailureMsg: "Expected failure when cpu-rt-runtime is set but kernel doesn't support it", 249 }, 250 { 251 ConfigCPURealtimePeriod: 5000, 252 ConfigCPURealtimeRuntime: 10000, 253 SysInfoCPURealtimePeriod: true, 254 SysInfoCPURealtimeRuntime: false, 255 ErrorExpected: true, 256 FailureMsg: "Expected failure when cpu-rt-runtime is greater than cpu-rt-period", 257 }, 258 } 259 260 for _, rt := range tests { 261 var hc container.HostConfig 262 hc.Resources.CPURealtimePeriod = rt.ConfigCPURealtimePeriod 263 hc.Resources.CPURealtimeRuntime = rt.ConfigCPURealtimeRuntime 264 265 var si sysinfo.SysInfo 266 si.CPURealtimePeriod = rt.SysInfoCPURealtimePeriod 267 si.CPURealtimeRuntime = rt.SysInfoCPURealtimeRuntime 268 269 if err := validateResources(&hc, &si); (err != nil) != rt.ErrorExpected { 270 t.Fatal(rt.FailureMsg, err) 271 } 272 } 273} 274