github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/metrics/rules/namespace_test.go (about) 1 // Copyright (c) 2017 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 rules 22 23 import ( 24 "testing" 25 26 "github.com/m3db/m3/src/metrics/generated/proto/rulepb" 27 "github.com/m3db/m3/src/metrics/rules/view" 28 29 "github.com/stretchr/testify/require" 30 ) 31 32 func TestNewNamespaceSnapshotFromNilProto(t *testing.T) { 33 _, err := newNamespaceSnapshot(nil) 34 require.Equal(t, err, errNilNamespaceSnapshotProto) 35 } 36 37 func TestNewNamespaceSnapshotFromValidProto(t *testing.T) { 38 snapshot, err := newNamespaceSnapshot(&rulepb.NamespaceSnapshot{ 39 ForRulesetVersion: 123, 40 Tombstoned: true, 41 LastUpdatedAtNanos: 456, 42 LastUpdatedBy: "someone", 43 }) 44 require.NoError(t, err) 45 require.Equal(t, 123, snapshot.ForRuleSetVersion()) 46 require.Equal(t, true, snapshot.Tombstoned()) 47 require.Equal(t, int64(456), snapshot.LastUpdatedAtNanos()) 48 require.Equal(t, "someone", snapshot.LastUpdatedBy()) 49 } 50 51 func TestNamespaceSnapshotToProto(t *testing.T) { 52 snapshot := NamespaceSnapshot{ 53 forRuleSetVersion: 123, 54 tombstoned: true, 55 lastUpdatedAtNanos: 456, 56 lastUpdatedBy: "someone", 57 } 58 proto := snapshot.Proto() 59 require.Equal(t, int32(123), proto.ForRulesetVersion) 60 require.Equal(t, true, proto.Tombstoned) 61 require.Equal(t, int64(456), proto.LastUpdatedAtNanos) 62 require.Equal(t, "someone", proto.LastUpdatedBy) 63 } 64 65 func TestNamespaceSnapshotRoundTrip(t *testing.T) { 66 proto := &rulepb.NamespaceSnapshot{ 67 ForRulesetVersion: 123, 68 Tombstoned: true, 69 LastUpdatedAtNanos: 456, 70 LastUpdatedBy: "someone", 71 } 72 snapshot, err := newNamespaceSnapshot(proto) 73 require.NoError(t, err) 74 res := snapshot.Proto() 75 require.Equal(t, proto, res) 76 } 77 78 func TestNamespaceView(t *testing.T) { 79 ns := Namespace{ 80 name: b("foo"), 81 snapshots: []NamespaceSnapshot{ 82 { 83 forRuleSetVersion: 123, 84 tombstoned: false, 85 lastUpdatedAtNanos: 456000000, 86 lastUpdatedBy: "someone", 87 }, 88 { 89 forRuleSetVersion: 456, 90 tombstoned: true, 91 lastUpdatedAtNanos: 7890000000, 92 lastUpdatedBy: "someone else", 93 }, 94 }, 95 } 96 97 expected := []view.Namespace{ 98 { 99 ID: "foo", 100 ForRuleSetVersion: 123, 101 Tombstoned: false, 102 LastUpdatedAtMillis: 456, 103 LastUpdatedBy: "someone", 104 }, 105 { 106 ID: "foo", 107 ForRuleSetVersion: 456, 108 Tombstoned: true, 109 LastUpdatedAtMillis: 7890, 110 LastUpdatedBy: "someone else", 111 }, 112 } 113 for i := range ns.snapshots { 114 res, err := ns.NamespaceView(i) 115 require.NoError(t, err) 116 require.Equal(t, expected[i], res) 117 } 118 } 119 120 func TestNamespaceViewError(t *testing.T) { 121 n := Namespace{ 122 name: b("test"), 123 snapshots: []NamespaceSnapshot{ 124 NamespaceSnapshot{forRuleSetVersion: 3, tombstoned: false}, 125 NamespaceSnapshot{forRuleSetVersion: 4, tombstoned: true}, 126 }, 127 } 128 129 badIdx := []int{-2, 2, 30} 130 for _, i := range badIdx { 131 _, err := n.NamespaceView(i) 132 require.Equal(t, errNamespaceSnapshotIndexOutOfRange, err) 133 } 134 } 135 136 func TestNamespaceClone(t *testing.T) { 137 ns := Namespace{ 138 name: b("foo"), 139 snapshots: []NamespaceSnapshot{ 140 { 141 forRuleSetVersion: 123, 142 tombstoned: false, 143 lastUpdatedAtNanos: 456, 144 lastUpdatedBy: "someone", 145 }, 146 { 147 forRuleSetVersion: 456, 148 tombstoned: true, 149 lastUpdatedAtNanos: 7890, 150 lastUpdatedBy: "someone else", 151 }, 152 }, 153 } 154 155 // Assert a clone looks the same as the original. 156 nsClone := ns.clone() 157 require.Equal(t, ns, nsClone) 158 159 // Assert changing the clone does not change the original. 160 nsClone.snapshots[0].forRuleSetVersion = 2934 161 require.NotEqual(t, ns, nsClone) 162 } 163 164 func TestNewNamespaceFromNilProto(t *testing.T) { 165 _, err := newNamespace(nil) 166 require.Equal(t, err, errNilNamespaceProto) 167 } 168 169 func TestNewNamespaceFromValidProto(t *testing.T) { 170 ns, err := newNamespace(&rulepb.Namespace{ 171 Name: "foo", 172 Snapshots: []*rulepb.NamespaceSnapshot{ 173 &rulepb.NamespaceSnapshot{ 174 ForRulesetVersion: 123, 175 Tombstoned: false, 176 LastUpdatedAtNanos: 456, 177 LastUpdatedBy: "someone", 178 }, 179 &rulepb.NamespaceSnapshot{ 180 ForRulesetVersion: 456, 181 Tombstoned: true, 182 LastUpdatedAtNanos: 7890, 183 LastUpdatedBy: "someone else", 184 }, 185 }, 186 }) 187 expected := []NamespaceSnapshot{ 188 { 189 forRuleSetVersion: 123, 190 tombstoned: false, 191 lastUpdatedAtNanos: 456, 192 lastUpdatedBy: "someone", 193 }, 194 { 195 forRuleSetVersion: 456, 196 tombstoned: true, 197 lastUpdatedAtNanos: 7890, 198 lastUpdatedBy: "someone else", 199 }, 200 } 201 require.NoError(t, err) 202 require.Equal(t, []byte("foo"), ns.Name()) 203 require.Equal(t, expected, ns.Snapshots()) 204 } 205 206 func TestNamespaceToProto(t *testing.T) { 207 ns := Namespace{ 208 name: b("foo"), 209 snapshots: []NamespaceSnapshot{ 210 { 211 forRuleSetVersion: 123, 212 tombstoned: false, 213 lastUpdatedAtNanos: 456, 214 lastUpdatedBy: "someone", 215 }, 216 { 217 forRuleSetVersion: 456, 218 tombstoned: true, 219 lastUpdatedAtNanos: 7890, 220 lastUpdatedBy: "someone else", 221 }, 222 }, 223 } 224 res, err := ns.Proto() 225 require.NoError(t, err) 226 227 expected := &rulepb.Namespace{ 228 Name: "foo", 229 Snapshots: []*rulepb.NamespaceSnapshot{ 230 &rulepb.NamespaceSnapshot{ 231 ForRulesetVersion: 123, 232 Tombstoned: false, 233 LastUpdatedAtNanos: 456, 234 LastUpdatedBy: "someone", 235 }, 236 &rulepb.NamespaceSnapshot{ 237 ForRulesetVersion: 456, 238 Tombstoned: true, 239 LastUpdatedAtNanos: 7890, 240 LastUpdatedBy: "someone else", 241 }, 242 }, 243 } 244 require.Equal(t, expected, res) 245 } 246 247 func TestNamespaceToProtoNoSnapshots(t *testing.T) { 248 badNs := Namespace{ 249 name: []byte("foo"), 250 } 251 res, err := badNs.Proto() 252 require.Equal(t, errNilNamespaceSnapshot, err) 253 require.Nil(t, res) 254 } 255 256 func TestNamespaceRoundTrip(t *testing.T) { 257 testNs := &rulepb.Namespace{ 258 Name: "foo", 259 Snapshots: []*rulepb.NamespaceSnapshot{ 260 &rulepb.NamespaceSnapshot{ 261 ForRulesetVersion: 123, 262 Tombstoned: false, 263 LastUpdatedAtNanos: 456, 264 LastUpdatedBy: "someone", 265 }, 266 &rulepb.NamespaceSnapshot{ 267 ForRulesetVersion: 456, 268 Tombstoned: true, 269 LastUpdatedAtNanos: 7890, 270 LastUpdatedBy: "someone else", 271 }, 272 }, 273 } 274 275 ns, err := newNamespace(testNs) 276 require.NoError(t, err) 277 278 res, err := ns.Proto() 279 require.NoError(t, err) 280 281 require.Equal(t, testNs, res) 282 } 283 284 func TestNamespaceMarkTombstoned(t *testing.T) { 285 ns := Namespace{ 286 name: b("foo"), 287 snapshots: []NamespaceSnapshot{ 288 { 289 forRuleSetVersion: 1, 290 tombstoned: false, 291 lastUpdatedAtNanos: 456, 292 lastUpdatedBy: "someone", 293 }, 294 }, 295 } 296 meta := UpdateMetadata{updatedAtNanos: 789, updatedBy: "someone else"} 297 require.NoError(t, ns.markTombstoned(4, meta)) 298 require.True(t, ns.Tombstoned()) 299 300 expected := Namespace{ 301 name: b("foo"), 302 snapshots: []NamespaceSnapshot{ 303 { 304 forRuleSetVersion: 1, 305 tombstoned: false, 306 lastUpdatedAtNanos: 456, 307 lastUpdatedBy: "someone", 308 }, 309 { 310 forRuleSetVersion: 4, 311 tombstoned: true, 312 lastUpdatedAtNanos: 789, 313 lastUpdatedBy: "someone else", 314 }, 315 }, 316 } 317 require.Equal(t, expected, ns) 318 } 319 320 func TestNamespaceMarkTombstonedAlreadyTombstoned(t *testing.T) { 321 ns := Namespace{ 322 name: b("foo"), 323 snapshots: []NamespaceSnapshot{ 324 { 325 forRuleSetVersion: 1, 326 tombstoned: false, 327 lastUpdatedAtNanos: 456, 328 lastUpdatedBy: "someone", 329 }, 330 { 331 forRuleSetVersion: 4, 332 tombstoned: true, 333 lastUpdatedAtNanos: 789, 334 lastUpdatedBy: "someone else", 335 }, 336 }, 337 } 338 require.Equal(t, errNamespaceAlreadyTombstoned, ns.markTombstoned(4, UpdateMetadata{})) 339 } 340 341 func TestNamespaceRevive(t *testing.T) { 342 ns := Namespace{ 343 name: b("foo"), 344 snapshots: []NamespaceSnapshot{ 345 { 346 forRuleSetVersion: 1, 347 tombstoned: false, 348 lastUpdatedAtNanos: 456, 349 lastUpdatedBy: "someone", 350 }, 351 { 352 forRuleSetVersion: 4, 353 tombstoned: true, 354 lastUpdatedAtNanos: 789, 355 lastUpdatedBy: "someone else", 356 }, 357 }, 358 } 359 meta := UpdateMetadata{updatedAtNanos: 2378, updatedBy: "john"} 360 require.NoError(t, ns.revive(meta)) 361 362 expected := Namespace{ 363 name: b("foo"), 364 snapshots: []NamespaceSnapshot{ 365 { 366 forRuleSetVersion: 1, 367 tombstoned: false, 368 lastUpdatedAtNanos: 456, 369 lastUpdatedBy: "someone", 370 }, 371 { 372 forRuleSetVersion: 4, 373 tombstoned: true, 374 lastUpdatedAtNanos: 789, 375 lastUpdatedBy: "someone else", 376 }, 377 { 378 forRuleSetVersion: 5, 379 tombstoned: false, 380 lastUpdatedAtNanos: 2378, 381 lastUpdatedBy: "john", 382 }, 383 }, 384 } 385 require.Equal(t, expected, ns) 386 } 387 388 func TestNamespaceReviveNotTombstoned(t *testing.T) { 389 ns := Namespace{ 390 name: b("foo"), 391 snapshots: []NamespaceSnapshot{ 392 { 393 forRuleSetVersion: 1, 394 tombstoned: false, 395 lastUpdatedAtNanos: 456, 396 lastUpdatedBy: "someone", 397 }, 398 }, 399 } 400 require.Equal(t, errNamespaceNotTombstoned, ns.revive(UpdateMetadata{})) 401 } 402 403 func TestNamespaceReviveNoSnapshots(t *testing.T) { 404 ns := Namespace{ 405 name: b("foo"), 406 snapshots: []NamespaceSnapshot{}, 407 } 408 require.Equal(t, errNoNamespaceSnapshots, ns.revive(UpdateMetadata{})) 409 } 410 411 func TestNamespaceTombstoned(t *testing.T) { 412 inputs := []struct { 413 ns Namespace 414 expected bool 415 }{ 416 { 417 ns: Namespace{name: b("foo")}, 418 expected: true, 419 }, 420 { 421 ns: Namespace{ 422 name: b("foo"), 423 snapshots: []NamespaceSnapshot{ 424 { 425 forRuleSetVersion: 1, 426 tombstoned: false, 427 lastUpdatedAtNanos: 456, 428 lastUpdatedBy: "someone", 429 }, 430 }, 431 }, 432 expected: false, 433 }, 434 { 435 ns: Namespace{ 436 name: b("foo"), 437 snapshots: []NamespaceSnapshot{ 438 { 439 forRuleSetVersion: 1, 440 tombstoned: false, 441 lastUpdatedAtNanos: 456, 442 lastUpdatedBy: "someone", 443 }, 444 { 445 forRuleSetVersion: 4, 446 tombstoned: true, 447 lastUpdatedAtNanos: 789, 448 lastUpdatedBy: "someone else", 449 }, 450 }, 451 }, 452 expected: true, 453 }, 454 } 455 456 for _, input := range inputs { 457 require.Equal(t, input.expected, input.ns.Tombstoned()) 458 } 459 } 460 461 func TestNamespacesView(t *testing.T) { 462 nss := Namespaces{ 463 version: 1, 464 namespaces: []Namespace{ 465 { 466 name: b("foo"), 467 snapshots: []NamespaceSnapshot{ 468 { 469 forRuleSetVersion: 123, 470 tombstoned: false, 471 lastUpdatedAtNanos: 456000000, 472 lastUpdatedBy: "someone", 473 }, 474 { 475 forRuleSetVersion: 456, 476 tombstoned: true, 477 lastUpdatedAtNanos: 7890000000, 478 lastUpdatedBy: "someone else", 479 }, 480 }, 481 }, 482 { 483 name: b("bar"), 484 snapshots: []NamespaceSnapshot{ 485 { 486 forRuleSetVersion: 789, 487 tombstoned: false, 488 lastUpdatedAtNanos: 12345000000, 489 lastUpdatedBy: "john", 490 }, 491 }, 492 }, 493 }, 494 } 495 496 expected := view.Namespaces{ 497 Version: 1, 498 Namespaces: []view.Namespace{ 499 { 500 ID: "foo", 501 ForRuleSetVersion: 456, 502 Tombstoned: true, 503 LastUpdatedAtMillis: 7890, 504 LastUpdatedBy: "someone else", 505 }, 506 { 507 ID: "bar", 508 ForRuleSetVersion: 789, 509 Tombstoned: false, 510 LastUpdatedAtMillis: 12345, 511 LastUpdatedBy: "john", 512 }, 513 }, 514 } 515 516 actual, err := nss.NamespacesView() 517 require.NoError(t, err) 518 require.Equal(t, expected, actual) 519 } 520 521 func TestNamespacesClone(t *testing.T) { 522 nss := Namespaces{ 523 version: 1, 524 namespaces: []Namespace{ 525 { 526 name: b("foo"), 527 snapshots: []NamespaceSnapshot{ 528 { 529 forRuleSetVersion: 123, 530 tombstoned: false, 531 lastUpdatedAtNanos: 456, 532 lastUpdatedBy: "someone", 533 }, 534 { 535 forRuleSetVersion: 456, 536 tombstoned: true, 537 lastUpdatedAtNanos: 7890, 538 lastUpdatedBy: "someone else", 539 }, 540 }, 541 }, 542 { 543 name: b("bar"), 544 snapshots: []NamespaceSnapshot{ 545 { 546 forRuleSetVersion: 789, 547 tombstoned: false, 548 lastUpdatedAtNanos: 12345, 549 lastUpdatedBy: "john", 550 }, 551 }, 552 }, 553 }, 554 } 555 556 // Assert clone looks the same as the original. 557 nssClone := nss.Clone() 558 require.Equal(t, nss, nssClone) 559 require.False(t, &nss.namespaces[0] == &nssClone.namespaces[0]) 560 561 // Assert changing the clone does not affect the original. 562 nssClone.Namespaces()[0].Snapshots()[0].forRuleSetVersion = 384 563 require.NotEqual(t, nss, nssClone) 564 } 565 566 func TestNewNamespacesFromNilProto(t *testing.T) { 567 _, err := NewNamespaces(1, nil) 568 require.Equal(t, errNilNamespacesProto, err) 569 } 570 571 func TestNewNamespacesFromValidProto(t *testing.T) { 572 ns, err := NewNamespaces(1, &rulepb.Namespaces{ 573 Namespaces: []*rulepb.Namespace{ 574 &rulepb.Namespace{ 575 Name: "foo", 576 Snapshots: []*rulepb.NamespaceSnapshot{ 577 &rulepb.NamespaceSnapshot{ 578 ForRulesetVersion: 123, 579 Tombstoned: false, 580 LastUpdatedAtNanos: 456, 581 LastUpdatedBy: "someone", 582 }, 583 &rulepb.NamespaceSnapshot{ 584 ForRulesetVersion: 456, 585 Tombstoned: true, 586 LastUpdatedAtNanos: 7890, 587 LastUpdatedBy: "someone else", 588 }, 589 }, 590 }, 591 &rulepb.Namespace{ 592 Name: "bar", 593 Snapshots: []*rulepb.NamespaceSnapshot{ 594 &rulepb.NamespaceSnapshot{ 595 ForRulesetVersion: 789, 596 Tombstoned: false, 597 LastUpdatedAtNanos: 12345, 598 LastUpdatedBy: "john", 599 }, 600 &rulepb.NamespaceSnapshot{ 601 ForRulesetVersion: 1000, 602 Tombstoned: true, 603 LastUpdatedAtNanos: 67890, 604 LastUpdatedBy: "joe", 605 }, 606 }, 607 }, 608 }, 609 }) 610 require.NoError(t, err) 611 require.Equal(t, 1, ns.Version()) 612 expected := []Namespace{ 613 { 614 name: b("foo"), 615 snapshots: []NamespaceSnapshot{ 616 { 617 forRuleSetVersion: 123, 618 tombstoned: false, 619 lastUpdatedAtNanos: 456, 620 lastUpdatedBy: "someone", 621 }, 622 { 623 forRuleSetVersion: 456, 624 tombstoned: true, 625 lastUpdatedAtNanos: 7890, 626 lastUpdatedBy: "someone else", 627 }, 628 }, 629 }, 630 { 631 name: b("bar"), 632 snapshots: []NamespaceSnapshot{ 633 { 634 forRuleSetVersion: 789, 635 tombstoned: false, 636 lastUpdatedAtNanos: 12345, 637 lastUpdatedBy: "john", 638 }, 639 { 640 forRuleSetVersion: 1000, 641 tombstoned: true, 642 lastUpdatedAtNanos: 67890, 643 lastUpdatedBy: "joe", 644 }, 645 }, 646 }, 647 } 648 require.Equal(t, expected, ns.Namespaces()) 649 } 650 651 func TestNamespacesRoundTrip(t *testing.T) { 652 testNss := &rulepb.Namespaces{ 653 Namespaces: []*rulepb.Namespace{ 654 &rulepb.Namespace{ 655 Name: "foo", 656 Snapshots: []*rulepb.NamespaceSnapshot{ 657 &rulepb.NamespaceSnapshot{ 658 ForRulesetVersion: 123, 659 Tombstoned: false, 660 LastUpdatedAtNanos: 456, 661 LastUpdatedBy: "someone", 662 }, 663 &rulepb.NamespaceSnapshot{ 664 ForRulesetVersion: 456, 665 Tombstoned: true, 666 LastUpdatedAtNanos: 7890, 667 LastUpdatedBy: "someone else", 668 }, 669 }, 670 }, 671 &rulepb.Namespace{ 672 Name: "foo2", 673 Snapshots: []*rulepb.NamespaceSnapshot{ 674 &rulepb.NamespaceSnapshot{ 675 ForRulesetVersion: 789, 676 Tombstoned: false, 677 LastUpdatedAtNanos: 12345, 678 LastUpdatedBy: "john", 679 }, 680 &rulepb.NamespaceSnapshot{ 681 ForRulesetVersion: 1000, 682 Tombstoned: true, 683 LastUpdatedAtNanos: 67890, 684 LastUpdatedBy: "joe", 685 }, 686 }, 687 }, 688 }, 689 } 690 691 nss, err := NewNamespaces(1, testNss) 692 require.NoError(t, err) 693 694 res, err := nss.Proto() 695 require.NoError(t, err) 696 require.Equal(t, testNss, res) 697 } 698 699 func TestNamespacesNamespace(t *testing.T) { 700 nss := Namespaces{ 701 version: 1, 702 namespaces: []Namespace{ 703 { 704 name: b("foo"), 705 snapshots: []NamespaceSnapshot{ 706 { 707 forRuleSetVersion: 123, 708 tombstoned: false, 709 lastUpdatedAtNanos: 456, 710 lastUpdatedBy: "someone", 711 }, 712 { 713 forRuleSetVersion: 456, 714 tombstoned: true, 715 lastUpdatedAtNanos: 7890, 716 lastUpdatedBy: "someone else", 717 }, 718 }, 719 }, 720 { 721 name: b("bar"), 722 snapshots: []NamespaceSnapshot{ 723 { 724 forRuleSetVersion: 789, 725 tombstoned: false, 726 lastUpdatedAtNanos: 12345, 727 lastUpdatedBy: "john", 728 }, 729 }, 730 }, 731 }, 732 } 733 734 inputs := []string{"foo", "bar"} 735 for _, input := range inputs { 736 ns, err := nss.Namespace(input) 737 require.NoError(t, err) 738 require.Equal(t, string(ns.Name()), input) 739 } 740 } 741 742 func TestNamespacesNamespaceNotFound(t *testing.T) { 743 nss := Namespaces{ 744 version: 1, 745 namespaces: []Namespace{ 746 { 747 name: b("bar"), 748 snapshots: []NamespaceSnapshot{ 749 { 750 forRuleSetVersion: 789, 751 tombstoned: false, 752 lastUpdatedAtNanos: 12345, 753 lastUpdatedBy: "john", 754 }, 755 }, 756 }, 757 }, 758 } 759 _, err := nss.Namespace("foo") 760 require.Equal(t, errNamespaceNotFound, err) 761 } 762 763 func TestNamespacesNamespaceMultipleMatches(t *testing.T) { 764 nss := Namespaces{ 765 version: 1, 766 namespaces: []Namespace{ 767 { 768 name: b("bar"), 769 snapshots: []NamespaceSnapshot{ 770 { 771 forRuleSetVersion: 789, 772 tombstoned: false, 773 lastUpdatedAtNanos: 12345, 774 lastUpdatedBy: "john", 775 }, 776 }, 777 }, 778 { 779 name: b("bar"), 780 snapshots: []NamespaceSnapshot{ 781 { 782 forRuleSetVersion: 789, 783 tombstoned: false, 784 lastUpdatedAtNanos: 12345, 785 lastUpdatedBy: "john", 786 }, 787 }, 788 }, 789 }, 790 } 791 _, err := nss.Namespace("bar") 792 require.Equal(t, errMultipleNamespaceMatches, err) 793 } 794 795 func TestNamespacesAddNewNamespace(t *testing.T) { 796 nss := Namespaces{ 797 version: 1, 798 namespaces: []Namespace{ 799 { 800 name: b("foo"), 801 snapshots: []NamespaceSnapshot{ 802 { 803 forRuleSetVersion: 123, 804 tombstoned: false, 805 lastUpdatedAtNanos: 456, 806 lastUpdatedBy: "someone", 807 }, 808 { 809 forRuleSetVersion: 456, 810 tombstoned: true, 811 lastUpdatedAtNanos: 7890, 812 lastUpdatedBy: "someone else", 813 }, 814 }, 815 }, 816 }, 817 } 818 meta := UpdateMetadata{updatedAtNanos: 12345, updatedBy: "john"} 819 revived, err := nss.AddNamespace("bar", meta) 820 require.NoError(t, err) 821 require.False(t, revived) 822 823 expected := Namespaces{ 824 version: 1, 825 namespaces: []Namespace{ 826 { 827 name: b("foo"), 828 snapshots: []NamespaceSnapshot{ 829 { 830 forRuleSetVersion: 123, 831 tombstoned: false, 832 lastUpdatedAtNanos: 456, 833 lastUpdatedBy: "someone", 834 }, 835 { 836 forRuleSetVersion: 456, 837 tombstoned: true, 838 lastUpdatedAtNanos: 7890, 839 lastUpdatedBy: "someone else", 840 }, 841 }, 842 }, 843 { 844 name: b("bar"), 845 snapshots: []NamespaceSnapshot{ 846 { 847 forRuleSetVersion: 1, 848 tombstoned: false, 849 lastUpdatedAtNanos: 12345, 850 lastUpdatedBy: "john", 851 }, 852 }, 853 }, 854 }, 855 } 856 require.Equal(t, expected, nss) 857 } 858 859 func TestNamespacesAddTombstonedNamespace(t *testing.T) { 860 nss := Namespaces{ 861 version: 1, 862 namespaces: []Namespace{ 863 { 864 name: b("foo"), 865 snapshots: []NamespaceSnapshot{ 866 { 867 forRuleSetVersion: 123, 868 tombstoned: false, 869 lastUpdatedAtNanos: 456, 870 lastUpdatedBy: "someone", 871 }, 872 { 873 forRuleSetVersion: 456, 874 tombstoned: true, 875 lastUpdatedAtNanos: 7890, 876 lastUpdatedBy: "someone else", 877 }, 878 }, 879 }, 880 }, 881 } 882 883 meta := UpdateMetadata{updatedAtNanos: 12345, updatedBy: "john"} 884 revived, err := nss.AddNamespace("foo", meta) 885 require.NoError(t, err) 886 require.True(t, revived) 887 888 expected := Namespaces{ 889 version: 1, 890 namespaces: []Namespace{ 891 { 892 name: b("foo"), 893 snapshots: []NamespaceSnapshot{ 894 { 895 forRuleSetVersion: 123, 896 tombstoned: false, 897 lastUpdatedAtNanos: 456, 898 lastUpdatedBy: "someone", 899 }, 900 { 901 forRuleSetVersion: 456, 902 tombstoned: true, 903 lastUpdatedAtNanos: 7890, 904 lastUpdatedBy: "someone else", 905 }, 906 { 907 forRuleSetVersion: 457, 908 tombstoned: false, 909 lastUpdatedAtNanos: 12345, 910 lastUpdatedBy: "john", 911 }, 912 }, 913 }, 914 }, 915 } 916 require.Equal(t, expected, nss) 917 } 918 919 func TestNamespacesAddLiveNamespace(t *testing.T) { 920 nss := Namespaces{ 921 version: 1, 922 namespaces: []Namespace{ 923 { 924 name: b("foo"), 925 snapshots: []NamespaceSnapshot{ 926 { 927 forRuleSetVersion: 123, 928 tombstoned: false, 929 lastUpdatedAtNanos: 456, 930 lastUpdatedBy: "someone", 931 }, 932 }, 933 }, 934 }, 935 } 936 _, err := nss.AddNamespace("foo", UpdateMetadata{}) 937 require.Error(t, err) 938 } 939 940 func TestNamespacesDeleteNamespace(t *testing.T) { 941 nss := Namespaces{ 942 version: 1, 943 namespaces: []Namespace{ 944 { 945 name: b("foo"), 946 snapshots: []NamespaceSnapshot{ 947 { 948 forRuleSetVersion: 123, 949 tombstoned: false, 950 lastUpdatedAtNanos: 456, 951 lastUpdatedBy: "someone", 952 }, 953 }, 954 }, 955 { 956 name: b("bar"), 957 snapshots: []NamespaceSnapshot{ 958 { 959 forRuleSetVersion: 789, 960 tombstoned: false, 961 lastUpdatedAtNanos: 12345, 962 lastUpdatedBy: "john", 963 }, 964 }, 965 }, 966 }, 967 } 968 969 meta := UpdateMetadata{updatedAtNanos: 1000, updatedBy: "someone else"} 970 require.NoError(t, nss.DeleteNamespace("foo", 200, meta)) 971 972 expected := Namespaces{ 973 version: 1, 974 namespaces: []Namespace{ 975 { 976 name: b("foo"), 977 snapshots: []NamespaceSnapshot{ 978 { 979 forRuleSetVersion: 123, 980 tombstoned: false, 981 lastUpdatedAtNanos: 456, 982 lastUpdatedBy: "someone", 983 }, 984 { 985 forRuleSetVersion: 201, 986 tombstoned: true, 987 lastUpdatedAtNanos: 1000, 988 lastUpdatedBy: "someone else", 989 }, 990 }, 991 }, 992 { 993 name: b("bar"), 994 snapshots: []NamespaceSnapshot{ 995 { 996 forRuleSetVersion: 789, 997 tombstoned: false, 998 lastUpdatedAtNanos: 12345, 999 lastUpdatedBy: "john", 1000 }, 1001 }, 1002 }, 1003 }, 1004 } 1005 require.Equal(t, expected, nss) 1006 } 1007 1008 func TestNamespacesDeleteMissingNamespace(t *testing.T) { 1009 nss := Namespaces{ 1010 version: 1, 1011 namespaces: []Namespace{ 1012 { 1013 name: b("foo"), 1014 snapshots: []NamespaceSnapshot{ 1015 { 1016 forRuleSetVersion: 123, 1017 tombstoned: false, 1018 lastUpdatedAtNanos: 456, 1019 lastUpdatedBy: "someone", 1020 }, 1021 }, 1022 }, 1023 }, 1024 } 1025 require.Error(t, nss.DeleteNamespace("bar", 300, UpdateMetadata{})) 1026 } 1027 1028 func TestNamespacesDeleteTombstonedNamespace(t *testing.T) { 1029 nss := Namespaces{ 1030 version: 1, 1031 namespaces: []Namespace{ 1032 { 1033 name: b("foo"), 1034 snapshots: []NamespaceSnapshot{ 1035 { 1036 forRuleSetVersion: 123, 1037 tombstoned: false, 1038 lastUpdatedAtNanos: 456, 1039 lastUpdatedBy: "someone", 1040 }, 1041 { 1042 forRuleSetVersion: 201, 1043 tombstoned: true, 1044 lastUpdatedAtNanos: 1000, 1045 lastUpdatedBy: "someone else", 1046 }, 1047 }, 1048 }, 1049 }, 1050 } 1051 require.Error(t, nss.DeleteNamespace("foo", 300, UpdateMetadata{})) 1052 } 1053 1054 func TestNamespacesDeleteAndReviveNamespace(t *testing.T) { 1055 nss := Namespaces{ 1056 version: 1, 1057 namespaces: []Namespace{ 1058 { 1059 name: b("foo"), 1060 snapshots: []NamespaceSnapshot{ 1061 { 1062 forRuleSetVersion: 1, 1063 tombstoned: false, 1064 lastUpdatedAtNanos: 456, 1065 lastUpdatedBy: "someone", 1066 }, 1067 }, 1068 }, 1069 }, 1070 } 1071 1072 ns, err := nss.Namespace("foo") 1073 require.NoError(t, err) 1074 require.False(t, ns.Tombstoned()) 1075 require.Equal(t, len(ns.Snapshots()), 1) 1076 lastSnapshot := ns.Snapshots()[0] 1077 require.Equal(t, 1, lastSnapshot.ForRuleSetVersion()) 1078 require.False(t, lastSnapshot.Tombstoned()) 1079 require.Equal(t, int64(456), lastSnapshot.LastUpdatedAtNanos()) 1080 require.Equal(t, "someone", lastSnapshot.LastUpdatedBy()) 1081 1082 meta := UpdateMetadata{updatedAtNanos: 1000, updatedBy: "someone else"} 1083 err = nss.DeleteNamespace("foo", 4, meta) 1084 require.NoError(t, err) 1085 ns, err = nss.Namespace("foo") 1086 require.NoError(t, err) 1087 require.Equal(t, len(ns.snapshots), 2) 1088 require.Equal(t, 1, ns.Snapshots()[0].ForRuleSetVersion()) 1089 lastSnapshot = ns.Snapshots()[1] 1090 require.Equal(t, 5, lastSnapshot.ForRuleSetVersion()) 1091 require.True(t, lastSnapshot.Tombstoned()) 1092 require.Equal(t, int64(1000), lastSnapshot.LastUpdatedAtNanos()) 1093 require.Equal(t, "someone else", lastSnapshot.LastUpdatedBy()) 1094 1095 meta = UpdateMetadata{updatedAtNanos: 2000, updatedBy: "john"} 1096 revived, err := nss.AddNamespace("foo", meta) 1097 require.NoError(t, err) 1098 require.True(t, revived) 1099 ns, err = nss.Namespace("foo") 1100 require.NoError(t, err) 1101 require.False(t, ns.Tombstoned()) 1102 require.Equal(t, len(ns.snapshots), 3) 1103 require.Equal(t, 1, ns.Snapshots()[0].ForRuleSetVersion()) 1104 lastSnapshot = ns.Snapshots()[2] 1105 require.Equal(t, 6, lastSnapshot.ForRuleSetVersion()) 1106 require.False(t, lastSnapshot.Tombstoned()) 1107 require.Equal(t, int64(2000), lastSnapshot.LastUpdatedAtNanos()) 1108 require.Equal(t, "john", lastSnapshot.LastUpdatedBy()) 1109 }