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