get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/server/jetstream_consumer_test.go (about) 1 // Copyright 2022-2023 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 //go:build !skip_js_tests 15 // +build !skip_js_tests 16 17 package server 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "math/rand" 23 "sort" 24 "strings" 25 "sync" 26 "sync/atomic" 27 "testing" 28 "time" 29 30 "github.com/nats-io/nats.go" 31 "github.com/nats-io/nuid" 32 ) 33 34 func TestJetStreamConsumerMultipleFiltersRemoveFilters(t *testing.T) { 35 36 s := RunBasicJetStreamServer(t) 37 defer s.Shutdown() 38 39 nc, js := jsClientConnect(t, s) 40 defer nc.Close() 41 acc := s.GlobalAccount() 42 43 mset, err := acc.addStream(&StreamConfig{ 44 Name: "TEST", 45 Retention: LimitsPolicy, 46 Subjects: []string{"one", "two", "three"}, 47 MaxAge: time.Second * 90, 48 }) 49 require_NoError(t, err) 50 51 _, err = mset.addConsumer(&ConsumerConfig{ 52 Durable: "consumer", 53 FilterSubjects: []string{"one", "two"}, 54 }) 55 require_NoError(t, err) 56 57 sendStreamMsg(t, nc, "one", "data") 58 sendStreamMsg(t, nc, "two", "data") 59 sendStreamMsg(t, nc, "three", "data") 60 61 consumer, err := js.PullSubscribe("", "consumer", nats.Bind("TEST", "consumer")) 62 require_NoError(t, err) 63 64 msgs, err := consumer.Fetch(1) 65 require_NoError(t, err) 66 require_True(t, len(msgs) == 1) 67 68 _, err = mset.addConsumer(&ConsumerConfig{ 69 Durable: "consumer", 70 FilterSubjects: []string{}, 71 }) 72 require_NoError(t, err) 73 74 msgs, err = consumer.Fetch(1) 75 require_NoError(t, err) 76 require_True(t, len(msgs) == 1) 77 78 msgs, err = consumer.Fetch(1) 79 require_NoError(t, err) 80 require_True(t, len(msgs) == 1) 81 82 } 83 84 func TestJetStreamConsumerMultipleFiltersRace(t *testing.T) { 85 s := RunBasicJetStreamServer(t) 86 defer s.Shutdown() 87 88 nc, js := jsClientConnect(t, s) 89 defer nc.Close() 90 acc := s.GlobalAccount() 91 92 mset, err := acc.addStream(&StreamConfig{ 93 Name: "TEST", 94 Retention: LimitsPolicy, 95 Subjects: []string{"one", "two", "three", "four"}, 96 MaxAge: time.Second * 90, 97 }) 98 require_NoError(t, err) 99 100 var seqs []uint64 101 var mu sync.Mutex 102 103 for i := 0; i < 10_000; i++ { 104 sendStreamMsg(t, nc, "one", "data") 105 sendStreamMsg(t, nc, "two", "data") 106 sendStreamMsg(t, nc, "three", "data") 107 sendStreamMsg(t, nc, "four", "data") 108 } 109 110 mset.addConsumer(&ConsumerConfig{ 111 Durable: "consumer", 112 FilterSubjects: []string{"one", "two", "three"}, 113 AckPolicy: AckExplicit, 114 }) 115 116 done := make(chan struct{}) 117 for i := 0; i < 10; i++ { 118 go func(t *testing.T) { 119 120 c, err := js.PullSubscribe("", "consumer", nats.Bind("TEST", "consumer")) 121 require_NoError(t, err) 122 123 for { 124 select { 125 case <-done: 126 return 127 default: 128 } 129 msgs, err := c.Fetch(10) 130 // We don't want to stop before at expected number of messages, as we want 131 // to also test against getting to many messages. 132 // Because of that, we ignore timeout and connection closed errors. 133 if err != nil && err != nats.ErrTimeout && err != nats.ErrConnectionClosed { 134 t.Errorf("error while fetching messages: %v", err) 135 } 136 137 for _, msg := range msgs { 138 info, err := msg.Metadata() 139 require_NoError(t, err) 140 mu.Lock() 141 seqs = append(seqs, info.Sequence.Consumer) 142 mu.Unlock() 143 msg.Ack() 144 } 145 } 146 }(t) 147 } 148 149 checkFor(t, time.Second*30, time.Second*1, func() error { 150 mu.Lock() 151 defer mu.Unlock() 152 if len(seqs) != 30_000 { 153 return fmt.Errorf("found %d messages instead of %d", len(seqs), 30_000) 154 } 155 sort.Slice(seqs, func(i, j int) bool { 156 return seqs[i] < seqs[j] 157 }) 158 for i := 1; i < len(seqs); i++ { 159 if seqs[i] != seqs[i-1]+1 { 160 fmt.Printf("seqs: %+v\n", seqs) 161 return fmt.Errorf("sequence mismatch at %v", i) 162 } 163 } 164 165 return nil 166 }) 167 168 close(done) 169 170 } 171 172 func TestJetStreamConsumerMultipleConsumersSingleFilter(t *testing.T) { 173 s := RunBasicJetStreamServer(t) 174 defer s.Shutdown() 175 176 nc, js := jsClientConnect(t, s) 177 defer nc.Close() 178 acc := s.GlobalAccount() 179 180 // Setup few subjects with varying messages count. 181 subjects := []struct { 182 subject string 183 messages int 184 wc bool 185 }{ 186 {subject: "one", messages: 5000}, 187 {subject: "two", messages: 7500}, 188 {subject: "three", messages: 2500}, 189 {subject: "four", messages: 1000}, 190 {subject: "five.>", messages: 3000, wc: true}, 191 } 192 193 totalMsgs := 0 194 for _, subject := range subjects { 195 totalMsgs += subject.messages 196 } 197 198 // Setup consumers, filtering some of the messages from the stream. 199 consumers := []*struct { 200 name string 201 subjects []string 202 expectedMsgs int 203 delivered atomic.Int32 204 }{ 205 {name: "C1", subjects: []string{"one"}, expectedMsgs: 5000}, 206 {name: "C2", subjects: []string{"two"}, expectedMsgs: 7500}, 207 {name: "C3", subjects: []string{"one"}, expectedMsgs: 5000}, 208 {name: "C4", subjects: []string{"one"}, expectedMsgs: 5000}, 209 } 210 211 mset, err := acc.addStream(&StreamConfig{ 212 Name: "TEST", 213 Retention: LimitsPolicy, 214 Subjects: []string{"one", "two", "three", "four", "five.>"}, 215 MaxAge: time.Second * 90, 216 }) 217 require_NoError(t, err) 218 219 for c, consumer := range consumers { 220 _, err := mset.addConsumer(&ConsumerConfig{ 221 Durable: consumer.name, 222 FilterSubjects: consumer.subjects, 223 AckPolicy: AckExplicit, 224 DeliverPolicy: DeliverAll, 225 AckWait: time.Second * 30, 226 DeliverSubject: nc.NewInbox(), 227 }) 228 require_NoError(t, err) 229 go func(c int, name string) { 230 _, err = js.Subscribe("", func(m *nats.Msg) { 231 require_NoError(t, m.Ack()) 232 require_NoError(t, err) 233 consumers[c].delivered.Add(1) 234 235 }, nats.Bind("TEST", name)) 236 require_NoError(t, err) 237 }(c, consumer.name) 238 } 239 240 // Publish with random intervals, while consumers are active. 241 var wg sync.WaitGroup 242 for _, subject := range subjects { 243 wg.Add(subject.messages) 244 go func(subject string, messages int, wc bool) { 245 nc, js := jsClientConnect(t, s) 246 defer nc.Close() 247 time.Sleep(time.Duration(rand.Int63n(1000)+1) * time.Millisecond) 248 for i := 0; i < messages; i++ { 249 time.Sleep(time.Duration(rand.Int63n(1000)+1) * time.Microsecond) 250 // If subject has wildcard, add random last subject token. 251 pubSubject := subject 252 if wc { 253 pubSubject = fmt.Sprintf("%v.%v", subject, rand.Int63n(10)) 254 } 255 _, err := js.PublishAsync(pubSubject, []byte("data")) 256 require_NoError(t, err) 257 wg.Done() 258 } 259 }(subject.subject, subject.messages, subject.wc) 260 } 261 wg.Wait() 262 263 checkFor(t, time.Second*10, time.Millisecond*500, func() error { 264 for _, consumer := range consumers { 265 info, err := js.ConsumerInfo("TEST", consumer.name) 266 require_NoError(t, err) 267 if info.Delivered.Consumer != uint64(consumer.expectedMsgs) { 268 return fmt.Errorf("%v:expected consumer delivered seq %v, got %v. actually delivered: %v", consumer.name, consumer.expectedMsgs, info.Delivered.Consumer, consumer.delivered.Load()) 269 } 270 if info.AckFloor.Consumer != uint64(consumer.expectedMsgs) { 271 return fmt.Errorf("%v: expected consumer ack floor %v, got %v", consumer.name, totalMsgs, info.AckFloor.Consumer) 272 } 273 if consumer.delivered.Load() != int32(consumer.expectedMsgs) { 274 275 return fmt.Errorf("%v: expected %v, got %v", consumer.name, consumer.expectedMsgs, consumer.delivered.Load()) 276 } 277 } 278 return nil 279 }) 280 281 } 282 283 func TestJetStreamConsumerMultipleConsumersMultipleFilters(t *testing.T) { 284 s := RunBasicJetStreamServer(t) 285 defer s.Shutdown() 286 287 nc, js := jsClientConnect(t, s) 288 defer nc.Close() 289 acc := s.GlobalAccount() 290 291 // Setup few subjects with varying messages count. 292 subjects := []struct { 293 subject string 294 messages int 295 wc bool 296 }{ 297 {subject: "one", messages: 50}, 298 {subject: "two", messages: 75}, 299 {subject: "three", messages: 250}, 300 {subject: "four", messages: 10}, 301 {subject: "five.>", messages: 300, wc: true}, 302 } 303 304 totalMsgs := 0 305 for _, subject := range subjects { 306 totalMsgs += subject.messages 307 } 308 309 // Setup consumers, filtering some of the messages from the stream. 310 consumers := []*struct { 311 name string 312 subjects []string 313 expectedMsgs int 314 delivered atomic.Int32 315 }{ 316 {name: "C1", subjects: []string{"one", "two"}, expectedMsgs: 125}, 317 {name: "C2", subjects: []string{"two", "three"}, expectedMsgs: 325}, 318 {name: "C3", subjects: []string{"one", "three"}, expectedMsgs: 300}, 319 {name: "C4", subjects: []string{"one", "five.>"}, expectedMsgs: 350}, 320 } 321 322 mset, err := acc.addStream(&StreamConfig{ 323 Name: "TEST", 324 Retention: LimitsPolicy, 325 Subjects: []string{"one", "two", "three", "four", "five.>"}, 326 MaxAge: time.Second * 90, 327 }) 328 require_NoError(t, err) 329 330 for c, consumer := range consumers { 331 _, err := mset.addConsumer(&ConsumerConfig{ 332 Durable: consumer.name, 333 FilterSubjects: consumer.subjects, 334 AckPolicy: AckExplicit, 335 DeliverPolicy: DeliverAll, 336 AckWait: time.Second * 30, 337 DeliverSubject: nc.NewInbox(), 338 }) 339 require_NoError(t, err) 340 go func(c int, name string) { 341 _, err = js.Subscribe("", func(m *nats.Msg) { 342 require_NoError(t, m.Ack()) 343 require_NoError(t, err) 344 consumers[c].delivered.Add(1) 345 346 }, nats.Bind("TEST", name)) 347 require_NoError(t, err) 348 }(c, consumer.name) 349 } 350 351 // Publish with random intervals, while consumers are active. 352 var wg sync.WaitGroup 353 for _, subject := range subjects { 354 wg.Add(subject.messages) 355 go func(subject string, messages int, wc bool) { 356 nc, js := jsClientConnect(t, s) 357 defer nc.Close() 358 time.Sleep(time.Duration(rand.Int63n(1000)+1) * time.Millisecond) 359 for i := 0; i < messages; i++ { 360 time.Sleep(time.Duration(rand.Int63n(1000)+1) * time.Microsecond) 361 // If subject has wildcard, add random last subject token. 362 pubSubject := subject 363 if wc { 364 pubSubject = fmt.Sprintf("%v.%v", subject, rand.Int63n(10)) 365 } 366 ack, err := js.PublishAsync(pubSubject, []byte("data")) 367 require_NoError(t, err) 368 go func() { 369 ack.Ok() 370 wg.Done() 371 }() 372 } 373 }(subject.subject, subject.messages, subject.wc) 374 } 375 done := make(chan struct{}) 376 go func() { 377 wg.Wait() 378 close(done) 379 }() 380 381 select { 382 case <-time.After(time.Second * 15): 383 t.Fatalf("Timed out waiting for acks") 384 case <-done: 385 } 386 wg.Wait() 387 388 checkFor(t, time.Second*15, time.Second*1, func() error { 389 for _, consumer := range consumers { 390 info, err := js.ConsumerInfo("TEST", consumer.name) 391 require_NoError(t, err) 392 if info.Delivered.Consumer != uint64(consumer.expectedMsgs) { 393 return fmt.Errorf("%v:expected consumer delivered seq %v, got %v. actually delivered: %v", consumer.name, consumer.expectedMsgs, info.Delivered.Consumer, consumer.delivered.Load()) 394 } 395 if info.AckFloor.Consumer != uint64(consumer.expectedMsgs) { 396 return fmt.Errorf("%v: expected consumer ack floor %v, got %v", consumer.name, totalMsgs, info.AckFloor.Consumer) 397 } 398 if consumer.delivered.Load() != int32(consumer.expectedMsgs) { 399 400 return fmt.Errorf("%v: expected %v, got %v", consumer.name, consumer.expectedMsgs, consumer.delivered.Load()) 401 } 402 } 403 return nil 404 }) 405 406 } 407 408 func TestJetStreamConsumerMultipleFiltersSequence(t *testing.T) { 409 s := RunBasicJetStreamServer(t) 410 defer s.Shutdown() 411 412 nc, js := jsClientConnect(t, s) 413 defer nc.Close() 414 acc := s.GlobalAccount() 415 416 mset, err := acc.addStream(&StreamConfig{ 417 Name: "TEST", 418 Retention: LimitsPolicy, 419 Subjects: []string{"one", "two", "three", "four", "five.>"}, 420 MaxAge: time.Second * 90, 421 }) 422 require_NoError(t, err) 423 424 _, err = mset.addConsumer(&ConsumerConfig{ 425 Durable: "DUR", 426 FilterSubjects: []string{"one", "two"}, 427 AckPolicy: AckExplicit, 428 DeliverPolicy: DeliverAll, 429 AckWait: time.Second * 30, 430 DeliverSubject: nc.NewInbox(), 431 }) 432 require_NoError(t, err) 433 434 for i := 0; i < 20; i++ { 435 sendStreamMsg(t, nc, "one", fmt.Sprintf("%d", i)) 436 } 437 for i := 20; i < 40; i++ { 438 sendStreamMsg(t, nc, "two", fmt.Sprintf("%d", i)) 439 } 440 for i := 40; i < 60; i++ { 441 sendStreamMsg(t, nc, "one", fmt.Sprintf("%d", i)) 442 } 443 444 sub, err := js.SubscribeSync("", nats.Bind("TEST", "DUR")) 445 require_NoError(t, err) 446 447 for i := 0; i < 60; i++ { 448 msg, err := sub.NextMsg(time.Second * 1) 449 require_NoError(t, err) 450 require_True(t, string(msg.Data) == fmt.Sprintf("%d", i)) 451 } 452 } 453 454 func TestJetStreamConsumerActions(t *testing.T) { 455 s := RunBasicJetStreamServer(t) 456 defer s.Shutdown() 457 458 nc, _ := jsClientConnect(t, s) 459 defer nc.Close() 460 acc := s.GlobalAccount() 461 462 mset, err := acc.addStream(&StreamConfig{ 463 Name: "TEST", 464 Retention: LimitsPolicy, 465 Subjects: []string{"one", "two", "three", "four", "five.>"}, 466 MaxAge: time.Second * 90, 467 }) 468 require_NoError(t, err) 469 470 // Create Consumer. No consumers existed before, so should be fine. 471 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 472 Durable: "DUR", 473 FilterSubjects: []string{"one", "two"}, 474 AckPolicy: AckExplicit, 475 DeliverPolicy: DeliverAll, 476 AckWait: time.Second * 30, 477 }, ActionCreate) 478 require_NoError(t, err) 479 // Create consumer again. Should be ok if action is CREATE but config is exactly the same. 480 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 481 Durable: "DUR", 482 FilterSubjects: []string{"one", "two"}, 483 AckPolicy: AckExplicit, 484 DeliverPolicy: DeliverAll, 485 AckWait: time.Second * 30, 486 }, ActionCreate) 487 require_NoError(t, err) 488 // Create consumer again. Should error if action is CREATE. 489 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 490 Durable: "DUR", 491 FilterSubjects: []string{"one"}, 492 AckPolicy: AckExplicit, 493 DeliverPolicy: DeliverAll, 494 AckWait: time.Second * 30, 495 }, ActionCreate) 496 require_Error(t, err) 497 498 // Update existing consumer. Should be fine, as consumer exists. 499 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 500 Durable: "DUR", 501 FilterSubjects: []string{"one"}, 502 AckPolicy: AckExplicit, 503 DeliverPolicy: DeliverAll, 504 AckWait: time.Second * 30, 505 }, ActionUpdate) 506 require_NoError(t, err) 507 508 // Update consumer. Should error, as this consumer does not exist. 509 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 510 Durable: "NEW", 511 FilterSubjects: []string{"one"}, 512 AckPolicy: AckExplicit, 513 DeliverPolicy: DeliverAll, 514 AckWait: time.Second * 30, 515 }, ActionUpdate) 516 require_Error(t, err) 517 518 // Create new ephemeral. Should be fine as the consumer doesn't exist already 519 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 520 Name: "EPH", 521 FilterSubjects: []string{"one"}, 522 AckPolicy: AckExplicit, 523 DeliverPolicy: DeliverAll, 524 AckWait: time.Second * 30, 525 }, ActionCreate) 526 require_NoError(t, err) 527 528 // Trying to create it again right away. Should error as it already exists (and hasn't been cleaned up yet) 529 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 530 Name: "EPH", 531 FilterSubjects: []string{"one"}, 532 AckPolicy: AckExplicit, 533 DeliverPolicy: DeliverAll, 534 AckWait: time.Second * 30, 535 }, ActionCreate) 536 require_Error(t, err) 537 } 538 539 func TestJetStreamConsumerActionsOnWorkQueuePolicyStream(t *testing.T) { 540 s := RunBasicJetStreamServer(t) 541 defer s.Shutdown() 542 543 nc, _ := jsClientConnect(t, s) 544 defer nc.Close() 545 acc := s.GlobalAccount() 546 547 mset, err := acc.addStream(&StreamConfig{ 548 Name: "TEST", 549 Retention: WorkQueuePolicy, 550 Subjects: []string{"one", "two", "three", "four", "five.>"}, 551 }) 552 require_NoError(t, err) 553 554 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 555 Durable: "C1", 556 FilterSubjects: []string{"one", "two"}, 557 AckPolicy: AckExplicit, 558 }, ActionCreate) 559 require_NoError(t, err) 560 561 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 562 Durable: "C2", 563 FilterSubjects: []string{"three", "four"}, 564 AckPolicy: AckExplicit, 565 }, ActionCreate) 566 require_NoError(t, err) 567 568 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 569 Durable: "C3", 570 FilterSubjects: []string{"five.*"}, 571 AckPolicy: AckExplicit, 572 }, ActionCreate) 573 require_NoError(t, err) 574 575 // Updating a consumer by removing a previous subject filter. 576 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 577 Durable: "C1", 578 FilterSubjects: []string{"one"}, // Remove a subject. 579 AckPolicy: AckExplicit, 580 }, ActionUpdate) 581 require_NoError(t, err) 582 583 // Updating a consumer without overlapping subjects. 584 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 585 Durable: "C2", 586 FilterSubjects: []string{"three", "four", "two"}, // Add previously removed subject. 587 AckPolicy: AckExplicit, 588 }, ActionUpdate) 589 require_NoError(t, err) 590 591 // Creating a consumer with overlapping subjects should return an error. 592 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 593 Durable: "C4", 594 FilterSubjects: []string{"one", "two", "three", "four"}, 595 AckPolicy: AckExplicit, 596 }, ActionCreate) 597 require_Error(t, err) 598 if !IsNatsErr(err, JSConsumerWQConsumerNotUniqueErr) { 599 t.Errorf("want error %q, got %q", ApiErrors[JSConsumerWQConsumerNotUniqueErr], err) 600 } 601 602 // Updating a consumer with overlapping subjects should return an error. 603 _, err = mset.addConsumerWithAction(&ConsumerConfig{ 604 Durable: "C3", 605 FilterSubjects: []string{"one", "two", "three", "four"}, 606 AckPolicy: AckExplicit, 607 }, ActionUpdate) 608 require_Error(t, err) 609 if !IsNatsErr(err, JSConsumerWQConsumerNotUniqueErr) { 610 t.Errorf("want error %q, got %q", ApiErrors[JSConsumerWQConsumerNotUniqueErr], err) 611 } 612 } 613 614 func TestJetStreamConsumerActionsViaAPI(t *testing.T) { 615 616 s := RunBasicJetStreamServer(t) 617 defer s.Shutdown() 618 619 nc, _ := jsClientConnect(t, s) 620 defer nc.Close() 621 acc := s.GlobalAccount() 622 623 _, err := acc.addStream(&StreamConfig{ 624 Name: "TEST", 625 Retention: LimitsPolicy, 626 Subjects: []string{"one"}, 627 MaxAge: time.Second * 90, 628 }) 629 require_NoError(t, err) 630 631 // Update non-existing consumer, which should fail. 632 request, err := json.Marshal(&CreateConsumerRequest{ 633 Action: ActionUpdate, 634 Config: ConsumerConfig{ 635 Durable: "hello", 636 }, 637 Stream: "TEST", 638 }) 639 require_NoError(t, err) 640 641 resp, err := nc.Request("$JS.API.CONSUMER.DURABLE.CREATE.TEST.hello", []byte(request), time.Second*6) 642 require_NoError(t, err) 643 var ccResp JSApiConsumerCreateResponse 644 err = json.Unmarshal(resp.Data, &ccResp) 645 require_NoError(t, err) 646 require_Error(t, ccResp.Error) 647 648 // create non existing consumer - which should be fine. 649 ccResp.Error = nil 650 request, err = json.Marshal(&CreateConsumerRequest{ 651 Action: ActionCreate, 652 Config: ConsumerConfig{ 653 Durable: "hello", 654 }, 655 Stream: "TEST", 656 }) 657 require_NoError(t, err) 658 659 resp, err = nc.Request("$JS.API.CONSUMER.DURABLE.CREATE.TEST.hello", []byte(request), time.Second*6) 660 require_NoError(t, err) 661 err = json.Unmarshal(resp.Data, &ccResp) 662 require_NoError(t, err) 663 if ccResp.Error != nil { 664 t.Fatalf("expected nil, got %v", ccResp.Error) 665 } 666 667 // re-create existing consumer - which should be an error. 668 ccResp.Error = nil 669 request, err = json.Marshal(&CreateConsumerRequest{ 670 Action: ActionCreate, 671 Config: ConsumerConfig{ 672 Durable: "hello", 673 FilterSubject: "one", 674 }, 675 Stream: "TEST", 676 }) 677 require_NoError(t, err) 678 resp, err = nc.Request("$JS.API.CONSUMER.DURABLE.CREATE.TEST.hello", []byte(request), time.Second*6) 679 require_NoError(t, err) 680 err = json.Unmarshal(resp.Data, &ccResp) 681 require_NoError(t, err) 682 if ccResp.Error == nil { 683 t.Fatalf("expected err, got nil") 684 } 685 686 // create a named ephemeral consumer 687 ccResp.Error = nil 688 request, err = json.Marshal(&CreateConsumerRequest{ 689 Action: ActionCreate, 690 Config: ConsumerConfig{ 691 Name: "ephemeral", 692 FilterSubject: "one", 693 }, 694 Stream: "TEST", 695 }) 696 require_NoError(t, err) 697 resp, err = nc.Request("$JS.API.CONSUMER.CREATE.TEST.ephemeral", []byte(request), time.Second*6) 698 require_NoError(t, err) 699 err = json.Unmarshal(resp.Data, &ccResp) 700 require_NoError(t, err) 701 702 // re-create existing consumer - which should be an error. 703 ccResp.Error = nil 704 request, err = json.Marshal(&CreateConsumerRequest{ 705 Action: ActionCreate, 706 Config: ConsumerConfig{ 707 Name: "ephemeral", 708 FilterSubject: "one", 709 }, 710 Stream: "TEST", 711 }) 712 require_NoError(t, err) 713 resp, err = nc.Request("$JS.API.CONSUMER.CREATE.TEST.ephemeral", []byte(request), time.Second*6) 714 require_NoError(t, err) 715 err = json.Unmarshal(resp.Data, &ccResp) 716 require_NoError(t, err) 717 if ccResp.Error == nil { 718 t.Fatalf("expected err, got nil") 719 } 720 } 721 722 func TestJetStreamConsumerActionsUnmarshal(t *testing.T) { 723 tests := []struct { 724 name string 725 given []byte 726 expected ConsumerAction 727 expectErr bool 728 }{ 729 {name: "action create", given: []byte(`{"action": "create"}`), expected: ActionCreate}, 730 {name: "action update", given: []byte(`{"action": "update"}`), expected: ActionUpdate}, 731 {name: "no action", given: []byte("{}"), expected: ActionCreateOrUpdate}, 732 {name: "unknown", given: []byte(`{"action": "unknown"}`), expected: ActionCreateOrUpdate, expectErr: true}, 733 } 734 735 for _, test := range tests { 736 t.Run(test.name, func(t *testing.T) { 737 738 var request CreateConsumerRequest 739 err := json.Unmarshal(test.given, &request) 740 fmt.Printf("given: %v, expected: %v\n", test.expectErr, err) 741 if !test.expectErr { 742 require_NoError(t, err) 743 } else { 744 require_Error(t, err) 745 } 746 require_True(t, test.expected == request.Action) 747 }) 748 } 749 } 750 751 func TestJetStreamConsumerMultipleFiltersLastPerSubject(t *testing.T) { 752 c := createJetStreamClusterExplicit(t, "R3S", 3) 753 defer c.shutdown() 754 755 nc, js := jsClientConnect(t, c.randomServer()) 756 defer nc.Close() 757 758 _, error := js.AddStream(&nats.StreamConfig{ 759 Name: "TEST", 760 Subjects: []string{"one", "two"}, 761 Replicas: 3, 762 }) 763 require_NoError(t, error) 764 765 sendStreamMsg(t, nc, "one", "1") 766 sendStreamMsg(t, nc, "one", "2") 767 sendStreamMsg(t, nc, "one", "3") 768 sendStreamMsg(t, nc, "two", "1") 769 sendStreamMsg(t, nc, "two", "2") 770 sendStreamMsg(t, nc, "two", "3") 771 772 _, err := js.AddConsumer("TEST", &nats.ConsumerConfig{ 773 Name: "C", 774 FilterSubjects: []string{"one", "two"}, 775 DeliverPolicy: nats.DeliverLastPerSubjectPolicy, 776 Replicas: 3, 777 DeliverSubject: "deliver", 778 }) 779 require_NoError(t, err) 780 781 consumer, err := js.SubscribeSync("", nats.Bind("TEST", "C")) 782 require_NoError(t, err) 783 784 // expect last message for subject "one" 785 msg, err := consumer.NextMsg(time.Second) 786 require_NoError(t, err) 787 require_Equal(t, "3", string(msg.Data)) 788 require_Equal(t, "one", msg.Subject) 789 790 // expect last message for subject "two" 791 msg, err = consumer.NextMsg(time.Second) 792 require_NoError(t, err) 793 require_Equal(t, "3", string(msg.Data)) 794 require_Equal(t, "two", msg.Subject) 795 796 } 797 798 func consumerWithFilterSubjects(filterSubjects []string) *consumer { 799 c := consumer{} 800 for _, filter := range filterSubjects { 801 sub := &subjectFilter{ 802 subject: filter, 803 hasWildcard: subjectHasWildcard(filter), 804 tokenizedSubject: tokenizeSubjectIntoSlice(nil, filter), 805 } 806 c.subjf = append(c.subjf, sub) 807 } 808 809 return &c 810 } 811 812 func filterSubjects(n int) []string { 813 fs := make([]string, 0, n) 814 for { 815 literals := []string{"foo", "bar", nuid.Next(), "xyz", "abcdef"} 816 fs = append(fs, strings.Join(literals, ".")) 817 if len(fs) == n { 818 return fs 819 } 820 // Create more filterSubjects by going through the literals and replacing one with the '*' wildcard. 821 l := len(literals) 822 for i := 0; i < l; i++ { 823 e := make([]string, l) 824 for j := 0; j < l; j++ { 825 if j == i { 826 e[j] = "*" 827 } else { 828 e[j] = literals[j] 829 } 830 } 831 fs = append(fs, strings.Join(e, ".")) 832 if len(fs) == n { 833 return fs 834 } 835 } 836 } 837 } 838 839 func TestJetStreamConsumerIsFilteredMatch(t *testing.T) { 840 for _, test := range []struct { 841 name string 842 filterSubjects []string 843 subject string 844 result bool 845 }{ 846 {"no filter", []string{}, "foo.bar", true}, 847 {"literal match", []string{"foo.baz", "foo.bar"}, "foo.bar", true}, 848 {"literal mismatch", []string{"foo.baz", "foo.bar"}, "foo.ban", false}, 849 {"wildcard > match", []string{"bar.>", "foo.>"}, "foo.bar", true}, 850 {"wildcard > match", []string{"bar.>", "foo.>"}, "bar.foo", true}, 851 {"wildcard > mismatch", []string{"bar.>", "foo.>"}, "baz.foo", false}, 852 {"wildcard * match", []string{"bar.*", "foo.*"}, "foo.bar", true}, 853 {"wildcard * match", []string{"bar.*", "foo.*"}, "bar.foo", true}, 854 {"wildcard * mismatch", []string{"bar.*", "foo.*"}, "baz.foo", false}, 855 {"wildcard * match", []string{"foo.*.x", "foo.*.y"}, "foo.bar.x", true}, 856 {"wildcard * match", []string{"foo.*.x", "foo.*.y", "foo.*.z"}, "foo.bar.z", true}, 857 {"many mismatch", filterSubjects(100), "foo.bar.do.not.match.any.filter.subject", false}, 858 {"many match", filterSubjects(100), "foo.bar.12345.xyz.abcdef", true}, // will be matched by "foo.bar.*.xyz.abcdef" 859 } { 860 test := test 861 862 t.Run(test.name, func(t *testing.T) { 863 t.Parallel() 864 865 c := consumerWithFilterSubjects(test.filterSubjects) 866 if res := c.isFilteredMatch(test.subject); res != test.result { 867 t.Fatalf("Subject %q filtered match of %v, should be %v, got %v", 868 test.subject, test.filterSubjects, test.result, res) 869 } 870 }) 871 } 872 } 873 874 func TestJetStreamConsumerIsEqualOrSubsetMatch(t *testing.T) { 875 for _, test := range []struct { 876 name string 877 filterSubjects []string 878 subject string 879 result bool 880 }{ 881 {"no filter", []string{}, "foo.bar", false}, 882 {"literal match", []string{"foo.baz", "foo.bar"}, "foo.bar", true}, 883 {"literal mismatch", []string{"foo.baz", "foo.bar"}, "foo.ban", false}, 884 {"literal match", []string{"bar.>", "foo.>"}, "foo.>", true}, 885 {"subset match", []string{"bar.foo.>", "foo.bar.>"}, "bar.>", true}, 886 {"subset mismatch", []string{"bar.>", "foo.>"}, "baz.foo.>", false}, 887 {"literal match", filterSubjects(100), "foo.bar.*.xyz.abcdef", true}, 888 {"subset match", filterSubjects(100), "foo.bar.>", true}, 889 } { 890 test := test 891 892 t.Run(test.name, func(t *testing.T) { 893 t.Parallel() 894 895 c := consumerWithFilterSubjects(test.filterSubjects) 896 if res := c.isEqualOrSubsetMatch(test.subject); res != test.result { 897 t.Fatalf("Subject %q subset match of %v, should be %v, got %v", 898 test.subject, test.filterSubjects, test.result, res) 899 } 900 }) 901 } 902 } 903 904 func Benchmark____JetStreamConsumerIsFilteredMatch(b *testing.B) { 905 subject := "foo.bar.do.not.match.any.filter.subject" 906 for n := 1; n <= 1024; n *= 2 { 907 name := fmt.Sprintf("%d filter subjects", int(n)) 908 c := consumerWithFilterSubjects(filterSubjects(int(n))) 909 b.Run(name, func(b *testing.B) { 910 c.isFilteredMatch(subject) 911 }) 912 } 913 }