github.com/hernad/nomad@v1.6.112/command/agent/consul/service_client_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package consul 5 6 import ( 7 "fmt" 8 "testing" 9 "time" 10 11 "github.com/hashicorp/consul/api" 12 "github.com/hernad/nomad/ci" 13 "github.com/hernad/nomad/client/serviceregistration" 14 "github.com/hernad/nomad/helper/testlog" 15 "github.com/hernad/nomad/helper/uuid" 16 "github.com/hernad/nomad/nomad/structs" 17 "github.com/shoenig/test/must" 18 "github.com/stretchr/testify/require" 19 "golang.org/x/exp/maps" 20 ) 21 22 func TestSyncLogic_maybeTweakTaggedAddresses(t *testing.T) { 23 ci.Parallel(t) 24 25 cases := []struct { 26 name string 27 wanted map[string]api.ServiceAddress 28 existing map[string]api.ServiceAddress 29 id string 30 exp []string 31 }{ 32 { 33 name: "not managed by nomad", 34 id: "_nomad-other-hello", 35 wanted: map[string]api.ServiceAddress{ 36 // empty 37 }, 38 existing: map[string]api.ServiceAddress{ 39 "lan_ipv4": {}, 40 "wan_ipv4": {}, 41 "custom": {}, 42 }, 43 exp: []string{"lan_ipv4", "wan_ipv4", "custom"}, 44 }, 45 { 46 name: "remove defaults", 47 id: "_nomad-task-hello", 48 wanted: map[string]api.ServiceAddress{ 49 "lan_custom": {}, 50 "wan_custom": {}, 51 }, 52 existing: map[string]api.ServiceAddress{ 53 "lan_ipv4": {}, 54 "wan_ipv4": {}, 55 "lan_ipv6": {}, 56 "wan_ipv6": {}, 57 "lan_custom": {}, 58 "wan_custom": {}, 59 }, 60 exp: []string{"lan_custom", "wan_custom"}, 61 }, 62 { 63 name: "overridden defaults", 64 id: "_nomad-task-hello", 65 wanted: map[string]api.ServiceAddress{ 66 "lan_ipv4": {}, 67 "wan_ipv4": {}, 68 "lan_ipv6": {}, 69 "wan_ipv6": {}, 70 "custom": {}, 71 }, 72 existing: map[string]api.ServiceAddress{ 73 "lan_ipv4": {}, 74 "wan_ipv4": {}, 75 "lan_ipv6": {}, 76 "wan_ipv6": {}, 77 "custom": {}, 78 }, 79 exp: []string{"lan_ipv4", "wan_ipv4", "lan_ipv6", "wan_ipv6", "custom"}, 80 }, 81 { 82 name: "applies to nomad client", 83 id: "_nomad-client-12345", 84 wanted: map[string]api.ServiceAddress{ 85 "custom": {}, 86 }, 87 existing: map[string]api.ServiceAddress{ 88 "lan_ipv4": {}, 89 "wan_ipv4": {}, 90 "lan_ipv6": {}, 91 "wan_ipv6": {}, 92 "custom": {}, 93 }, 94 exp: []string{"custom"}, 95 }, 96 { 97 name: "applies to nomad server", 98 id: "_nomad-server-12345", 99 wanted: map[string]api.ServiceAddress{ 100 "custom": {}, 101 }, 102 existing: map[string]api.ServiceAddress{ 103 "lan_ipv4": {}, 104 "wan_ipv4": {}, 105 "lan_ipv6": {}, 106 "wan_ipv6": {}, 107 "custom": {}, 108 }, 109 exp: []string{"custom"}, 110 }, 111 } 112 113 for _, tc := range cases { 114 t.Run(tc.name, func(t *testing.T) { 115 asr := &api.AgentServiceRegistration{ 116 ID: tc.id, 117 TaggedAddresses: maps.Clone(tc.wanted), 118 } 119 as := &api.AgentService{ 120 TaggedAddresses: maps.Clone(tc.existing), 121 } 122 maybeTweakTaggedAddresses(asr, as) 123 must.MapContainsKeys(t, as.TaggedAddresses, tc.exp) 124 }) 125 } 126 } 127 128 func TestSyncLogic_agentServiceUpdateRequired(t *testing.T) { 129 ci.Parallel(t) 130 131 // the service as known by nomad 132 wanted := func() api.AgentServiceRegistration { 133 return api.AgentServiceRegistration{ 134 Kind: "", 135 ID: "aca4c175-1778-5ef4-0220-2ab434147d35", 136 Name: "myservice", 137 Tags: []string{"a", "b"}, 138 Port: 9000, 139 Address: "1.1.1.1", 140 EnableTagOverride: true, 141 Meta: map[string]string{"foo": "1"}, 142 TaggedAddresses: map[string]api.ServiceAddress{ 143 "public_wan": {Address: "1.2.3.4", Port: 8080}, 144 }, 145 Connect: &api.AgentServiceConnect{ 146 Native: false, 147 SidecarService: &api.AgentServiceRegistration{ 148 Kind: "connect-proxy", 149 ID: "_nomad-task-8e8413af-b5bb-aa67-2c24-c146c45f1ec9-group-mygroup-myservice-9001-sidecar-proxy", 150 Name: "name-sidecar-proxy", 151 Tags: []string{"x", "y", "z"}, 152 Proxy: &api.AgentServiceConnectProxyConfig{ 153 Upstreams: []api.Upstream{{ 154 Datacenter: "dc1", 155 DestinationName: "dest1", 156 }}, 157 }, 158 }, 159 }, 160 } 161 } 162 163 // the service (and + connect proxy) as known by consul 164 existing := &api.AgentService{ 165 Kind: "", 166 ID: "aca4c175-1778-5ef4-0220-2ab434147d35", 167 Service: "myservice", 168 Tags: []string{"a", "b"}, 169 Port: 9000, 170 Address: "1.1.1.1", 171 EnableTagOverride: true, 172 Meta: map[string]string{"foo": "1"}, 173 TaggedAddresses: map[string]api.ServiceAddress{ 174 "public_wan": {Address: "1.2.3.4", Port: 8080}, 175 }, 176 } 177 178 sidecar := &api.AgentService{ 179 Kind: "connect-proxy", 180 ID: "_nomad-task-8e8413af-b5bb-aa67-2c24-c146c45f1ec9-group-mygroup-myservice-9001-sidecar-proxy", 181 Service: "myservice-sidecar-proxy", 182 Tags: []string{"x", "y", "z"}, 183 Proxy: &api.AgentServiceConnectProxyConfig{ 184 Upstreams: []api.Upstream{{ 185 Datacenter: "dc1", 186 DestinationName: "dest1", 187 }}, 188 }, 189 } 190 191 // By default wanted and existing match. Each test should modify wanted in 192 // 1 way, and / or configure the type of sync operation that is being 193 // considered, then evaluate the result of the update-required algebra. 194 195 type asr = api.AgentServiceRegistration 196 type tweaker func(w asr) *asr // create a conveniently modifiable copy 197 198 s := &ServiceClient{ 199 logger: testlog.HCLogger(t), 200 } 201 202 try := func( 203 t *testing.T, 204 exp bool, 205 reason syncReason, 206 tweak tweaker) { 207 result := s.agentServiceUpdateRequired(reason, tweak(wanted()), existing, sidecar) 208 require.Equal(t, exp, result) 209 } 210 211 t.Run("matching", func(t *testing.T) { 212 try(t, false, syncNewOps, func(w asr) *asr { 213 return &w 214 }) 215 }) 216 217 t.Run("different kind", func(t *testing.T) { 218 try(t, true, syncNewOps, func(w asr) *asr { 219 w.Kind = "other" 220 return &w 221 }) 222 }) 223 224 t.Run("different id", func(t *testing.T) { 225 try(t, true, syncNewOps, func(w asr) *asr { 226 w.ID = "_other" 227 return &w 228 }) 229 }) 230 231 t.Run("different port", func(t *testing.T) { 232 try(t, true, syncNewOps, func(w asr) *asr { 233 w.Port = 9001 234 return &w 235 }) 236 }) 237 238 t.Run("different address", func(t *testing.T) { 239 try(t, true, syncNewOps, func(w asr) *asr { 240 w.Address = "2.2.2.2" 241 return &w 242 }) 243 }) 244 245 t.Run("different name", func(t *testing.T) { 246 try(t, true, syncNewOps, func(w asr) *asr { 247 w.Name = "bob" 248 return &w 249 }) 250 }) 251 252 t.Run("different enable_tag_override", func(t *testing.T) { 253 try(t, true, syncNewOps, func(w asr) *asr { 254 w.EnableTagOverride = false 255 return &w 256 }) 257 }) 258 259 t.Run("different meta", func(t *testing.T) { 260 try(t, true, syncNewOps, func(w asr) *asr { 261 w.Meta = map[string]string{"foo": "2"} 262 return &w 263 }) 264 }) 265 266 t.Run("different sidecar upstream", func(t *testing.T) { 267 try(t, true, syncNewOps, func(w asr) *asr { 268 w.Connect.SidecarService.Proxy.Upstreams[0].DestinationName = "dest2" 269 return &w 270 }) 271 }) 272 273 t.Run("remove sidecar upstream", func(t *testing.T) { 274 try(t, true, syncNewOps, func(w asr) *asr { 275 w.Connect.SidecarService.Proxy.Upstreams = nil 276 return &w 277 }) 278 }) 279 280 t.Run("additional sidecar upstream", func(t *testing.T) { 281 try(t, true, syncNewOps, func(w asr) *asr { 282 w.Connect.SidecarService.Proxy.Upstreams = append( 283 w.Connect.SidecarService.Proxy.Upstreams, 284 api.Upstream{ 285 Datacenter: "dc2", 286 DestinationName: "dest2", 287 }, 288 ) 289 return &w 290 }) 291 }) 292 293 t.Run("nil proxy block", func(t *testing.T) { 294 try(t, true, syncNewOps, func(w asr) *asr { 295 w.Connect.SidecarService.Proxy = nil 296 return &w 297 }) 298 }) 299 300 t.Run("different tags syncNewOps eto=true", func(t *testing.T) { 301 // sync is required even though eto=true, because NewOps indicates the 302 // service definition in nomad has changed (e.g. job run a modified job) 303 try(t, true, syncNewOps, func(w asr) *asr { 304 w.Tags = []string{"other", "tags"} 305 return &w 306 }) 307 }) 308 309 t.Run("different tags syncPeriodic eto=true", func(t *testing.T) { 310 // sync is not required since eto=true and this is a periodic sync 311 // with consul - in which case we keep Consul's definition of the tags 312 try(t, false, syncPeriodic, func(w asr) *asr { 313 w.Tags = []string{"other", "tags"} 314 return &w 315 }) 316 }) 317 318 t.Run("different sidecar tags on syncPeriodic eto=true", func(t *testing.T) { 319 try(t, false, syncPeriodic, func(w asr) *asr { 320 // like the parent service, the sidecar's tags do not get enforced 321 // if ETO is true and this is a periodic sync 322 w.Connect.SidecarService.Tags = []string{"other", "tags"} 323 return &w 324 }) 325 }) 326 327 t.Run("different sidecar tags on syncNewOps eto=true", func(t *testing.T) { 328 try(t, true, syncNewOps, func(w asr) *asr { 329 // like the parent service, the sidecar's tags always get enforced 330 // regardless of ETO if this is a sync due to applied operations 331 w.Connect.SidecarService.Tags = []string{"other", "tags"} 332 return &w 333 }) 334 }) 335 336 t.Run("different tagged addresses", func(t *testing.T) { 337 try(t, true, syncNewOps, func(w asr) *asr { 338 w.TaggedAddresses = map[string]api.ServiceAddress{ 339 "public_wan": {Address: "5.6.7.8", Port: 8080}, 340 } 341 return &w 342 }) 343 }) 344 345 // for remaining tests, EnableTagOverride = false 346 existing.EnableTagOverride = false 347 348 t.Run("different tags syncPeriodic eto=false", func(t *testing.T) { 349 // sync is required because eto=false and the tags do not match 350 try(t, true, syncPeriodic, func(w asr) *asr { 351 w.EnableTagOverride = false 352 w.Tags = []string{"other", "tags"} 353 return &w 354 }) 355 }) 356 357 t.Run("different tags syncNewOps eto=false", func(t *testing.T) { 358 // sync is required because eto=false and the tags do not match 359 try(t, true, syncNewOps, func(w asr) *asr { 360 w.EnableTagOverride = false 361 w.Tags = []string{"other", "tags"} 362 return &w 363 }) 364 }) 365 366 t.Run("different sidecar tags on syncPeriodic eto=false", func(t *testing.T) { 367 // like the parent service, sync is required because eto=false and the 368 // sidecar's tags do not match 369 try(t, true, syncPeriodic, func(w asr) *asr { 370 w.EnableTagOverride = false 371 w.Connect.SidecarService.Tags = []string{"other", "tags"} 372 return &w 373 }) 374 }) 375 376 t.Run("different sidecar tags syncNewOps eto=false", func(t *testing.T) { 377 // like the parent service, sync is required because eto=false and the 378 // sidecar's tags do not match 379 try(t, true, syncNewOps, func(w asr) *asr { 380 w.EnableTagOverride = false 381 w.Connect.SidecarService.Tags = []string{"other", "tags"} 382 return &w 383 }) 384 }) 385 } 386 387 func TestSyncLogic_sidecarTagsDifferent(t *testing.T) { 388 ci.Parallel(t) 389 390 type tc struct { 391 parent, wanted, sidecar []string 392 expect bool 393 } 394 395 try := func(t *testing.T, test tc) { 396 result := sidecarTagsDifferent(test.parent, test.wanted, test.sidecar) 397 require.Equal(t, test.expect, result) 398 } 399 400 try(t, tc{parent: nil, wanted: nil, sidecar: nil, expect: false}) 401 402 // wanted is nil, compare sidecar to parent 403 try(t, tc{parent: []string{"foo"}, wanted: nil, sidecar: nil, expect: true}) 404 try(t, tc{parent: []string{"foo"}, wanted: nil, sidecar: []string{"foo"}, expect: false}) 405 try(t, tc{parent: []string{"foo"}, wanted: nil, sidecar: []string{"bar"}, expect: true}) 406 try(t, tc{parent: nil, wanted: nil, sidecar: []string{"foo"}, expect: true}) 407 408 // wanted is non-nil, compare sidecar to wanted 409 try(t, tc{parent: nil, wanted: []string{"foo"}, sidecar: nil, expect: true}) 410 try(t, tc{parent: nil, wanted: []string{"foo"}, sidecar: []string{"foo"}, expect: false}) 411 try(t, tc{parent: nil, wanted: []string{"foo"}, sidecar: []string{"bar"}, expect: true}) 412 try(t, tc{parent: []string{"foo"}, wanted: []string{"foo"}, sidecar: []string{"bar"}, expect: true}) 413 } 414 415 func TestSyncLogic_maybeTweakTags(t *testing.T) { 416 ci.Parallel(t) 417 418 differentPointers := func(a, b []string) bool { 419 return &(a) != &(b) 420 } 421 422 try := func(inConsul, inConsulSC []string, eto bool) { 423 wanted := &api.AgentServiceRegistration{ 424 Tags: []string{"original"}, 425 Connect: &api.AgentServiceConnect{ 426 SidecarService: &api.AgentServiceRegistration{ 427 Tags: []string{"original-sidecar"}, 428 }, 429 }, 430 EnableTagOverride: eto, 431 } 432 433 existing := &api.AgentService{Tags: inConsul} 434 sidecar := &api.AgentService{Tags: inConsulSC} 435 436 maybeTweakTags(wanted, existing, sidecar) 437 438 switch eto { 439 case false: 440 require.Equal(t, []string{"original"}, wanted.Tags) 441 require.Equal(t, []string{"original-sidecar"}, wanted.Connect.SidecarService.Tags) 442 require.True(t, differentPointers(wanted.Tags, wanted.Connect.SidecarService.Tags)) 443 case true: 444 require.Equal(t, inConsul, wanted.Tags) 445 require.Equal(t, inConsulSC, wanted.Connect.SidecarService.Tags) 446 require.True(t, differentPointers(wanted.Tags, wanted.Connect.SidecarService.Tags)) 447 } 448 } 449 450 try([]string{"original"}, []string{"original-sidecar"}, true) 451 try([]string{"original"}, []string{"original-sidecar"}, false) 452 try([]string{"modified"}, []string{"original-sidecar"}, true) 453 try([]string{"modified"}, []string{"original-sidecar"}, false) 454 try([]string{"original"}, []string{"modified-sidecar"}, true) 455 try([]string{"original"}, []string{"modified-sidecar"}, false) 456 try([]string{"modified"}, []string{"modified-sidecar"}, true) 457 try([]string{"modified"}, []string{"modified-sidecar"}, false) 458 } 459 460 func TestSyncLogic_maybeTweakTags_emptySC(t *testing.T) { 461 ci.Parallel(t) 462 463 // Check the edge cases where the connect service is deleted on the nomad 464 // side (i.e. are we checking multiple nil pointers). 465 466 try := func(asr *api.AgentServiceRegistration) { 467 existing := &api.AgentService{Tags: []string{"a", "b"}} 468 sidecar := &api.AgentService{Tags: []string{"a", "b"}} 469 maybeTweakTags(asr, existing, sidecar) 470 must.NotEq(t, []string{"original"}, asr.Tags) 471 } 472 473 try(&api.AgentServiceRegistration{ 474 Tags: []string{"original"}, 475 EnableTagOverride: true, 476 Connect: nil, // ooh danger! 477 }) 478 479 try(&api.AgentServiceRegistration{ 480 Tags: []string{"original"}, 481 EnableTagOverride: true, 482 Connect: &api.AgentServiceConnect{ 483 SidecarService: nil, // ooh danger! 484 }, 485 }) 486 } 487 488 // TestServiceRegistration_CheckOnUpdate tests that a ServiceRegistrations 489 // CheckOnUpdate is populated and updated properly 490 func TestServiceRegistration_CheckOnUpdate(t *testing.T) { 491 ci.Parallel(t) 492 493 mockAgent := NewMockAgent(ossFeatures) 494 namespacesClient := NewNamespacesClient(NewMockNamespaces(nil), mockAgent) 495 logger := testlog.HCLogger(t) 496 sc := NewServiceClient(mockAgent, namespacesClient, logger, true) 497 498 allocID := uuid.Generate() 499 ws := &serviceregistration.WorkloadServices{ 500 AllocInfo: structs.AllocInfo{ 501 AllocID: allocID, 502 Task: "taskname", 503 }, 504 Restarter: &restartRecorder{}, 505 Services: []*structs.Service{ 506 { 507 Name: "taskname-service", 508 PortLabel: "x", 509 Tags: []string{"tag1", "tag2"}, 510 Meta: map[string]string{"meta1": "foo"}, 511 Checks: []*structs.ServiceCheck{ 512 { 513 514 Name: "c1", 515 Type: "tcp", 516 Interval: time.Second, 517 Timeout: time.Second, 518 PortLabel: "x", 519 OnUpdate: structs.OnUpdateIgnoreWarn, 520 }, 521 }, 522 }, 523 }, 524 Networks: []*structs.NetworkResource{ 525 { 526 DynamicPorts: []structs.Port{ 527 {Label: "x", Value: xPort}, 528 {Label: "y", Value: yPort}, 529 }, 530 }, 531 }, 532 } 533 534 require.NoError(t, sc.RegisterWorkload(ws)) 535 536 require.NotNil(t, sc.allocRegistrations[allocID]) 537 538 allocReg := sc.allocRegistrations[allocID] 539 serviceReg := allocReg.Tasks["taskname"] 540 require.NotNil(t, serviceReg) 541 542 // Ensure that CheckOnUpdate was set correctly 543 require.Len(t, serviceReg.Services, 1) 544 for _, sreg := range serviceReg.Services { 545 require.NotEmpty(t, sreg.CheckOnUpdate) 546 for _, onupdate := range sreg.CheckOnUpdate { 547 require.Equal(t, structs.OnUpdateIgnoreWarn, onupdate) 548 } 549 } 550 551 // Update 552 wsUpdate := new(serviceregistration.WorkloadServices) 553 *wsUpdate = *ws 554 wsUpdate.Services[0].Checks[0].OnUpdate = structs.OnUpdateRequireHealthy 555 556 require.NoError(t, sc.UpdateWorkload(ws, wsUpdate)) 557 558 require.NotNil(t, sc.allocRegistrations[allocID]) 559 560 allocReg = sc.allocRegistrations[allocID] 561 serviceReg = allocReg.Tasks["taskname"] 562 require.NotNil(t, serviceReg) 563 564 // Ensure that CheckOnUpdate was updated correctly 565 require.Len(t, serviceReg.Services, 1) 566 for _, sreg := range serviceReg.Services { 567 require.NotEmpty(t, sreg.CheckOnUpdate) 568 for _, onupdate := range sreg.CheckOnUpdate { 569 require.Equal(t, structs.OnUpdateRequireHealthy, onupdate) 570 } 571 } 572 } 573 574 func TestSyncLogic_proxyUpstreamsDifferent(t *testing.T) { 575 ci.Parallel(t) 576 577 upstream1 := func() api.Upstream { 578 return api.Upstream{ 579 Datacenter: "sfo", 580 DestinationName: "billing", 581 LocalBindAddress: "127.0.0.1", 582 LocalBindPort: 5050, 583 MeshGateway: api.MeshGatewayConfig{ 584 Mode: "remote", 585 }, 586 Config: map[string]interface{}{"foo": 1}, 587 } 588 } 589 590 upstream2 := func() api.Upstream { 591 return api.Upstream{ 592 Datacenter: "ny", 593 DestinationName: "metrics", 594 LocalBindAddress: "127.0.0.1", 595 LocalBindPort: 6060, 596 MeshGateway: api.MeshGatewayConfig{ 597 Mode: "local", 598 }, 599 Config: nil, 600 } 601 } 602 603 newASC := func() *api.AgentServiceConnect { 604 return &api.AgentServiceConnect{ 605 SidecarService: &api.AgentServiceRegistration{ 606 Proxy: &api.AgentServiceConnectProxyConfig{ 607 Upstreams: []api.Upstream{ 608 upstream1(), 609 upstream2(), 610 }, 611 }, 612 }, 613 } 614 } 615 616 original := newASC() 617 618 t.Run("same", func(t *testing.T) { 619 require.False(t, proxyUpstreamsDifferent(original, newASC().SidecarService.Proxy)) 620 }) 621 622 type proxy = *api.AgentServiceConnectProxyConfig 623 type tweaker = func(proxy) 624 625 try := func(t *testing.T, desc string, tweak tweaker) { 626 t.Run(desc, func(t *testing.T) { 627 p := newASC().SidecarService.Proxy 628 tweak(p) 629 require.True(t, proxyUpstreamsDifferent(original, p)) 630 }) 631 } 632 633 try(t, "empty upstreams", func(p proxy) { 634 p.Upstreams = make([]api.Upstream, 0) 635 }) 636 637 try(t, "missing upstream", func(p proxy) { 638 p.Upstreams = []api.Upstream{ 639 upstream1(), 640 } 641 }) 642 643 try(t, "extra upstream", func(p proxy) { 644 p.Upstreams = []api.Upstream{ 645 upstream1(), 646 upstream2(), 647 { 648 Datacenter: "north", 649 DestinationName: "dest3", 650 }, 651 } 652 }) 653 654 try(t, "different datacenter", func(p proxy) { 655 diff := upstream2() 656 diff.Datacenter = "south" 657 p.Upstreams = []api.Upstream{ 658 upstream1(), 659 diff, 660 } 661 }) 662 663 try(t, "different destination", func(p proxy) { 664 diff := upstream2() 665 diff.DestinationName = "sink" 666 p.Upstreams = []api.Upstream{ 667 upstream1(), 668 diff, 669 } 670 }) 671 672 try(t, "different local_bind_address", func(p proxy) { 673 diff := upstream2() 674 diff.LocalBindAddress = "10.0.0.1" 675 p.Upstreams = []api.Upstream{ 676 upstream1(), 677 diff, 678 } 679 }) 680 681 try(t, "different local_bind_port", func(p proxy) { 682 diff := upstream2() 683 diff.LocalBindPort = 9999 684 p.Upstreams = []api.Upstream{ 685 upstream1(), 686 diff, 687 } 688 }) 689 690 try(t, "different mesh gateway mode", func(p proxy) { 691 diff := upstream2() 692 diff.MeshGateway.Mode = "none" 693 p.Upstreams = []api.Upstream{ 694 upstream1(), 695 diff, 696 } 697 }) 698 699 try(t, "different config", func(p proxy) { 700 diff := upstream1() 701 diff.Config = map[string]interface{}{"foo": 2} 702 p.Upstreams = []api.Upstream{ 703 diff, 704 upstream2(), 705 } 706 }) 707 } 708 709 func TestSyncReason_String(t *testing.T) { 710 ci.Parallel(t) 711 712 require.Equal(t, "periodic", fmt.Sprintf("%s", syncPeriodic)) 713 require.Equal(t, "shutdown", fmt.Sprintf("%s", syncShutdown)) 714 require.Equal(t, "operations", fmt.Sprintf("%s", syncNewOps)) 715 require.Equal(t, "unexpected", fmt.Sprintf("%s", syncReason(128))) 716 } 717 718 func TestSyncOps_empty(t *testing.T) { 719 ci.Parallel(t) 720 721 try := func(ops *operations, exp bool) { 722 require.Equal(t, exp, ops.empty()) 723 } 724 725 try(&operations{regServices: make([]*api.AgentServiceRegistration, 1)}, false) 726 try(&operations{regChecks: make([]*api.AgentCheckRegistration, 1)}, false) 727 try(&operations{deregServices: make([]string, 1)}, false) 728 try(&operations{deregChecks: make([]string, 1)}, false) 729 try(&operations{}, true) 730 try(nil, true) 731 } 732 733 func TestSyncLogic_maybeSidecarProxyCheck(t *testing.T) { 734 ci.Parallel(t) 735 736 try := func(input string, exp bool) { 737 result := maybeSidecarProxyCheck(input) 738 require.Equal(t, exp, result) 739 } 740 741 try("service:_nomad-task-2f5fb517-57d4-44ee-7780-dc1cb6e103cd-group-api-count-api-9001-sidecar-proxy", true) 742 try("service:_nomad-task-2f5fb517-57d4-44ee-7780-dc1cb6e103cd-group-api-count-api-9001-sidecar-proxy:1", true) 743 try("service:_nomad-task-2f5fb517-57d4-44ee-7780-dc1cb6e103cd-group-api-count-api-9001-sidecar-proxy:2", true) 744 try("service:_nomad-task-2f5fb517-57d4-44ee-7780-dc1cb6e103cd-group-api-count-api-9001", false) 745 try("_nomad-task-2f5fb517-57d4-44ee-7780-dc1cb6e103cd-group-api-count-api-9001-sidecar-proxy:1", false) 746 try("service:_nomad-task-2f5fb517-57d4-44ee-7780-dc1cb6e103cd-group-api-count-api-9001-sidecar-proxy:X", false) 747 try("service:_nomad-task-2f5fb517-57d4-44ee-7780-dc1cb6e103cd-group-api-count-api-9001-sidecar-proxy: ", false) 748 try("service", false) 749 } 750 751 func TestSyncLogic_parseTaggedAddresses(t *testing.T) { 752 ci.Parallel(t) 753 754 t.Run("nil", func(t *testing.T) { 755 m, err := parseTaggedAddresses(nil, 0) 756 must.NoError(t, err) 757 must.MapEmpty(t, m) 758 }) 759 760 t.Run("parse fail", func(t *testing.T) { 761 ta := map[string]string{ 762 "public_wan": "not an address", 763 } 764 result, err := parseTaggedAddresses(ta, 8080) 765 must.Error(t, err) 766 must.MapEmpty(t, result) 767 }) 768 769 t.Run("parse address", func(t *testing.T) { 770 ta := map[string]string{ 771 "public_wan": "1.2.3.4", 772 } 773 result, err := parseTaggedAddresses(ta, 8080) 774 must.NoError(t, err) 775 must.MapEq(t, map[string]api.ServiceAddress{ 776 "public_wan": {Address: "1.2.3.4", Port: 8080}, 777 }, result) 778 }) 779 780 t.Run("parse address and port", func(t *testing.T) { 781 ta := map[string]string{ 782 "public_wan": "1.2.3.4:9999", 783 } 784 result, err := parseTaggedAddresses(ta, 8080) 785 must.NoError(t, err) 786 must.MapEq(t, map[string]api.ServiceAddress{ 787 "public_wan": {Address: "1.2.3.4", Port: 9999}, 788 }, result) 789 }) 790 }