github.com/uchennaokeke444/nomad@v0.11.8/nomad/structs/services_test.go (about) 1 package structs 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/hashicorp/nomad/helper" 8 "github.com/stretchr/testify/require" 9 ) 10 11 func TestService_Hash(t *testing.T) { 12 t.Parallel() 13 14 original := &Service{ 15 Name: "myService", 16 PortLabel: "portLabel", 17 // AddressMode: "bridge", // not hashed (used internally by Nomad) 18 Tags: []string{"original", "tags"}, 19 CanaryTags: []string{"canary", "tags"}, 20 // Checks: nil, // not hashed (managed independently) 21 Connect: &ConsulConnect{ 22 // Native: false, // not hashed 23 SidecarService: &ConsulSidecarService{ 24 Tags: []string{"original", "sidecar", "tags"}, 25 Port: "9000", 26 Proxy: &ConsulProxy{ 27 LocalServiceAddress: "127.0.0.1", 28 LocalServicePort: 24000, 29 Config: map[string]interface{}{"foo": "bar"}, 30 Upstreams: []ConsulUpstream{{ 31 DestinationName: "upstream1", 32 LocalBindPort: 29000, 33 }}, 34 }, 35 }, 36 // SidecarTask: nil // not hashed 37 }} 38 39 type svc = Service 40 type tweaker = func(service *svc) 41 42 hash := func(s *svc, canary bool) string { 43 return s.Hash("AllocID", "TaskName", canary) 44 } 45 46 t.Run("matching and is canary", func(t *testing.T) { 47 require.Equal(t, hash(original, true), hash(original, true)) 48 }) 49 50 t.Run("matching and is not canary", func(t *testing.T) { 51 require.Equal(t, hash(original, false), hash(original, false)) 52 }) 53 54 t.Run("matching mod canary", func(t *testing.T) { 55 require.NotEqual(t, hash(original, true), hash(original, false)) 56 }) 57 58 try := func(t *testing.T, tweak tweaker) { 59 originalHash := hash(original, true) 60 modifiable := original.Copy() 61 tweak(modifiable) 62 tweakedHash := hash(modifiable, true) 63 require.NotEqual(t, originalHash, tweakedHash) 64 } 65 66 // these tests use tweaker to modify 1 field and make the false assertion 67 // on comparing the resulting hash output 68 69 t.Run("mod name", func(t *testing.T) { 70 try(t, func(s *svc) { s.Name = "newName" }) 71 }) 72 73 t.Run("mod port label", func(t *testing.T) { 74 try(t, func(s *svc) { s.PortLabel = "newPortLabel" }) 75 }) 76 77 t.Run("mod tags", func(t *testing.T) { 78 try(t, func(s *svc) { s.Tags = []string{"new", "tags"} }) 79 }) 80 81 t.Run("mod canary tags", func(t *testing.T) { 82 try(t, func(s *svc) { s.CanaryTags = []string{"new", "tags"} }) 83 }) 84 85 t.Run("mod enable tag override", func(t *testing.T) { 86 try(t, func(s *svc) { s.EnableTagOverride = true }) 87 }) 88 89 t.Run("mod connect sidecar tags", func(t *testing.T) { 90 try(t, func(s *svc) { s.Connect.SidecarService.Tags = []string{"new", "tags"} }) 91 }) 92 93 t.Run("mod connect sidecar port", func(t *testing.T) { 94 try(t, func(s *svc) { s.Connect.SidecarService.Port = "9090" }) 95 }) 96 97 t.Run("mod connect sidecar proxy local service address", func(t *testing.T) { 98 try(t, func(s *svc) { s.Connect.SidecarService.Proxy.LocalServiceAddress = "1.1.1.1" }) 99 }) 100 101 t.Run("mod connect sidecar proxy local service port", func(t *testing.T) { 102 try(t, func(s *svc) { s.Connect.SidecarService.Proxy.LocalServicePort = 9999 }) 103 }) 104 105 t.Run("mod connect sidecar proxy config", func(t *testing.T) { 106 try(t, func(s *svc) { s.Connect.SidecarService.Proxy.Config = map[string]interface{}{"foo": "baz"} }) 107 }) 108 109 t.Run("mod connect sidecar proxy upstream dest name", func(t *testing.T) { 110 try(t, func(s *svc) { s.Connect.SidecarService.Proxy.Upstreams[0].DestinationName = "dest2" }) 111 }) 112 113 t.Run("mod connect sidecar proxy upstream dest local bind port", func(t *testing.T) { 114 try(t, func(s *svc) { s.Connect.SidecarService.Proxy.Upstreams[0].LocalBindPort = 29999 }) 115 }) 116 } 117 118 func TestConsulConnect_Validate(t *testing.T) { 119 t.Parallel() 120 121 c := &ConsulConnect{} 122 123 // An empty Connect stanza is invalid 124 require.Error(t, c.Validate()) 125 126 // Native=true is valid 127 c.Native = true 128 require.NoError(t, c.Validate()) 129 130 // Native=true + Sidecar!=nil is invalid 131 c.SidecarService = &ConsulSidecarService{} 132 require.Error(t, c.Validate()) 133 134 // Native=false + Sidecar!=nil is valid 135 c.Native = false 136 require.NoError(t, c.Validate()) 137 } 138 139 func TestConsulConnect_CopyEquals(t *testing.T) { 140 t.Parallel() 141 142 c := &ConsulConnect{ 143 SidecarService: &ConsulSidecarService{ 144 Tags: []string{"tag1", "tag2"}, 145 Port: "9001", 146 Proxy: &ConsulProxy{ 147 LocalServiceAddress: "127.0.0.1", 148 LocalServicePort: 8080, 149 Upstreams: []ConsulUpstream{ 150 { 151 DestinationName: "up1", 152 LocalBindPort: 9002, 153 }, 154 { 155 DestinationName: "up2", 156 LocalBindPort: 9003, 157 }, 158 }, 159 Config: map[string]interface{}{ 160 "foo": 1, 161 }, 162 }, 163 }, 164 } 165 166 require.NoError(t, c.Validate()) 167 168 // Copies should be equivalent 169 o := c.Copy() 170 require.True(t, c.Equals(o)) 171 172 o.SidecarService.Proxy.Upstreams = nil 173 require.False(t, c.Equals(o)) 174 } 175 176 func TestSidecarTask_MergeIntoTask(t *testing.T) { 177 t.Parallel() 178 179 task := MockJob().TaskGroups[0].Tasks[0] 180 sTask := &SidecarTask{ 181 Name: "sidecar", 182 Driver: "sidecar", 183 User: "test", 184 Config: map[string]interface{}{ 185 "foo": "bar", 186 }, 187 Resources: &Resources{ 188 CPU: 10000, 189 MemoryMB: 10000, 190 }, 191 Env: map[string]string{ 192 "sidecar": "proxy", 193 }, 194 Meta: map[string]string{ 195 "abc": "123", 196 }, 197 KillTimeout: helper.TimeToPtr(15 * time.Second), 198 LogConfig: &LogConfig{ 199 MaxFiles: 3, 200 }, 201 ShutdownDelay: helper.TimeToPtr(5 * time.Second), 202 KillSignal: "SIGABRT", 203 } 204 205 expected := task.Copy() 206 expected.Name = "sidecar" 207 expected.Driver = "sidecar" 208 expected.User = "test" 209 expected.Config = map[string]interface{}{ 210 "foo": "bar", 211 } 212 expected.Resources.CPU = 10000 213 expected.Resources.MemoryMB = 10000 214 expected.Env["sidecar"] = "proxy" 215 expected.Meta["abc"] = "123" 216 expected.KillTimeout = 15 * time.Second 217 expected.LogConfig.MaxFiles = 3 218 expected.ShutdownDelay = 5 * time.Second 219 expected.KillSignal = "SIGABRT" 220 221 sTask.MergeIntoTask(task) 222 require.Exactly(t, expected, task) 223 224 // Check that changing just driver config doesn't replace map 225 sTask.Config["abc"] = 123 226 expected.Config["abc"] = 123 227 228 sTask.MergeIntoTask(task) 229 require.Exactly(t, expected, task) 230 } 231 232 func TestConsulUpstream_upstreamEquals(t *testing.T) { 233 t.Parallel() 234 235 up := func(name string, port int) ConsulUpstream { 236 return ConsulUpstream{ 237 DestinationName: name, 238 LocalBindPort: port, 239 } 240 } 241 242 t.Run("size mismatch", func(t *testing.T) { 243 a := []ConsulUpstream{up("foo", 8000)} 244 b := []ConsulUpstream{up("foo", 8000), up("bar", 9000)} 245 require.False(t, upstreamsEquals(a, b)) 246 }) 247 248 t.Run("different", func(t *testing.T) { 249 a := []ConsulUpstream{up("bar", 9000)} 250 b := []ConsulUpstream{up("foo", 8000)} 251 require.False(t, upstreamsEquals(a, b)) 252 }) 253 254 t.Run("identical", func(t *testing.T) { 255 a := []ConsulUpstream{up("foo", 8000), up("bar", 9000)} 256 b := []ConsulUpstream{up("foo", 8000), up("bar", 9000)} 257 require.True(t, upstreamsEquals(a, b)) 258 }) 259 260 t.Run("unsorted", func(t *testing.T) { 261 a := []ConsulUpstream{up("foo", 8000), up("bar", 9000)} 262 b := []ConsulUpstream{up("bar", 9000), up("foo", 8000)} 263 require.True(t, upstreamsEquals(a, b)) 264 }) 265 } 266 267 func TestConsulExposePath_exposePathsEqual(t *testing.T) { 268 t.Parallel() 269 270 expose := func(path, protocol, listen string, local int) ConsulExposePath { 271 return ConsulExposePath{ 272 Path: path, 273 Protocol: protocol, 274 LocalPathPort: local, 275 ListenerPort: listen, 276 } 277 } 278 279 t.Run("size mismatch", func(t *testing.T) { 280 a := []ConsulExposePath{expose("/1", "http", "myPort", 8000)} 281 b := []ConsulExposePath{expose("/1", "http", "myPort", 8000), expose("/2", "http", "myPort", 8000)} 282 require.False(t, exposePathsEqual(a, b)) 283 }) 284 285 t.Run("different", func(t *testing.T) { 286 a := []ConsulExposePath{expose("/1", "http", "myPort", 8000)} 287 b := []ConsulExposePath{expose("/2", "http", "myPort", 8000)} 288 require.False(t, exposePathsEqual(a, b)) 289 }) 290 291 t.Run("identical", func(t *testing.T) { 292 a := []ConsulExposePath{expose("/1", "http", "myPort", 8000)} 293 b := []ConsulExposePath{expose("/1", "http", "myPort", 8000)} 294 require.True(t, exposePathsEqual(a, b)) 295 }) 296 297 t.Run("unsorted", func(t *testing.T) { 298 a := []ConsulExposePath{expose("/2", "http", "myPort", 8000), expose("/1", "http", "myPort", 8000)} 299 b := []ConsulExposePath{expose("/1", "http", "myPort", 8000), expose("/2", "http", "myPort", 8000)} 300 require.True(t, exposePathsEqual(a, b)) 301 }) 302 } 303 304 func TestConsulExposeConfig_Copy(t *testing.T) { 305 t.Parallel() 306 307 require.Nil(t, (*ConsulExposeConfig)(nil).Copy()) 308 require.Equal(t, &ConsulExposeConfig{ 309 Paths: []ConsulExposePath{{ 310 Path: "/health", 311 }}, 312 }, (&ConsulExposeConfig{ 313 Paths: []ConsulExposePath{{ 314 Path: "/health", 315 }}, 316 }).Copy()) 317 } 318 319 func TestConsulExposeConfig_Equals(t *testing.T) { 320 t.Parallel() 321 322 require.True(t, (*ConsulExposeConfig)(nil).Equals(nil)) 323 require.True(t, (&ConsulExposeConfig{ 324 Paths: []ConsulExposePath{{ 325 Path: "/health", 326 }}, 327 }).Equals(&ConsulExposeConfig{ 328 Paths: []ConsulExposePath{{ 329 Path: "/health", 330 }}, 331 })) 332 } 333 334 func TestConsulSidecarService_Copy(t *testing.T) { 335 t.Parallel() 336 337 t.Run("nil", func(t *testing.T) { 338 s := (*ConsulSidecarService)(nil) 339 result := s.Copy() 340 require.Nil(t, result) 341 }) 342 343 t.Run("not nil", func(t *testing.T) { 344 s := &ConsulSidecarService{ 345 Tags: []string{"foo", "bar"}, 346 Port: "port1", 347 Proxy: &ConsulProxy{LocalServiceAddress: "10.0.0.1"}, 348 } 349 result := s.Copy() 350 require.Equal(t, &ConsulSidecarService{ 351 Tags: []string{"foo", "bar"}, 352 Port: "port1", 353 Proxy: &ConsulProxy{LocalServiceAddress: "10.0.0.1"}, 354 }, result) 355 }) 356 }