github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/metrics/rules/ruleset_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 "bytes" 25 "strings" 26 "testing" 27 "time" 28 29 "github.com/m3db/m3/src/metrics/aggregation" 30 merrors "github.com/m3db/m3/src/metrics/errors" 31 "github.com/m3db/m3/src/metrics/filters" 32 "github.com/m3db/m3/src/metrics/generated/proto/aggregationpb" 33 "github.com/m3db/m3/src/metrics/generated/proto/metricpb" 34 "github.com/m3db/m3/src/metrics/generated/proto/pipelinepb" 35 "github.com/m3db/m3/src/metrics/generated/proto/policypb" 36 "github.com/m3db/m3/src/metrics/generated/proto/rulepb" 37 "github.com/m3db/m3/src/metrics/matcher/namespace" 38 "github.com/m3db/m3/src/metrics/metadata" 39 "github.com/m3db/m3/src/metrics/metric" 40 "github.com/m3db/m3/src/metrics/metric/id" 41 "github.com/m3db/m3/src/metrics/pipeline" 42 "github.com/m3db/m3/src/metrics/policy" 43 "github.com/m3db/m3/src/metrics/rules/view" 44 "github.com/m3db/m3/src/metrics/rules/view/changes" 45 xbytes "github.com/m3db/m3/src/metrics/x/bytes" 46 "github.com/m3db/m3/src/query/models" 47 xerrors "github.com/m3db/m3/src/x/errors" 48 xtime "github.com/m3db/m3/src/x/time" 49 50 "github.com/google/go-cmp/cmp" 51 "github.com/google/go-cmp/cmp/cmpopts" 52 "github.com/stretchr/testify/require" 53 ) 54 55 var ( 56 testUser = "test_user" 57 testActiveRuleSetCmpOpts = []cmp.Option{ 58 cmp.AllowUnexported(activeRuleSet{}), 59 cmp.AllowUnexported(mappingRule{}), 60 cmp.AllowUnexported(mappingRuleSnapshot{}), 61 cmp.AllowUnexported(rollupRule{}), 62 cmp.AllowUnexported(rollupRuleSnapshot{}), 63 cmpopts.IgnoreTypes( 64 activeRuleSet{}.tagsFilterOpts, 65 activeRuleSet{}.newRollupIDFn, 66 activeRuleSet{}.isRollupIDFn, 67 ), 68 cmpopts.IgnoreInterfaces(struct{ filters.TagsFilter }{}), 69 cmpopts.IgnoreInterfaces(struct{ aggregation.TypesOptions }{}), 70 } 71 testRuleSetCmpOpts = []cmp.Option{ 72 cmp.AllowUnexported(ruleSet{}), 73 cmp.AllowUnexported(mappingRule{}), 74 cmp.AllowUnexported(mappingRuleSnapshot{}), 75 cmp.AllowUnexported(rollupRule{}), 76 cmp.AllowUnexported(rollupRuleSnapshot{}), 77 cmpopts.IgnoreTypes( 78 ruleSet{}.tagsFilterOpts, 79 ruleSet{}.newRollupIDFn, 80 ruleSet{}.isRollupIDFn, 81 ), 82 cmpopts.IgnoreInterfaces(struct{ filters.TagsFilter }{}), 83 cmpopts.IgnoreInterfaces(struct{ aggregation.TypesOptions }{}), 84 } 85 ) 86 87 func TestRuleSetProperties(t *testing.T) { 88 opts := testRuleSetOptions() 89 version := 1 90 rs := &rulepb.RuleSet{ 91 Uuid: "ruleset", 92 Namespace: "namespace", 93 CreatedAtNanos: 1234, 94 LastUpdatedAtNanos: 5678, 95 Tombstoned: false, 96 CutoverNanos: 34923, 97 } 98 newRuleSet, err := NewRuleSetFromProto(version, rs, opts) 99 require.NoError(t, err) 100 ruleSet := newRuleSet.(*ruleSet) 101 102 require.Equal(t, "ruleset", ruleSet.uuid) 103 require.Equal(t, []byte("namespace"), ruleSet.Namespace()) 104 require.Equal(t, 1, ruleSet.Version()) 105 require.Equal(t, int64(34923), ruleSet.CutoverNanos()) 106 require.Equal(t, false, ruleSet.Tombstoned()) 107 } 108 109 func TestRuleSetActiveSet(t *testing.T) { 110 var ( 111 version = 1 112 proto = testRuleSetProto() 113 opts = testRuleSetOptions() 114 ) 115 res, err := NewRuleSetFromProto(version, proto, opts) 116 require.NoError(t, err) 117 rs := res.(*ruleSet) 118 119 inputs := []struct { 120 activeSetTimeNanos int64 121 expectedMappingRules []*mappingRule 122 expectedRollupRules []*rollupRule 123 }{ 124 { 125 activeSetTimeNanos: 0, 126 expectedMappingRules: rs.mappingRules, 127 expectedRollupRules: rs.rollupRules, 128 }, 129 { 130 activeSetTimeNanos: 30000, 131 expectedMappingRules: []*mappingRule{ 132 &mappingRule{ 133 uuid: rs.mappingRules[0].uuid, 134 snapshots: rs.mappingRules[0].snapshots[2:], 135 }, 136 &mappingRule{ 137 uuid: rs.mappingRules[1].uuid, 138 snapshots: rs.mappingRules[1].snapshots[1:], 139 }, 140 rs.mappingRules[2], 141 rs.mappingRules[3], 142 rs.mappingRules[4], 143 }, 144 expectedRollupRules: []*rollupRule{ 145 &rollupRule{ 146 uuid: rs.rollupRules[0].uuid, 147 snapshots: rs.rollupRules[0].snapshots[2:], 148 }, 149 &rollupRule{ 150 uuid: rs.rollupRules[1].uuid, 151 snapshots: rs.rollupRules[1].snapshots[1:], 152 }, 153 rs.rollupRules[2], 154 rs.rollupRules[3], 155 rs.rollupRules[4], 156 rs.rollupRules[5], 157 }, 158 }, 159 { 160 activeSetTimeNanos: 200000, 161 expectedMappingRules: []*mappingRule{ 162 &mappingRule{ 163 uuid: rs.mappingRules[0].uuid, 164 snapshots: rs.mappingRules[0].snapshots[2:], 165 }, 166 &mappingRule{ 167 uuid: rs.mappingRules[1].uuid, 168 snapshots: rs.mappingRules[1].snapshots[2:], 169 }, 170 &mappingRule{ 171 uuid: rs.mappingRules[2].uuid, 172 snapshots: rs.mappingRules[2].snapshots[1:], 173 }, 174 rs.mappingRules[3], 175 rs.mappingRules[4], 176 }, 177 expectedRollupRules: []*rollupRule{ 178 &rollupRule{ 179 uuid: rs.rollupRules[0].uuid, 180 snapshots: rs.rollupRules[0].snapshots[2:], 181 }, 182 &rollupRule{ 183 uuid: rs.rollupRules[1].uuid, 184 snapshots: rs.rollupRules[1].snapshots[2:], 185 }, 186 &rollupRule{ 187 uuid: rs.rollupRules[2].uuid, 188 snapshots: rs.rollupRules[2].snapshots[1:], 189 }, 190 rs.rollupRules[3], 191 rs.rollupRules[4], 192 rs.rollupRules[5], 193 }, 194 }, 195 } 196 197 for _, input := range inputs { 198 as := rs.ActiveSet(input.activeSetTimeNanos).(*activeRuleSet) 199 expected := newActiveRuleSet( 200 version, 201 input.expectedMappingRules, 202 input.expectedRollupRules, 203 rs.tagsFilterOpts, 204 rs.newRollupIDFn, 205 rs.isRollupIDFn, 206 ) 207 require.True(t, cmp.Equal(expected, as, testActiveRuleSetCmpOpts...)) 208 } 209 } 210 211 func TestNewRuleSetFromProtoToProtoRoundtrip(t *testing.T) { 212 var ( 213 version = 1 214 proto = testRuleSetProto() 215 opts = testRuleSetOptions() 216 ) 217 rs, err := NewRuleSetFromProto(version, proto, opts) 218 require.NoError(t, err) 219 res, err := rs.Proto() 220 require.NoError(t, err) 221 require.Equal(t, proto.MappingRules[0].Snapshots[0], res.MappingRules[0].Snapshots[0]) 222 require.Equal(t, proto, res) 223 } 224 225 func TestRuleSetMappingRules(t *testing.T) { 226 var ( 227 version = 1 228 proto = testRuleSetProto() 229 opts = testRuleSetOptions() 230 ) 231 res, err := NewRuleSetFromProto(version, proto, opts) 232 require.NoError(t, err) 233 rs := res.(*ruleSet) 234 235 mr, err := rs.MappingRules() 236 require.NoError(t, err) 237 require.True(t, len(mr) > 0) 238 for _, m := range rs.mappingRules { 239 require.Contains(t, mr, m.uuid) 240 mrv, err := m.mappingRuleView(len(m.snapshots) - 1) 241 require.NoError(t, err) 242 require.Equal(t, mr[m.uuid][0], mrv) 243 } 244 } 245 246 func TestRuleSetRollupRules(t *testing.T) { 247 var ( 248 version = 1 249 proto = testRuleSetProto() 250 opts = testRuleSetOptions() 251 ) 252 res, err := NewRuleSetFromProto(version, proto, opts) 253 require.NoError(t, err) 254 rs := res.(*ruleSet) 255 256 rr, err := rs.RollupRules() 257 require.NoError(t, err) 258 require.True(t, len(rr) > 0) 259 for _, r := range rs.rollupRules { 260 require.Contains(t, rr, r.uuid) 261 rrv, err := r.rollupRuleView(len(r.snapshots) - 1) 262 require.NoError(t, err) 263 require.Equal(t, rr[r.uuid][0], rrv) 264 } 265 } 266 267 func TestRuleSetLatest(t *testing.T) { 268 proto := &rulepb.RuleSet{ 269 Namespace: "testNamespace", 270 CutoverNanos: 998234000000, 271 MappingRules: testMappingRulesConfig(), 272 RollupRules: testRollupRulesConfig(), 273 } 274 rs, err := NewRuleSetFromProto(123, proto, testRuleSetOptions()) 275 require.NoError(t, err) 276 latest, err := rs.Latest() 277 require.NoError(t, err) 278 279 r1, err := pipeline.NewRollupOp( 280 pipeline.GroupByRollupType, 281 "rName1", 282 []string{"rtagName1", "rtagName2"}, 283 aggregation.DefaultID, 284 ) 285 require.NoError(t, err) 286 r3, err := pipeline.NewRollupOp( 287 pipeline.GroupByRollupType, 288 "rName3", 289 []string{"rtagName1", "rtagName2"}, 290 aggregation.DefaultID, 291 ) 292 require.NoError(t, err) 293 r4, err := pipeline.NewRollupOp( 294 pipeline.GroupByRollupType, 295 "rName4", 296 []string{"rtagName1", "rtagName2"}, 297 aggregation.DefaultID, 298 ) 299 require.NoError(t, err) 300 r5, err := pipeline.NewRollupOp( 301 pipeline.GroupByRollupType, 302 "rName5", 303 []string{"rtagName1"}, 304 aggregation.DefaultID, 305 ) 306 require.NoError(t, err) 307 r6, err := pipeline.NewRollupOp( 308 pipeline.GroupByRollupType, 309 "rName6", 310 []string{"rtagName1", "rtagName2"}, 311 aggregation.DefaultID, 312 ) 313 require.NoError(t, err) 314 315 expected := view.RuleSet{ 316 Namespace: "testNamespace", 317 Version: 123, 318 CutoverMillis: 998234, 319 MappingRules: []view.MappingRule{ 320 { 321 ID: "mappingRule1", 322 Name: "mappingRule1.snapshot3", 323 Tombstoned: false, 324 Filter: "mtagName1:mtagValue1", 325 AggregationID: aggregation.DefaultID, 326 StoragePolicies: policy.StoragePolicies{ 327 policy.NewStoragePolicy(30*time.Second, xtime.Second, 6*time.Hour), 328 }, 329 Tags: []models.Tag{}, 330 }, 331 { 332 ID: "mappingRule3", 333 Name: "mappingRule3.snapshot2", 334 Tombstoned: false, 335 Filter: "mtagName1:mtagValue1", 336 AggregationID: aggregation.DefaultID, 337 StoragePolicies: policy.StoragePolicies{ 338 policy.NewStoragePolicy(10*time.Second, xtime.Second, 2*time.Hour), 339 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 340 }, 341 Tags: []models.Tag{}, 342 }, 343 { 344 ID: "mappingRule4", 345 Name: "mappingRule4.snapshot1", 346 Tombstoned: false, 347 Filter: "mtagName1:mtagValue2", 348 AggregationID: aggregation.MustCompressTypes(aggregation.P999), 349 StoragePolicies: policy.StoragePolicies{ 350 policy.NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour), 351 }, 352 Tags: []models.Tag{}, 353 }, 354 { 355 ID: "mappingRule5", 356 Name: "mappingRule5.snapshot1", 357 Tombstoned: false, 358 LastUpdatedBy: "test", 359 Filter: "mtagName1:mtagValue1", 360 AggregationID: aggregation.DefaultID, 361 StoragePolicies: policy.StoragePolicies{ 362 policy.NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour), 363 }, 364 Tags: []models.Tag{}, 365 }, 366 }, 367 RollupRules: []view.RollupRule{ 368 { 369 ID: "rollupRule1", 370 Name: "rollupRule1.snapshot3", 371 Tombstoned: false, 372 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 373 Tags: []models.Tag{}, 374 Targets: []view.RollupTarget{ 375 { 376 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 377 { 378 Type: pipeline.RollupOpType, 379 Rollup: r1, 380 }, 381 }), 382 StoragePolicies: policy.StoragePolicies{ 383 policy.NewStoragePolicy(30*time.Second, xtime.Second, 6*time.Hour), 384 }, 385 }, 386 }, 387 }, 388 { 389 ID: "rollupRule3", 390 Name: "rollupRule3.snapshot2", 391 Tombstoned: false, 392 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 393 Tags: []models.Tag{}, 394 Targets: []view.RollupTarget{ 395 { 396 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 397 { 398 Type: pipeline.RollupOpType, 399 Rollup: r3, 400 }, 401 }), 402 StoragePolicies: policy.StoragePolicies{ 403 policy.NewStoragePolicy(10*time.Second, xtime.Second, 2*time.Hour), 404 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 405 }, 406 }, 407 }, 408 }, 409 { 410 ID: "rollupRule4", 411 Name: "rollupRule4.snapshot1", 412 Tombstoned: false, 413 Filter: "rtagName1:rtagValue2", 414 Tags: []models.Tag{}, 415 Targets: []view.RollupTarget{ 416 { 417 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 418 { 419 Type: pipeline.RollupOpType, 420 Rollup: r4, 421 }, 422 }), 423 StoragePolicies: policy.StoragePolicies{ 424 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 425 }, 426 }, 427 }, 428 }, 429 { 430 ID: "rollupRule5", 431 Name: "rollupRule5.snapshot1", 432 Tombstoned: false, 433 Filter: "rtagName1:rtagValue2", 434 Tags: []models.Tag{}, 435 Targets: []view.RollupTarget{ 436 { 437 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 438 { 439 Type: pipeline.RollupOpType, 440 Rollup: r5, 441 }, 442 }), 443 StoragePolicies: policy.StoragePolicies{ 444 policy.NewStoragePolicy(time.Second, xtime.Second, time.Minute), 445 }, 446 }, 447 }, 448 }, 449 { 450 ID: "rollupRule6", 451 Name: "rollupRule6.snapshot1", 452 Tombstoned: false, 453 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 454 Tags: []models.Tag{}, 455 Targets: []view.RollupTarget{ 456 { 457 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 458 { 459 Type: pipeline.RollupOpType, 460 Rollup: r6, 461 }, 462 }), 463 StoragePolicies: policy.StoragePolicies{ 464 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 465 }, 466 }, 467 }, 468 }, 469 }, 470 } 471 require.Equal(t, expected, latest) 472 } 473 474 func TestRuleSetClone(t *testing.T) { 475 var ( 476 version = 1 477 proto = testRuleSetProto() 478 opts = testRuleSetOptions() 479 ) 480 res, err := NewRuleSetFromProto(version, proto, opts) 481 require.NoError(t, err) 482 rs := res.(*ruleSet) 483 484 rsClone := rs.Clone().(*ruleSet) 485 require.True(t, cmp.Equal(rs, rsClone, testRuleSetCmpOpts...), cmp.Diff(rs, rsClone, testRuleSetCmpOpts...)) 486 for i, m := range rs.mappingRules { 487 require.False(t, m == rsClone.mappingRules[i]) 488 } 489 for i, r := range rs.rollupRules { 490 require.False(t, r == rsClone.rollupRules[i]) 491 } 492 493 rsClone.mappingRules = []*mappingRule{} 494 rsClone.rollupRules = []*rollupRule{} 495 require.NotEqual(t, rs.mappingRules, rsClone.mappingRules) 496 require.NotEqual(t, rs.rollupRules, rsClone.rollupRules) 497 } 498 499 func TestRuleSetAddMappingRuleInvalidFilter(t *testing.T) { 500 var ( 501 version = 1 502 proto = testRuleSetProto() 503 opts = testRuleSetOptions() 504 ) 505 res, err := NewRuleSetFromProto(version, proto, opts) 506 require.NoError(t, err) 507 rs := res.(*ruleSet) 508 509 view := view.MappingRule{ 510 Name: "testInvalidFilter", 511 Filter: "tag1:value1 tag2:abc[def", 512 StoragePolicies: policy.StoragePolicies{ 513 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 514 }, 515 } 516 helper := NewRuleSetUpdateHelper(10) 517 newID, err := rs.AddMappingRule(view, helper.NewUpdateMetadata(time.Now().UnixNano(), testUser)) 518 require.Error(t, err) 519 require.Empty(t, newID) 520 require.True(t, strings.Contains(err.Error(), "cannot add rule testInvalidFilter:")) 521 _, ok := xerrors.InnerError(err).(merrors.ValidationError) 522 require.True(t, ok) 523 } 524 525 func TestRuleSetAddMappingRuleNewRule(t *testing.T) { 526 var ( 527 version = 1 528 proto = testRuleSetProto() 529 opts = testRuleSetOptions() 530 ) 531 res, err := NewRuleSetFromProto(version, proto, opts) 532 require.NoError(t, err) 533 rs := res.(*ruleSet) 534 535 _, err = rs.getMappingRuleByName("foo") 536 require.Equal(t, errRuleNotFound, err) 537 538 view := view.MappingRule{ 539 Name: "foo", 540 Filter: "tag1:value tag2:value", 541 StoragePolicies: policy.StoragePolicies{ 542 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 543 }, 544 } 545 nowNanos := time.Now().UnixNano() 546 helper := NewRuleSetUpdateHelper(10) 547 newID, err := rs.AddMappingRule(view, helper.NewUpdateMetadata(nowNanos, testUser)) 548 require.NoError(t, err) 549 mrs, err := rs.MappingRules() 550 require.NoError(t, err) 551 require.Contains(t, mrs, newID) 552 553 mr, err := rs.getMappingRuleByName("foo") 554 require.NoError(t, err) 555 556 expected := &mappingRuleSnapshot{ 557 name: "foo", 558 tombstoned: false, 559 cutoverNanos: nowNanos + 10, 560 rawFilter: "tag1:value tag2:value", 561 aggregationID: aggregation.DefaultID, 562 storagePolicies: policy.StoragePolicies{ 563 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 564 }, 565 lastUpdatedBy: testUser, 566 lastUpdatedAtNanos: nowNanos, 567 } 568 require.True(t, cmp.Equal(expected, mr.snapshots[len(mr.snapshots)-1], testMappingRuleSnapshotCmpOpts...)) 569 570 require.Equal(t, nowNanos+10, rs.cutoverNanos) 571 require.Equal(t, testUser, rs.lastUpdatedBy) 572 require.Equal(t, nowNanos, rs.lastUpdatedAtNanos) 573 } 574 575 func TestRuleSetAddMappingRuleDuplicateRule(t *testing.T) { 576 var ( 577 version = 1 578 proto = testRuleSetProto() 579 opts = testRuleSetOptions() 580 ) 581 res, err := NewRuleSetFromProto(version, proto, opts) 582 require.NoError(t, err) 583 rs := res.(*ruleSet) 584 585 mr, err := rs.getMappingRuleByName("mappingRule5.snapshot1") 586 require.NoError(t, err) 587 require.NotNil(t, mr) 588 589 view := view.MappingRule{ 590 Name: "mappingRule5.snapshot1", 591 Filter: "tag1:value tag2:value", 592 StoragePolicies: policy.StoragePolicies{ 593 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 594 }, 595 } 596 nowNanos := time.Now().UnixNano() 597 helper := NewRuleSetUpdateHelper(10) 598 newID, err := rs.AddMappingRule(view, helper.NewUpdateMetadata(nowNanos, testUser)) 599 require.Error(t, err) 600 require.Empty(t, newID) 601 err = xerrors.InnerError(err) 602 require.NotNil(t, err) 603 _, ok := err.(merrors.InvalidInputError) //nolint:errorlint 604 require.True(t, ok) 605 } 606 607 func TestRuleSetAddMappingRuleReviveRule(t *testing.T) { 608 var ( 609 version = 1 610 proto = testRuleSetProto() 611 opts = testRuleSetOptions() 612 ) 613 res, err := NewRuleSetFromProto(version, proto, opts) 614 require.NoError(t, err) 615 rs := res.(*ruleSet) 616 617 mr, err := rs.getMappingRuleByName("mappingRule2.snapshot3") 618 require.NoError(t, err) 619 require.NotNil(t, mr) 620 621 view := view.MappingRule{ 622 Name: "mappingRule2.snapshot3", 623 Filter: "test:bar", 624 AggregationID: aggregation.MustCompressTypes(aggregation.Sum), 625 StoragePolicies: policy.StoragePolicies{ 626 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 627 }, 628 } 629 nowNanos := time.Now().UnixNano() 630 helper := NewRuleSetUpdateHelper(10) 631 newID, err := rs.AddMappingRule(view, helper.NewUpdateMetadata(nowNanos, testUser)) 632 require.NoError(t, err) 633 mrs, err := rs.MappingRules() 634 require.NoError(t, err) 635 require.Contains(t, mrs, newID) 636 637 mr, err = rs.getMappingRuleByID(newID) 638 require.NoError(t, err) 639 require.Equal(t, mr.snapshots[len(mr.snapshots)-1].rawFilter, view.Filter) 640 641 expected := &mappingRuleSnapshot{ 642 name: "mappingRule2.snapshot3", 643 tombstoned: false, 644 cutoverNanos: nowNanos + 10, 645 rawFilter: "test:bar", 646 aggregationID: aggregation.MustCompressTypes(aggregation.Sum), 647 storagePolicies: policy.StoragePolicies{ 648 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 649 }, 650 lastUpdatedBy: testUser, 651 lastUpdatedAtNanos: nowNanos, 652 } 653 require.True(t, cmp.Equal(expected, mr.snapshots[len(mr.snapshots)-1], testMappingRuleSnapshotCmpOpts...)) 654 655 require.Equal(t, nowNanos+10, rs.cutoverNanos) 656 require.Equal(t, testUser, rs.lastUpdatedBy) 657 require.Equal(t, nowNanos, rs.lastUpdatedAtNanos) 658 } 659 660 func TestRuleSetUpdateMappingRule(t *testing.T) { 661 var ( 662 version = 1 663 proto = testRuleSetProto() 664 opts = testRuleSetOptions() 665 ) 666 res, err := NewRuleSetFromProto(version, proto, opts) 667 require.NoError(t, err) 668 rs := res.(*ruleSet) 669 670 mr, err := rs.getMappingRuleByID("mappingRule5") 671 require.NoError(t, err) 672 673 mrs, err := rs.MappingRules() 674 require.NoError(t, err) 675 require.Contains(t, mrs, "mappingRule5") 676 677 view := view.MappingRule{ 678 ID: "mappingRule5", 679 Name: "mappingRule5.snapshot2", 680 Filter: "tag3:value", 681 StoragePolicies: policy.StoragePolicies{ 682 policy.NewStoragePolicy(time.Second, xtime.Second, time.Hour), 683 }, 684 } 685 nowNanos := time.Now().UnixNano() 686 helper := NewRuleSetUpdateHelper(10) 687 err = rs.UpdateMappingRule(view, helper.NewUpdateMetadata(nowNanos, testUser)) 688 require.NoError(t, err) 689 690 r, err := rs.getMappingRuleByID(mr.uuid) 691 require.NoError(t, err) 692 693 mrs, err = rs.MappingRules() 694 require.NoError(t, err) 695 require.Contains(t, mrs, r.uuid) 696 697 expected := &mappingRuleSnapshot{ 698 name: "mappingRule5.snapshot2", 699 tombstoned: false, 700 cutoverNanos: nowNanos + 10, 701 rawFilter: "tag3:value", 702 aggregationID: aggregation.DefaultID, 703 storagePolicies: policy.StoragePolicies{ 704 policy.NewStoragePolicy(time.Second, xtime.Second, time.Hour), 705 }, 706 lastUpdatedBy: testUser, 707 lastUpdatedAtNanos: nowNanos, 708 } 709 require.True(t, cmp.Equal(expected, r.snapshots[len(mr.snapshots)-1], testMappingRuleSnapshotCmpOpts...)) 710 711 require.Equal(t, nowNanos+10, rs.cutoverNanos) 712 require.Equal(t, testUser, rs.lastUpdatedBy) 713 require.Equal(t, nowNanos, rs.lastUpdatedAtNanos) 714 } 715 716 func TestRuleSetDeleteMappingRule(t *testing.T) { 717 var ( 718 version = 1 719 proto = testRuleSetProto() 720 opts = testRuleSetOptions() 721 ) 722 res, err := NewRuleSetFromProto(version, proto, opts) 723 require.NoError(t, err) 724 rs := res.(*ruleSet) 725 726 mrs, err := rs.MappingRules() 727 require.NoError(t, err) 728 require.Contains(t, mrs, "mappingRule5") 729 730 m, err := rs.getMappingRuleByID("mappingRule5") 731 require.NoError(t, err) 732 require.NotNil(t, m) 733 734 nowNanos := time.Now().UnixNano() 735 helper := NewRuleSetUpdateHelper(10) 736 err = rs.DeleteMappingRule("mappingRule5", helper.NewUpdateMetadata(nowNanos, testUser)) 737 require.NoError(t, err) 738 739 m, err = rs.getMappingRuleByID("mappingRule5") 740 require.NoError(t, err) 741 require.True(t, m.tombstoned()) 742 require.Equal(t, nowNanos+10, m.snapshots[len(m.snapshots)-1].cutoverNanos) 743 require.Equal(t, aggregation.DefaultID, m.snapshots[len(m.snapshots)-1].aggregationID) 744 require.Nil(t, m.snapshots[len(m.snapshots)-1].storagePolicies) 745 746 mrs, err = rs.MappingRules() 747 require.NoError(t, err) 748 require.Contains(t, mrs, "mappingRule5") 749 } 750 751 func TestRuleSetAddRollupRuleNewRule(t *testing.T) { 752 var ( 753 version = 1 754 proto = testRuleSetProto() 755 opts = testRuleSetOptions() 756 ) 757 res, err := NewRuleSetFromProto(version, proto, opts) 758 require.NoError(t, err) 759 rs := res.(*ruleSet) 760 761 _, err = rs.getRollupRuleByName("foo") 762 require.Equal(t, errRuleNotFound, err) 763 r1, err := pipeline.NewRollupOp( 764 pipeline.GroupByRollupType, 765 "blah", 766 []string{"a"}, 767 aggregation.DefaultID, 768 ) 769 require.NoError(t, err) 770 771 view := view.RollupRule{ 772 Name: "foo", 773 Filter: "tag1:value tag2:value", 774 KeepOriginal: true, 775 Targets: []view.RollupTarget{ 776 { 777 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 778 { 779 Type: pipeline.RollupOpType, 780 Rollup: r1, 781 }, 782 }), 783 StoragePolicies: policy.StoragePolicies{ 784 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 785 }, 786 ResendEnabled: true, 787 }, 788 }, 789 } 790 nowNanos := time.Now().UnixNano() 791 helper := NewRuleSetUpdateHelper(10) 792 newID, err := rs.AddRollupRule(view, helper.NewUpdateMetadata(nowNanos, testUser)) 793 require.NoError(t, err) 794 rrs, err := rs.RollupRules() 795 require.Contains(t, rrs, newID) 796 require.NoError(t, err) 797 798 rr, err := rs.getRollupRuleByName("foo") 799 require.NoError(t, err) 800 require.Contains(t, rrs, rr.uuid) 801 802 expected := &rollupRuleSnapshot{ 803 name: "foo", 804 tombstoned: false, 805 cutoverNanos: nowNanos + 10, 806 rawFilter: "tag1:value tag2:value", 807 keepOriginal: true, 808 targets: []rollupTarget{ 809 { 810 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 811 { 812 Type: pipeline.RollupOpType, 813 Rollup: r1, 814 }, 815 }), 816 StoragePolicies: policy.StoragePolicies{ 817 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 818 }, 819 ResendEnabled: true, 820 }, 821 }, 822 lastUpdatedBy: testUser, 823 lastUpdatedAtNanos: nowNanos, 824 } 825 require.True(t, cmp.Equal(expected, rr.snapshots[len(rr.snapshots)-1], testRollupRuleSnapshotCmpOpts...)) 826 827 require.Equal(t, nowNanos+10, rs.cutoverNanos) 828 require.Equal(t, testUser, rs.lastUpdatedBy) 829 require.Equal(t, nowNanos, rs.lastUpdatedAtNanos) 830 } 831 832 func TestRuleSetAddRollupRuleDuplicateRule(t *testing.T) { 833 var ( 834 version = 1 835 proto = testRuleSetProto() 836 opts = testRuleSetOptions() 837 ) 838 res, err := NewRuleSetFromProto(version, proto, opts) 839 require.NoError(t, err) 840 rs := res.(*ruleSet) 841 842 r, err := rs.getRollupRuleByID("rollupRule5") 843 require.NoError(t, err) 844 require.NotNil(t, r) 845 r1, err := pipeline.NewRollupOp( 846 pipeline.GroupByRollupType, 847 "blah", 848 []string{"a"}, 849 aggregation.DefaultID, 850 ) 851 require.NoError(t, err) 852 view := view.RollupRule{ 853 Name: "rollupRule5.snapshot1", 854 Filter: "test:bar", 855 Targets: []view.RollupTarget{ 856 { 857 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 858 { 859 Type: pipeline.RollupOpType, 860 Rollup: r1, 861 }, 862 }), 863 StoragePolicies: policy.StoragePolicies{ 864 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 865 }, 866 }, 867 }, 868 } 869 nowNanos := time.Now().UnixNano() 870 helper := NewRuleSetUpdateHelper(10) 871 newID, err := rs.AddRollupRule(view, helper.NewUpdateMetadata(nowNanos, testUser)) 872 require.Error(t, err) 873 require.Empty(t, newID) 874 err = xerrors.InnerError(err) 875 require.NotNil(t, err) 876 _, ok := err.(merrors.InvalidInputError) //nolint:errorlint 877 require.True(t, ok) 878 } 879 880 func TestRuleSetAddRollupRuleReviveRule(t *testing.T) { 881 var ( 882 version = 1 883 proto = testRuleSetProto() 884 opts = testRuleSetOptions() 885 ) 886 res, err := NewRuleSetFromProto(version, proto, opts) 887 require.NoError(t, err) 888 rs := res.(*ruleSet) 889 890 rr, err := rs.getRollupRuleByID("rollupRule3") 891 require.NoError(t, err) 892 require.NotNil(t, rr) 893 894 view := view.RollupRule{ 895 Name: "rollupRule3.snapshot4", 896 Filter: "test:bar", 897 Targets: []view.RollupTarget{ 898 { 899 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 900 { 901 Type: pipeline.RollupOpType, 902 Rollup: rr1, 903 }, 904 }), 905 StoragePolicies: policy.StoragePolicies{ 906 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 907 }, 908 }, 909 }, 910 } 911 nowNanos := time.Now().UnixNano() 912 helper := NewRuleSetUpdateHelper(10) 913 newID, err := rs.AddRollupRule(view, helper.NewUpdateMetadata(nowNanos, testUser)) 914 require.NoError(t, err) 915 require.NotEmpty(t, newID) 916 rrs, err := rs.RollupRules() 917 require.NoError(t, err) 918 require.Contains(t, rrs, newID) 919 920 rr, err = rs.getRollupRuleByID(newID) 921 require.NoError(t, err) 922 require.Equal(t, rr.snapshots[len(rr.snapshots)-1].rawFilter, view.Filter) 923 924 expected := &rollupRuleSnapshot{ 925 name: "rollupRule3.snapshot4", 926 tombstoned: false, 927 cutoverNanos: nowNanos + 10, 928 rawFilter: "test:bar", 929 targets: []rollupTarget{ 930 { 931 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 932 { 933 Type: pipeline.RollupOpType, 934 Rollup: rr1, 935 }, 936 }), 937 StoragePolicies: policy.StoragePolicies{ 938 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 939 }, 940 }, 941 }, 942 lastUpdatedBy: testUser, 943 lastUpdatedAtNanos: nowNanos, 944 } 945 require.True(t, cmp.Equal(expected, rr.snapshots[len(rr.snapshots)-1], testRollupRuleSnapshotCmpOpts...)) 946 947 require.Equal(t, nowNanos+10, rs.cutoverNanos) 948 require.Equal(t, testUser, rs.lastUpdatedBy) 949 require.Equal(t, nowNanos, rs.lastUpdatedAtNanos) 950 } 951 952 func TestRuleSetUpdateRollupRule(t *testing.T) { 953 var ( 954 version = 1 955 proto = testRuleSetProto() 956 opts = testRuleSetOptions() 957 ) 958 res, err := NewRuleSetFromProto(version, proto, opts) 959 require.NoError(t, err) 960 rs := res.(*ruleSet) 961 962 rr, err := rs.getRollupRuleByID("rollupRule5") 963 require.NoError(t, err) 964 965 rr1, err := pipeline.NewRollupOp( 966 pipeline.GroupByRollupType, 967 "blah", 968 []string{"a"}, 969 aggregation.DefaultID, 970 ) 971 require.NoError(t, err) 972 973 view := view.RollupRule{ 974 ID: "rollupRule5", 975 Name: "rollupRule5.snapshot2", 976 Filter: "test:bar", 977 KeepOriginal: true, 978 Targets: []view.RollupTarget{ 979 { 980 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 981 { 982 Type: pipeline.RollupOpType, 983 Rollup: rr1, 984 }, 985 }), 986 StoragePolicies: policy.StoragePolicies{ 987 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 988 }, 989 }, 990 }, 991 } 992 nowNanos := time.Now().UnixNano() 993 helper := NewRuleSetUpdateHelper(10) 994 err = rs.UpdateRollupRule(view, helper.NewUpdateMetadata(nowNanos, testUser)) 995 require.NoError(t, err) 996 997 r, err := rs.getRollupRuleByID(rr.uuid) 998 require.NoError(t, err) 999 1000 rrs, err := rs.RollupRules() 1001 require.NoError(t, err) 1002 require.Contains(t, rrs, r.uuid) 1003 1004 expected := &rollupRuleSnapshot{ 1005 name: "rollupRule5.snapshot2", 1006 tombstoned: false, 1007 cutoverNanos: nowNanos + 10, 1008 rawFilter: "test:bar", 1009 keepOriginal: true, 1010 targets: []rollupTarget{ 1011 { 1012 Pipeline: pipeline.NewPipeline([]pipeline.OpUnion{ 1013 { 1014 Type: pipeline.RollupOpType, 1015 Rollup: rr1, 1016 }, 1017 }), 1018 StoragePolicies: policy.StoragePolicies{ 1019 policy.NewStoragePolicy(time.Minute, xtime.Minute, time.Hour), 1020 }, 1021 }, 1022 }, 1023 lastUpdatedBy: testUser, 1024 lastUpdatedAtNanos: nowNanos, 1025 } 1026 require.True(t, cmp.Equal(expected, r.snapshots[len(r.snapshots)-1], testRollupRuleSnapshotCmpOpts...)) 1027 1028 require.Equal(t, nowNanos+10, rs.cutoverNanos) 1029 require.Equal(t, testUser, rs.lastUpdatedBy) 1030 require.Equal(t, nowNanos, rs.lastUpdatedAtNanos) 1031 } 1032 1033 func TestRuleSetDeleteRollupRule(t *testing.T) { 1034 var ( 1035 version = 1 1036 proto = testRuleSetProto() 1037 opts = testRuleSetOptions() 1038 ) 1039 res, err := NewRuleSetFromProto(version, proto, opts) 1040 require.NoError(t, err) 1041 rs := res.(*ruleSet) 1042 1043 rrs, err := rs.RollupRules() 1044 require.NoError(t, err) 1045 require.Contains(t, rrs, "rollupRule5") 1046 1047 rr, err := rs.getRollupRuleByID("rollupRule5") 1048 require.NoError(t, err) 1049 1050 nowNanos := time.Now().UnixNano() 1051 helper := NewRuleSetUpdateHelper(10) 1052 err = rs.DeleteRollupRule(rr.uuid, helper.NewUpdateMetadata(nowNanos, testUser)) 1053 require.NoError(t, err) 1054 1055 rr, err = rs.getRollupRuleByName("rollupRule5.snapshot1") 1056 require.NoError(t, err) 1057 require.True(t, rr.tombstoned()) 1058 1059 require.Equal(t, nowNanos+10, rr.snapshots[len(rr.snapshots)-1].cutoverNanos) 1060 require.Nil(t, rr.snapshots[len(rr.snapshots)-1].targets) 1061 1062 rrs, err = rs.RollupRules() 1063 require.NoError(t, err) 1064 require.Contains(t, rrs, "rollupRule5") 1065 } 1066 1067 func TestRuleSetDelete(t *testing.T) { 1068 var ( 1069 version = 1 1070 proto = testRuleSetProto() 1071 opts = testRuleSetOptions() 1072 ) 1073 res, err := NewRuleSetFromProto(version, proto, opts) 1074 require.NoError(t, err) 1075 rs := res.(*ruleSet) 1076 1077 nowNanos := time.Now().UnixNano() 1078 helper := NewRuleSetUpdateHelper(10) 1079 err = rs.Delete(helper.NewUpdateMetadata(nowNanos, testUser)) 1080 require.NoError(t, err) 1081 1082 require.True(t, rs.Tombstoned()) 1083 for _, m := range rs.mappingRules { 1084 require.True(t, m.tombstoned()) 1085 } 1086 1087 for _, r := range rs.rollupRules { 1088 require.True(t, r.tombstoned()) 1089 } 1090 } 1091 1092 func TestRuleSetRevive(t *testing.T) { 1093 var ( 1094 version = 1 1095 proto = testRuleSetProto() 1096 opts = testRuleSetOptions() 1097 ) 1098 res, err := NewRuleSetFromProto(version, proto, opts) 1099 require.NoError(t, err) 1100 rs := res.(*ruleSet) 1101 1102 nowNanos := time.Now().UnixNano() 1103 helper := NewRuleSetUpdateHelper(10) 1104 err = rs.Delete(helper.NewUpdateMetadata(nowNanos, testUser)) 1105 require.NoError(t, err) 1106 1107 err = rs.Revive(helper.NewUpdateMetadata(nowNanos, testUser)) 1108 require.NoError(t, err) 1109 1110 require.False(t, rs.Tombstoned()) 1111 for _, m := range rs.mappingRules { 1112 require.True(t, m.tombstoned()) 1113 } 1114 1115 for _, r := range rs.rollupRules { 1116 require.True(t, r.tombstoned()) 1117 } 1118 } 1119 1120 func TestApplyRuleSetChanges(t *testing.T) { 1121 var ( 1122 version = 1 1123 proto = testRuleSetProto() 1124 opts = testRuleSetOptions() 1125 ) 1126 res, err := NewRuleSetFromProto(version, proto, opts) 1127 require.NoError(t, err) 1128 rs := res.(*ruleSet) 1129 1130 changes := changes.RuleSetChanges{ 1131 MappingRuleChanges: []changes.MappingRuleChange{ 1132 { 1133 Op: changes.AddOp, 1134 RuleData: &view.MappingRule{ 1135 ID: "mrID1", 1136 Name: "mappingRuleAdd", 1137 }, 1138 }, 1139 { 1140 Op: changes.ChangeOp, 1141 RuleID: ptr("mappingRule1"), 1142 RuleData: &view.MappingRule{ 1143 ID: "mappingRule1", 1144 Name: "updatedMappingRule", 1145 }, 1146 }, 1147 { 1148 Op: changes.DeleteOp, 1149 RuleID: ptr("mappingRule3"), 1150 }, 1151 }, 1152 RollupRuleChanges: []changes.RollupRuleChange{ 1153 { 1154 Op: changes.AddOp, 1155 RuleData: &view.RollupRule{ 1156 ID: "rrID1", 1157 Name: "rollupRuleAdd", 1158 }, 1159 }, 1160 { 1161 Op: changes.ChangeOp, 1162 RuleID: ptr("rollupRule1"), 1163 RuleData: &view.RollupRule{ 1164 ID: "rollupRule1", 1165 Name: "updatedRollupRule", 1166 }, 1167 }, 1168 { 1169 Op: changes.DeleteOp, 1170 RuleID: ptr("rollupRule3"), 1171 }, 1172 }, 1173 } 1174 1175 nowNanos := time.Now().UnixNano() 1176 helper := NewRuleSetUpdateHelper(10) 1177 err = rs.ApplyRuleSetChanges(changes, helper.NewUpdateMetadata(nowNanos, testUser)) 1178 require.NoError(t, err) 1179 1180 _, err = rs.getMappingRuleByName("mappingRuleAdd") 1181 require.NoError(t, err) 1182 _, err = rs.getRollupRuleByName("rollupRuleAdd") 1183 require.NoError(t, err) 1184 1185 updatedMappingRule, err := rs.getMappingRuleByID("mappingRule1") 1186 require.NoError(t, err) 1187 name, err := updatedMappingRule.name() 1188 require.NoError(t, err) 1189 require.Equal(t, name, "updatedMappingRule") 1190 updatedRollupRule, err := rs.getRollupRuleByID("rollupRule1") 1191 require.NoError(t, err) 1192 name, err = updatedRollupRule.name() 1193 require.NoError(t, err) 1194 require.Equal(t, name, "updatedRollupRule") 1195 1196 tombstonedMappingRule, err := rs.getMappingRuleByID("mappingRule3") 1197 require.NoError(t, err) 1198 require.True(t, tombstonedMappingRule.tombstoned()) 1199 tombstonedRollupRule, err := rs.getRollupRuleByID("rollupRule3") 1200 require.NoError(t, err) 1201 require.True(t, tombstonedRollupRule.tombstoned()) 1202 } 1203 1204 func TestApplyMappingRuleChangesAddFailure(t *testing.T) { 1205 var ( 1206 version = 1 1207 proto = testRuleSetProto() 1208 opts = testRuleSetOptions() 1209 ) 1210 res, err := NewRuleSetFromProto(version, proto, opts) 1211 require.NoError(t, err) 1212 rs := res.(*ruleSet) 1213 1214 changes := changes.RuleSetChanges{ 1215 MappingRuleChanges: []changes.MappingRuleChange{ 1216 { 1217 Op: changes.AddOp, 1218 RuleData: &view.MappingRule{ 1219 ID: "mappingRule1", 1220 Name: "mappingRule1.snapshot3", 1221 }, 1222 }, 1223 }, 1224 } 1225 1226 nowNanos := time.Now().UnixNano() 1227 helper := NewRuleSetUpdateHelper(10) 1228 err = rs.ApplyRuleSetChanges(changes, helper.NewUpdateMetadata(nowNanos, testUser)) 1229 require.Error(t, err) 1230 err = xerrors.InnerError(err) 1231 require.NotNil(t, err) 1232 _, ok := err.(merrors.InvalidInputError) //nolint:errorlint 1233 require.True(t, ok) 1234 } 1235 1236 func TestApplyRollupRuleChangesAddFailure(t *testing.T) { 1237 var ( 1238 version = 1 1239 proto = testRuleSetProto() 1240 opts = testRuleSetOptions() 1241 ) 1242 res, err := NewRuleSetFromProto(version, proto, opts) 1243 require.NoError(t, err) 1244 rs := res.(*ruleSet) 1245 1246 changes := changes.RuleSetChanges{ 1247 RollupRuleChanges: []changes.RollupRuleChange{ 1248 { 1249 Op: changes.AddOp, 1250 RuleData: &view.RollupRule{ 1251 ID: "rollupRule1", 1252 Name: "rollupRule1.snapshot3", 1253 }, 1254 }, 1255 }, 1256 } 1257 1258 nowNanos := time.Now().UnixNano() 1259 helper := NewRuleSetUpdateHelper(10) 1260 err = rs.ApplyRuleSetChanges(changes, helper.NewUpdateMetadata(nowNanos, testUser)) 1261 require.Error(t, err) 1262 err = xerrors.InnerError(err) 1263 require.NotNil(t, err) 1264 _, ok := err.(merrors.InvalidInputError) //nolint:errorlint 1265 require.True(t, ok) 1266 } 1267 1268 func TestApplyMappingRuleChangesDeleteFailure(t *testing.T) { 1269 var ( 1270 version = 1 1271 proto = testRuleSetProto() 1272 opts = testRuleSetOptions() 1273 ) 1274 res, err := NewRuleSetFromProto(version, proto, opts) 1275 require.NoError(t, err) 1276 rs := res.(*ruleSet) 1277 1278 changes := changes.RuleSetChanges{ 1279 MappingRuleChanges: []changes.MappingRuleChange{ 1280 { 1281 Op: changes.DeleteOp, 1282 RuleID: ptr("mappingRule2"), 1283 }, 1284 }, 1285 } 1286 1287 nowNanos := time.Now().UnixNano() 1288 helper := NewRuleSetUpdateHelper(10) 1289 err = rs.ApplyRuleSetChanges(changes, helper.NewUpdateMetadata(nowNanos, testUser)) 1290 require.Error(t, err) 1291 err = xerrors.InnerError(err) 1292 require.NotNil(t, err) 1293 _, ok := err.(merrors.InvalidInputError) //nolint:errorlint 1294 require.True(t, ok) 1295 } 1296 1297 func TestApplyRollupRuleChangesDeleteFailure(t *testing.T) { 1298 var ( 1299 version = 1 1300 proto = testRuleSetProto() 1301 opts = testRuleSetOptions() 1302 ) 1303 res, err := NewRuleSetFromProto(version, proto, opts) 1304 require.NoError(t, err) 1305 rs := res.(*ruleSet) 1306 1307 changes := changes.RuleSetChanges{ 1308 RollupRuleChanges: []changes.RollupRuleChange{ 1309 { 1310 Op: changes.DeleteOp, 1311 RuleID: ptr("rollupRule2"), 1312 }, 1313 }, 1314 } 1315 1316 nowNanos := time.Now().UnixNano() 1317 helper := NewRuleSetUpdateHelper(10) 1318 err = rs.ApplyRuleSetChanges(changes, helper.NewUpdateMetadata(nowNanos, testUser)) 1319 require.Error(t, err) 1320 err = xerrors.InnerError(err) 1321 require.NotNil(t, err) 1322 _, ok := err.(merrors.InvalidInputError) //nolint:errorlint 1323 require.True(t, ok) 1324 } 1325 1326 func TestApplyMappingRuleChangesUpdateFailure(t *testing.T) { 1327 var ( 1328 version = 1 1329 proto = testRuleSetProto() 1330 opts = testRuleSetOptions() 1331 ) 1332 res, err := NewRuleSetFromProto(version, proto, opts) 1333 require.NoError(t, err) 1334 rs := res.(*ruleSet) 1335 1336 changes := changes.RuleSetChanges{ 1337 MappingRuleChanges: []changes.MappingRuleChange{ 1338 { 1339 Op: changes.ChangeOp, 1340 RuleID: ptr("invalidMappingRule"), 1341 RuleData: &view.MappingRule{ 1342 ID: "invalidMappingRule", 1343 Name: "updatedMappingRule", 1344 }, 1345 }, 1346 }, 1347 } 1348 1349 nowNanos := time.Now().UnixNano() 1350 helper := NewRuleSetUpdateHelper(10) 1351 err = rs.ApplyRuleSetChanges(changes, helper.NewUpdateMetadata(nowNanos, testUser)) 1352 require.Error(t, err) 1353 require.IsType(t, merrors.NewInvalidInputError(""), err) 1354 } 1355 1356 func TestApplyRollupRuleChangesUpdateFailure(t *testing.T) { 1357 var ( 1358 version = 1 1359 proto = testRuleSetProto() 1360 opts = testRuleSetOptions() 1361 ) 1362 res, err := NewRuleSetFromProto(version, proto, opts) 1363 require.NoError(t, err) 1364 rs := res.(*ruleSet) 1365 1366 changes := changes.RuleSetChanges{ 1367 RollupRuleChanges: []changes.RollupRuleChange{ 1368 { 1369 Op: changes.ChangeOp, 1370 RuleID: ptr("rollupRule1"), 1371 RuleData: &view.RollupRule{ 1372 ID: "invalidRollupRule", 1373 Name: "updatedRollupRule", 1374 }, 1375 }, 1376 }, 1377 } 1378 1379 nowNanos := time.Now().UnixNano() 1380 helper := NewRuleSetUpdateHelper(10) 1381 err = rs.ApplyRuleSetChanges(changes, helper.NewUpdateMetadata(nowNanos, testUser)) 1382 require.Error(t, err) 1383 require.IsType(t, merrors.NewInvalidInputError(""), err) 1384 } 1385 1386 func TestApplyMappingRuleWithInvalidOp(t *testing.T) { 1387 var ( 1388 version = 1 1389 proto = testRuleSetProto() 1390 opts = testRuleSetOptions() 1391 ) 1392 res, err := NewRuleSetFromProto(version, proto, opts) 1393 require.NoError(t, err) 1394 rs := res.(*ruleSet) 1395 1396 changes := changes.RuleSetChanges{ 1397 MappingRuleChanges: []changes.MappingRuleChange{{}}, 1398 } 1399 1400 nowNanos := time.Now().UnixNano() 1401 helper := NewRuleSetUpdateHelper(10) 1402 err = rs.ApplyRuleSetChanges(changes, helper.NewUpdateMetadata(nowNanos, testUser)) 1403 require.Error(t, err) 1404 require.IsType(t, merrors.NewInvalidInputError(""), err) 1405 } 1406 1407 func TestApplyRollupRuleWithInvalidOp(t *testing.T) { 1408 var ( 1409 version = 1 1410 proto = testRuleSetProto() 1411 opts = testRuleSetOptions() 1412 ) 1413 res, err := NewRuleSetFromProto(version, proto, opts) 1414 require.NoError(t, err) 1415 rs := res.(*ruleSet) 1416 1417 changes := changes.RuleSetChanges{ 1418 RollupRuleChanges: []changes.RollupRuleChange{{}}, 1419 } 1420 1421 nowNanos := time.Now().UnixNano() 1422 helper := NewRuleSetUpdateHelper(10) 1423 err = rs.ApplyRuleSetChanges(changes, helper.NewUpdateMetadata(nowNanos, testUser)) 1424 require.Error(t, err) 1425 require.IsType(t, merrors.NewInvalidInputError(""), err) 1426 } 1427 1428 func testRuleSetProto() *rulepb.RuleSet { 1429 return &rulepb.RuleSet{ 1430 Uuid: "ruleset", 1431 Namespace: "namespace", 1432 CreatedAtNanos: 1234, 1433 LastUpdatedAtNanos: 5678, 1434 LastUpdatedBy: "someone", 1435 Tombstoned: false, 1436 CutoverNanos: 34923, 1437 MappingRules: testMappingRulesConfig(), 1438 RollupRules: testRollupRulesConfig(), 1439 } 1440 } 1441 1442 func testMappingRulesConfig() []*rulepb.MappingRule { 1443 return []*rulepb.MappingRule{ 1444 &rulepb.MappingRule{ 1445 Uuid: "mappingRule1", 1446 Snapshots: []*rulepb.MappingRuleSnapshot{ 1447 &rulepb.MappingRuleSnapshot{ 1448 Name: "mappingRule1.snapshot1", 1449 Tombstoned: false, 1450 CutoverNanos: 10000, 1451 Filter: "mtagName1:mtagValue1", 1452 StoragePolicies: []*policypb.StoragePolicy{ 1453 &policypb.StoragePolicy{ 1454 Resolution: policypb.Resolution{ 1455 WindowSize: 10 * time.Second.Nanoseconds(), 1456 Precision: time.Second.Nanoseconds(), 1457 }, 1458 Retention: policypb.Retention{ 1459 Period: 24 * time.Hour.Nanoseconds(), 1460 }, 1461 }, 1462 }, 1463 Tags: []*metricpb.Tag{}, 1464 }, 1465 &rulepb.MappingRuleSnapshot{ 1466 Name: "mappingRule1.snapshot2", 1467 Tombstoned: false, 1468 CutoverNanos: 20000, 1469 Filter: "mtagName1:mtagValue1", 1470 StoragePolicies: []*policypb.StoragePolicy{ 1471 &policypb.StoragePolicy{ 1472 Resolution: policypb.Resolution{ 1473 WindowSize: 10 * time.Second.Nanoseconds(), 1474 Precision: time.Second.Nanoseconds(), 1475 }, 1476 Retention: policypb.Retention{ 1477 Period: 6 * time.Hour.Nanoseconds(), 1478 }, 1479 }, 1480 &policypb.StoragePolicy{ 1481 Resolution: policypb.Resolution{ 1482 WindowSize: 5 * time.Minute.Nanoseconds(), 1483 Precision: time.Minute.Nanoseconds(), 1484 }, 1485 Retention: policypb.Retention{ 1486 Period: 48 * time.Hour.Nanoseconds(), 1487 }, 1488 }, 1489 &policypb.StoragePolicy{ 1490 Resolution: policypb.Resolution{ 1491 WindowSize: 10 * time.Minute.Nanoseconds(), 1492 Precision: time.Minute.Nanoseconds(), 1493 }, 1494 Retention: policypb.Retention{ 1495 Period: 48 * time.Hour.Nanoseconds(), 1496 }, 1497 }, 1498 }, 1499 Tags: []*metricpb.Tag{}, 1500 }, 1501 &rulepb.MappingRuleSnapshot{ 1502 Name: "mappingRule1.snapshot3", 1503 Tombstoned: false, 1504 CutoverNanos: 30000, 1505 Filter: "mtagName1:mtagValue1", 1506 StoragePolicies: []*policypb.StoragePolicy{ 1507 &policypb.StoragePolicy{ 1508 Resolution: policypb.Resolution{ 1509 WindowSize: 30 * time.Second.Nanoseconds(), 1510 Precision: time.Second.Nanoseconds(), 1511 }, 1512 Retention: policypb.Retention{ 1513 Period: 6 * time.Hour.Nanoseconds(), 1514 }, 1515 }, 1516 }, 1517 Tags: []*metricpb.Tag{}, 1518 }, 1519 }, 1520 }, 1521 &rulepb.MappingRule{ 1522 Uuid: "mappingRule2", 1523 Snapshots: []*rulepb.MappingRuleSnapshot{ 1524 &rulepb.MappingRuleSnapshot{ 1525 Name: "mappingRule2.snapshot1", 1526 Tombstoned: false, 1527 CutoverNanos: 15000, 1528 Filter: "mtagName1:mtagValue1", 1529 StoragePolicies: []*policypb.StoragePolicy{ 1530 &policypb.StoragePolicy{ 1531 Resolution: policypb.Resolution{ 1532 WindowSize: 10 * time.Second.Nanoseconds(), 1533 Precision: time.Second.Nanoseconds(), 1534 }, 1535 Retention: policypb.Retention{ 1536 Period: 12 * time.Hour.Nanoseconds(), 1537 }, 1538 }, 1539 }, 1540 Tags: []*metricpb.Tag{}, 1541 }, 1542 &rulepb.MappingRuleSnapshot{ 1543 Name: "mappingRule2.snapshot2", 1544 Tombstoned: false, 1545 CutoverNanos: 22000, 1546 Filter: "mtagName1:mtagValue1", 1547 AggregationTypes: []aggregationpb.AggregationType{ 1548 aggregationpb.AggregationType_MIN, 1549 }, 1550 StoragePolicies: []*policypb.StoragePolicy{ 1551 &policypb.StoragePolicy{ 1552 Resolution: policypb.Resolution{ 1553 WindowSize: 10 * time.Second.Nanoseconds(), 1554 Precision: time.Second.Nanoseconds(), 1555 }, 1556 Retention: policypb.Retention{ 1557 Period: 2 * time.Hour.Nanoseconds(), 1558 }, 1559 }, 1560 &policypb.StoragePolicy{ 1561 Resolution: policypb.Resolution{ 1562 WindowSize: int64(time.Minute), 1563 Precision: int64(time.Minute), 1564 }, 1565 Retention: policypb.Retention{ 1566 Period: int64(time.Hour), 1567 }, 1568 }, 1569 }, 1570 Tags: []*metricpb.Tag{}, 1571 }, 1572 &rulepb.MappingRuleSnapshot{ 1573 Name: "mappingRule2.snapshot3", 1574 Tombstoned: true, 1575 CutoverNanos: 35000, 1576 Filter: "mtagName1:mtagValue1", 1577 AggregationTypes: []aggregationpb.AggregationType{ 1578 aggregationpb.AggregationType_MIN, 1579 }, 1580 StoragePolicies: []*policypb.StoragePolicy{ 1581 &policypb.StoragePolicy{ 1582 Resolution: policypb.Resolution{ 1583 WindowSize: int64(10 * time.Second), 1584 Precision: int64(time.Second), 1585 }, 1586 Retention: policypb.Retention{ 1587 Period: int64(2 * time.Hour), 1588 }, 1589 }, 1590 &policypb.StoragePolicy{ 1591 Resolution: policypb.Resolution{ 1592 WindowSize: int64(time.Minute), 1593 Precision: int64(time.Minute), 1594 }, 1595 Retention: policypb.Retention{ 1596 Period: int64(time.Hour), 1597 }, 1598 }, 1599 }, 1600 Tags: []*metricpb.Tag{}, 1601 }, 1602 }, 1603 }, 1604 &rulepb.MappingRule{ 1605 Uuid: "mappingRule3", 1606 Snapshots: []*rulepb.MappingRuleSnapshot{ 1607 &rulepb.MappingRuleSnapshot{ 1608 Name: "mappingRule3.snapshot1", 1609 Tombstoned: false, 1610 CutoverNanos: 22000, 1611 Filter: "mtagName1:mtagValue1", 1612 AggregationTypes: []aggregationpb.AggregationType{ 1613 aggregationpb.AggregationType_MAX, 1614 }, 1615 StoragePolicies: []*policypb.StoragePolicy{ 1616 &policypb.StoragePolicy{ 1617 Resolution: policypb.Resolution{ 1618 WindowSize: int64(10 * time.Second), 1619 Precision: int64(time.Second), 1620 }, 1621 Retention: policypb.Retention{ 1622 Period: int64(12 * time.Hour), 1623 }, 1624 }, 1625 &policypb.StoragePolicy{ 1626 Resolution: policypb.Resolution{ 1627 WindowSize: int64(5 * time.Minute), 1628 Precision: int64(time.Minute), 1629 }, 1630 Retention: policypb.Retention{ 1631 Period: int64(48 * time.Hour), 1632 }, 1633 }, 1634 }, 1635 Tags: []*metricpb.Tag{}, 1636 }, 1637 &rulepb.MappingRuleSnapshot{ 1638 Name: "mappingRule3.snapshot2", 1639 Tombstoned: false, 1640 CutoverNanos: 34000, 1641 Filter: "mtagName1:mtagValue1", 1642 StoragePolicies: []*policypb.StoragePolicy{ 1643 &policypb.StoragePolicy{ 1644 Resolution: policypb.Resolution{ 1645 WindowSize: int64(10 * time.Second), 1646 Precision: int64(time.Second), 1647 }, 1648 Retention: policypb.Retention{ 1649 Period: int64(2 * time.Hour), 1650 }, 1651 }, 1652 &policypb.StoragePolicy{ 1653 Resolution: policypb.Resolution{ 1654 WindowSize: int64(time.Minute), 1655 Precision: int64(time.Minute), 1656 }, 1657 Retention: policypb.Retention{ 1658 Period: int64(time.Hour), 1659 }, 1660 }, 1661 }, 1662 Tags: []*metricpb.Tag{}, 1663 }, 1664 }, 1665 }, 1666 &rulepb.MappingRule{ 1667 Uuid: "mappingRule4", 1668 Snapshots: []*rulepb.MappingRuleSnapshot{ 1669 &rulepb.MappingRuleSnapshot{ 1670 Name: "mappingRule4.snapshot1", 1671 Tombstoned: false, 1672 CutoverNanos: 24000, 1673 Filter: "mtagName1:mtagValue2", 1674 AggregationTypes: []aggregationpb.AggregationType{ 1675 aggregationpb.AggregationType_P999, 1676 }, 1677 StoragePolicies: []*policypb.StoragePolicy{ 1678 &policypb.StoragePolicy{ 1679 Resolution: policypb.Resolution{ 1680 WindowSize: int64(10 * time.Second), 1681 Precision: int64(time.Second), 1682 }, 1683 Retention: policypb.Retention{ 1684 Period: int64(24 * time.Hour), 1685 }, 1686 }, 1687 }, 1688 Tags: []*metricpb.Tag{}, 1689 }, 1690 }, 1691 }, 1692 &rulepb.MappingRule{ 1693 Uuid: "mappingRule5", 1694 Snapshots: []*rulepb.MappingRuleSnapshot{ 1695 &rulepb.MappingRuleSnapshot{ 1696 Name: "mappingRule5.snapshot1", 1697 Tombstoned: false, 1698 CutoverNanos: 100000, 1699 LastUpdatedAtNanos: 123456, 1700 LastUpdatedBy: "test", 1701 Filter: "mtagName1:mtagValue1", 1702 StoragePolicies: []*policypb.StoragePolicy{ 1703 &policypb.StoragePolicy{ 1704 Resolution: policypb.Resolution{ 1705 WindowSize: int64(10 * time.Second), 1706 Precision: int64(time.Second), 1707 }, 1708 Retention: policypb.Retention{ 1709 Period: int64(24 * time.Hour), 1710 }, 1711 }, 1712 }, 1713 Tags: []*metricpb.Tag{}, 1714 }, 1715 }, 1716 }, 1717 } 1718 } 1719 1720 func testRollupRulesConfig() []*rulepb.RollupRule { 1721 return []*rulepb.RollupRule{ 1722 &rulepb.RollupRule{ 1723 Uuid: "rollupRule1", 1724 Snapshots: []*rulepb.RollupRuleSnapshot{ 1725 &rulepb.RollupRuleSnapshot{ 1726 Name: "rollupRule1.snapshot1", 1727 Tombstoned: false, 1728 CutoverNanos: 10000, 1729 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 1730 TargetsV2: []*rulepb.RollupTargetV2{ 1731 &rulepb.RollupTargetV2{ 1732 Pipeline: &pipelinepb.Pipeline{ 1733 Ops: []pipelinepb.PipelineOp{ 1734 { 1735 Type: pipelinepb.PipelineOp_ROLLUP, 1736 Rollup: &pipelinepb.RollupOp{ 1737 NewName: "rName1", 1738 Tags: []string{"rtagName1", "rtagName2"}, 1739 }, 1740 }, 1741 }, 1742 }, 1743 StoragePolicies: []*policypb.StoragePolicy{ 1744 &policypb.StoragePolicy{ 1745 Resolution: policypb.Resolution{ 1746 WindowSize: int64(10 * time.Second), 1747 Precision: int64(time.Second), 1748 }, 1749 Retention: policypb.Retention{ 1750 Period: int64(24 * time.Hour), 1751 }, 1752 }, 1753 }, 1754 }, 1755 }, 1756 Tags: []*metricpb.Tag{}, 1757 }, 1758 &rulepb.RollupRuleSnapshot{ 1759 Name: "rollupRule1.snapshot2", 1760 Tombstoned: false, 1761 CutoverNanos: 20000, 1762 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 1763 TargetsV2: []*rulepb.RollupTargetV2{ 1764 &rulepb.RollupTargetV2{ 1765 Pipeline: &pipelinepb.Pipeline{ 1766 Ops: []pipelinepb.PipelineOp{ 1767 { 1768 Type: pipelinepb.PipelineOp_ROLLUP, 1769 Rollup: &pipelinepb.RollupOp{ 1770 NewName: "rName1", 1771 Tags: []string{"rtagName1", "rtagName2"}, 1772 }, 1773 }, 1774 }, 1775 }, 1776 StoragePolicies: []*policypb.StoragePolicy{ 1777 &policypb.StoragePolicy{ 1778 Resolution: policypb.Resolution{ 1779 WindowSize: int64(10 * time.Second), 1780 Precision: int64(time.Second), 1781 }, 1782 Retention: policypb.Retention{ 1783 Period: int64(6 * time.Hour), 1784 }, 1785 }, 1786 &policypb.StoragePolicy{ 1787 Resolution: policypb.Resolution{ 1788 WindowSize: int64(5 * time.Minute), 1789 Precision: int64(time.Minute), 1790 }, 1791 Retention: policypb.Retention{ 1792 Period: int64(48 * time.Hour), 1793 }, 1794 }, 1795 &policypb.StoragePolicy{ 1796 Resolution: policypb.Resolution{ 1797 WindowSize: int64(10 * time.Minute), 1798 Precision: int64(time.Minute), 1799 }, 1800 Retention: policypb.Retention{ 1801 Period: int64(48 * time.Hour), 1802 }, 1803 }, 1804 }, 1805 }, 1806 }, 1807 Tags: []*metricpb.Tag{}, 1808 }, 1809 &rulepb.RollupRuleSnapshot{ 1810 Name: "rollupRule1.snapshot3", 1811 Tombstoned: false, 1812 CutoverNanos: 30000, 1813 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 1814 TargetsV2: []*rulepb.RollupTargetV2{ 1815 &rulepb.RollupTargetV2{ 1816 Pipeline: &pipelinepb.Pipeline{ 1817 Ops: []pipelinepb.PipelineOp{ 1818 { 1819 Type: pipelinepb.PipelineOp_ROLLUP, 1820 Rollup: &pipelinepb.RollupOp{ 1821 NewName: "rName1", 1822 Tags: []string{"rtagName1", "rtagName2"}, 1823 }, 1824 }, 1825 }, 1826 }, 1827 StoragePolicies: []*policypb.StoragePolicy{ 1828 &policypb.StoragePolicy{ 1829 Resolution: policypb.Resolution{ 1830 WindowSize: int64(30 * time.Second), 1831 Precision: int64(time.Second), 1832 }, 1833 Retention: policypb.Retention{ 1834 Period: int64(6 * time.Hour), 1835 }, 1836 }, 1837 }, 1838 }, 1839 }, 1840 Tags: []*metricpb.Tag{}, 1841 }, 1842 }, 1843 }, 1844 &rulepb.RollupRule{ 1845 Uuid: "rollupRule2", 1846 Snapshots: []*rulepb.RollupRuleSnapshot{ 1847 &rulepb.RollupRuleSnapshot{ 1848 Name: "rollupRule2.snapshot1", 1849 Tombstoned: false, 1850 CutoverNanos: 15000, 1851 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 1852 TargetsV2: []*rulepb.RollupTargetV2{ 1853 &rulepb.RollupTargetV2{ 1854 Pipeline: &pipelinepb.Pipeline{ 1855 Ops: []pipelinepb.PipelineOp{ 1856 { 1857 Type: pipelinepb.PipelineOp_ROLLUP, 1858 Rollup: &pipelinepb.RollupOp{ 1859 NewName: "rName2", 1860 Tags: []string{"rtagName1", "rtagName2"}, 1861 }, 1862 }, 1863 }, 1864 }, 1865 StoragePolicies: []*policypb.StoragePolicy{ 1866 &policypb.StoragePolicy{ 1867 Resolution: policypb.Resolution{ 1868 WindowSize: int64(10 * time.Second), 1869 Precision: int64(time.Second), 1870 }, 1871 Retention: policypb.Retention{ 1872 Period: int64(12 * time.Hour), 1873 }, 1874 }, 1875 }, 1876 }, 1877 }, 1878 Tags: []*metricpb.Tag{}, 1879 }, 1880 &rulepb.RollupRuleSnapshot{ 1881 Name: "rollupRule2.snapshot2", 1882 Tombstoned: false, 1883 CutoverNanos: 22000, 1884 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 1885 TargetsV2: []*rulepb.RollupTargetV2{ 1886 &rulepb.RollupTargetV2{ 1887 Pipeline: &pipelinepb.Pipeline{ 1888 Ops: []pipelinepb.PipelineOp{ 1889 { 1890 Type: pipelinepb.PipelineOp_ROLLUP, 1891 Rollup: &pipelinepb.RollupOp{ 1892 NewName: "rName2", 1893 Tags: []string{"rtagName1", "rtagName2"}, 1894 }, 1895 }, 1896 }, 1897 }, 1898 StoragePolicies: []*policypb.StoragePolicy{ 1899 &policypb.StoragePolicy{ 1900 Resolution: policypb.Resolution{ 1901 WindowSize: int64(10 * time.Second), 1902 Precision: int64(time.Second), 1903 }, 1904 Retention: policypb.Retention{ 1905 Period: int64(2 * time.Hour), 1906 }, 1907 }, 1908 &policypb.StoragePolicy{ 1909 Resolution: policypb.Resolution{ 1910 WindowSize: int64(time.Minute), 1911 Precision: int64(time.Minute), 1912 }, 1913 Retention: policypb.Retention{ 1914 Period: int64(time.Hour), 1915 }, 1916 }, 1917 }, 1918 }, 1919 }, 1920 Tags: []*metricpb.Tag{}, 1921 }, 1922 &rulepb.RollupRuleSnapshot{ 1923 Name: "rollupRule2.snapshot3", 1924 Tombstoned: true, 1925 CutoverNanos: 35000, 1926 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 1927 TargetsV2: []*rulepb.RollupTargetV2{ 1928 &rulepb.RollupTargetV2{ 1929 Pipeline: &pipelinepb.Pipeline{ 1930 Ops: []pipelinepb.PipelineOp{ 1931 { 1932 Type: pipelinepb.PipelineOp_ROLLUP, 1933 Rollup: &pipelinepb.RollupOp{ 1934 NewName: "rName2", 1935 Tags: []string{"rtagName1", "rtagName2"}, 1936 }, 1937 }, 1938 }, 1939 }, 1940 StoragePolicies: []*policypb.StoragePolicy{ 1941 &policypb.StoragePolicy{ 1942 Resolution: policypb.Resolution{ 1943 WindowSize: int64(time.Minute), 1944 Precision: int64(time.Minute), 1945 }, 1946 Retention: policypb.Retention{ 1947 Period: int64(time.Hour), 1948 }, 1949 }, 1950 }, 1951 }, 1952 }, 1953 Tags: []*metricpb.Tag{}, 1954 }, 1955 }, 1956 }, 1957 &rulepb.RollupRule{ 1958 Uuid: "rollupRule3", 1959 Snapshots: []*rulepb.RollupRuleSnapshot{ 1960 &rulepb.RollupRuleSnapshot{ 1961 Name: "rollupRule3.snapshot1", 1962 Tombstoned: false, 1963 CutoverNanos: 22000, 1964 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 1965 TargetsV2: []*rulepb.RollupTargetV2{ 1966 &rulepb.RollupTargetV2{ 1967 Pipeline: &pipelinepb.Pipeline{ 1968 Ops: []pipelinepb.PipelineOp{ 1969 { 1970 Type: pipelinepb.PipelineOp_ROLLUP, 1971 Rollup: &pipelinepb.RollupOp{ 1972 NewName: "rName3", 1973 Tags: []string{"rtagName1", "rtagName2"}, 1974 }, 1975 }, 1976 }, 1977 }, 1978 StoragePolicies: []*policypb.StoragePolicy{ 1979 &policypb.StoragePolicy{ 1980 Resolution: policypb.Resolution{ 1981 WindowSize: int64(10 * time.Second), 1982 Precision: int64(time.Second), 1983 }, 1984 Retention: policypb.Retention{ 1985 Period: int64(12 * time.Hour), 1986 }, 1987 }, 1988 &policypb.StoragePolicy{ 1989 Resolution: policypb.Resolution{ 1990 WindowSize: int64(time.Minute), 1991 Precision: int64(time.Minute), 1992 }, 1993 Retention: policypb.Retention{ 1994 Period: int64(24 * time.Hour), 1995 }, 1996 }, 1997 &policypb.StoragePolicy{ 1998 Resolution: policypb.Resolution{ 1999 WindowSize: int64(5 * time.Minute), 2000 Precision: int64(time.Minute), 2001 }, 2002 Retention: policypb.Retention{ 2003 Period: int64(48 * time.Hour), 2004 }, 2005 }, 2006 }, 2007 }, 2008 &rulepb.RollupTargetV2{ 2009 Pipeline: &pipelinepb.Pipeline{ 2010 Ops: []pipelinepb.PipelineOp{ 2011 { 2012 Type: pipelinepb.PipelineOp_ROLLUP, 2013 Rollup: &pipelinepb.RollupOp{ 2014 NewName: "rName3", 2015 Tags: []string{"rtagName1"}, 2016 }, 2017 }, 2018 }, 2019 }, 2020 StoragePolicies: []*policypb.StoragePolicy{ 2021 &policypb.StoragePolicy{ 2022 Resolution: policypb.Resolution{ 2023 WindowSize: int64(10 * time.Second), 2024 Precision: int64(time.Second), 2025 }, 2026 Retention: policypb.Retention{ 2027 Period: int64(24 * time.Hour), 2028 }, 2029 }, 2030 }, 2031 }, 2032 }, 2033 Tags: []*metricpb.Tag{}, 2034 }, 2035 &rulepb.RollupRuleSnapshot{ 2036 Name: "rollupRule3.snapshot2", 2037 Tombstoned: false, 2038 CutoverNanos: 34000, 2039 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 2040 TargetsV2: []*rulepb.RollupTargetV2{ 2041 &rulepb.RollupTargetV2{ 2042 Pipeline: &pipelinepb.Pipeline{ 2043 Ops: []pipelinepb.PipelineOp{ 2044 { 2045 Type: pipelinepb.PipelineOp_ROLLUP, 2046 Rollup: &pipelinepb.RollupOp{ 2047 NewName: "rName3", 2048 Tags: []string{"rtagName1", "rtagName2"}, 2049 }, 2050 }, 2051 }, 2052 }, 2053 StoragePolicies: []*policypb.StoragePolicy{ 2054 &policypb.StoragePolicy{ 2055 Resolution: policypb.Resolution{ 2056 WindowSize: int64(10 * time.Second), 2057 Precision: int64(time.Second), 2058 }, 2059 Retention: policypb.Retention{ 2060 Period: int64(2 * time.Hour), 2061 }, 2062 }, 2063 &policypb.StoragePolicy{ 2064 Resolution: policypb.Resolution{ 2065 WindowSize: int64(time.Minute), 2066 Precision: int64(time.Minute), 2067 }, 2068 Retention: policypb.Retention{ 2069 Period: int64(time.Hour), 2070 }, 2071 }, 2072 }, 2073 }, 2074 }, 2075 Tags: []*metricpb.Tag{}, 2076 }, 2077 }, 2078 }, 2079 &rulepb.RollupRule{ 2080 Uuid: "rollupRule4", 2081 Snapshots: []*rulepb.RollupRuleSnapshot{ 2082 &rulepb.RollupRuleSnapshot{ 2083 Name: "rollupRule4.snapshot1", 2084 Tombstoned: false, 2085 CutoverNanos: 24000, 2086 Filter: "rtagName1:rtagValue2", 2087 TargetsV2: []*rulepb.RollupTargetV2{ 2088 &rulepb.RollupTargetV2{ 2089 Pipeline: &pipelinepb.Pipeline{ 2090 Ops: []pipelinepb.PipelineOp{ 2091 { 2092 Type: pipelinepb.PipelineOp_ROLLUP, 2093 Rollup: &pipelinepb.RollupOp{ 2094 NewName: "rName4", 2095 Tags: []string{"rtagName1", "rtagName2"}, 2096 }, 2097 }, 2098 }, 2099 }, 2100 StoragePolicies: []*policypb.StoragePolicy{ 2101 &policypb.StoragePolicy{ 2102 Resolution: policypb.Resolution{ 2103 WindowSize: int64(time.Minute), 2104 Precision: int64(time.Minute), 2105 }, 2106 Retention: policypb.Retention{ 2107 Period: int64(time.Hour), 2108 }, 2109 }, 2110 }, 2111 }, 2112 }, 2113 Tags: []*metricpb.Tag{}, 2114 }, 2115 }, 2116 }, 2117 &rulepb.RollupRule{ 2118 Uuid: "rollupRule5", 2119 Snapshots: []*rulepb.RollupRuleSnapshot{ 2120 &rulepb.RollupRuleSnapshot{ 2121 Name: "rollupRule5.snapshot1", 2122 Tombstoned: false, 2123 CutoverNanos: 24000, 2124 Filter: "rtagName1:rtagValue2", 2125 TargetsV2: []*rulepb.RollupTargetV2{ 2126 &rulepb.RollupTargetV2{ 2127 Pipeline: &pipelinepb.Pipeline{ 2128 Ops: []pipelinepb.PipelineOp{ 2129 { 2130 Type: pipelinepb.PipelineOp_ROLLUP, 2131 Rollup: &pipelinepb.RollupOp{ 2132 NewName: "rName5", 2133 Tags: []string{"rtagName1"}, 2134 }, 2135 }, 2136 }, 2137 }, 2138 StoragePolicies: []*policypb.StoragePolicy{ 2139 &policypb.StoragePolicy{ 2140 Resolution: policypb.Resolution{ 2141 WindowSize: int64(time.Second), 2142 Precision: int64(time.Second), 2143 }, 2144 Retention: policypb.Retention{ 2145 Period: int64(time.Minute), 2146 }, 2147 }, 2148 }, 2149 }, 2150 }, 2151 Tags: []*metricpb.Tag{}, 2152 }, 2153 }, 2154 }, 2155 &rulepb.RollupRule{ 2156 Uuid: "rollupRule6", 2157 Snapshots: []*rulepb.RollupRuleSnapshot{ 2158 &rulepb.RollupRuleSnapshot{ 2159 Name: "rollupRule6.snapshot1", 2160 Tombstoned: false, 2161 CutoverNanos: 100000, 2162 Filter: "rtagName1:rtagValue1 rtagName2:rtagValue2", 2163 TargetsV2: []*rulepb.RollupTargetV2{ 2164 &rulepb.RollupTargetV2{ 2165 Pipeline: &pipelinepb.Pipeline{ 2166 Ops: []pipelinepb.PipelineOp{ 2167 { 2168 Type: pipelinepb.PipelineOp_ROLLUP, 2169 Rollup: &pipelinepb.RollupOp{ 2170 NewName: "rName6", 2171 Tags: []string{"rtagName1", "rtagName2"}, 2172 }, 2173 }, 2174 }, 2175 }, 2176 StoragePolicies: []*policypb.StoragePolicy{ 2177 &policypb.StoragePolicy{ 2178 Resolution: policypb.Resolution{ 2179 WindowSize: int64(time.Minute), 2180 Precision: int64(time.Minute), 2181 }, 2182 Retention: policypb.Retention{ 2183 Period: int64(time.Hour), 2184 }, 2185 }, 2186 }, 2187 }, 2188 }, 2189 Tags: []*metricpb.Tag{}, 2190 }, 2191 }, 2192 }, 2193 } 2194 } 2195 2196 func testMatchOptions() MatchOptions { 2197 return MatchOptions{ 2198 NameAndTagsFn: func(b []byte) ([]byte, []byte, error) { 2199 idx := bytes.Index(b, []byte("|")) 2200 if idx == -1 { 2201 return nil, b, nil 2202 } 2203 return b[:idx], b[idx+1:], nil 2204 }, 2205 SortedTagIteratorFn: filters.NewMockSortedTagIterator, 2206 } 2207 } 2208 2209 func testTagsFilterOptions() filters.TagsFilterOptions { 2210 return filters.TagsFilterOptions{ 2211 NameTagKey: []byte("name"), 2212 NameAndTagsFn: func(b []byte) ([]byte, []byte, error) { 2213 idx := bytes.Index(b, []byte("|")) 2214 if idx == -1 { 2215 return nil, b, nil 2216 } 2217 return b[:idx], b[idx+1:], nil 2218 }, 2219 SortedTagIteratorFn: filters.NewMockSortedTagIterator, 2220 } 2221 } 2222 2223 func mockNewID(name []byte, tags []id.TagPair) []byte { 2224 if len(tags) == 0 { 2225 return name 2226 } 2227 var buf bytes.Buffer 2228 buf.Write(name) 2229 if len(tags) > 0 { 2230 buf.WriteString("|") 2231 for idx, p := range tags { 2232 buf.Write(p.Name) 2233 buf.WriteString("=") 2234 buf.Write(p.Value) 2235 if idx < len(tags)-1 { 2236 buf.WriteString(",") 2237 } 2238 } 2239 } 2240 return buf.Bytes() 2241 } 2242 2243 func testRuleSetOptions() Options { 2244 return NewOptions(). 2245 SetTagsFilterOptions(testTagsFilterOptions()). 2246 SetNewRollupIDFn(mockNewID) 2247 } 2248 2249 func b(v string) []byte { return []byte(v) } 2250 func bs(v ...string) [][]byte { return xbytes.ArraysFromStringArray(v) } 2251 func ptr(str string) *string { return &str } 2252 2253 type testMatchInput struct { 2254 id string 2255 matchFrom int64 2256 matchTo int64 2257 metricType metric.Type // reverse matching only 2258 aggregationType aggregation.Type // reverse matching only 2259 expireAtNanos int64 2260 forExistingIDResult metadata.StagedMetadatas 2261 forNewRollupIDsResult []IDWithMetadatas 2262 keepOriginal bool 2263 } 2264 2265 func (t testMatchInput) ID() id.ID { 2266 return namespace.NewTestID(t.id, "ns") 2267 }