package testing import ( "context" "sort" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/notification" "github.com/influxdata/influxdb/v2/notification/endpoint" "github.com/influxdata/influxdb/v2/notification/rule" ) // NotificationRuleFields includes prepopulated data for mapping tests. type NotificationRuleFields struct { IDGenerator influxdb.IDGenerator TimeGenerator influxdb.TimeGenerator NotificationRules []influxdb.NotificationRule Orgs []*influxdb.Organization UserResourceMappings []*influxdb.UserResourceMapping Tasks []influxdb.TaskCreate Endpoints []influxdb.NotificationEndpoint } var notificationRuleCmpOptions = cmp.Options{ cmpopts.IgnoreFields(rule.Base{}, "TaskID"), cmp.Transformer("Sort", func(in []influxdb.NotificationRule) []influxdb.NotificationRule { out := append([]influxdb.NotificationRule(nil), in...) sort.Slice(out, func(i, j int) bool { return out[i].GetID() > out[j].GetID() }) return out }), } // NotificationRuleStore tests all the service functions. func NotificationRuleStore( init func(NotificationRuleFields, *testing.T) (influxdb.NotificationRuleStore, func()), t *testing.T, ) { tests := []struct { name string fn func(init func(NotificationRuleFields, *testing.T) (influxdb.NotificationRuleStore, func()), t *testing.T) }{ { name: "CreateNotificationRule", fn: CreateNotificationRule, }, { name: "FindNotificationRuleByID", fn: FindNotificationRuleByID, }, { name: "FindNotificationRules", fn: FindNotificationRules, }, { name: "UpdateNotificationRule", fn: UpdateNotificationRule, }, { name: "PatchNotificationRule", fn: PatchNotificationRule, }, { name: "DeleteNotificationRule", fn: DeleteNotificationRule, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.fn(init, t) }) } } // CreateNotificationRule testing. func CreateNotificationRule( init func(NotificationRuleFields, *testing.T) (influxdb.NotificationRuleStore, func()), t *testing.T, ) { type args struct { notificationRule influxdb.NotificationRule userID influxdb.ID } type wants struct { err error notificationRules []influxdb.NotificationRule userResourceMapping []*influxdb.UserResourceMapping } tests := []struct { name string fields NotificationRuleFields args args wants wants }{ { name: "basic create notification rule", fields: NotificationRuleFields{ IDGenerator: mock.NewIDGenerator(twoID, t), TimeGenerator: fakeGenerator, Orgs: []*influxdb.Organization{ { Name: "org", ID: MustIDBase16(fourID), }, }, Endpoints: []influxdb.NotificationEndpoint{ &endpoint.Slack{ URL: "http://localhost:7777", Token: influxdb.SecretField{ // TODO(desa): not sure why this has to end in token, but it does Key: "020f755c3c082001-token", Value: strPtr("abc123"), }, Base: endpoint.Base{ OrgID: MustIDBase16Ptr(fourID), Name: "foo", Status: influxdb.Active, }, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Critical, }, }, TagRules: []notification.TagRule{ { Tag: influxdb.Tag{ Key: "k1", Value: "v1", }, Operator: influxdb.NotEqual, }, { Tag: influxdb.Tag{ Key: "k2", Value: "v2", }, Operator: influxdb.RegexEqual, }, }, CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, }, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Member, }, }, }, args: args{ userID: MustIDBase16(sixID), notificationRule: &rule.Slack{ Base: rule.Base{ OwnerID: MustIDBase16(sixID), Name: "name2", OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Critical, }, }, TagRules: []notification.TagRule{ { Tag: influxdb.Tag{ Key: "k1", Value: "v1", }, Operator: influxdb.NotEqual, }, { Tag: influxdb.Tag{ Key: "k2", Value: "v2", }, Operator: influxdb.RegexEqual, }, }, }, MessageTemplate: "msg1", }, }, wants: wants{ notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Critical, }, }, TagRules: []notification.TagRule{ { Tag: influxdb.Tag{ Key: "k1", Value: "v1", }, Operator: influxdb.NotEqual, }, { Tag: influxdb.Tag{ Key: "k2", Value: "v2", }, Operator: influxdb.RegexEqual, }, }, CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Critical, }, }, TagRules: []notification.TagRule{ { Tag: influxdb.Tag{ Key: "k1", Value: "v1", }, Operator: influxdb.NotEqual, }, { Tag: influxdb.Tag{ Key: "k2", Value: "v2", }, Operator: influxdb.RegexEqual, }, }, CRUDLog: influxdb.CRUDLog{ CreatedAt: fakeDate, UpdatedAt: fakeDate, }, }, MessageTemplate: "msg1", }, }, userResourceMapping: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Member, }, { ResourceID: MustIDBase16(twoID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, done := init(tt.fields, t) defer done() ctx := context.Background() nrc := influxdb.NotificationRuleCreate{ NotificationRule: tt.args.notificationRule, Status: influxdb.Active, } err := s.CreateNotificationRule(ctx, nrc, tt.args.userID) if (err != nil) != (tt.wants.err != nil) { t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err) } if tt.wants.err == nil && !tt.args.notificationRule.GetID().Valid() { t.Fatalf("notification rule ID not set from CreateNotificationRule") } if err != nil && tt.wants.err != nil { if influxdb.ErrorCode(err) != influxdb.ErrorCode(tt.wants.err) { t.Fatalf("expected error messages to match '%v' got '%v'", influxdb.ErrorCode(tt.wants.err), influxdb.ErrorCode(err)) } } urmFilter := influxdb.UserResourceMappingFilter{ UserID: tt.args.userID, ResourceType: influxdb.NotificationRuleResourceType, } filter := influxdb.NotificationRuleFilter{ UserResourceMappingFilter: urmFilter, } nrs, _, err := s.FindNotificationRules(ctx, filter) if err != nil { t.Fatalf("failed to retrieve notification rules: %v", err) } if diff := cmp.Diff(nrs, tt.wants.notificationRules, notificationRuleCmpOptions...); diff != "" { t.Errorf("notificationRules are different -got/+want\ndiff %s", diff) } }) } } // FindNotificationRuleByID testing. func FindNotificationRuleByID( init func(NotificationRuleFields, *testing.T) (influxdb.NotificationRuleStore, func()), t *testing.T, ) { type args struct { id influxdb.ID } type wants struct { err error notificationRule influxdb.NotificationRule } tests := []struct { name string fields NotificationRuleFields args args wants wants }{ { name: "bad id", fields: NotificationRuleFields{ UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ id: influxdb.ID(0), }, wants: wants{ err: &influxdb.Error{ Code: influxdb.EInvalid, Msg: "provided notification rule ID has invalid format", }, }, }, { name: "not found", fields: NotificationRuleFields{ UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ id: MustIDBase16(threeID), }, wants: wants{ err: &influxdb.Error{ Code: influxdb.ENotFound, Msg: "notification rule not found", }, }, }, { name: "basic find telegraf config by id", fields: NotificationRuleFields{ UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ id: MustIDBase16(twoID), }, wants: wants{ notificationRule: &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, done := init(tt.fields, t) defer done() ctx := context.Background() nr, err := s.FindNotificationRuleByID(ctx, tt.args.id) ErrorsEqual(t, err, tt.wants.err) if diff := cmp.Diff(nr, tt.wants.notificationRule, notificationRuleCmpOptions...); diff != "" { t.Errorf("notification rule is different -got/+want\ndiff %s", diff) } }) } } // FindNotificationRules testing func FindNotificationRules( init func(NotificationRuleFields, *testing.T) (influxdb.NotificationRuleStore, func()), t *testing.T, ) { type args struct { filter influxdb.NotificationRuleFilter opts influxdb.FindOptions } type wants struct { notificationRules []influxdb.NotificationRule err error } tests := []struct { name string fields NotificationRuleFields args args wants wants }{ { name: "find nothing (empty set)", fields: NotificationRuleFields{ UserResourceMappings: []*influxdb.UserResourceMapping{}, NotificationRules: []influxdb.NotificationRule{}, }, args: args{ filter: influxdb.NotificationRuleFilter{ UserResourceMappingFilter: influxdb.UserResourceMappingFilter{ ResourceType: influxdb.NotificationRuleResourceType, }, }, }, wants: wants{ notificationRules: []influxdb.NotificationRule{}, }, }, { name: "find all notification rules", fields: NotificationRuleFields{ UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ filter: influxdb.NotificationRuleFilter{ UserResourceMappingFilter: influxdb.UserResourceMappingFilter{ UserID: MustIDBase16(sixID), ResourceType: influxdb.NotificationRuleResourceType, }, }, }, wants: wants{ notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, }, { name: "find owners only", fields: NotificationRuleFields{ UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ filter: influxdb.NotificationRuleFilter{ UserResourceMappingFilter: influxdb.UserResourceMappingFilter{ UserID: MustIDBase16(sixID), ResourceType: influxdb.NotificationRuleResourceType, UserType: influxdb.Owner, }, }, }, wants: wants{ notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, }, }, }, { name: "filter by organization id only", fields: NotificationRuleFields{ Orgs: []*influxdb.Organization{ { ID: MustIDBase16(oneID), Name: "org1", }, { ID: MustIDBase16(fourID), Name: "org4", }, }, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, { ResourceID: MustIDBase16(twoID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Member, }, { ResourceID: MustIDBase16(fourID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), OrgID: MustIDBase16(fourID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr1", }, Channel: "ch1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), OrgID: MustIDBase16(fourID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr2", }, MessageTemplate: "body2", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(fourID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr3", }, MessageTemplate: "msg", }, }, }, args: args{ filter: influxdb.NotificationRuleFilter{ OrgID: idPtr(MustIDBase16(oneID)), }, }, wants: wants{ notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(fourID), OrgID: MustIDBase16(oneID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr3", }, MessageTemplate: "msg", }, }, }, }, { name: "filter by organization name only", fields: NotificationRuleFields{ Orgs: []*influxdb.Organization{ { ID: MustIDBase16(oneID), Name: "org1", }, { ID: MustIDBase16(fourID), Name: "org4", }, }, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, { ResourceID: MustIDBase16(twoID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Member, }, { ResourceID: MustIDBase16(fourID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), OrgID: MustIDBase16(fourID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr1", }, Channel: "ch1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), OrgID: MustIDBase16(fourID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr2", }, MessageTemplate: "body2", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(fourID), OrgID: MustIDBase16(oneID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr3", }, MessageTemplate: "msg", }, }, }, args: args{ filter: influxdb.NotificationRuleFilter{ Organization: strPtr("org4"), }, }, wants: wants{ notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), OrgID: MustIDBase16(fourID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr1", }, Channel: "ch1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), OrgID: MustIDBase16(fourID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr2", }, MessageTemplate: "body2", }, }, }, }, // { // name: "filter by tags", // fields: NotificationRuleFields{ // Orgs: []*influxdb.Organization{ // { // ID: MustIDBase16(oneID), // Name: "org1", // }, // { // ID: MustIDBase16(fourID), // Name: "org4", // }, // }, // UserResourceMappings: []*influxdb.UserResourceMapping{ // { // ResourceID: MustIDBase16(oneID), // ResourceType: influxdb.NotificationRuleResourceType, // UserID: MustIDBase16(sixID), // UserType: influxdb.Owner, // }, // { // ResourceID: MustIDBase16(twoID), // ResourceType: influxdb.NotificationRuleResourceType, // UserID: MustIDBase16(sixID), // UserType: influxdb.Member, // }, // { // ResourceID: MustIDBase16(fourID), // ResourceType: influxdb.NotificationRuleResourceType, // UserID: MustIDBase16(sixID), // UserType: influxdb.Owner, // }, // }, // NotificationRules: []influxdb.NotificationRule{ // &rule.Slack{ // Base: rule.Base{ // ID: MustIDBase16(oneID), // OrgID: MustIDBase16(fourID), // OwnerID: MustIDBase16(sixID), // EndpointID: 1, // Status: influxdb.Active, // Name: "nr1", // TagRules: []influxdb.TagRule{ // { // Tag: influxdb.Tag{ // Key: "environment", // Value: "production", // }, // Operator: notification.Equal, // }, // }, // }, // Channel: "ch1", // MessageTemplate: "msg1", // }, // &rule.Slack{ // Base: rule.Base{ // ID: MustIDBase16(twoID), // OrgID: MustIDBase16(fourID), // OwnerID: MustIDBase16(sixID), // EndpointID: 1, // Status: influxdb.Active, // Name: "nr2", // TagRules: []influxdb.TagRule{ // { // Tag: influxdb.Tag{ // Key: "environment", // Value: "production", // }, // Operator: notification.Equal, // }, // { // Tag: influxdb.Tag{ // Key: "location", // Value: "paris", // }, // Operator: notification.Equal, // }, // }, // }, // MessageTemplate: "body2", // }, // &rule.Slack{ // Base: rule.Base{ // ID: MustIDBase16(fourID), // OrgID: MustIDBase16(oneID), // OwnerID: MustIDBase16(sixID), // EndpointID: 1, // Status: influxdb.Active, // Name: "nr3", // TagRules: []influxdb.TagRule{ // { // Tag: influxdb.Tag{ // Key: "environment", // Value: "production", // }, // Operator: notification.Equal, // }, // { // Tag: influxdb.Tag{ // Key: "location", // Value: "paris", // }, // Operator: notification.Equal, // }, // }, // }, // MessageTemplate: "msg", // }, // }, // }, // args: args{ // filter: influxdb.NotificationRuleFilter{ // Organization: strPtr("org4"), // Tags: []influxdb.Tag{ // { // Key: "environment", // Value: "production", // }, // { // Key: "location", // Value: "paris", // }, // }, // }, // }, // wants: wants{ // notificationRules: []influxdb.NotificationRule{ // &rule.Slack{ // Base: rule.Base{ // ID: MustIDBase16(fourID), // OrgID: MustIDBase16(oneID), // OwnerID: MustIDBase16(sixID), // EndpointID: 1, // Status: influxdb.Active, // Name: "nr3", // TagRules: []influxdb.TagRule{ // { // Tag: influxdb.Tag{ // Key: "environment", // Value: "production", // }, // Operator: notification.Equal, // }, // { // Tag: influxdb.Tag{ // Key: "location", // Value: "paris", // }, // Operator: notification.Equal, // }, // }, // }, // MessageTemplate: "msg", // }, // }, // }, // }, { name: "find owners and restrict by organization", fields: NotificationRuleFields{ Orgs: []*influxdb.Organization{ { ID: MustIDBase16(oneID), Name: "org1", }, { ID: MustIDBase16(fourID), Name: "org4", }, }, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, { ResourceID: MustIDBase16(twoID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Member, }, { ResourceID: MustIDBase16(fourID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), OrgID: MustIDBase16(fourID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr1", }, Channel: "ch1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), OrgID: MustIDBase16(fourID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr2", }, MessageTemplate: "body2", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(fourID), OrgID: MustIDBase16(oneID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr3", }, MessageTemplate: "msg", }, }, }, args: args{ filter: influxdb.NotificationRuleFilter{ OrgID: idPtr(MustIDBase16(oneID)), UserResourceMappingFilter: influxdb.UserResourceMappingFilter{ UserID: MustIDBase16(sixID), ResourceType: influxdb.NotificationRuleResourceType, UserType: influxdb.Owner, }, }, }, wants: wants{ notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(fourID), OrgID: MustIDBase16(oneID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr3", }, MessageTemplate: "msg", }, }, }, }, { name: "look for organization not bound to any notification rule", fields: NotificationRuleFields{ Orgs: []*influxdb.Organization{ { ID: MustIDBase16(oneID), Name: "org1", }, { ID: MustIDBase16(fourID), Name: "org4", }, }, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, { ResourceID: MustIDBase16(twoID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Member, }, { ResourceID: MustIDBase16(fourID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), OrgID: MustIDBase16(fourID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr1", }, Channel: "ch1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), OrgID: MustIDBase16(fourID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr2", }, MessageTemplate: "body2", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(fourID), OrgID: MustIDBase16(fourID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr3", }, MessageTemplate: "msg", }, }, }, args: args{ filter: influxdb.NotificationRuleFilter{ OrgID: idPtr(MustIDBase16(oneID)), }, }, wants: wants{ notificationRules: []influxdb.NotificationRule{}, }, }, { name: "find options limit", fields: NotificationRuleFields{ Orgs: []*influxdb.Organization{ { ID: MustIDBase16(oneID), Name: "org1", }, { ID: MustIDBase16(fourID), Name: "org4", }, }, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, { ResourceID: MustIDBase16(twoID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Member, }, { ResourceID: MustIDBase16(fourID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr1", }, Channel: "ch1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr2", }, MessageTemplate: "body2", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(fourID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr3", }, MessageTemplate: "msg", }, }, }, args: args{ filter: influxdb.NotificationRuleFilter{ OrgID: idPtr(MustIDBase16(oneID)), }, opts: influxdb.FindOptions{ Limit: 2, }, }, wants: wants{ notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr1", }, Channel: "ch1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr2", }, MessageTemplate: "body2", }, }, }, }, { name: "find options offset", fields: NotificationRuleFields{ Orgs: []*influxdb.Organization{ { ID: MustIDBase16(oneID), Name: "org1", }, { ID: MustIDBase16(fourID), Name: "org4", }, }, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, { ResourceID: MustIDBase16(twoID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Member, }, { ResourceID: MustIDBase16(fourID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr1", }, Channel: "ch1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr2", }, MessageTemplate: "body2", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(fourID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr3", }, MessageTemplate: "msg", }, }, }, args: args{ filter: influxdb.NotificationRuleFilter{ OrgID: idPtr(MustIDBase16(oneID)), }, opts: influxdb.FindOptions{ Offset: 1, }, }, wants: wants{ notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr2", }, MessageTemplate: "body2", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(fourID), OrgID: MustIDBase16(oneID), EndpointID: 1, OwnerID: MustIDBase16(sixID), Name: "nr3", }, MessageTemplate: "msg", }, }, }, }, { name: "find nothing", fields: NotificationRuleFields{ Orgs: []*influxdb.Organization{ { ID: MustIDBase16(oneID), Name: "org1", }, { ID: MustIDBase16(fourID), Name: "org4", }, }, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, { ResourceID: MustIDBase16(twoID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Member, }, { ResourceID: MustIDBase16(fourID), ResourceType: influxdb.NotificationRuleResourceType, UserID: MustIDBase16(sixID), UserType: influxdb.Owner, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), OrgID: MustIDBase16(fourID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr1", }, Channel: "ch1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), OrgID: MustIDBase16(fourID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr2", }, MessageTemplate: "body2", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(fourID), OrgID: MustIDBase16(fourID), OwnerID: MustIDBase16(sixID), EndpointID: 1, Name: "nr3", }, MessageTemplate: "msg", }, }, }, args: args{ filter: influxdb.NotificationRuleFilter{ UserResourceMappingFilter: influxdb.UserResourceMappingFilter{ UserID: MustIDBase16(fourID), ResourceType: influxdb.NotificationRuleResourceType, }, }, }, wants: wants{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, done := init(tt.fields, t) defer done() ctx := context.Background() nrs, n, err := s.FindNotificationRules(ctx, tt.args.filter, tt.args.opts) ErrorsEqual(t, err, tt.wants.err) if n != len(tt.wants.notificationRules) { t.Fatalf("notification rules length is different got %d, want %d", n, len(tt.wants.notificationRules)) } if diff := cmp.Diff(nrs, tt.wants.notificationRules, notificationRuleCmpOptions...); diff != "" { t.Errorf("notification rules are different -got/+want\ndiff %s", diff) } }) } } // UpdateNotificationRule testing. func UpdateNotificationRule( init func(NotificationRuleFields, *testing.T) (influxdb.NotificationRuleStore, func()), t *testing.T, ) { type args struct { userID influxdb.ID id influxdb.ID notificationRule influxdb.NotificationRule } type wants struct { notificationRule influxdb.NotificationRule err error } tests := []struct { name string fields NotificationRuleFields args args wants wants }{ { name: "can't find the id", fields: NotificationRuleFields{ TimeGenerator: fakeGenerator, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ userID: MustIDBase16(sixID), id: MustIDBase16(fourID), notificationRule: &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink3", SleepUntil: &time3, Every: mustDuration("2h"), }, MessageTemplate: "msg2", }, }, wants: wants{ err: &influxdb.Error{ Code: influxdb.ENotFound, Msg: "notification rule not found", }, }, }, { name: "regular update", fields: NotificationRuleFields{ TimeGenerator: fakeGenerator, IDGenerator: mock.NewIDGenerator(twoID, t), UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, Tasks: []influxdb.TaskCreate{ { OwnerID: MustIDBase16(sixID), OrganizationID: MustIDBase16(fourID), Flux: `from(bucket: "foo") |> range(start: -1m) option task = {name: "bar", every: 1m} `, }, }, Endpoints: []influxdb.NotificationEndpoint{ &endpoint.Slack{ URL: "http://localhost:7777", Token: influxdb.SecretField{ // TODO(desa): not sure why this has to end in token, but it does Key: "020f755c3c082001-token", Value: strPtr("abc123"), }, Base: endpoint.Base{ OrgID: MustIDBase16Ptr(fourID), Name: "foo", Status: influxdb.Active, }, }, }, Orgs: []*influxdb.Organization{ { ID: MustIDBase16(fourID), Name: "foo", }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Info, }, }, EndpointID: MustIDBase16(twoID), TaskID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Info, }, }, TaskID: MustIDBase16(twoID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ userID: MustIDBase16(sixID), id: MustIDBase16(twoID), notificationRule: &rule.Slack{ Base: rule.Base{ OwnerID: MustIDBase16(sixID), Name: "name3", OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Info, }, }, RunbookLink: "runbooklink3", SleepUntil: &time3, Every: mustDuration("2h"), }, MessageTemplate: "msg2", }, }, wants: wants{ notificationRule: &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name3", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), TaskID: MustIDBase16(twoID), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Info, }, }, EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink3", SleepUntil: &time3, Every: mustDuration("2h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: fakeDate, }, }, MessageTemplate: "msg2", }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, done := init(tt.fields, t) defer done() ctx := context.Background() nrc := influxdb.NotificationRuleCreate{ NotificationRule: tt.args.notificationRule, Status: influxdb.Active, } tc, err := s.UpdateNotificationRule(ctx, tt.args.id, nrc, tt.args.userID) ErrorsEqual(t, err, tt.wants.err) if diff := cmp.Diff(tc, tt.wants.notificationRule, notificationRuleCmpOptions...); tt.wants.err == nil && diff != "" { t.Errorf("notificationRules are different -got/+want\ndiff %s", diff) } }) } } // PatchNotificationRule testing. func PatchNotificationRule( init func(NotificationRuleFields, *testing.T) (influxdb.NotificationRuleStore, func()), t *testing.T, ) { name3 := "name2" status3 := influxdb.Inactive type args struct { //userID influxdb.ID id influxdb.ID upd influxdb.NotificationRuleUpdate } type wants struct { notificationRule influxdb.NotificationRule err error } tests := []struct { name string fields NotificationRuleFields args args wants wants }{ { name: "can't find the id", fields: NotificationRuleFields{ TimeGenerator: fakeGenerator, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ id: MustIDBase16(fourID), upd: influxdb.NotificationRuleUpdate{ Name: &name3, Status: &status3, }, }, wants: wants{ err: &influxdb.Error{ Code: influxdb.ENotFound, Msg: "notification rule not found", }, }, }, { name: "patch without status", fields: NotificationRuleFields{ TimeGenerator: fakeGenerator, IDGenerator: mock.NewIDGenerator(twoID, t), Tasks: []influxdb.TaskCreate{ { OwnerID: MustIDBase16(sixID), OrganizationID: MustIDBase16(fourID), Flux: `from(bucket: "foo") |> range(start: -1m) option task = {name: "bar", every: 1m} `, }, }, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, Endpoints: []influxdb.NotificationEndpoint{ &endpoint.Slack{ URL: "http://localhost:7777", Token: influxdb.SecretField{ // TODO(desa): not sure why this has to end in token, but it does Key: "020f755c3c082001-token", Value: strPtr("abc123"), }, Base: endpoint.Base{ OrgID: MustIDBase16Ptr(fourID), Name: "foo", Status: influxdb.Active, }, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Critical, }, { CurrentLevel: notification.Info, }, }, CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), EndpointID: MustIDBase16(twoID), TaskID: MustIDBase16(twoID), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Critical, }, { CurrentLevel: notification.Info, }, }, OrgID: MustIDBase16(fourID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, Orgs: []*influxdb.Organization{ { ID: MustIDBase16(fourID), Name: "foo", }, }, }, args: args{ id: MustIDBase16(twoID), upd: influxdb.NotificationRuleUpdate{ Name: &name3, }, }, wants: wants{ notificationRule: &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: name3, OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), TaskID: MustIDBase16(twoID), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Critical, }, { CurrentLevel: notification.Info, }, }, RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: fakeDate, }, }, MessageTemplate: "msg", }, }, }, { name: "regular patch", fields: NotificationRuleFields{ TimeGenerator: fakeGenerator, IDGenerator: mock.NewIDGenerator(twoID, t), Tasks: []influxdb.TaskCreate{ { OwnerID: MustIDBase16(sixID), OrganizationID: MustIDBase16(fourID), Flux: `from(bucket: "foo") |> range(start: -1m) option task = {name: "bar", every: 1m} `, }, }, UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, Endpoints: []influxdb.NotificationEndpoint{ &endpoint.Slack{ URL: "http://localhost:7777", Token: influxdb.SecretField{ // TODO(desa): not sure why this has to end in token, but it does Key: "020f755c3c082001-token", Value: strPtr("abc123"), }, Base: endpoint.Base{ OrgID: MustIDBase16Ptr(fourID), Name: "foo", Status: influxdb.Active, }, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Critical, }, { CurrentLevel: notification.Info, }, }, CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), EndpointID: MustIDBase16(twoID), TaskID: MustIDBase16(twoID), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Critical, }, { CurrentLevel: notification.Info, }, }, OrgID: MustIDBase16(fourID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, Orgs: []*influxdb.Organization{ { ID: MustIDBase16(fourID), Name: "foo", }, }, }, args: args{ id: MustIDBase16(twoID), upd: influxdb.NotificationRuleUpdate{ Name: &name3, Status: &status3, }, }, wants: wants{ notificationRule: &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: name3, OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), TaskID: MustIDBase16(twoID), StatusRules: []notification.StatusRule{ { CurrentLevel: notification.Critical, }, { CurrentLevel: notification.Info, }, }, RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: fakeDate, }, }, MessageTemplate: "msg", }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, done := init(tt.fields, t) defer done() ctx := context.Background() tc, err := s.PatchNotificationRule(ctx, tt.args.id, tt.args.upd) ErrorsEqual(t, err, tt.wants.err) if diff := cmp.Diff(tc, tt.wants.notificationRule, notificationRuleCmpOptions...); tt.wants.err == nil && diff != "" { t.Errorf("notificationRules are different -got/+want\ndiff %s", diff) } }) } } // DeleteNotificationRule testing. func DeleteNotificationRule( init func(NotificationRuleFields, *testing.T) (influxdb.NotificationRuleStore, func()), t *testing.T, ) { type args struct { id influxdb.ID userID influxdb.ID } type wants struct { notificationRules []influxdb.NotificationRule userResourceMappings []*influxdb.UserResourceMapping err error } tests := []struct { name string fields NotificationRuleFields args args wants wants }{ { name: "bad id", fields: NotificationRuleFields{ UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ id: influxdb.ID(0), userID: MustIDBase16(sixID), }, wants: wants{ err: &influxdb.Error{ Code: influxdb.EInvalid, Msg: "provided notification rule ID has invalid format", }, userResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), EndpointID: MustIDBase16(twoID), OrgID: MustIDBase16(fourID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, }, { name: "none existing config", fields: NotificationRuleFields{ UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, IDGenerator: mock.NewIDGenerator(twoID, t), Tasks: []influxdb.TaskCreate{ { OwnerID: MustIDBase16(sixID), OrganizationID: MustIDBase16(fourID), Flux: `from(bucket: "foo") |> range(start: -1m) option task = {name: "bar", every: 1m} `, }, }, Orgs: []*influxdb.Organization{ { ID: MustIDBase16(fourID), Name: "foo", }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), TaskID: MustIDBase16(twoID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ id: MustIDBase16(fourID), userID: MustIDBase16(sixID), }, wants: wants{ err: &influxdb.Error{ Code: influxdb.ENotFound, Msg: "notification rule not found", }, userResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink2", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, }, { name: "regular delete", fields: NotificationRuleFields{ UserResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, { ResourceID: MustIDBase16(twoID), UserID: MustIDBase16(sixID), UserType: influxdb.Member, ResourceType: influxdb.NotificationRuleResourceType, }, }, Tasks: []influxdb.TaskCreate{ { OwnerID: MustIDBase16(sixID), OrganizationID: MustIDBase16(fourID), Flux: `from(bucket: "foo") |> range(start: -1m) option task = {name: "bar", every: 1m} `, }, }, IDGenerator: mock.NewIDGenerator(twoID, t), Orgs: []*influxdb.Organization{ { ID: MustIDBase16(fourID), Name: "foo", }, }, NotificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), EndpointID: MustIDBase16(twoID), TaskID: MustIDBase16(twoID), OrgID: MustIDBase16(fourID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(twoID), Name: "name2", OwnerID: MustIDBase16(sixID), TaskID: MustIDBase16(twoID), OrgID: MustIDBase16(fourID), RunbookLink: "runbooklink2", EndpointID: MustIDBase16(twoID), SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, MessageTemplate: "msg", }, }, }, args: args{ id: MustIDBase16(twoID), userID: MustIDBase16(sixID), }, wants: wants{ userResourceMappings: []*influxdb.UserResourceMapping{ { ResourceID: MustIDBase16(oneID), UserID: MustIDBase16(sixID), UserType: influxdb.Owner, ResourceType: influxdb.NotificationRuleResourceType, }, }, notificationRules: []influxdb.NotificationRule{ &rule.Slack{ Base: rule.Base{ ID: MustIDBase16(oneID), Name: "name1", OwnerID: MustIDBase16(sixID), OrgID: MustIDBase16(fourID), TaskID: MustIDBase16(twoID), EndpointID: MustIDBase16(twoID), RunbookLink: "runbooklink1", SleepUntil: &time3, Every: mustDuration("1h"), CRUDLog: influxdb.CRUDLog{ CreatedAt: timeGen1.Now(), UpdatedAt: timeGen2.Now(), }, }, Channel: "channel1", MessageTemplate: "msg1", }, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, done := init(tt.fields, t) defer done() ctx := context.Background() err := s.DeleteNotificationRule(ctx, tt.args.id) ErrorsEqual(t, err, tt.wants.err) filter := influxdb.NotificationRuleFilter{ UserResourceMappingFilter: influxdb.UserResourceMappingFilter{ UserID: tt.args.userID, ResourceType: influxdb.NotificationRuleResourceType, }, } nrs, n, err := s.FindNotificationRules(ctx, filter) if err != nil && tt.wants.err == nil { t.Fatalf("expected errors to be nil got '%v'", err) } if err != nil && tt.wants.err != nil { if want, got := tt.wants.err.Error(), err.Error(); want != got { t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err) } } if n != len(tt.wants.notificationRules) { t.Fatalf("notification rules length is different got %d, want %d", n, len(tt.wants.notificationRules)) } if diff := cmp.Diff(nrs, tt.wants.notificationRules, notificationRuleCmpOptions...); diff != "" { t.Errorf("notification rules are different -got/+want\ndiff %s", diff) } }) } }