github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/msg/producer/writer/writer_test.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package writer 22 23 import ( 24 "errors" 25 "net" 26 "sync" 27 "testing" 28 "time" 29 30 "github.com/m3db/m3/src/cluster/client" 31 "github.com/m3db/m3/src/cluster/kv" 32 "github.com/m3db/m3/src/cluster/kv/mem" 33 "github.com/m3db/m3/src/cluster/placement" 34 "github.com/m3db/m3/src/cluster/services" 35 "github.com/m3db/m3/src/cluster/shard" 36 "github.com/m3db/m3/src/msg/producer" 37 "github.com/m3db/m3/src/msg/topic" 38 xtest "github.com/m3db/m3/src/x/test" 39 40 "github.com/fortytw2/leaktest" 41 "github.com/golang/mock/gomock" 42 "github.com/stretchr/testify/require" 43 "go.uber.org/atomic" 44 ) 45 46 func TestWriterInitErrorNoTopic(t *testing.T) { 47 defer leaktest.Check(t)() 48 49 ctrl := xtest.NewController(t) 50 defer ctrl.Finish() 51 52 store := mem.NewStore() 53 cs := client.NewMockClient(ctrl) 54 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 55 56 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 57 require.NoError(t, err) 58 59 opts := testOptions().SetTopicService(ts) 60 w := NewWriter(opts) 61 require.Error(t, w.Init()) 62 w.Close() 63 } 64 65 func TestWriterWriteAfterClosed(t *testing.T) { 66 defer leaktest.Check(t)() 67 68 ctrl := xtest.NewController(t) 69 defer ctrl.Finish() 70 71 store := mem.NewStore() 72 cs := client.NewMockClient(ctrl) 73 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 74 75 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 76 require.NoError(t, err) 77 78 opts := testOptions().SetTopicService(ts) 79 w := NewWriter(opts) 80 w.Init() 81 w.Close() 82 83 mm := producer.NewMockMessage(ctrl) 84 mm.EXPECT().Finalize(producer.Dropped) 85 mm.EXPECT().Size().Return(3) 86 rm := producer.NewRefCountedMessage(mm, nil) 87 err = w.Write(rm) 88 require.Error(t, err) 89 require.Equal(t, errWriterClosed, err) 90 } 91 92 func TestWriterWriteWithInvalidShard(t *testing.T) { 93 defer leaktest.Check(t)() 94 95 ctrl := xtest.NewController(t) 96 defer ctrl.Finish() 97 98 store := mem.NewStore() 99 cs := client.NewMockClient(ctrl) 100 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 101 102 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 103 require.NoError(t, err) 104 105 opts := testOptions().SetTopicService(ts) 106 w := NewWriter(opts).(*writer) 107 w.numShards = 2 108 109 mm := producer.NewMockMessage(ctrl) 110 mm.EXPECT().Shard().Return(uint32(2)) 111 mm.EXPECT().Finalize(producer.Dropped) 112 mm.EXPECT().Size().Return(3) 113 rm := producer.NewRefCountedMessage(mm, nil) 114 err = w.Write(rm) 115 require.Error(t, err) 116 117 mm.EXPECT().Shard().Return(uint32(100)) 118 mm.EXPECT().Finalize(producer.Dropped) 119 mm.EXPECT().Size().Return(3) 120 rm = producer.NewRefCountedMessage(mm, nil) 121 err = w.Write(rm) 122 require.Error(t, err) 123 } 124 125 func TestWriterInvalidTopicUpdate(t *testing.T) { 126 defer leaktest.Check(t)() 127 128 ctrl := xtest.NewController(t) 129 defer ctrl.Finish() 130 131 store := mem.NewStore() 132 cs := client.NewMockClient(ctrl) 133 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 134 135 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 136 require.NoError(t, err) 137 138 opts := testOptions().SetTopicService(ts) 139 sid1 := services.NewServiceID().SetName("s1") 140 cs1 := topic.NewConsumerService().SetConsumptionType(topic.Replicated).SetServiceID(sid1) 141 testTopic := topic.NewTopic(). 142 SetName(opts.TopicName()). 143 SetNumberOfShards(2). 144 SetConsumerServices([]topic.ConsumerService{cs1}) 145 _, err = ts.CheckAndSet(testTopic, kv.UninitializedVersion) 146 require.NoError(t, err) 147 148 sd := services.NewMockServices(ctrl) 149 opts = opts.SetServiceDiscovery(sd) 150 ps1 := testPlacementService(store, sid1) 151 sd.EXPECT().PlacementService(sid1, gomock.Any()).Return(ps1, nil) 152 153 p1 := placement.NewPlacement(). 154 SetInstances([]placement.Instance{ 155 placement.NewInstance(). 156 SetID("i1"). 157 SetEndpoint("addr1"). 158 SetShards(shard.NewShards([]shard.Shard{ 159 shard.NewShard(0).SetState(shard.Available), 160 shard.NewShard(1).SetState(shard.Available), 161 })), 162 }). 163 SetShards([]uint32{0, 1}). 164 SetReplicaFactor(1). 165 SetIsSharded(true) 166 _, err = ps1.Set(p1) 167 require.NoError(t, err) 168 169 w := NewWriter(opts).(*writer) 170 var wg sync.WaitGroup 171 w.processFn = func(i interface{}) error { 172 defer wg.Done() 173 return w.process(i) 174 } 175 wg.Add(1) 176 require.NoError(t, w.Init()) 177 wg.Wait() 178 defer w.Close() 179 180 require.Equal(t, 2, int(w.numShards)) 181 testTopic = topic.NewTopic(). 182 SetName(opts.TopicName()). 183 SetNumberOfShards(3). 184 SetConsumerServices([]topic.ConsumerService{cs1}). 185 SetVersion(1) 186 wg.Add(1) 187 _, err = ts.CheckAndSet(testTopic, 1) 188 require.NoError(t, err) 189 wg.Wait() 190 191 require.Equal(t, 2, int(w.numShards)) 192 } 193 194 func TestWriterRegisterFilter(t *testing.T) { 195 defer leaktest.Check(t)() 196 197 ctrl := xtest.NewController(t) 198 defer ctrl.Finish() 199 200 store := mem.NewStore() 201 cs := client.NewMockClient(ctrl) 202 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 203 204 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 205 require.NoError(t, err) 206 207 opts := testOptions().SetTopicService(ts) 208 209 sid1 := services.NewServiceID().SetName("s1") 210 cs1 := topic.NewConsumerService().SetConsumptionType(topic.Replicated).SetServiceID(sid1) 211 csw1 := NewMockconsumerServiceWriter(ctrl) 212 213 sid2 := services.NewServiceID().SetName("s2") 214 filter := func(producer.Message) bool { return false } 215 filter2 := func(producer.Message) bool { return true } 216 217 w := NewWriter(opts).(*writer) 218 w.consumerServiceWriters[cs1.ServiceID().String()] = csw1 219 220 csw1.EXPECT().UnregisterFilters() 221 w.UnregisterFilters(sid1) 222 _, ok := w.filterRegistry[sid1.String()] 223 require.True(t, !ok) 224 225 // Wrong service id triggers nothing. 226 w.RegisterFilter(sid2, filter) 227 _, ok = w.filterRegistry[sid2.String()] 228 require.True(t, ok) 229 230 csw1.EXPECT().RegisterFilter(gomock.Any()) 231 w.RegisterFilter(sid1, filter) 232 233 csw1.EXPECT().UnregisterFilters() 234 w.UnregisterFilters(sid1) 235 236 csw1.EXPECT().RegisterFilter(gomock.Any()) 237 w.RegisterFilter(sid1, filter) 238 239 csw1.EXPECT().RegisterFilter(gomock.Any()) 240 csw1.EXPECT().SetMessageTTLNanos(int64(0)) 241 testTopic := topic.NewTopic(). 242 SetName(opts.TopicName()). 243 SetNumberOfShards(6). 244 SetConsumerServices([]topic.ConsumerService{cs1}) 245 w.process(testTopic) 246 247 csw1.EXPECT().RegisterFilter(gomock.Any()) 248 w.RegisterFilter(sid1, filter2) 249 require.True(t, len(w.filterRegistry[sid1.String()]) == 2) 250 csw1.EXPECT().UnregisterFilters() 251 w.UnregisterFilters(sid1) 252 } 253 254 func TestWriterTopicUpdate(t *testing.T) { 255 defer leaktest.Check(t)() 256 257 ctrl := xtest.NewController(t) 258 defer ctrl.Finish() 259 260 store := mem.NewStore() 261 cs := client.NewMockClient(ctrl) 262 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 263 264 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 265 require.NoError(t, err) 266 267 opts := testOptions().SetTopicService(ts) 268 269 sid1 := services.NewServiceID().SetName("s1") 270 cs1 := topic.NewConsumerService().SetConsumptionType(topic.Replicated).SetServiceID(sid1) 271 testTopic := topic.NewTopic(). 272 SetName(opts.TopicName()). 273 SetNumberOfShards(2). 274 SetConsumerServices([]topic.ConsumerService{cs1}) 275 _, err = ts.CheckAndSet(testTopic, kv.UninitializedVersion) 276 require.NoError(t, err) 277 278 sd := services.NewMockServices(ctrl) 279 opts = opts.SetServiceDiscovery(sd) 280 ps1 := testPlacementService(store, sid1) 281 sd.EXPECT().PlacementService(sid1, gomock.Any()).Return(ps1, nil) 282 283 p1 := placement.NewPlacement(). 284 SetInstances([]placement.Instance{ 285 placement.NewInstance(). 286 SetID("i1"). 287 SetEndpoint("addr1"). 288 SetShards(shard.NewShards([]shard.Shard{ 289 shard.NewShard(0).SetState(shard.Available), 290 shard.NewShard(1).SetState(shard.Available), 291 })), 292 }). 293 SetShards([]uint32{0, 1}). 294 SetReplicaFactor(1). 295 SetIsSharded(true) 296 _, err = ps1.Set(p1) 297 require.NoError(t, err) 298 299 w := NewWriter(opts).(*writer) 300 require.NoError(t, w.Init()) 301 defer w.Close() 302 303 require.Equal(t, 1, len(w.consumerServiceWriters)) 304 305 sid2 := services.NewServiceID().SetName("s2") 306 cs2 := topic.NewConsumerService().SetConsumptionType(topic.Shared).SetServiceID(sid2) 307 ps2 := testPlacementService(store, sid2) 308 sd.EXPECT().PlacementService(sid2, gomock.Any()).Return(ps2, nil) 309 310 sid3 := services.NewServiceID().SetName("s3") 311 cs3 := topic.NewConsumerService().SetConsumptionType(topic.Replicated).SetServiceID(sid3) 312 sd.EXPECT().PlacementService(sid3, gomock.Any()).Return(nil, errors.New("test error")) 313 314 sid4 := services.NewServiceID().SetName("s4") 315 cs4 := topic.NewConsumerService().SetConsumptionType(topic.Shared).SetServiceID(sid4) 316 ps4 := placement.NewMockService(ctrl) 317 sd.EXPECT().PlacementService(sid4, gomock.Any()).Return(ps4, nil) 318 ps4.EXPECT().Watch().Return(nil, errors.New("watch error")) 319 320 testTopic = testTopic. 321 SetConsumerServices([]topic.ConsumerService{ 322 cs1, cs2, 323 cs3, // Could not create consumer service write for cs3. 324 cs4, // Could not init cs4. 325 }). 326 SetVersion(1) 327 _, err = ts.CheckAndSet(testTopic, 1) 328 require.NoError(t, err) 329 330 for { 331 w.RLock() 332 l := len(w.consumerServiceWriters) 333 w.RUnlock() 334 if l == 2 { 335 break 336 } 337 time.Sleep(100 * time.Millisecond) 338 } 339 340 store.Delete(opts.TopicName()) 341 time.Sleep(100 * time.Millisecond) 342 require.Equal(t, 2, len(w.consumerServiceWriters)) 343 344 testTopic = testTopic. 345 SetConsumerServices([]topic.ConsumerService{cs2}). 346 SetVersion(0) 347 _, err = ts.CheckAndSet(testTopic, kv.UninitializedVersion) 348 require.NoError(t, err) 349 350 for { 351 w.RLock() 352 l := len(w.consumerServiceWriters) 353 w.RUnlock() 354 if l == 1 { 355 break 356 } 357 time.Sleep(100 * time.Millisecond) 358 } 359 w.Close() 360 361 testTopic = testTopic. 362 SetConsumerServices([]topic.ConsumerService{cs1, cs2}). 363 SetVersion(1) 364 _, err = ts.CheckAndSet(testTopic, 1) 365 require.NoError(t, err) 366 367 // Not going to process topic update anymore. 368 time.Sleep(100 * time.Millisecond) 369 require.Equal(t, 1, len(w.consumerServiceWriters)) 370 } 371 372 func TestTopicUpdateWithSameConsumerServicesButDifferentOrder(t *testing.T) { 373 defer leaktest.Check(t)() 374 375 ctrl := xtest.NewController(t) 376 defer ctrl.Finish() 377 378 store := mem.NewStore() 379 cs := client.NewMockClient(ctrl) 380 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 381 382 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 383 require.NoError(t, err) 384 385 opts := testOptions().SetTopicService(ts) 386 387 sid1 := services.NewServiceID().SetName("s1") 388 cs1 := topic.NewConsumerService().SetConsumptionType(topic.Replicated).SetServiceID(sid1) 389 sid2 := services.NewServiceID().SetName("s2") 390 cs2 := topic.NewConsumerService().SetConsumptionType(topic.Shared).SetServiceID(sid2).SetMessageTTLNanos(500) 391 testTopic := topic.NewTopic(). 392 SetName(opts.TopicName()). 393 SetNumberOfShards(1). 394 SetConsumerServices([]topic.ConsumerService{cs1, cs2}) 395 _, err = ts.CheckAndSet(testTopic, kv.UninitializedVersion) 396 require.NoError(t, err) 397 398 sd := services.NewMockServices(ctrl) 399 opts = opts.SetServiceDiscovery(sd) 400 ps1 := testPlacementService(store, sid1) 401 sd.EXPECT().PlacementService(sid1, gomock.Any()).Return(ps1, nil) 402 ps2 := testPlacementService(store, sid2) 403 sd.EXPECT().PlacementService(sid2, gomock.Any()).Return(ps2, nil) 404 405 p1 := placement.NewPlacement(). 406 SetInstances([]placement.Instance{ 407 placement.NewInstance(). 408 SetID("i1"). 409 SetEndpoint("i1"). 410 SetShards(shard.NewShards([]shard.Shard{ 411 shard.NewShard(0).SetState(shard.Available), 412 })), 413 }). 414 SetShards([]uint32{0}). 415 SetReplicaFactor(1). 416 SetIsSharded(true) 417 _, err = ps1.Set(p1) 418 require.NoError(t, err) 419 420 p2 := placement.NewPlacement(). 421 SetInstances([]placement.Instance{ 422 placement.NewInstance(). 423 SetID("i2"). 424 SetEndpoint("i2"). 425 SetShards(shard.NewShards([]shard.Shard{ 426 shard.NewShard(0).SetState(shard.Available), 427 })), 428 }). 429 SetShards([]uint32{0}). 430 SetReplicaFactor(1). 431 SetIsSharded(true) 432 _, err = ps2.Set(p2) 433 require.NoError(t, err) 434 435 w := NewWriter(opts).(*writer) 436 437 called := atomic.NewInt32(0) 438 w.processFn = func(update interface{}) error { 439 called.Inc() 440 return w.process(update) 441 } 442 require.NoError(t, w.Init()) 443 require.Equal(t, 1, int(called.Load())) 444 require.Equal(t, 2, len(w.consumerServiceWriters)) 445 csw, ok := w.consumerServiceWriters[cs1.ServiceID().String()] 446 require.True(t, ok) 447 cswMock1 := NewMockconsumerServiceWriter(ctrl) 448 w.consumerServiceWriters[cs1.ServiceID().String()] = cswMock1 449 defer csw.Close() 450 451 csw, ok = w.consumerServiceWriters[cs2.ServiceID().String()] 452 require.True(t, ok) 453 cswMock2 := NewMockconsumerServiceWriter(ctrl) 454 w.consumerServiceWriters[cs2.ServiceID().String()] = cswMock2 455 defer csw.Close() 456 457 cswMock1.EXPECT().SetMessageTTLNanos(int64(0)) 458 cswMock2.EXPECT().SetMessageTTLNanos(int64(500)) 459 testTopic = testTopic. 460 SetConsumerServices([]topic.ConsumerService{cs2, cs1}). 461 SetVersion(1) 462 _, err = ts.CheckAndSet(testTopic, 1) 463 require.NoError(t, err) 464 465 // The update will be processed, but nothing will be called on any of the mock writers. 466 for called.Load() != 2 { 467 time.Sleep(50 * time.Millisecond) 468 } 469 cswMock1.EXPECT().Close() 470 cswMock2.EXPECT().Close() 471 w.Close() 472 } 473 474 func TestWriterWrite(t *testing.T) { 475 defer leaktest.Check(t)() 476 477 ctrl := xtest.NewController(t) 478 defer ctrl.Finish() 479 480 store := mem.NewStore() 481 cs := client.NewMockClient(ctrl) 482 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 483 484 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 485 require.NoError(t, err) 486 487 opts := testOptions().SetTopicService(ts) 488 489 sid1 := services.NewServiceID().SetName("s1") 490 cs1 := topic.NewConsumerService().SetConsumptionType(topic.Replicated).SetServiceID(sid1) 491 sid2 := services.NewServiceID().SetName("s2") 492 cs2 := topic.NewConsumerService().SetConsumptionType(topic.Shared).SetServiceID(sid2) 493 testTopic := topic.NewTopic(). 494 SetName(opts.TopicName()). 495 SetNumberOfShards(1). 496 SetConsumerServices([]topic.ConsumerService{cs1, cs2}) 497 _, err = ts.CheckAndSet(testTopic, kv.UninitializedVersion) 498 require.NoError(t, err) 499 500 sd := services.NewMockServices(ctrl) 501 opts = opts.SetServiceDiscovery(sd) 502 ps1 := testPlacementService(store, sid1) 503 sd.EXPECT().PlacementService(sid1, gomock.Any()).Return(ps1, nil) 504 ps2 := testPlacementService(store, sid2) 505 sd.EXPECT().PlacementService(sid2, gomock.Any()).Return(ps2, nil) 506 507 lis1, err := net.Listen("tcp", "127.0.0.1:0") 508 require.NoError(t, err) 509 defer lis1.Close() 510 511 lis2, err := net.Listen("tcp", "127.0.0.1:0") 512 require.NoError(t, err) 513 defer lis2.Close() 514 515 lis3, err := net.Listen("tcp", "127.0.0.1:0") 516 require.NoError(t, err) 517 defer lis3.Close() 518 519 p1 := placement.NewPlacement(). 520 SetInstances([]placement.Instance{ 521 placement.NewInstance(). 522 SetID("i1"). 523 SetEndpoint(lis1.Addr().String()). 524 SetShards(shard.NewShards([]shard.Shard{ 525 shard.NewShard(0).SetState(shard.Available), 526 })), 527 placement.NewInstance(). 528 SetID("i2"). 529 SetEndpoint(lis2.Addr().String()). 530 SetShards(shard.NewShards([]shard.Shard{ 531 shard.NewShard(0).SetState(shard.Available), 532 })), 533 }). 534 SetShards([]uint32{0}). 535 SetReplicaFactor(2). 536 SetIsSharded(true) 537 _, err = ps1.Set(p1) 538 require.NoError(t, err) 539 540 p2 := placement.NewPlacement(). 541 SetInstances([]placement.Instance{ 542 placement.NewInstance(). 543 SetID("i13"). 544 SetEndpoint(lis3.Addr().String()). 545 SetShards(shard.NewShards([]shard.Shard{ 546 shard.NewShard(0).SetState(shard.Available), 547 })), 548 placement.NewInstance(). 549 SetID("i4"). 550 SetEndpoint("addr4"). 551 SetShards(shard.NewShards([]shard.Shard{ 552 shard.NewShard(0).SetState(shard.Available), 553 })), 554 }). 555 SetShards([]uint32{0}). 556 SetReplicaFactor(2). 557 SetIsSharded(true) 558 _, err = ps2.Set(p2) 559 require.NoError(t, err) 560 561 w := NewWriter(opts).(*writer) 562 require.NoError(t, w.Init()) 563 defer w.Close() 564 565 require.Equal(t, 2, len(w.consumerServiceWriters)) 566 567 var wg sync.WaitGroup 568 mm := producer.NewMockMessage(ctrl) 569 mm.EXPECT().Shard().Return(uint32(0)).Times(3) 570 mm.EXPECT().Size().Return(3) 571 mm.EXPECT().Bytes().Return([]byte("foo")).Times(3) 572 mm.EXPECT().Finalize(producer.Consumed).Do(func(interface{}) { wg.Done() }) 573 rm := producer.NewRefCountedMessage(mm, nil) 574 wg.Add(1) 575 require.NoError(t, w.Write(rm)) 576 577 wg.Add(1) 578 go func() { 579 testConsumeAndAckOnConnectionListener(t, lis1, opts.EncoderOptions(), opts.DecoderOptions()) 580 wg.Done() 581 }() 582 583 wg.Add(1) 584 go func() { 585 testConsumeAndAckOnConnectionListener(t, lis2, opts.EncoderOptions(), opts.DecoderOptions()) 586 wg.Done() 587 }() 588 589 wg.Add(1) 590 go func() { 591 testConsumeAndAckOnConnectionListener(t, lis3, opts.EncoderOptions(), opts.DecoderOptions()) 592 wg.Done() 593 }() 594 595 wg.Wait() 596 w.Close() 597 } 598 599 func TestWriterCloseBlocking(t *testing.T) { 600 defer leaktest.Check(t)() 601 602 ctrl := xtest.NewController(t) 603 defer ctrl.Finish() 604 605 store := mem.NewStore() 606 cs := client.NewMockClient(ctrl) 607 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 608 609 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 610 require.NoError(t, err) 611 612 opts := testOptions().SetTopicService(ts) 613 614 sid1 := services.NewServiceID().SetName("s1") 615 cs1 := topic.NewConsumerService().SetConsumptionType(topic.Shared).SetServiceID(sid1) 616 testTopic := topic.NewTopic(). 617 SetName(opts.TopicName()). 618 SetNumberOfShards(1). 619 SetConsumerServices([]topic.ConsumerService{cs1}) 620 _, err = ts.CheckAndSet(testTopic, kv.UninitializedVersion) 621 require.NoError(t, err) 622 623 sd := services.NewMockServices(ctrl) 624 opts = opts.SetServiceDiscovery(sd) 625 ps1 := testPlacementService(store, sid1) 626 sd.EXPECT().PlacementService(sid1, gomock.Any()).Return(ps1, nil) 627 628 p1 := placement.NewPlacement(). 629 SetInstances([]placement.Instance{ 630 placement.NewInstance(). 631 SetID("i1"). 632 SetEndpoint("addr1"). 633 SetShards(shard.NewShards([]shard.Shard{ 634 shard.NewShard(0).SetState(shard.Available), 635 })), 636 }). 637 SetShards([]uint32{0}). 638 SetReplicaFactor(1). 639 SetIsSharded(true) 640 _, err = ps1.Set(p1) 641 require.NoError(t, err) 642 643 w := NewWriter(opts).(*writer) 644 require.NoError(t, w.Init()) 645 require.Equal(t, 1, len(w.consumerServiceWriters)) 646 647 mm := producer.NewMockMessage(ctrl) 648 mm.EXPECT().Size().Return(3) 649 mm.EXPECT().Shard().Return(uint32(0)).Times(2) 650 mm.EXPECT().Bytes().Return([]byte("foo")).Times(1) 651 mm.EXPECT().Finalize(producer.Dropped) 652 rm := producer.NewRefCountedMessage(mm, nil) 653 require.NoError(t, w.Write(rm)) 654 655 doneCh := make(chan struct{}) 656 go func() { 657 w.Close() 658 close(doneCh) 659 }() 660 661 select { 662 case <-doneCh: 663 require.FailNow(t, "writer.Close() should block until all messages dropped or consumed") 664 default: 665 } 666 667 rm.Drop() 668 <-doneCh 669 } 670 671 func TestWriterSetMessageTTLNanosDropMetric(t *testing.T) { 672 defer leaktest.Check(t)() 673 674 ctrl := xtest.NewController(t) 675 defer ctrl.Finish() 676 677 store := mem.NewStore() 678 cs := client.NewMockClient(ctrl) 679 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 680 681 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 682 require.NoError(t, err) 683 684 opts := testOptions().SetTopicService(ts) 685 686 sid1 := services.NewServiceID().SetName("s1") 687 cs1 := topic.NewConsumerService().SetConsumptionType(topic.Replicated).SetServiceID(sid1) 688 sid2 := services.NewServiceID().SetName("s2") 689 cs2 := topic.NewConsumerService().SetConsumptionType(topic.Shared).SetServiceID(sid2) 690 testTopic := topic.NewTopic(). 691 SetName(opts.TopicName()). 692 SetNumberOfShards(1). 693 SetConsumerServices([]topic.ConsumerService{cs1, cs2}) 694 _, err = ts.CheckAndSet(testTopic, kv.UninitializedVersion) 695 require.NoError(t, err) 696 697 sd := services.NewMockServices(ctrl) 698 opts = opts.SetServiceDiscovery(sd) 699 ps1 := testPlacementService(store, sid1) 700 sd.EXPECT().PlacementService(sid1, gomock.Any()).Return(ps1, nil) 701 ps2 := testPlacementService(store, sid2) 702 sd.EXPECT().PlacementService(sid2, gomock.Any()).Return(ps2, nil) 703 704 lis1, err := net.Listen("tcp", "127.0.0.1:0") 705 require.NoError(t, err) 706 defer lis1.Close() 707 708 p1 := placement.NewPlacement(). 709 SetInstances([]placement.Instance{ 710 placement.NewInstance(). 711 SetID("i1"). 712 SetEndpoint(lis1.Addr().String()). 713 SetShards(shard.NewShards([]shard.Shard{ 714 shard.NewShard(0).SetState(shard.Available), 715 })), 716 }). 717 SetShards([]uint32{0}). 718 SetReplicaFactor(1). 719 SetIsSharded(true) 720 _, err = ps1.Set(p1) 721 require.NoError(t, err) 722 723 p2 := placement.NewPlacement(). 724 SetInstances([]placement.Instance{ 725 placement.NewInstance(). 726 SetID("i2"). 727 SetEndpoint("i2"). 728 SetShards(shard.NewShards([]shard.Shard{ 729 shard.NewShard(0).SetState(shard.Available), 730 })), 731 }). 732 SetShards([]uint32{0}). 733 SetReplicaFactor(1). 734 SetIsSharded(true) 735 _, err = ps2.Set(p2) 736 require.NoError(t, err) 737 738 w := NewWriter(opts).(*writer) 739 require.NoError(t, w.Init()) 740 defer w.Close() 741 742 require.Equal(t, 2, len(w.consumerServiceWriters)) 743 744 var called int 745 var wg sync.WaitGroup 746 mm := producer.NewMockMessage(ctrl) 747 mm.EXPECT().Shard().Return(uint32(0)).AnyTimes() 748 mm.EXPECT().Size().Return(3).AnyTimes() 749 mm.EXPECT().Bytes().Return([]byte("foo")).AnyTimes() 750 mm.EXPECT().Finalize(producer.Consumed).Do(func(interface{}) { called++; wg.Done() }) 751 require.NoError(t, w.Write(producer.NewRefCountedMessage(mm, nil))) 752 753 wg.Add(1) 754 go func() { 755 testConsumeAndAckOnConnectionListener(t, lis1, opts.EncoderOptions(), opts.DecoderOptions()) 756 wg.Done() 757 }() 758 wg.Wait() 759 require.Equal(t, 0, called) 760 761 // Wait for the message ttl update to trigger finalize. 762 wg.Add(1) 763 testTopic = topic.NewTopic(). 764 SetName(opts.TopicName()). 765 SetNumberOfShards(1). 766 SetConsumerServices([]topic.ConsumerService{cs1, cs2.SetMessageTTLNanos(int64(50 * time.Millisecond))}) 767 _, err = ts.CheckAndSet(testTopic, 1) 768 require.NoError(t, err) 769 wg.Wait() 770 require.Equal(t, 1, called) 771 772 lis2, err := net.Listen("tcp", "127.0.0.1:0") 773 require.NoError(t, err) 774 defer lis2.Close() 775 776 p2 = placement.NewPlacement(). 777 SetInstances([]placement.Instance{ 778 placement.NewInstance(). 779 SetID("i2"). 780 SetEndpoint(lis2.Addr().String()). 781 SetShards(shard.NewShards([]shard.Shard{ 782 shard.NewShard(0).SetState(shard.Available), 783 })), 784 }). 785 SetShards([]uint32{0}). 786 SetReplicaFactor(1). 787 SetIsSharded(true) 788 _, err = ps2.Set(p2) 789 require.NoError(t, err) 790 791 testTopic = topic.NewTopic(). 792 SetName(opts.TopicName()). 793 SetNumberOfShards(1). 794 SetConsumerServices([]topic.ConsumerService{cs1, cs2.SetMessageTTLNanos(0)}) 795 _, err = ts.CheckAndSet(testTopic, 2) 796 require.NoError(t, err) 797 798 require.NoError(t, w.Write(producer.NewRefCountedMessage(mm, nil))) 799 800 called = 0 801 mm.EXPECT().Finalize(producer.Consumed).Do(func(interface{}) { called++; wg.Done() }) 802 wg.Add(1) 803 go func() { 804 testConsumeAndAckOnConnectionListener(t, lis1, opts.EncoderOptions(), opts.DecoderOptions()) 805 wg.Done() 806 }() 807 wg.Wait() 808 require.Equal(t, 0, called) 809 810 time.Sleep(200 * time.Millisecond) 811 require.Equal(t, 0, called) 812 813 // Wait for the consumer to trigger finalize because there is no more message ttl. 814 wg.Add(1) 815 go func() { 816 testConsumeAndAckOnConnectionListener(t, lis2, opts.EncoderOptions(), opts.DecoderOptions()) 817 }() 818 wg.Wait() 819 require.Equal(t, 1, called) 820 821 w.Close() 822 } 823 824 func TestWriterNumShards(t *testing.T) { 825 defer leaktest.Check(t)() 826 827 ctrl := xtest.NewController(t) 828 defer ctrl.Finish() 829 830 store := mem.NewStore() 831 cs := client.NewMockClient(ctrl) 832 cs.EXPECT().Store(gomock.Any()).Return(store, nil) 833 834 ts, err := topic.NewService(topic.NewServiceOptions().SetConfigService(cs)) 835 require.NoError(t, err) 836 837 opts := testOptions().SetTopicService(ts) 838 839 testTopic := topic.NewTopic(). 840 SetName(opts.TopicName()). 841 SetNumberOfShards(2) 842 _, err = ts.CheckAndSet(testTopic, kv.UninitializedVersion) 843 require.NoError(t, err) 844 845 w := NewWriter(opts).(*writer) 846 defer w.Close() 847 848 require.Equal(t, 0, int(w.NumShards())) 849 850 require.NoError(t, w.Init()) 851 require.Equal(t, 2, int(w.NumShards())) 852 }