update_test.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. package service
  2. import (
  3. "reflect"
  4. "sort"
  5. "testing"
  6. "time"
  7. "github.com/docker/docker/api/types/container"
  8. mounttypes "github.com/docker/docker/api/types/mount"
  9. "github.com/docker/docker/api/types/swarm"
  10. "github.com/docker/docker/pkg/testutil/assert"
  11. )
  12. func TestUpdateServiceArgs(t *testing.T) {
  13. flags := newUpdateCommand(nil).Flags()
  14. flags.Set("args", "the \"new args\"")
  15. spec := &swarm.ServiceSpec{}
  16. cspec := &spec.TaskTemplate.ContainerSpec
  17. cspec.Args = []string{"old", "args"}
  18. updateService(flags, spec)
  19. assert.EqualStringSlice(t, cspec.Args, []string{"the", "new args"})
  20. }
  21. func TestUpdateLabels(t *testing.T) {
  22. flags := newUpdateCommand(nil).Flags()
  23. flags.Set("label-add", "toadd=newlabel")
  24. flags.Set("label-rm", "toremove")
  25. labels := map[string]string{
  26. "toremove": "thelabeltoremove",
  27. "tokeep": "value",
  28. }
  29. updateLabels(flags, &labels)
  30. assert.Equal(t, len(labels), 2)
  31. assert.Equal(t, labels["tokeep"], "value")
  32. assert.Equal(t, labels["toadd"], "newlabel")
  33. }
  34. func TestUpdateLabelsRemoveALabelThatDoesNotExist(t *testing.T) {
  35. flags := newUpdateCommand(nil).Flags()
  36. flags.Set("label-rm", "dne")
  37. labels := map[string]string{"foo": "theoldlabel"}
  38. updateLabels(flags, &labels)
  39. assert.Equal(t, len(labels), 1)
  40. }
  41. func TestUpdatePlacement(t *testing.T) {
  42. flags := newUpdateCommand(nil).Flags()
  43. flags.Set("constraint-add", "node=toadd")
  44. flags.Set("constraint-rm", "node!=toremove")
  45. placement := &swarm.Placement{
  46. Constraints: []string{"node!=toremove", "container=tokeep"},
  47. }
  48. updatePlacement(flags, placement)
  49. assert.Equal(t, len(placement.Constraints), 2)
  50. assert.Equal(t, placement.Constraints[0], "container=tokeep")
  51. assert.Equal(t, placement.Constraints[1], "node=toadd")
  52. }
  53. func TestUpdateEnvironment(t *testing.T) {
  54. flags := newUpdateCommand(nil).Flags()
  55. flags.Set("env-add", "toadd=newenv")
  56. flags.Set("env-rm", "toremove")
  57. envs := []string{"toremove=theenvtoremove", "tokeep=value"}
  58. updateEnvironment(flags, &envs)
  59. assert.Equal(t, len(envs), 2)
  60. // Order has been removed in updateEnvironment (map)
  61. sort.Strings(envs)
  62. assert.Equal(t, envs[0], "toadd=newenv")
  63. assert.Equal(t, envs[1], "tokeep=value")
  64. }
  65. func TestUpdateEnvironmentWithDuplicateValues(t *testing.T) {
  66. flags := newUpdateCommand(nil).Flags()
  67. flags.Set("env-add", "foo=newenv")
  68. flags.Set("env-add", "foo=dupe")
  69. flags.Set("env-rm", "foo")
  70. envs := []string{"foo=value"}
  71. updateEnvironment(flags, &envs)
  72. assert.Equal(t, len(envs), 0)
  73. }
  74. func TestUpdateEnvironmentWithDuplicateKeys(t *testing.T) {
  75. // Test case for #25404
  76. flags := newUpdateCommand(nil).Flags()
  77. flags.Set("env-add", "A=b")
  78. envs := []string{"A=c"}
  79. updateEnvironment(flags, &envs)
  80. assert.Equal(t, len(envs), 1)
  81. assert.Equal(t, envs[0], "A=b")
  82. }
  83. func TestUpdateGroups(t *testing.T) {
  84. flags := newUpdateCommand(nil).Flags()
  85. flags.Set("group-add", "wheel")
  86. flags.Set("group-add", "docker")
  87. flags.Set("group-rm", "root")
  88. flags.Set("group-add", "foo")
  89. flags.Set("group-rm", "docker")
  90. groups := []string{"bar", "root"}
  91. updateGroups(flags, &groups)
  92. assert.Equal(t, len(groups), 3)
  93. assert.Equal(t, groups[0], "bar")
  94. assert.Equal(t, groups[1], "foo")
  95. assert.Equal(t, groups[2], "wheel")
  96. }
  97. func TestUpdateDNSConfig(t *testing.T) {
  98. flags := newUpdateCommand(nil).Flags()
  99. // IPv4, with duplicates
  100. flags.Set("dns-add", "1.1.1.1")
  101. flags.Set("dns-add", "1.1.1.1")
  102. flags.Set("dns-add", "2.2.2.2")
  103. flags.Set("dns-rm", "3.3.3.3")
  104. flags.Set("dns-rm", "2.2.2.2")
  105. // IPv6
  106. flags.Set("dns-add", "2001:db8:abc8::1")
  107. // Invalid dns record
  108. assert.Error(t, flags.Set("dns-add", "x.y.z.w"), "x.y.z.w is not an ip address")
  109. // domains with duplicates
  110. flags.Set("dns-search-add", "example.com")
  111. flags.Set("dns-search-add", "example.com")
  112. flags.Set("dns-search-add", "example.org")
  113. flags.Set("dns-search-rm", "example.org")
  114. // Invalid dns search domain
  115. assert.Error(t, flags.Set("dns-search-add", "example$com"), "example$com is not a valid domain")
  116. flags.Set("dns-options-add", "ndots:9")
  117. flags.Set("dns-options-rm", "timeout:3")
  118. config := &swarm.DNSConfig{
  119. Nameservers: []string{"3.3.3.3", "5.5.5.5"},
  120. Search: []string{"localdomain"},
  121. Options: []string{"timeout:3"},
  122. }
  123. updateDNSConfig(flags, &config)
  124. assert.Equal(t, len(config.Nameservers), 3)
  125. assert.Equal(t, config.Nameservers[0], "1.1.1.1")
  126. assert.Equal(t, config.Nameservers[1], "2001:db8:abc8::1")
  127. assert.Equal(t, config.Nameservers[2], "5.5.5.5")
  128. assert.Equal(t, len(config.Search), 2)
  129. assert.Equal(t, config.Search[0], "example.com")
  130. assert.Equal(t, config.Search[1], "localdomain")
  131. assert.Equal(t, len(config.Options), 1)
  132. assert.Equal(t, config.Options[0], "ndots:9")
  133. }
  134. func TestUpdateMounts(t *testing.T) {
  135. flags := newUpdateCommand(nil).Flags()
  136. flags.Set("mount-add", "type=volume,source=vol2,target=/toadd")
  137. flags.Set("mount-rm", "/toremove")
  138. mounts := []mounttypes.Mount{
  139. {Target: "/toremove", Source: "vol1", Type: mounttypes.TypeBind},
  140. {Target: "/tokeep", Source: "vol3", Type: mounttypes.TypeBind},
  141. }
  142. updateMounts(flags, &mounts)
  143. assert.Equal(t, len(mounts), 2)
  144. assert.Equal(t, mounts[0].Target, "/toadd")
  145. assert.Equal(t, mounts[1].Target, "/tokeep")
  146. }
  147. func TestUpdateMountsWithDuplicateMounts(t *testing.T) {
  148. flags := newUpdateCommand(nil).Flags()
  149. flags.Set("mount-add", "type=volume,source=vol4,target=/toadd")
  150. mounts := []mounttypes.Mount{
  151. {Target: "/tokeep1", Source: "vol1", Type: mounttypes.TypeBind},
  152. {Target: "/toadd", Source: "vol2", Type: mounttypes.TypeBind},
  153. {Target: "/tokeep2", Source: "vol3", Type: mounttypes.TypeBind},
  154. }
  155. updateMounts(flags, &mounts)
  156. assert.Equal(t, len(mounts), 3)
  157. assert.Equal(t, mounts[0].Target, "/tokeep1")
  158. assert.Equal(t, mounts[1].Target, "/tokeep2")
  159. assert.Equal(t, mounts[2].Target, "/toadd")
  160. }
  161. func TestUpdatePorts(t *testing.T) {
  162. flags := newUpdateCommand(nil).Flags()
  163. flags.Set("publish-add", "1000:1000")
  164. flags.Set("publish-rm", "333/udp")
  165. portConfigs := []swarm.PortConfig{
  166. {TargetPort: 333, Protocol: swarm.PortConfigProtocolUDP},
  167. {TargetPort: 555},
  168. }
  169. err := updatePorts(flags, &portConfigs)
  170. assert.Equal(t, err, nil)
  171. assert.Equal(t, len(portConfigs), 2)
  172. // Do a sort to have the order (might have changed by map)
  173. targetPorts := []int{int(portConfigs[0].TargetPort), int(portConfigs[1].TargetPort)}
  174. sort.Ints(targetPorts)
  175. assert.Equal(t, targetPorts[0], 555)
  176. assert.Equal(t, targetPorts[1], 1000)
  177. }
  178. func TestUpdatePortsDuplicateEntries(t *testing.T) {
  179. // Test case for #25375
  180. flags := newUpdateCommand(nil).Flags()
  181. flags.Set("publish-add", "80:80")
  182. portConfigs := []swarm.PortConfig{
  183. {TargetPort: 80, PublishedPort: 80},
  184. }
  185. err := updatePorts(flags, &portConfigs)
  186. assert.Equal(t, err, nil)
  187. assert.Equal(t, len(portConfigs), 1)
  188. assert.Equal(t, portConfigs[0].TargetPort, uint32(80))
  189. }
  190. func TestUpdatePortsDuplicateKeys(t *testing.T) {
  191. // Test case for #25375
  192. flags := newUpdateCommand(nil).Flags()
  193. flags.Set("publish-add", "80:20")
  194. portConfigs := []swarm.PortConfig{
  195. {TargetPort: 80, PublishedPort: 80},
  196. }
  197. err := updatePorts(flags, &portConfigs)
  198. assert.Equal(t, err, nil)
  199. assert.Equal(t, len(portConfigs), 1)
  200. assert.Equal(t, portConfigs[0].TargetPort, uint32(20))
  201. }
  202. func TestUpdatePortsConflictingFlags(t *testing.T) {
  203. // Test case for #25375
  204. flags := newUpdateCommand(nil).Flags()
  205. flags.Set("publish-add", "80:80")
  206. flags.Set("publish-add", "80:20")
  207. portConfigs := []swarm.PortConfig{
  208. {TargetPort: 80, PublishedPort: 80},
  209. }
  210. err := updatePorts(flags, &portConfigs)
  211. assert.Error(t, err, "conflicting port mapping")
  212. }
  213. func TestUpdateHealthcheckTable(t *testing.T) {
  214. type test struct {
  215. flags [][2]string
  216. initial *container.HealthConfig
  217. expected *container.HealthConfig
  218. err string
  219. }
  220. testCases := []test{
  221. {
  222. flags: [][2]string{{"no-healthcheck", "true"}},
  223. initial: &container.HealthConfig{Test: []string{"CMD-SHELL", "cmd1"}, Retries: 10},
  224. expected: &container.HealthConfig{Test: []string{"NONE"}},
  225. },
  226. {
  227. flags: [][2]string{{"health-cmd", "cmd1"}},
  228. initial: &container.HealthConfig{Test: []string{"NONE"}},
  229. expected: &container.HealthConfig{Test: []string{"CMD-SHELL", "cmd1"}},
  230. },
  231. {
  232. flags: [][2]string{{"health-retries", "10"}},
  233. initial: &container.HealthConfig{Test: []string{"NONE"}},
  234. expected: &container.HealthConfig{Retries: 10},
  235. },
  236. {
  237. flags: [][2]string{{"health-retries", "10"}},
  238. initial: &container.HealthConfig{Test: []string{"CMD", "cmd1"}},
  239. expected: &container.HealthConfig{Test: []string{"CMD", "cmd1"}, Retries: 10},
  240. },
  241. {
  242. flags: [][2]string{{"health-interval", "1m"}},
  243. initial: &container.HealthConfig{Test: []string{"CMD", "cmd1"}},
  244. expected: &container.HealthConfig{Test: []string{"CMD", "cmd1"}, Interval: time.Minute},
  245. },
  246. {
  247. flags: [][2]string{{"health-cmd", ""}},
  248. initial: &container.HealthConfig{Test: []string{"CMD", "cmd1"}, Retries: 10},
  249. expected: &container.HealthConfig{Retries: 10},
  250. },
  251. {
  252. flags: [][2]string{{"health-retries", "0"}},
  253. initial: &container.HealthConfig{Test: []string{"CMD", "cmd1"}, Retries: 10},
  254. expected: &container.HealthConfig{Test: []string{"CMD", "cmd1"}},
  255. },
  256. {
  257. flags: [][2]string{{"health-cmd", "cmd1"}, {"no-healthcheck", "true"}},
  258. err: "--no-healthcheck conflicts with --health-* options",
  259. },
  260. {
  261. flags: [][2]string{{"health-interval", "10m"}, {"no-healthcheck", "true"}},
  262. err: "--no-healthcheck conflicts with --health-* options",
  263. },
  264. {
  265. flags: [][2]string{{"health-timeout", "1m"}, {"no-healthcheck", "true"}},
  266. err: "--no-healthcheck conflicts with --health-* options",
  267. },
  268. }
  269. for i, c := range testCases {
  270. flags := newUpdateCommand(nil).Flags()
  271. for _, flag := range c.flags {
  272. flags.Set(flag[0], flag[1])
  273. }
  274. cspec := &swarm.ContainerSpec{
  275. Healthcheck: c.initial,
  276. }
  277. err := updateHealthcheck(flags, cspec)
  278. if c.err != "" {
  279. assert.Error(t, err, c.err)
  280. } else {
  281. assert.NilError(t, err)
  282. if !reflect.DeepEqual(cspec.Healthcheck, c.expected) {
  283. t.Errorf("incorrect result for test %d, expected health config:\n\t%#v\ngot:\n\t%#v", i, c.expected, cspec.Healthcheck)
  284. }
  285. }
  286. }
  287. }