diff --git a/service.go b/service.go index 461e5318..1547fac8 100644 --- a/service.go +++ b/service.go @@ -8,17 +8,6 @@ import ( "github.com/google/go-querystring/query" ) -// Integration is an endpoint (like Nagios, email, or an API call) that generates events, which are normalized and de-duplicated by PagerDuty to create incidents. -type Integration struct { - APIObject - Name string `json:"name,omitempty"` - Service *APIObject `json:"service,omitempty"` - CreatedAt string `json:"created_at,omitempty"` - Vendor *APIObject `json:"vendor,omitempty"` - IntegrationKey string `json:"integration_key,omitempty"` - IntegrationEmail string `json:"integration_email,omitempty"` -} - // InlineModel represents when a scheduled action will occur. type InlineModel struct { Type string `json:"type,omitempty"` @@ -265,72 +254,6 @@ func (c *Client) DeleteServiceWithContext(ctx context.Context, id string) error return err } -// CreateIntegration creates a new integration belonging to a service. -// -// Deprecated: Use CreateIntegrationWithContext instead. -func (c *Client) CreateIntegration(id string, i Integration) (*Integration, error) { - return c.CreateIntegrationWithContext(context.Background(), id, i) -} - -// CreateIntegrationWithContext creates a new integration belonging to a service. -func (c *Client) CreateIntegrationWithContext(ctx context.Context, id string, i Integration) (*Integration, error) { - d := map[string]Integration{ - "integration": i, - } - - resp, err := c.post(ctx, "/services/"+id+"/integrations", d, nil) - return getIntegrationFromResponse(c, resp, err) -} - -// GetIntegrationOptions is the data structure used when calling the GetIntegration API endpoint. -type GetIntegrationOptions struct { - Includes []string `url:"include,omitempty,brackets"` -} - -// GetIntegration gets details about an integration belonging to a service. -// -// Deprecated: Use GetIntegrationWithContext instead. -func (c *Client) GetIntegration(serviceID, integrationID string, o GetIntegrationOptions) (*Integration, error) { - return c.GetIntegrationWithContext(context.Background(), serviceID, integrationID, o) -} - -// GetIntegrationWithContext gets details about an integration belonging to a service. -func (c *Client) GetIntegrationWithContext(ctx context.Context, serviceID, integrationID string, o GetIntegrationOptions) (*Integration, error) { - v, err := query.Values(o) - if err != nil { - return nil, err - } - - resp, err := c.get(ctx, "/services/"+serviceID+"/integrations/"+integrationID+"?"+v.Encode()) - return getIntegrationFromResponse(c, resp, err) -} - -// UpdateIntegration updates an integration belonging to a service. -// -// Deprecated: Use UpdateIntegrationWithContext instead. -func (c *Client) UpdateIntegration(serviceID string, i Integration) (*Integration, error) { - return c.UpdateIntegrationWithContext(context.Background(), serviceID, i) -} - -// UpdateIntegrationWithContext updates an integration belonging to a service. -func (c *Client) UpdateIntegrationWithContext(ctx context.Context, serviceID string, i Integration) (*Integration, error) { - resp, err := c.put(ctx, "/services/"+serviceID+"/integrations/"+i.ID, i, nil) - return getIntegrationFromResponse(c, resp, err) -} - -// DeleteIntegration deletes an existing integration. -// -// Deprecated: Use DeleteIntegrationWithContext instead. -func (c *Client) DeleteIntegration(serviceID string, integrationID string) error { - return c.DeleteIntegrationWithContext(context.Background(), serviceID, integrationID) -} - -// DeleteIntegrationWithContext deletes an existing integration. -func (c *Client) DeleteIntegrationWithContext(ctx context.Context, serviceID string, integrationID string) error { - _, err := c.delete(ctx, "/services/"+serviceID+"/integrations/"+integrationID) - return err -} - // ListServiceRulesPaginated gets all rules for a service. func (c *Client) ListServiceRulesPaginated(ctx context.Context, serviceID string) ([]ServiceRule, error) { var rules []ServiceRule diff --git a/service_integration.go b/service_integration.go new file mode 100644 index 00000000..c1068b4a --- /dev/null +++ b/service_integration.go @@ -0,0 +1,354 @@ +package pagerduty + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + + "github.com/google/go-querystring/query" +) + +// IntegrationEmailFilterMode is a type to respresent the different filter modes +// for a Generic Email Integration. This defines how the email filter rules +// (IntegrationEmailFilterRuleMode) are used when emails are ingested. +type IntegrationEmailFilterMode uint8 + +const ( + // EmailFilterModeInvalid only exists to make it harder to use values of + // this type incorrectly. Please instead use one of EmailFilterModeAll, + // EmailFilterModeOr, EmailFilterModeAnd + // + // This value should not get marshaled to JSON by the encoding/json package. + EmailFilterModeInvalid IntegrationEmailFilterMode = iota + + // EmailFilterModeAll means that all incoming email will be be accepted, and + // no email rules will be considered. + EmailFilterModeAll + + // EmailFilterModeOr instructs the email filtering system to accept the + // email if one or more rules match the message. + EmailFilterModeOr + + // EmailFilterModeAnd instructs the email filtering system to accept the + // email only if all of the rules match the message. + EmailFilterModeAnd +) + +// string values for each IntegrationEmailFilterMode value +const ( + efmAll = "all-email" // EmailFilterModeAll + efmOr = "or-rules-email" // EmailFilterModeOr + efmAnd = "and-rules-email" // EmailFilterModeAnd +) + +func (i IntegrationEmailFilterMode) String() string { + switch i { + case EmailFilterModeAll: + return efmAll + + case EmailFilterModeOr: + return efmOr + + case EmailFilterModeAnd: + return efmAnd + + default: + return "invalid" + } +} + +// compile time encoding/json interface satisfaction assertions +var ( + _ json.Marshaler = IntegrationEmailFilterMode(0) + _ json.Unmarshaler = (*IntegrationEmailFilterMode)(nil) +) + +// MarshalJSON satisfies json.Marshaler +func (i IntegrationEmailFilterMode) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf("%q", i.String())), nil +} + +// UnmarshalJSON satisfies json.Unmarshaler +func (i *IntegrationEmailFilterMode) UnmarshalJSON(b []byte) error { + if b[0] != '"' { + if bytes.Equal(b, []byte(`null`)) { + return errors.New("value cannot be null") + } + + // just return json.Unmarshal error + var s string + + err := json.Unmarshal(b, &s) + if err == nil { + panic("this should not be possible...") + } + + return err + } + + v := string(b[1 : len(b)-1]) + + switch v { + case efmAll: + *i = EmailFilterModeAll + + case efmOr: + *i = EmailFilterModeOr + + case efmAnd: + *i = EmailFilterModeAnd + + default: + return fmt.Errorf("unknown value %q", v) + } + + return nil +} + +// IntegrationEmailFilterRuleMode is a type to represent the different matching +// modes of Generic Email Integration Filer Rules without consumers of this +// package needing to be intimately familiar with the specifics of the REST API. +type IntegrationEmailFilterRuleMode uint8 + +const ( + // EmailFilterRuleModeInvalid only exists to make it harder to use values of this + // type incorrectly. Please instead use one of EmailFilterRuleModeAlways, + // EmailFilterRuleModeMatch, or EmailFilterRuleModeNoMatch. + // + // This value should not get marshaled to JSON by the encoding/json package. + EmailFilterRuleModeInvalid IntegrationEmailFilterRuleMode = iota + + // EmailFilterRuleModeAlways means that the specific value can be anything. Any + // associated regular expression will be ignored. + EmailFilterRuleModeAlways + + // EmailFilterRuleModeMatch means that the associated regular expression must + // match the associated value. + EmailFilterRuleModeMatch + + // EmailFilterRuleModeNoMatch means that the associated regular expression must NOT + // match the associated value. + EmailFilterRuleModeNoMatch +) + +// string values for each IntegrationEmailFilterRuleMode value +const ( + efrmAlways = "always" // EmailFilterRuleModeAlways + efrmMatch = "match" // EmailFilterRuleModeMatch + efrmNoMatch = "no-match" // EmailFilterRuleModeNoMatch +) + +func (i IntegrationEmailFilterRuleMode) String() string { + switch i { + case EmailFilterRuleModeMatch: + return efrmMatch + + case EmailFilterRuleModeNoMatch: + return efrmNoMatch + + case EmailFilterRuleModeAlways: + return efrmAlways + + default: + return "invalid" + } +} + +// compile time encoding/json interface satisfaction assertions +var ( + _ json.Marshaler = IntegrationEmailFilterRuleMode(0) + _ json.Unmarshaler = (*IntegrationEmailFilterRuleMode)(nil) +) + +// MarshalJSON satisfies json.Marshaler +func (i IntegrationEmailFilterRuleMode) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf("%q", i.String())), nil +} + +// UnmarshalJSON satisfies json.Unmarshaler +func (i *IntegrationEmailFilterRuleMode) UnmarshalJSON(b []byte) error { + if b[0] != '"' { + if bytes.Equal(b, []byte(`null`)) { + return errors.New("value cannot be null") + } + + // just return json.Unmarshal error + var s string + + err := json.Unmarshal(b, &s) + if err == nil { + panic("this should not be possible...") + } + + return err + } + + v := string(b[1 : len(b)-1]) + + switch v { + case efrmMatch: + *i = EmailFilterRuleModeMatch + + case efrmNoMatch: + *i = EmailFilterRuleModeNoMatch + + case efrmAlways: + *i = EmailFilterRuleModeAlways + + default: + return fmt.Errorf("unknown value %q", v) + } + + return nil +} + +// IntegrationEmailFilterRule represents a single email filter rule for an +// integration of type generic_email_inbound_integration. Information about how +// to configure email rules can be found here: +// https://support.pagerduty.com/docs/email-management-filters-and-rules. +type IntegrationEmailFilterRule struct { + // SubjectMode and SubjectRegex control the behaviors of how this filter + // matches the subject of an inbound email. + SubjectMode IntegrationEmailFilterRuleMode `json:"subject_mode,omitempty"` + SubjectRegex *string `json:"subject_regex,omitempty"` + + // BodyMode and BodyRegex control the behaviors of how this filter matches + // the body of an inbound email. + BodyMode IntegrationEmailFilterRuleMode `json:"body_mode,omitempty"` + BodyRegex *string `json:"body_regex,omitempty"` + + FromEmailMode IntegrationEmailFilterRuleMode `json:"from_email_mode,omitempty"` + FromEmailRegex *string `json:"from_email_regex,omitempty"` +} + +// UnmarshalJSON satisfies json.Unmarshaler. +func (i *IntegrationEmailFilterRule) UnmarshalJSON(b []byte) error { + // the purpose of this function is to ensure that when unmarshaling, the + // different *string values are never nil pointers. + // + // this is not a communicated feature of the API, so if it chnages + // it's not a breaking change -- doesn't mean we can't try. + var ief integrationEmailFilterRule + if err := json.Unmarshal(b, &ief); err != nil { + return err + } + + i.BodyMode = ief.BodyMode + i.SubjectMode = ief.SubjectMode + i.FromEmailMode = ief.FromEmailMode + + // if the *string is nil, set it to a *string with value "" + if ief.SubjectRegex == nil { + i.SubjectRegex = strPtr("") + } else { + i.SubjectRegex = ief.SubjectRegex + } + + if ief.BodyRegex == nil { + i.BodyRegex = strPtr("") + } else { + i.BodyRegex = ief.BodyRegex + } + + if ief.FromEmailRegex == nil { + i.FromEmailRegex = strPtr("") + } else { + i.FromEmailRegex = ief.FromEmailRegex + } + + return nil +} + +func strPtr(s string) *string { return &s } + +type integrationEmailFilterRule struct { + SubjectMode IntegrationEmailFilterRuleMode `json:"subject_mode"` + SubjectRegex *string `json:"subject_regex,omitempty"` + BodyMode IntegrationEmailFilterRuleMode `json:"body_mode"` + BodyRegex *string `json:"body_regex,omitempty"` + FromEmailMode IntegrationEmailFilterRuleMode `json:"from_email_mode"` + FromEmailRegex *string `json:"from_email_regex,omitempty"` +} + +// Integration is an endpoint (like Nagios, email, or an API call) that +// generates events, which are normalized and de-duplicated by PagerDuty to +// create incidents. +type Integration struct { + APIObject + Name string `json:"name,omitempty"` + Service *APIObject `json:"service,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + Vendor *APIObject `json:"vendor,omitempty"` + IntegrationKey string `json:"integration_key,omitempty"` + IntegrationEmail string `json:"integration_email,omitempty"` + EmailFilterMode IntegrationEmailFilterMode `json:"email_filter_mode,omitempty"` + EmailFilters []IntegrationEmailFilterRule `json:"email_filters,omitempty"` +} + +// CreateIntegration creates a new integration belonging to a service. +// +// Deprecated: Use CreateIntegrationWithContext instead. +func (c *Client) CreateIntegration(id string, i Integration) (*Integration, error) { + return c.CreateIntegrationWithContext(context.Background(), id, i) +} + +// CreateIntegrationWithContext creates a new integration belonging to a service. +func (c *Client) CreateIntegrationWithContext(ctx context.Context, id string, i Integration) (*Integration, error) { + d := map[string]Integration{ + "integration": i, + } + + resp, err := c.post(ctx, "/services/"+id+"/integrations", d, nil) + return getIntegrationFromResponse(c, resp, err) +} + +// GetIntegrationOptions is the data structure used when calling the GetIntegration API endpoint. +type GetIntegrationOptions struct { + Includes []string `url:"include,omitempty,brackets"` +} + +// GetIntegration gets details about an integration belonging to a service. +// +// Deprecated: Use GetIntegrationWithContext instead. +func (c *Client) GetIntegration(serviceID, integrationID string, o GetIntegrationOptions) (*Integration, error) { + return c.GetIntegrationWithContext(context.Background(), serviceID, integrationID, o) +} + +// GetIntegrationWithContext gets details about an integration belonging to a service. +func (c *Client) GetIntegrationWithContext(ctx context.Context, serviceID, integrationID string, o GetIntegrationOptions) (*Integration, error) { + v, err := query.Values(o) + if err != nil { + return nil, err + } + + resp, err := c.get(ctx, "/services/"+serviceID+"/integrations/"+integrationID+"?"+v.Encode()) + return getIntegrationFromResponse(c, resp, err) +} + +// UpdateIntegration updates an integration belonging to a service. +// +// Deprecated: Use UpdateIntegrationWithContext instead. +func (c *Client) UpdateIntegration(serviceID string, i Integration) (*Integration, error) { + return c.UpdateIntegrationWithContext(context.Background(), serviceID, i) +} + +// UpdateIntegrationWithContext updates an integration belonging to a service. +func (c *Client) UpdateIntegrationWithContext(ctx context.Context, serviceID string, i Integration) (*Integration, error) { + resp, err := c.put(ctx, "/services/"+serviceID+"/integrations/"+i.ID, i, nil) + return getIntegrationFromResponse(c, resp, err) +} + +// DeleteIntegration deletes an existing integration. +// +// Deprecated: Use DeleteIntegrationWithContext instead. +func (c *Client) DeleteIntegration(serviceID string, integrationID string) error { + return c.DeleteIntegrationWithContext(context.Background(), serviceID, integrationID) +} + +// DeleteIntegrationWithContext deletes an existing integration. +func (c *Client) DeleteIntegrationWithContext(ctx context.Context, serviceID string, integrationID string) error { + _, err := c.delete(ctx, "/services/"+serviceID+"/integrations/"+integrationID) + return err +} diff --git a/service_integration_test.go b/service_integration_test.go new file mode 100644 index 00000000..2d4bce12 --- /dev/null +++ b/service_integration_test.go @@ -0,0 +1,355 @@ +package pagerduty + +import ( + "encoding/json" + "fmt" + "net/http" + "testing" +) + +// Create Integration +func TestClient_CreateIntegration(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/services/1/integrations", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + _, _ = w.Write([]byte(`{"integration": {"id": "1","name":"foo"}}`)) + }) + + client := defaultTestClient(server.URL, "foo") + input := Integration{ + Name: "foo", + } + servID := "1" + + res, err := client.CreateIntegration(servID, input) + + want := &Integration{ + APIObject: APIObject{ + ID: "1", + }, + Name: "foo", + } + + if err != nil { + t.Fatal(err) + } + testEqual(t, want, res) +} + +// Get Integration +func TestClient_GetIntegration(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/services/1/integrations/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + _, _ = w.Write([]byte(`{"integration": {"id": "1","name":"foo"}}`)) + }) + + client := defaultTestClient(server.URL, "foo") + input := GetIntegrationOptions{ + Includes: []string{}, + } + servID := "1" + intID := "1" + + res, err := client.GetIntegration(servID, intID, input) + + want := &Integration{ + APIObject: APIObject{ + ID: "1", + }, + Name: "foo", + } + + if err != nil { + t.Fatal(err) + } + testEqual(t, want, res) +} + +// Update Integration +func TestClient_UpdateIntegration(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/services/1/integrations/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + _, _ = w.Write([]byte(`{"integration": {"id": "1","name":"foo"}}`)) + }) + + client := defaultTestClient(server.URL, "foo") + input := Integration{ + APIObject: APIObject{ + ID: "1", + }, + Name: "foo", + } + servID := "1" + + res, err := client.UpdateIntegration(servID, input) + + want := &Integration{ + APIObject: APIObject{ + ID: "1", + }, + Name: "foo", + } + + if err != nil { + t.Fatal(err) + } + testEqual(t, want, res) +} + +// Delete Integration +func TestClient_DeleteIntegration(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/services/1/integrations/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + }) + + client := defaultTestClient(server.URL, "foo") + servID := "1" + intID := "1" + err := client.DeleteIntegration(servID, intID) + if err != nil { + t.Fatal(err) + } +} + +func TestIntegrationEmailFilterMode_String(t *testing.T) { + tests := []struct { + name string + input IntegrationEmailFilterMode + want string + }{ + {name: "unknown", input: ^IntegrationEmailFilterMode(0), want: "invalid"}, + {name: "invalid", input: EmailFilterModeInvalid, want: "invalid"}, + {name: "all", input: EmailFilterModeAll, want: "all-email"}, + {name: "or", input: EmailFilterModeOr, want: "or-rules-email"}, + {name: "and", input: EmailFilterModeAnd, want: "and-rules-email"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.input.String(); got != tt.want { + t.Fatalf("String() = %q, want %q", got, tt.want) + } + }) + } +} + +func TestIntegrationEmailFilterMode_MarshalJSON(t *testing.T) { + tests := []struct { + name string + input IntegrationEmailFilterMode + want string + }{ + {name: "unknown", input: ^IntegrationEmailFilterMode(0), want: "invalid"}, + {name: "invalid", input: EmailFilterModeInvalid, want: "invalid"}, + {name: "all", input: EmailFilterModeAll, want: "all-email"}, + {name: "or", input: EmailFilterModeOr, want: "or-rules-email"}, + {name: "and", input: EmailFilterModeAnd, want: "and-rules-email"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + json, err := tt.input.MarshalJSON() + testErrCheck(t, "tt.input.MarshalJSON()", "", err) + + want := fmt.Sprintf("%q", tt.want) + + if got := string(json); got != want { + t.Fatalf("MarshalJSON() = `%s`, want `%s`", got, want) + } + }) + } +} + +func TestIntegrationEmailFilterMode_UnmarshalJSON(t *testing.T) { + tests := []struct { + name string + input string + want IntegrationEmailFilterMode + err string + }{ + {name: "invalid", input: `"invalid"`, err: `unknown value "invalid"`}, + {name: "null", input: `null`, err: `value cannot be null`}, + {name: "not_string", input: `42`, err: `json: cannot unmarshal number into Go value of type string`}, + {name: "all", input: `"all-email"`, want: EmailFilterModeAll}, + {name: "or", input: `"or-rules-email"`, want: EmailFilterModeOr}, + {name: "and", input: `"and-rules-email"`, want: EmailFilterModeAnd}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := new(IntegrationEmailFilterMode) + + if cont := testErrCheck(t, "got.UnmarshalJSON()", tt.err, got.UnmarshalJSON([]byte(tt.input))); !cont { + return + } + + if *got != tt.want { + t.Fatalf("got = %d (%s), want = %d (%s)", *got, got.String(), tt.want, tt.want.String()) + } + }) + } +} + +func TestIntegrationEmailFilterRuleMode_String(t *testing.T) { + tests := []struct { + name string + input IntegrationEmailFilterRuleMode + want string + }{ + {name: "unknown", input: ^IntegrationEmailFilterRuleMode(0), want: "invalid"}, + {name: "invalid", input: EmailFilterRuleModeInvalid, want: "invalid"}, + {name: "always", input: EmailFilterRuleModeAlways, want: "always"}, + {name: "match", input: EmailFilterRuleModeMatch, want: "match"}, + {name: "no_match", input: EmailFilterRuleModeNoMatch, want: "no-match"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.input.String(); got != tt.want { + t.Fatalf("String() = %q, want %q", got, tt.want) + } + }) + } +} + +func TestIntegrationEmailFilterRuleMode_MarshalJSON(t *testing.T) { + tests := []struct { + name string + input IntegrationEmailFilterRuleMode + want string + }{ + {name: "unknown", input: ^IntegrationEmailFilterRuleMode(0), want: "invalid"}, + {name: "invalid", input: EmailFilterRuleModeInvalid, want: "invalid"}, + {name: "always", input: EmailFilterRuleModeAlways, want: "always"}, + {name: "match", input: EmailFilterRuleModeMatch, want: "match"}, + {name: "no_match", input: EmailFilterRuleModeNoMatch, want: "no-match"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + json, err := tt.input.MarshalJSON() + testErrCheck(t, "tt.input.MarshalJSON()", "", err) + + want := fmt.Sprintf("%q", tt.want) + + if got := string(json); got != want { + t.Fatalf("MarshalJSON() = `%s`, want `%s`", got, want) + } + }) + } +} + +func TestIntegrationEmailFilterRuleMode_UnmarshalJSON(t *testing.T) { + tests := []struct { + name string + input string + want IntegrationEmailFilterRuleMode + err string + }{ + {name: "invalid", input: `"invalid"`, err: `unknown value "invalid"`}, + {name: "null", input: `null`, err: `value cannot be null`}, + {name: "not_string", input: `42`, err: `json: cannot unmarshal number into Go value of type string`}, + {name: "always", input: `"always"`, want: EmailFilterRuleModeAlways}, + {name: "match", input: `"match"`, want: EmailFilterRuleModeMatch}, + {name: "no_match", input: `"no-match"`, want: EmailFilterRuleModeNoMatch}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := new(IntegrationEmailFilterRuleMode) + + if cont := testErrCheck(t, "got.UnmarshalJSON()", tt.err, got.UnmarshalJSON([]byte(tt.input))); !cont { + return + } + + if *got != tt.want { + t.Fatalf("got = %d (%s), want = %d (%s)", *got, got.String(), tt.want, tt.want.String()) + } + }) + } +} + +func TestIntegrationEmailFilterRule(t *testing.T) { + t.Run("zero_value/omitempty", func(t *testing.T) { + var iefr IntegrationEmailFilterRule + + j, err := json.Marshal(iefr) + testErrCheck(t, "json.Marshal()", "", err) + + if string(j) != "{}" { + t.Fatalf("expected empty object, got %q", string(j)) + } + }) +} + +func TestIntegrationEmailFilterRule_UnmarshalJSON(t *testing.T) { + tests := []struct { + name string + input string + want IntegrationEmailFilterRule + err string + }{ + { + name: "full", + input: `{"subject_mode":"always", "subject_regex":"", "body_mode":"match", "body_regex":"testbody", "from_email_mode":"no-match", "from_email_regex":"testfrom"}`, + want: IntegrationEmailFilterRule{ + SubjectMode: EmailFilterRuleModeAlways, + SubjectRegex: strPtr(""), + BodyMode: EmailFilterRuleModeMatch, + BodyRegex: strPtr("testbody"), + FromEmailMode: EmailFilterRuleModeNoMatch, + FromEmailRegex: strPtr("testfrom"), + }, + }, + + { + name: "empty", + input: `{}`, + want: IntegrationEmailFilterRule{ + SubjectMode: EmailFilterRuleModeInvalid, + SubjectRegex: strPtr(""), + BodyMode: EmailFilterRuleModeInvalid, + BodyRegex: strPtr(""), + FromEmailMode: EmailFilterRuleModeInvalid, + FromEmailRegex: strPtr(""), + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := new(IntegrationEmailFilterRule) + + err := got.UnmarshalJSON([]byte(tt.input)) + + if !testErrCheck(t, "got.UnmarshalJSON()", tt.err, err) { + return + } + + if got.SubjectRegex == nil { + t.Error("got.SubjectRegex = ") + } + + if got.BodyRegex == nil { + t.Error("got.BodyRegex = ") + } + + if got.FromEmailRegex == nil { + t.Error("got.FromEmailRegex = ") + } + + testEqual(t, tt.want, *got) + }) + } +} diff --git a/service_test.go b/service_test.go index 6f05a0fd..dbcc5303 100644 --- a/service_test.go +++ b/service_test.go @@ -314,121 +314,6 @@ func TestService_Delete(t *testing.T) { } } -// Create Integration -func TestService_CreateIntegration(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/services/1/integrations", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "POST") - _, _ = w.Write([]byte(`{"integration": {"id": "1","name":"foo"}}`)) - }) - - client := defaultTestClient(server.URL, "foo") - input := Integration{ - Name: "foo", - } - servID := "1" - - res, err := client.CreateIntegration(servID, input) - - want := &Integration{ - APIObject: APIObject{ - ID: "1", - }, - Name: "foo", - } - - if err != nil { - t.Fatal(err) - } - testEqual(t, want, res) -} - -// Get Integration -func TestService_GetIntegration(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/services/1/integrations/1", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - _, _ = w.Write([]byte(`{"integration": {"id": "1","name":"foo"}}`)) - }) - - client := defaultTestClient(server.URL, "foo") - input := GetIntegrationOptions{ - Includes: []string{}, - } - servID := "1" - intID := "1" - - res, err := client.GetIntegration(servID, intID, input) - - want := &Integration{ - APIObject: APIObject{ - ID: "1", - }, - Name: "foo", - } - - if err != nil { - t.Fatal(err) - } - testEqual(t, want, res) -} - -// Update Integration -func TestService_UpdateIntegration(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/services/1/integrations/1", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - _, _ = w.Write([]byte(`{"integration": {"id": "1","name":"foo"}}`)) - }) - - client := defaultTestClient(server.URL, "foo") - input := Integration{ - APIObject: APIObject{ - ID: "1", - }, - Name: "foo", - } - servID := "1" - - res, err := client.UpdateIntegration(servID, input) - - want := &Integration{ - APIObject: APIObject{ - ID: "1", - }, - Name: "foo", - } - - if err != nil { - t.Fatal(err) - } - testEqual(t, want, res) -} - -// Delete Integration -func TestService_DeleteIntegration(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/services/1/integrations/1", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - }) - - client := defaultTestClient(server.URL, "foo") - servID := "1" - intID := "1" - err := client.DeleteIntegration(servID, intID) - if err != nil { - t.Fatal(err) - } -} - // List Service Rules func TestService_ListRules(t *testing.T) { setup()