go.temporal.io/server@v1.23.0/common/namespace/registry_test.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package namespace_test 26 27 import ( 28 "sync" 29 "testing" 30 "time" 31 32 "github.com/golang/mock/gomock" 33 "github.com/stretchr/testify/require" 34 "github.com/stretchr/testify/suite" 35 enumspb "go.temporal.io/api/enums/v1" 36 namespacepb "go.temporal.io/api/namespace/v1" 37 "go.temporal.io/api/serviceerror" 38 39 persistencespb "go.temporal.io/server/api/persistence/v1" 40 "go.temporal.io/server/common/cluster" 41 "go.temporal.io/server/common/dynamicconfig" 42 "go.temporal.io/server/common/log" 43 "go.temporal.io/server/common/metrics" 44 "go.temporal.io/server/common/namespace" 45 "go.temporal.io/server/common/persistence" 46 "go.temporal.io/server/common/primitives/timestamp" 47 ) 48 49 type ( 50 registrySuite struct { 51 suite.Suite 52 *require.Assertions 53 54 controller *gomock.Controller 55 regPersistence *namespace.MockPersistence 56 registry namespace.Registry 57 } 58 ) 59 60 func TestRegistrySuite(t *testing.T) { 61 s := new(registrySuite) 62 suite.Run(t, s) 63 } 64 65 func (s *registrySuite) SetupSuite() {} 66 67 func (s *registrySuite) TearDownSuite() {} 68 69 func (s *registrySuite) SetupTest() { 70 s.Assertions = require.New(s.T()) 71 s.controller = gomock.NewController(s.T()) 72 s.regPersistence = namespace.NewMockPersistence(s.controller) 73 s.registry = namespace.NewRegistry( 74 s.regPersistence, 75 true, 76 dynamicconfig.GetDurationPropertyFn(time.Second), 77 dynamicconfig.GetBoolPropertyFn(false), 78 metrics.NoopMetricsHandler, 79 log.NewTestLogger()) 80 } 81 82 func (s *registrySuite) TearDownTest() { 83 s.registry.Stop() 84 s.controller.Finish() 85 } 86 87 func (s *registrySuite) TestListNamespace() { 88 namespaceNotificationVersion := int64(0) 89 namespaceRecord1 := &persistence.GetNamespaceResponse{ 90 Namespace: &persistencespb.NamespaceDetail{ 91 Info: &persistencespb.NamespaceInfo{ 92 Id: namespace.NewID().String(), 93 Name: "some random namespace name", 94 State: enumspb.NAMESPACE_STATE_REGISTERED, 95 Data: make(map[string]string)}, 96 Config: &persistencespb.NamespaceConfig{ 97 Retention: timestamp.DurationFromDays(1), 98 BadBinaries: &namespacepb.BadBinaries{ 99 Binaries: map[string]*namespacepb.BadBinaryInfo{}, 100 }}, 101 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 102 ActiveClusterName: cluster.TestCurrentClusterName, 103 Clusters: []string{ 104 cluster.TestCurrentClusterName, 105 cluster.TestAlternativeClusterName, 106 }, 107 }, 108 FailoverNotificationVersion: 0, 109 }, 110 NotificationVersion: namespaceNotificationVersion, 111 } 112 entry1 := namespace.FromPersistentState(namespaceRecord1) 113 namespaceNotificationVersion++ 114 115 namespaceRecord2 := &persistence.GetNamespaceResponse{ 116 Namespace: &persistencespb.NamespaceDetail{ 117 Info: &persistencespb.NamespaceInfo{ 118 Id: namespace.NewID().String(), 119 Name: "another random namespace name", 120 State: enumspb.NAMESPACE_STATE_DELETED, // Still must be included. 121 Data: make(map[string]string)}, 122 Config: &persistencespb.NamespaceConfig{ 123 Retention: timestamp.DurationFromDays(2), 124 BadBinaries: &namespacepb.BadBinaries{ 125 Binaries: map[string]*namespacepb.BadBinaryInfo{}, 126 }}, 127 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 128 ActiveClusterName: cluster.TestAlternativeClusterName, 129 Clusters: []string{ 130 cluster.TestCurrentClusterName, 131 cluster.TestAlternativeClusterName, 132 }, 133 }, 134 FailoverNotificationVersion: 0, 135 }, 136 NotificationVersion: namespaceNotificationVersion, 137 } 138 entry2 := namespace.FromPersistentState(namespaceRecord2) 139 namespaceNotificationVersion++ 140 141 namespaceRecord3 := &persistence.GetNamespaceResponse{ 142 Namespace: &persistencespb.NamespaceDetail{ 143 Info: &persistencespb.NamespaceInfo{ 144 Id: namespace.NewID().String(), 145 Name: "yet another random namespace name", 146 State: enumspb.NAMESPACE_STATE_DEPRECATED, // Still must be included. 147 Data: make(map[string]string)}, 148 Config: &persistencespb.NamespaceConfig{ 149 Retention: timestamp.DurationFromDays(3), 150 BadBinaries: &namespacepb.BadBinaries{ 151 Binaries: map[string]*namespacepb.BadBinaryInfo{}, 152 }}, 153 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 154 ActiveClusterName: cluster.TestAlternativeClusterName, 155 Clusters: []string{ 156 cluster.TestCurrentClusterName, 157 cluster.TestAlternativeClusterName, 158 }, 159 }, 160 FailoverNotificationVersion: 0, 161 }, 162 NotificationVersion: namespaceNotificationVersion, 163 } 164 // there is no namespaceNotificationVersion++ here 165 // this is to test that if new namespace change event happen during the pagination, 166 // new change will not be loaded to namespace cache 167 168 pageToken := []byte("some random page token") 169 170 s.regPersistence.EXPECT().ListNamespaces(gomock.Any(), &persistence.ListNamespacesRequest{ 171 PageSize: namespace.CacheRefreshPageSize, 172 IncludeDeleted: true, 173 NextPageToken: nil, 174 }).Return(&persistence.ListNamespacesResponse{ 175 Namespaces: []*persistence.GetNamespaceResponse{namespaceRecord1}, 176 NextPageToken: pageToken, 177 }, nil) 178 179 s.regPersistence.EXPECT().ListNamespaces(gomock.Any(), &persistence.ListNamespacesRequest{ 180 PageSize: namespace.CacheRefreshPageSize, 181 IncludeDeleted: true, 182 NextPageToken: pageToken, 183 }).Return(&persistence.ListNamespacesResponse{ 184 Namespaces: []*persistence.GetNamespaceResponse{ 185 namespaceRecord2, 186 namespaceRecord3}, 187 NextPageToken: nil, 188 }, nil) 189 190 // load namespaces 191 s.registry.Start() 192 defer s.registry.Stop() 193 194 entryByName1, err := s.registry.GetNamespace(namespace.Name(namespaceRecord1.Namespace.Info.Name)) 195 s.Nil(err) 196 s.Equal(entry1, entryByName1) 197 entryByID1, err := s.registry.GetNamespaceByID(namespace.ID(namespaceRecord1.Namespace.Info.Id)) 198 s.Nil(err) 199 s.Equal(entry1, entryByID1) 200 201 entryByName2, err := s.registry.GetNamespace(namespace.Name(namespaceRecord2.Namespace.Info.Name)) 202 s.Nil(err) 203 s.Equal(entry2, entryByName2) 204 entryByID2, err := s.registry.GetNamespaceByID(namespace.ID(namespaceRecord2.Namespace.Info.Id)) 205 s.Nil(err) 206 s.Equal(entry2, entryByID2) 207 } 208 209 func (s *registrySuite) TestRegisterStateChangeCallback_CatchUp() { 210 namespaceNotificationVersion := int64(0) 211 namespaceRecord1 := &persistence.GetNamespaceResponse{ 212 Namespace: &persistencespb.NamespaceDetail{ 213 Info: &persistencespb.NamespaceInfo{ 214 Id: namespace.NewID().String(), 215 Name: "some random namespace name", 216 Data: make(map[string]string)}, 217 Config: &persistencespb.NamespaceConfig{ 218 Retention: timestamp.DurationFromDays(1), 219 BadBinaries: &namespacepb.BadBinaries{ 220 Binaries: map[string]*namespacepb.BadBinaryInfo{}, 221 }}, 222 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 223 ActiveClusterName: cluster.TestCurrentClusterName, 224 Clusters: []string{ 225 cluster.TestCurrentClusterName, 226 cluster.TestAlternativeClusterName, 227 }, 228 }, 229 ConfigVersion: 10, 230 FailoverVersion: 11, 231 FailoverNotificationVersion: 0, 232 }, 233 NotificationVersion: namespaceNotificationVersion, 234 } 235 entry1 := namespace.FromPersistentState(namespaceRecord1) 236 namespaceNotificationVersion++ 237 238 namespaceRecord2 := &persistence.GetNamespaceResponse{ 239 Namespace: &persistencespb.NamespaceDetail{ 240 Info: &persistencespb.NamespaceInfo{ 241 Id: namespace.NewID().String(), 242 Name: "another random namespace name", 243 Data: make(map[string]string)}, 244 Config: &persistencespb.NamespaceConfig{ 245 Retention: timestamp.DurationFromDays(2), 246 BadBinaries: &namespacepb.BadBinaries{ 247 Binaries: map[string]*namespacepb.BadBinaryInfo{}, 248 }}, 249 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 250 ActiveClusterName: cluster.TestAlternativeClusterName, 251 Clusters: []string{ 252 cluster.TestCurrentClusterName, 253 cluster.TestAlternativeClusterName, 254 }, 255 }, 256 ConfigVersion: 20, 257 FailoverVersion: 21, 258 FailoverNotificationVersion: 0, 259 }, 260 NotificationVersion: namespaceNotificationVersion, 261 } 262 entry2 := namespace.FromPersistentState(namespaceRecord2) 263 namespaceNotificationVersion++ 264 265 s.regPersistence.EXPECT().ListNamespaces(gomock.Any(), &persistence.ListNamespacesRequest{ 266 PageSize: namespace.CacheRefreshPageSize, 267 IncludeDeleted: true, 268 NextPageToken: nil, 269 }).Return(&persistence.ListNamespacesResponse{ 270 Namespaces: []*persistence.GetNamespaceResponse{ 271 namespaceRecord1, 272 namespaceRecord2}, 273 NextPageToken: nil, 274 }, nil) 275 276 // load namespaces 277 s.registry.Start() 278 defer s.registry.Stop() 279 280 var entriesNotification []*namespace.Namespace 281 s.registry.RegisterStateChangeCallback( 282 "0", 283 func(ns *namespace.Namespace, deletedFromDb bool) { 284 s.False(deletedFromDb) 285 entriesNotification = append(entriesNotification, ns) 286 }, 287 ) 288 289 s.Len(entriesNotification, 2) 290 if entriesNotification[0].NotificationVersion() > entriesNotification[1].NotificationVersion() { 291 entriesNotification[0], entriesNotification[1] = entriesNotification[1], entriesNotification[0] 292 } 293 s.Equal([]*namespace.Namespace{entry1, entry2}, entriesNotification) 294 } 295 296 func (s *registrySuite) TestUpdateCache_TriggerCallBack() { 297 namespaceNotificationVersion := int64(0) 298 namespaceRecord1Old := &persistence.GetNamespaceResponse{ 299 Namespace: &persistencespb.NamespaceDetail{ 300 Info: &persistencespb.NamespaceInfo{ 301 Id: namespace.NewID().String(), 302 Name: "some random namespace name", 303 Data: make(map[string]string)}, 304 Config: &persistencespb.NamespaceConfig{ 305 Retention: timestamp.DurationFromDays(1), 306 BadBinaries: &namespacepb.BadBinaries{ 307 Binaries: map[string]*namespacepb.BadBinaryInfo{}, 308 }}, 309 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 310 ActiveClusterName: cluster.TestCurrentClusterName, 311 Clusters: []string{ 312 cluster.TestCurrentClusterName, 313 cluster.TestAlternativeClusterName, 314 }, 315 }, 316 ConfigVersion: 10, 317 FailoverVersion: 11, 318 FailoverNotificationVersion: 0, 319 }, 320 NotificationVersion: namespaceNotificationVersion, 321 } 322 entry1Old := namespace.FromPersistentState(namespaceRecord1Old) 323 namespaceNotificationVersion++ 324 325 namespaceRecord2Old := &persistence.GetNamespaceResponse{ 326 Namespace: &persistencespb.NamespaceDetail{ 327 Info: &persistencespb.NamespaceInfo{ 328 Id: namespace.NewID().String(), 329 Name: "another random namespace name", 330 Data: make(map[string]string)}, 331 Config: &persistencespb.NamespaceConfig{ 332 Retention: timestamp.DurationFromDays(2), 333 BadBinaries: &namespacepb.BadBinaries{ 334 Binaries: map[string]*namespacepb.BadBinaryInfo{}, 335 }}, 336 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 337 ActiveClusterName: cluster.TestAlternativeClusterName, 338 Clusters: []string{ 339 cluster.TestCurrentClusterName, 340 cluster.TestAlternativeClusterName, 341 }, 342 }, 343 ConfigVersion: 20, 344 FailoverVersion: 21, 345 FailoverNotificationVersion: 0, 346 }, 347 NotificationVersion: namespaceNotificationVersion, 348 } 349 entry2Old := namespace.FromPersistentState(namespaceRecord2Old) 350 namespaceNotificationVersion++ 351 352 s.regPersistence.EXPECT().ListNamespaces(gomock.Any(), &persistence.ListNamespacesRequest{ 353 PageSize: namespace.CacheRefreshPageSize, 354 IncludeDeleted: true, 355 NextPageToken: nil, 356 }).Return(&persistence.ListNamespacesResponse{ 357 Namespaces: []*persistence.GetNamespaceResponse{namespaceRecord1Old, namespaceRecord2Old}, 358 NextPageToken: nil, 359 }, nil) 360 361 namespaceRecord2New := &persistence.GetNamespaceResponse{ 362 Namespace: &persistencespb.NamespaceDetail{ 363 Info: namespaceRecord2Old.Namespace.Info, 364 Config: namespaceRecord2Old.Namespace.Config, 365 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 366 ActiveClusterName: cluster.TestCurrentClusterName, // only this changed 367 Clusters: []string{ 368 cluster.TestCurrentClusterName, 369 cluster.TestAlternativeClusterName, 370 }, 371 }, 372 ConfigVersion: namespaceRecord2Old.Namespace.ConfigVersion, 373 FailoverVersion: namespaceRecord2Old.Namespace.FailoverVersion + 1, 374 FailoverNotificationVersion: namespaceNotificationVersion, 375 }, 376 NotificationVersion: namespaceNotificationVersion, 377 } 378 entry2New := namespace.FromPersistentState(namespaceRecord2New) 379 namespaceNotificationVersion++ 380 381 namespaceRecord1New := &persistence.GetNamespaceResponse{ // only the description changed 382 Namespace: &persistencespb.NamespaceDetail{ 383 Info: &persistencespb.NamespaceInfo{ 384 Id: namespaceRecord1Old.Namespace.Info.Id, 385 Name: namespaceRecord1Old.Namespace.Info.Name, 386 Description: "updated description", Data: make(map[string]string)}, 387 Config: namespaceRecord2Old.Namespace.Config, 388 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 389 ActiveClusterName: cluster.TestCurrentClusterName, 390 Clusters: []string{ 391 cluster.TestCurrentClusterName, 392 cluster.TestAlternativeClusterName, 393 }, 394 }, 395 ConfigVersion: namespaceRecord1Old.Namespace.ConfigVersion + 1, 396 FailoverVersion: namespaceRecord1Old.Namespace.FailoverVersion, 397 FailoverNotificationVersion: namespaceRecord1Old.Namespace.FailoverNotificationVersion, 398 }, 399 NotificationVersion: namespaceNotificationVersion, 400 } 401 namespaceNotificationVersion++ 402 403 s.regPersistence.EXPECT().ListNamespaces(gomock.Any(), &persistence.ListNamespacesRequest{ 404 PageSize: namespace.CacheRefreshPageSize, 405 IncludeDeleted: true, 406 NextPageToken: nil, 407 }).Return(&persistence.ListNamespacesResponse{ 408 Namespaces: []*persistence.GetNamespaceResponse{ 409 namespaceRecord1New, 410 namespaceRecord2New}, 411 NextPageToken: nil, 412 }, nil) 413 414 // load namespaces 415 s.registry.Start() 416 defer s.registry.Stop() 417 418 var entries []*namespace.Namespace 419 420 wg := &sync.WaitGroup{} 421 wg.Add(2) 422 s.registry.RegisterStateChangeCallback( 423 "0", 424 func(ns *namespace.Namespace, deletedFromDb bool) { 425 defer wg.Done() 426 s.False(deletedFromDb) 427 entries = append(entries, ns) 428 }, 429 ) 430 wg.Wait() 431 432 s.Len(entries, 2) 433 if entries[0].NotificationVersion() > entries[1].NotificationVersion() { 434 entries[0], entries[1] = entries[1], entries[0] 435 } 436 s.Equal([]*namespace.Namespace{entry1Old, entry2Old}, entries) 437 438 wg.Add(1) 439 wg.Wait() 440 441 newEntries := entries[2:] 442 443 // entry1 only has descrption update, so won't trigger the state change callback 444 s.Len(newEntries, 1) 445 s.Equal([]*namespace.Namespace{entry2New}, newEntries) 446 } 447 448 func (s *registrySuite) TestGetTriggerListAndUpdateCache_ConcurrentAccess() { 449 id := namespace.NewID() 450 namespaceRecordOld := &persistence.GetNamespaceResponse{ 451 Namespace: &persistencespb.NamespaceDetail{ 452 Info: &persistencespb.NamespaceInfo{Id: id.String(), Name: "some random namespace name", Data: make(map[string]string)}, 453 Config: &persistencespb.NamespaceConfig{ 454 Retention: timestamp.DurationFromDays(1), 455 BadBinaries: &namespacepb.BadBinaries{ 456 Binaries: map[string]*namespacepb.BadBinaryInfo{}, 457 }}, 458 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 459 ActiveClusterName: cluster.TestCurrentClusterName, 460 Clusters: []string{ 461 cluster.TestCurrentClusterName, 462 cluster.TestAlternativeClusterName, 463 }, 464 }, 465 ConfigVersion: 0, 466 FailoverVersion: 0, 467 }, 468 } 469 entryOld := namespace.FromPersistentState(namespaceRecordOld) 470 471 s.regPersistence.EXPECT().ListNamespaces(gomock.Any(), &persistence.ListNamespacesRequest{ 472 PageSize: namespace.CacheRefreshPageSize, 473 IncludeDeleted: true, 474 NextPageToken: nil, 475 }).Return(&persistence.ListNamespacesResponse{ 476 Namespaces: []*persistence.GetNamespaceResponse{namespaceRecordOld}, 477 NextPageToken: nil, 478 }, nil) 479 480 // load namespaces 481 s.registry.Start() 482 defer s.registry.Stop() 483 484 coroutineCountGet := 1000 485 waitGroup := &sync.WaitGroup{} 486 startChan := make(chan struct{}) 487 testGetFn := func() { 488 <-startChan 489 entryNew, err := s.registry.GetNamespaceByID(id) 490 switch err.(type) { 491 case nil: 492 s.Equal(entryOld, entryNew) 493 waitGroup.Done() 494 case *serviceerror.NamespaceNotFound: 495 time.Sleep(4 * time.Second) 496 entryNew, err := s.registry.GetNamespaceByID(id) 497 s.NoError(err) 498 s.Equal(entryOld, entryNew) 499 waitGroup.Done() 500 default: 501 s.NoError(err) 502 waitGroup.Done() 503 } 504 } 505 506 for i := 0; i < coroutineCountGet; i++ { 507 waitGroup.Add(1) 508 go testGetFn() 509 } 510 close(startChan) 511 waitGroup.Wait() 512 } 513 514 func (s *registrySuite) TestRemoveDeletedNamespace() { 515 namespaceNotificationVersion := int64(0) 516 namespaceRecord1 := &persistence.GetNamespaceResponse{ 517 Namespace: &persistencespb.NamespaceDetail{ 518 Info: &persistencespb.NamespaceInfo{ 519 Id: namespace.NewID().String(), 520 Name: "some random namespace name", 521 Data: make(map[string]string)}, 522 Config: &persistencespb.NamespaceConfig{ 523 Retention: timestamp.DurationFromDays(1), 524 BadBinaries: &namespacepb.BadBinaries{ 525 Binaries: map[string]*namespacepb.BadBinaryInfo{}, 526 }}, 527 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 528 ActiveClusterName: cluster.TestCurrentClusterName, 529 Clusters: []string{ 530 cluster.TestCurrentClusterName, 531 cluster.TestAlternativeClusterName, 532 }, 533 }, 534 ConfigVersion: 10, 535 FailoverVersion: 11, 536 FailoverNotificationVersion: 0, 537 }, 538 NotificationVersion: namespaceNotificationVersion, 539 } 540 namespaceNotificationVersion++ 541 542 namespaceRecord2 := &persistence.GetNamespaceResponse{ 543 Namespace: &persistencespb.NamespaceDetail{ 544 Info: &persistencespb.NamespaceInfo{ 545 Id: namespace.NewID().String(), 546 Name: "another random namespace name", 547 Data: make(map[string]string)}, 548 Config: &persistencespb.NamespaceConfig{ 549 Retention: timestamp.DurationFromDays(2), 550 BadBinaries: &namespacepb.BadBinaries{ 551 Binaries: map[string]*namespacepb.BadBinaryInfo{}, 552 }}, 553 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{ 554 ActiveClusterName: cluster.TestAlternativeClusterName, 555 Clusters: []string{ 556 cluster.TestCurrentClusterName, 557 cluster.TestAlternativeClusterName, 558 }, 559 }, 560 ConfigVersion: 20, 561 FailoverVersion: 21, 562 FailoverNotificationVersion: 0, 563 }, 564 NotificationVersion: namespaceNotificationVersion, 565 } 566 namespaceNotificationVersion++ 567 568 s.regPersistence.EXPECT().ListNamespaces(gomock.Any(), &persistence.ListNamespacesRequest{ 569 PageSize: namespace.CacheRefreshPageSize, 570 IncludeDeleted: true, 571 NextPageToken: nil, 572 }).Return(&persistence.ListNamespacesResponse{ 573 Namespaces: []*persistence.GetNamespaceResponse{ 574 namespaceRecord1, 575 namespaceRecord2}, 576 NextPageToken: nil, 577 }, nil) 578 579 s.regPersistence.EXPECT().ListNamespaces(gomock.Any(), &persistence.ListNamespacesRequest{ 580 PageSize: namespace.CacheRefreshPageSize, 581 IncludeDeleted: true, 582 NextPageToken: nil, 583 }).Return(&persistence.ListNamespacesResponse{ 584 Namespaces: []*persistence.GetNamespaceResponse{ 585 // namespaceRecord1 is removed 586 namespaceRecord2}, 587 NextPageToken: nil, 588 }, nil) 589 590 // load namespaces 591 s.registry.Start() 592 defer s.registry.Stop() 593 594 // use WaitGroup and callback to wait until refresh loop picks up delete 595 wg := &sync.WaitGroup{} 596 wg.Add(1) 597 s.registry.RegisterStateChangeCallback( 598 "1", 599 func(ns *namespace.Namespace, deletedFromDb bool) { 600 if deletedFromDb { 601 wg.Done() 602 } 603 }, 604 ) 605 wg.Wait() 606 607 ns2FromRegistry, err := s.registry.GetNamespace(namespace.Name(namespaceRecord2.Namespace.Info.Name)) 608 s.NotNil(ns2FromRegistry) 609 s.NoError(err) 610 611 // expect readthrough call for missing ns 612 s.regPersistence.EXPECT().GetNamespace(gomock.Any(), &persistence.GetNamespaceRequest{ 613 Name: namespaceRecord1.Namespace.Info.Name, 614 }).Return(nil, serviceerror.NewNamespaceNotFound(namespaceRecord1.Namespace.Info.Name)) 615 616 ns1FromRegistry, err := s.registry.GetNamespace(namespace.Name(namespaceRecord1.Namespace.Info.Name)) 617 s.Nil(ns1FromRegistry) 618 s.Error(err) 619 var notFound *serviceerror.NamespaceNotFound 620 s.ErrorAs(err, ¬Found) 621 } 622 623 func (s *registrySuite) TestCacheByName() { 624 nsrec := persistence.GetNamespaceResponse{ 625 Namespace: &persistencespb.NamespaceDetail{ 626 Info: &persistencespb.NamespaceInfo{ 627 Id: namespace.NewID().String(), 628 Name: "foo", 629 }, 630 Config: &persistencespb.NamespaceConfig{}, 631 ReplicationConfig: &persistencespb.NamespaceReplicationConfig{}, 632 }, 633 } 634 635 s.regPersistence.EXPECT().ListNamespaces(gomock.Any(), gomock.Any()).Return(&persistence.ListNamespacesResponse{ 636 Namespaces: []*persistence.GetNamespaceResponse{&nsrec}, 637 }, nil) 638 639 s.registry.Start() 640 defer s.registry.Stop() 641 ns, err := s.registry.GetNamespace(namespace.Name("foo")) 642 s.NoError(err) 643 s.Equal(namespace.Name("foo"), ns.Name()) 644 }