github.com/m3db/m3@v1.5.0/src/metrics/rules/mapping_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 "strings" 25 "testing" 26 "time" 27 28 "github.com/m3db/m3/src/metrics/aggregation" 29 "github.com/m3db/m3/src/metrics/errors" 30 "github.com/m3db/m3/src/metrics/filters" 31 "github.com/m3db/m3/src/metrics/generated/proto/aggregationpb" 32 "github.com/m3db/m3/src/metrics/generated/proto/metricpb" 33 "github.com/m3db/m3/src/metrics/generated/proto/policypb" 34 "github.com/m3db/m3/src/metrics/generated/proto/rulepb" 35 "github.com/m3db/m3/src/metrics/policy" 36 "github.com/m3db/m3/src/metrics/rules/view" 37 "github.com/m3db/m3/src/query/models" 38 xtime "github.com/m3db/m3/src/x/time" 39 40 "github.com/google/go-cmp/cmp" 41 "github.com/google/go-cmp/cmp/cmpopts" 42 "github.com/stretchr/testify/require" 43 ) 44 45 var ( 46 testMappingRuleSnapshot1V1Proto = &rulepb.MappingRuleSnapshot{ 47 Name: "foo", 48 Tombstoned: false, 49 CutoverNanos: 12345000000, 50 Filter: "tag1:value1 tag2:value2", 51 Policies: []*policypb.Policy{ 52 &policypb.Policy{ 53 StoragePolicy: &policypb.StoragePolicy{ 54 Resolution: policypb.Resolution{ 55 WindowSize: int64(10 * time.Second), 56 Precision: int64(time.Second), 57 }, 58 Retention: policypb.Retention{ 59 Period: int64(24 * time.Hour), 60 }, 61 }, 62 }, 63 }, 64 DropPolicy: policypb.DropPolicy_NONE, 65 LastUpdatedAtNanos: 12345000000, 66 LastUpdatedBy: "someone", 67 } 68 testMappingRuleSnapshot2V1Proto = &rulepb.MappingRuleSnapshot{ 69 Name: "bar", 70 Tombstoned: true, 71 CutoverNanos: 67890000000, 72 Filter: "tag3:value3 tag4:value4", 73 Policies: []*policypb.Policy{ 74 &policypb.Policy{ 75 StoragePolicy: &policypb.StoragePolicy{ 76 Resolution: policypb.Resolution{ 77 WindowSize: int64(time.Minute), 78 Precision: int64(time.Minute), 79 }, 80 Retention: policypb.Retention{ 81 Period: int64(24 * time.Hour), 82 }, 83 }, 84 AggregationTypes: []aggregationpb.AggregationType{ 85 aggregationpb.AggregationType_MEAN, 86 }, 87 }, 88 &policypb.Policy{ 89 StoragePolicy: &policypb.StoragePolicy{ 90 Resolution: policypb.Resolution{ 91 WindowSize: int64(5 * time.Minute), 92 Precision: int64(time.Minute), 93 }, 94 Retention: policypb.Retention{ 95 Period: int64(48 * time.Hour), 96 }, 97 }, 98 AggregationTypes: []aggregationpb.AggregationType{ 99 aggregationpb.AggregationType_MEAN, 100 }, 101 }, 102 }, 103 DropPolicy: policypb.DropPolicy_NONE, 104 LastUpdatedAtNanos: 67890000000, 105 LastUpdatedBy: "someone-else", 106 } 107 testMappingRuleSnapshot3V2Proto = &rulepb.MappingRuleSnapshot{ 108 Name: "foo", 109 Tombstoned: false, 110 CutoverNanos: 12345000000, 111 Filter: "tag1:value1 tag2:value2", 112 LastUpdatedAtNanos: 12345000000, 113 LastUpdatedBy: "someone", 114 StoragePolicies: []*policypb.StoragePolicy{ 115 &policypb.StoragePolicy{ 116 Resolution: policypb.Resolution{ 117 WindowSize: 10 * time.Second.Nanoseconds(), 118 Precision: time.Second.Nanoseconds(), 119 }, 120 Retention: policypb.Retention{ 121 Period: 24 * time.Hour.Nanoseconds(), 122 }, 123 }, 124 &policypb.StoragePolicy{ 125 Resolution: policypb.Resolution{ 126 WindowSize: time.Minute.Nanoseconds(), 127 Precision: time.Minute.Nanoseconds(), 128 }, 129 Retention: policypb.Retention{ 130 Period: 720 * time.Hour.Nanoseconds(), 131 }, 132 }, 133 &policypb.StoragePolicy{ 134 Resolution: policypb.Resolution{ 135 WindowSize: time.Hour.Nanoseconds(), 136 Precision: time.Hour.Nanoseconds(), 137 }, 138 Retention: policypb.Retention{ 139 Period: 365 * 24 * time.Hour.Nanoseconds(), 140 }, 141 }, 142 }, 143 DropPolicy: policypb.DropPolicy_NONE, 144 Tags: []*metricpb.Tag{}, 145 } 146 testMappingRuleSnapshot4V2Proto = &rulepb.MappingRuleSnapshot{ 147 Name: "bar", 148 Tombstoned: true, 149 CutoverNanos: 67890000000, 150 Filter: "tag3:value3 tag4:value4", 151 LastUpdatedAtNanos: 67890000000, 152 LastUpdatedBy: "someone-else", 153 AggregationTypes: []aggregationpb.AggregationType{ 154 aggregationpb.AggregationType_MIN, 155 aggregationpb.AggregationType_MAX, 156 }, 157 StoragePolicies: []*policypb.StoragePolicy{ 158 &policypb.StoragePolicy{ 159 Resolution: policypb.Resolution{ 160 WindowSize: 10 * time.Minute.Nanoseconds(), 161 Precision: time.Minute.Nanoseconds(), 162 }, 163 Retention: policypb.Retention{ 164 Period: 1800 * time.Hour.Nanoseconds(), 165 }, 166 }, 167 }, 168 DropPolicy: policypb.DropPolicy_NONE, 169 Tags: []*metricpb.Tag{}, 170 } 171 testMappingRuleSnapshot5V2Proto = &rulepb.MappingRuleSnapshot{ 172 Name: "foo", 173 Tombstoned: false, 174 CutoverNanos: 12345000000, 175 Filter: "tag1:value1 tag2:value2", 176 LastUpdatedAtNanos: 12345000000, 177 LastUpdatedBy: "someone", 178 StoragePolicies: []*policypb.StoragePolicy{}, 179 DropPolicy: policypb.DropPolicy_DROP_MUST, 180 Tags: []*metricpb.Tag{}, 181 } 182 testMappingRuleSnapshot6V2Proto = &rulepb.MappingRuleSnapshot{ 183 Name: "foo", 184 Tombstoned: false, 185 CutoverNanos: 67890000000, 186 Filter: "tag1:value1 tag2:value2", 187 LastUpdatedAtNanos: 67890000000, 188 LastUpdatedBy: "someone-else", 189 StoragePolicies: []*policypb.StoragePolicy{}, 190 DropPolicy: policypb.DropPolicy_DROP_IF_ONLY_MATCH, 191 Tags: []*metricpb.Tag{}, 192 } 193 testMappingRule1V1Proto = &rulepb.MappingRule{ 194 Uuid: "12669817-13ae-40e6-ba2f-33087b262c68", 195 Snapshots: []*rulepb.MappingRuleSnapshot{ 196 testMappingRuleSnapshot1V1Proto, 197 testMappingRuleSnapshot2V1Proto, 198 }, 199 } 200 testMappingRule2V2Proto = &rulepb.MappingRule{ 201 Uuid: "12669817-13ae-40e6-ba2f-33087b262c68", 202 Snapshots: []*rulepb.MappingRuleSnapshot{ 203 testMappingRuleSnapshot3V2Proto, 204 testMappingRuleSnapshot4V2Proto, 205 }, 206 } 207 testMappingRule3V2Proto = &rulepb.MappingRule{ 208 Uuid: "12669817-13ae-40e6-ba2f-33087b262c68", 209 Snapshots: []*rulepb.MappingRuleSnapshot{ 210 testMappingRuleSnapshot5V2Proto, 211 testMappingRuleSnapshot6V2Proto, 212 }, 213 } 214 testMappingRuleSnapshot1 = &mappingRuleSnapshot{ 215 name: "foo", 216 tombstoned: false, 217 cutoverNanos: 12345000000, 218 rawFilter: "tag1:value1 tag2:value2", 219 aggregationID: aggregation.DefaultID, 220 storagePolicies: policy.StoragePolicies{ 221 policy.NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour), 222 }, 223 dropPolicy: policy.DropNone, 224 lastUpdatedAtNanos: 12345000000, 225 lastUpdatedBy: "someone", 226 tags: []models.Tag{}, 227 } 228 testMappingRuleSnapshot2 = &mappingRuleSnapshot{ 229 name: "bar", 230 tombstoned: true, 231 cutoverNanos: 67890000000, 232 rawFilter: "tag3:value3 tag4:value4", 233 aggregationID: aggregation.MustCompressTypes(aggregation.Mean), 234 storagePolicies: policy.StoragePolicies{ 235 policy.NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour), 236 policy.NewStoragePolicy(5*time.Minute, xtime.Minute, 48*time.Hour), 237 }, 238 dropPolicy: policy.DropNone, 239 lastUpdatedAtNanos: 67890000000, 240 lastUpdatedBy: "someone-else", 241 tags: []models.Tag{}, 242 } 243 testMappingRuleSnapshot3 = &mappingRuleSnapshot{ 244 name: "foo", 245 tombstoned: false, 246 cutoverNanos: 12345000000, 247 rawFilter: "tag1:value1 tag2:value2", 248 aggregationID: aggregation.DefaultID, 249 storagePolicies: policy.StoragePolicies{ 250 policy.NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour), 251 policy.NewStoragePolicy(time.Minute, xtime.Minute, 720*time.Hour), 252 policy.NewStoragePolicy(time.Hour, xtime.Hour, 365*24*time.Hour), 253 }, 254 dropPolicy: policy.DropNone, 255 lastUpdatedAtNanos: 12345000000, 256 lastUpdatedBy: "someone", 257 tags: []models.Tag{}, 258 } 259 testMappingRuleSnapshot4 = &mappingRuleSnapshot{ 260 name: "bar", 261 tombstoned: true, 262 cutoverNanos: 67890000000, 263 rawFilter: "tag3:value3 tag4:value4", 264 aggregationID: aggregation.MustCompressTypes(aggregation.Min, aggregation.Max), 265 storagePolicies: policy.StoragePolicies{ 266 policy.NewStoragePolicy(10*time.Minute, xtime.Minute, 1800*time.Hour), 267 }, 268 dropPolicy: policy.DropNone, 269 lastUpdatedAtNanos: 67890000000, 270 lastUpdatedBy: "someone-else", 271 tags: []models.Tag{}, 272 } 273 testMappingRuleSnapshot5 = &mappingRuleSnapshot{ 274 name: "foo", 275 tombstoned: false, 276 cutoverNanos: 12345000000, 277 rawFilter: "tag1:value1 tag2:value2", 278 aggregationID: aggregation.DefaultID, 279 storagePolicies: policy.StoragePolicies{}, 280 dropPolicy: policy.DropMust, 281 lastUpdatedAtNanos: 12345000000, 282 lastUpdatedBy: "someone", 283 tags: []models.Tag{}, 284 } 285 testMappingRuleSnapshot6 = &mappingRuleSnapshot{ 286 name: "foo", 287 tombstoned: false, 288 cutoverNanos: 67890000000, 289 rawFilter: "tag1:value1 tag2:value2", 290 aggregationID: aggregation.DefaultID, 291 storagePolicies: policy.StoragePolicies{}, 292 dropPolicy: policy.DropIfOnlyMatch, 293 lastUpdatedAtNanos: 67890000000, 294 lastUpdatedBy: "someone-else", 295 tags: []models.Tag{}, 296 } 297 testMappingRule1 = &mappingRule{ 298 uuid: "12669817-13ae-40e6-ba2f-33087b262c68", 299 snapshots: []*mappingRuleSnapshot{ 300 testMappingRuleSnapshot1, 301 testMappingRuleSnapshot2, 302 }, 303 } 304 testMappingRule2 = &mappingRule{ 305 uuid: "12669817-13ae-40e6-ba2f-33087b262c68", 306 snapshots: []*mappingRuleSnapshot{ 307 testMappingRuleSnapshot3, 308 testMappingRuleSnapshot4, 309 }, 310 } 311 testMappingRule3 = &mappingRule{ 312 uuid: "12669817-13ae-40e6-ba2f-33087b262c68", 313 snapshots: []*mappingRuleSnapshot{ 314 testMappingRuleSnapshot5, 315 testMappingRuleSnapshot6, 316 }, 317 } 318 testMappingRuleSnapshotCmpOpts = []cmp.Option{ 319 cmp.AllowUnexported(mappingRuleSnapshot{}), 320 cmpopts.IgnoreInterfaces(struct{ filters.TagsFilter }{}), 321 } 322 testMappingRuleCmpOpts = []cmp.Option{ 323 cmp.AllowUnexported(mappingRule{}), 324 cmp.AllowUnexported(mappingRuleSnapshot{}), 325 cmpopts.IgnoreInterfaces(struct{ filters.TagsFilter }{}), 326 } 327 ) 328 329 func TestNewMappingRuleSnapshotFromProtoNilProto(t *testing.T) { 330 _, err := newMappingRuleSnapshotFromProto(nil, testTagsFilterOptions()) 331 require.Equal(t, errNilMappingRuleSnapshotProto, err) 332 } 333 334 func TestNewMappingRuleSnapshotFromV1ProtoInvalidProto(t *testing.T) { 335 proto := &rulepb.MappingRuleSnapshot{ 336 Policies: []*policypb.Policy{ 337 &policypb.Policy{}, 338 }, 339 } 340 _, err := newMappingRuleSnapshotFromProto(proto, testTagsFilterOptions()) 341 require.Error(t, err) 342 } 343 344 func TestNewMappingRuleSnapshotFromV1Proto(t *testing.T) { 345 filterOpts := testTagsFilterOptions() 346 inputs := []*rulepb.MappingRuleSnapshot{ 347 testMappingRuleSnapshot1V1Proto, 348 testMappingRuleSnapshot2V1Proto, 349 } 350 expected := []*mappingRuleSnapshot{ 351 testMappingRuleSnapshot1, 352 testMappingRuleSnapshot2, 353 } 354 for i, input := range inputs { 355 res, err := newMappingRuleSnapshotFromProto(input, filterOpts) 356 require.NoError(t, err) 357 require.True(t, cmp.Equal(expected[i], res, testMappingRuleSnapshotCmpOpts...)) 358 require.NotNil(t, res.filter) 359 } 360 } 361 362 func TestNewMappingRuleSnapshotFromV2ProtoInvalidProto(t *testing.T) { 363 filterOpts := testTagsFilterOptions() 364 proto := &rulepb.MappingRuleSnapshot{ 365 AggregationTypes: []aggregationpb.AggregationType{ 366 aggregationpb.AggregationType_UNKNOWN, 367 }, 368 } 369 _, err := newMappingRuleSnapshotFromProto(proto, filterOpts) 370 require.Error(t, err) 371 } 372 373 func TestNewMappingRuleSnapshotFromV2Proto(t *testing.T) { 374 filterOpts := testTagsFilterOptions() 375 inputs := []*rulepb.MappingRuleSnapshot{ 376 testMappingRuleSnapshot3V2Proto, 377 testMappingRuleSnapshot4V2Proto, 378 testMappingRuleSnapshot5V2Proto, 379 testMappingRuleSnapshot6V2Proto, 380 } 381 expected := []*mappingRuleSnapshot{ 382 testMappingRuleSnapshot3, 383 testMappingRuleSnapshot4, 384 testMappingRuleSnapshot5, 385 testMappingRuleSnapshot6, 386 } 387 for i, input := range inputs { 388 res, err := newMappingRuleSnapshotFromProto(input, filterOpts) 389 require.NoError(t, err) 390 require.True(t, cmp.Equal(expected[i], res, testMappingRuleSnapshotCmpOpts...)) 391 require.NotNil(t, res.filter) 392 } 393 } 394 395 func TestNewMappingRuleSnapshotFromProtoTombstoned(t *testing.T) { 396 filterOpts := testTagsFilterOptions() 397 input := &rulepb.MappingRuleSnapshot{ 398 Name: "foo", 399 Tombstoned: true, 400 CutoverNanos: 12345000000, 401 Filter: "tag1:value1 tag2:value2", 402 LastUpdatedAtNanos: 12345000000, 403 LastUpdatedBy: "someone", 404 Tags: []*metricpb.Tag{}, 405 } 406 res, err := newMappingRuleSnapshotFromProto(input, filterOpts) 407 require.NoError(t, err) 408 409 expected := &mappingRuleSnapshot{ 410 name: "foo", 411 tombstoned: true, 412 cutoverNanos: 12345000000, 413 rawFilter: "tag1:value1 tag2:value2", 414 aggregationID: aggregation.DefaultID, 415 lastUpdatedAtNanos: 12345000000, 416 lastUpdatedBy: "someone", 417 tags: []models.Tag{}, 418 } 419 require.True(t, cmp.Equal(expected, res, testMappingRuleSnapshotCmpOpts...)) 420 require.NotNil(t, res.filter) 421 } 422 423 func TestNewMappingRuleSnapshotNoStoragePoliciesAndDropPolicy(t *testing.T) { 424 proto := &rulepb.MappingRuleSnapshot{} 425 _, err := newMappingRuleSnapshotFromProto(proto, testTagsFilterOptions()) 426 require.Equal(t, errNoStoragePoliciesAndDropPolicyInMappingRuleSnapshot, err) 427 } 428 429 func TestNewMappingRuleSnapshotStoragePoliciesAndDropPolicy(t *testing.T) { 430 proto := &rulepb.MappingRuleSnapshot{ 431 StoragePolicies: []*policypb.StoragePolicy{ 432 &policypb.StoragePolicy{ 433 Resolution: policypb.Resolution{ 434 WindowSize: 10 * time.Second.Nanoseconds(), 435 Precision: time.Second.Nanoseconds(), 436 }, 437 Retention: policypb.Retention{ 438 Period: 24 * time.Hour.Nanoseconds(), 439 }, 440 }, 441 }, 442 DropPolicy: policypb.DropPolicy_DROP_MUST, 443 } 444 _, err := newMappingRuleSnapshotFromProto(proto, testTagsFilterOptions()) 445 require.Equal(t, errStoragePoliciesAndDropPolicyInMappingRuleSnapshot, err) 446 } 447 448 func TestNewMappingRuleSnapshotInvalidDropPolicy(t *testing.T) { 449 proto := &rulepb.MappingRuleSnapshot{ 450 DropPolicy: policypb.DropPolicy(-1), 451 } 452 _, err := newMappingRuleSnapshotFromProto(proto, testTagsFilterOptions()) 453 require.Equal(t, errInvalidDropPolicyInMappRuleSnapshot, err) 454 } 455 456 func TestNewMappingRuleSnapshotFromFields(t *testing.T) { 457 res, err := newMappingRuleSnapshotFromFields( 458 testMappingRuleSnapshot3.name, 459 testMappingRuleSnapshot3.cutoverNanos, 460 testMappingRuleSnapshot3.filter, 461 testMappingRuleSnapshot3.rawFilter, 462 testMappingRuleSnapshot3.aggregationID, 463 testMappingRuleSnapshot3.storagePolicies, 464 testMappingRuleSnapshot3.dropPolicy, 465 testMappingRuleSnapshot3.tags, 466 testMappingRuleSnapshot3.lastUpdatedAtNanos, 467 testMappingRuleSnapshot3.lastUpdatedBy, 468 ) 469 require.NoError(t, err) 470 require.True(t, cmp.Equal(testMappingRuleSnapshot3, res, testMappingRuleSnapshotCmpOpts...)) 471 } 472 473 func TestNewMappingRuleSnapshotFromFieldsValidationError(t *testing.T) { 474 badFilters := []string{ 475 "tag3:", 476 "tag3:*a*b*c*d", 477 "ab[cd", 478 } 479 480 for _, f := range badFilters { 481 _, err := newMappingRuleSnapshotFromFields( 482 "bar", 483 12345000000, 484 nil, 485 f, 486 aggregation.DefaultID, 487 nil, 488 policy.DropNone, 489 nil, 490 1234, 491 "test_user", 492 ) 493 require.Error(t, err) 494 _, ok := err.(errors.ValidationError) 495 require.True(t, ok) 496 } 497 } 498 499 func TestMappingRuleSnapshotProto(t *testing.T) { 500 snapshots := []*mappingRuleSnapshot{ 501 testMappingRuleSnapshot3, 502 testMappingRuleSnapshot4, 503 } 504 expected := []*rulepb.MappingRuleSnapshot{ 505 testMappingRuleSnapshot3V2Proto, 506 testMappingRuleSnapshot4V2Proto, 507 } 508 for i, snapshot := range snapshots { 509 proto, err := snapshot.proto() 510 require.NoError(t, err) 511 require.Equal(t, expected[i], proto) 512 } 513 } 514 515 func TestNewMappingRuleFromProtoNilProto(t *testing.T) { 516 _, err := newMappingRuleFromProto(nil, testTagsFilterOptions()) 517 require.Equal(t, errNilMappingRuleProto, err) 518 } 519 520 func TestNewMappingRuleFromProtoValidProto(t *testing.T) { 521 filterOpts := testTagsFilterOptions() 522 inputs := []*rulepb.MappingRule{ 523 testMappingRule1V1Proto, 524 testMappingRule2V2Proto, 525 } 526 expected := []*mappingRule{ 527 testMappingRule1, 528 testMappingRule2, 529 } 530 for i, input := range inputs { 531 res, err := newMappingRuleFromProto(input, filterOpts) 532 require.NoError(t, err) 533 require.True(t, cmp.Equal(expected[i], res, testMappingRuleCmpOpts...)) 534 } 535 } 536 537 func TestMappingRuleClone(t *testing.T) { 538 inputs := []*mappingRule{ 539 testMappingRule1, 540 testMappingRule2, 541 testMappingRule3, 542 } 543 for _, input := range inputs { 544 cloned := input.clone() 545 require.True(t, cmp.Equal(&cloned, input, testMappingRuleCmpOpts...)) 546 547 // Asserting that modifying the clone doesn't modify the original mapping rule. 548 cloned2 := input.clone() 549 require.True(t, cmp.Equal(&cloned2, input, testMappingRuleCmpOpts...)) 550 cloned2.snapshots[0].tombstoned = true 551 require.False(t, cmp.Equal(&cloned2, input, testMappingRuleCmpOpts...)) 552 require.True(t, cmp.Equal(&cloned, input, testMappingRuleCmpOpts...)) 553 } 554 } 555 556 func TestMappingRuleProto(t *testing.T) { 557 inputs := []*mappingRule{ 558 testMappingRule2, 559 testMappingRule3, 560 } 561 expected := []*rulepb.MappingRule{ 562 testMappingRule2V2Proto, 563 testMappingRule3V2Proto, 564 } 565 for i, input := range inputs { 566 res, err := input.proto() 567 require.NoError(t, err) 568 require.Equal(t, expected[i], res) 569 } 570 } 571 572 func TestMappingRuleActiveSnapshotNotFound(t *testing.T) { 573 require.Nil(t, testMappingRule2.activeSnapshot(0)) 574 } 575 576 func TestMappingRuleActiveSnapshotFound(t *testing.T) { 577 require.Equal(t, testMappingRule2.snapshots[1], testMappingRule2.activeSnapshot(100000000000)) 578 } 579 580 func TestMappingRuleActiveRuleNotFound(t *testing.T) { 581 require.Equal(t, testMappingRule2, testMappingRule2.activeRule(0)) 582 } 583 584 func TestMappingRuleActiveRuleFound(t *testing.T) { 585 expected := &mappingRule{ 586 uuid: testMappingRule2.uuid, 587 snapshots: testMappingRule2.snapshots[1:], 588 } 589 require.Equal(t, expected, testMappingRule2.activeRule(100000000000)) 590 } 591 592 func TestMappingNameNoSnapshot(t *testing.T) { 593 rr := mappingRule{ 594 uuid: "blah", 595 snapshots: []*mappingRuleSnapshot{}, 596 } 597 _, err := rr.name() 598 require.Equal(t, errNoRuleSnapshots, err) 599 } 600 601 func TestMappingTombstonedNoSnapshot(t *testing.T) { 602 rr := mappingRule{ 603 uuid: "blah", 604 snapshots: []*mappingRuleSnapshot{}, 605 } 606 require.True(t, rr.tombstoned()) 607 } 608 609 func TestMappingTombstoned(t *testing.T) { 610 require.True(t, testMappingRule2.tombstoned()) 611 } 612 613 func TestMappingRuleMarkTombstoned(t *testing.T) { 614 proto := &rulepb.MappingRule{ 615 Uuid: "12669817-13ae-40e6-ba2f-33087b262c68", 616 Snapshots: []*rulepb.MappingRuleSnapshot{ 617 testMappingRuleSnapshot3V2Proto, 618 }, 619 } 620 rr, err := newMappingRuleFromProto(proto, testTagsFilterOptions()) 621 require.NoError(t, err) 622 623 meta := UpdateMetadata{ 624 cutoverNanos: 67890000000, 625 updatedAtNanos: 10000, 626 updatedBy: "john", 627 } 628 require.NoError(t, rr.markTombstoned(meta)) 629 require.Equal(t, 2, len(rr.snapshots)) 630 require.True(t, cmp.Equal(testMappingRuleSnapshot3, rr.snapshots[0], testMappingRuleSnapshotCmpOpts...)) 631 632 expected := &mappingRuleSnapshot{ 633 name: "foo", 634 tombstoned: true, 635 cutoverNanos: 67890000000, 636 rawFilter: "tag1:value1 tag2:value2", 637 lastUpdatedAtNanos: 10000, 638 lastUpdatedBy: "john", 639 tags: []models.Tag{}, 640 } 641 require.True(t, cmp.Equal(expected, rr.snapshots[1], testMappingRuleSnapshotCmpOpts...)) 642 } 643 644 func TestMappingRuleMarkTombstonedNoSnapshots(t *testing.T) { 645 rr := &mappingRule{} 646 require.Error(t, rr.markTombstoned(UpdateMetadata{})) 647 } 648 649 func TestMappingRuleMarkTombstonedAlreadyTombstoned(t *testing.T) { 650 err := testMappingRule2.markTombstoned(UpdateMetadata{}) 651 require.Error(t, err) 652 require.True(t, strings.Contains(err.Error(), "bar is already tombstoned")) 653 } 654 655 func TestMappingRuleMappingRuleView(t *testing.T) { 656 res, err := testMappingRule2.mappingRuleView(1) 657 require.NoError(t, err) 658 659 expected := view.MappingRule{ 660 ID: "12669817-13ae-40e6-ba2f-33087b262c68", 661 Name: "bar", 662 Tombstoned: true, 663 CutoverMillis: 67890, 664 Filter: "tag3:value3 tag4:value4", 665 AggregationID: aggregation.MustCompressTypes(aggregation.Min, aggregation.Max), 666 StoragePolicies: policy.StoragePolicies{ 667 policy.NewStoragePolicy(10*time.Minute, xtime.Minute, 1800*time.Hour), 668 }, 669 LastUpdatedAtMillis: 67890, 670 LastUpdatedBy: "someone-else", 671 DropPolicy: res.DropPolicy, 672 Tags: []models.Tag{}, 673 } 674 require.Equal(t, expected, res) 675 } 676 677 func TestNewMappingRuleViewError(t *testing.T) { 678 badIndices := []int{-2, 2, 30} 679 for _, i := range badIndices { 680 _, err := testMappingRule2.mappingRuleView(i) 681 require.Equal(t, errMappingRuleSnapshotIndexOutOfRange, err) 682 } 683 } 684 685 func TestNewMappingRuleHistory(t *testing.T) { 686 history, err := testMappingRule2.history() 687 require.NoError(t, err) 688 689 expected := []view.MappingRule{ 690 { 691 ID: "12669817-13ae-40e6-ba2f-33087b262c68", 692 Name: "bar", 693 Tombstoned: true, 694 CutoverMillis: 67890, 695 Filter: "tag3:value3 tag4:value4", 696 AggregationID: aggregation.MustCompressTypes(aggregation.Min, aggregation.Max), 697 StoragePolicies: policy.StoragePolicies{ 698 policy.NewStoragePolicy(10*time.Minute, xtime.Minute, 1800*time.Hour), 699 }, 700 LastUpdatedAtMillis: 67890, 701 LastUpdatedBy: "someone-else", 702 Tags: []models.Tag{}, 703 }, 704 { 705 ID: "12669817-13ae-40e6-ba2f-33087b262c68", 706 Name: "foo", 707 Tombstoned: false, 708 CutoverMillis: 12345, 709 Filter: "tag1:value1 tag2:value2", 710 AggregationID: aggregation.DefaultID, 711 StoragePolicies: policy.StoragePolicies{ 712 policy.NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour), 713 policy.NewStoragePolicy(time.Minute, xtime.Minute, 720*time.Hour), 714 policy.NewStoragePolicy(time.Hour, xtime.Hour, 365*24*time.Hour), 715 }, 716 LastUpdatedAtMillis: 12345, 717 LastUpdatedBy: "someone", 718 Tags: []models.Tag{}, 719 }, 720 } 721 require.Equal(t, expected, history) 722 }