diff --git a/datadog-accessors.go b/datadog-accessors.go index da637a4..588bdca 100644 --- a/datadog-accessors.go +++ b/datadog-accessors.go @@ -3517,223 +3517,6 @@ func (c *CreatedBy) SetVerified(v bool) { c.Verified = &v } -// GetSLO returns the SLO field if non-nil, zero value otherwise. -func (c *createSLOThreshold) GetSLO() float64 { - if c == nil || c.SLO == nil { - return 0 - } - return *c.SLO -} - -// GetSLOOk returns a tuple with the SLO field if it's non-nil, zero value otherwise -// and a boolean to check if the value has been set. -func (c *createSLOThreshold) GetSLOOk() (float64, bool) { - if c == nil || c.SLO == nil { - return 0, false - } - return *c.SLO, true -} - -// HasSLO returns a boolean if a field has been set. -func (c *createSLOThreshold) HasSLO() bool { - if c != nil && c.SLO != nil { - return true - } - - return false -} - -// SetSLO allocates a new c.SLO and returns the pointer to it. -func (c *createSLOThreshold) SetSLO(v float64) { - c.SLO = &v -} - -// GetWarning returns the Warning field if non-nil, zero value otherwise. -func (c *createSLOThreshold) GetWarning() float64 { - if c == nil || c.Warning == nil { - return 0 - } - return *c.Warning -} - -// GetWarningOk returns a tuple with the Warning field if it's non-nil, zero value otherwise -// and a boolean to check if the value has been set. -func (c *createSLOThreshold) GetWarningOk() (float64, bool) { - if c == nil || c.Warning == nil { - return 0, false - } - return *c.Warning, true -} - -// HasWarning returns a boolean if a field has been set. -func (c *createSLOThreshold) HasWarning() bool { - if c != nil && c.Warning != nil { - return true - } - - return false -} - -// SetWarning allocates a new c.Warning and returns the pointer to it. -func (c *createSLOThreshold) SetWarning(v float64) { - c.Warning = &v -} - -// GetDescription returns the Description field if non-nil, zero value otherwise. -func (c *createUpdateServiceLevelObjective) GetDescription() string { - if c == nil || c.Description == nil { - return "" - } - return *c.Description -} - -// GetDescriptionOk returns a tuple with the Description field if it's non-nil, zero value otherwise -// and a boolean to check if the value has been set. -func (c *createUpdateServiceLevelObjective) GetDescriptionOk() (string, bool) { - if c == nil || c.Description == nil { - return "", false - } - return *c.Description, true -} - -// HasDescription returns a boolean if a field has been set. -func (c *createUpdateServiceLevelObjective) HasDescription() bool { - if c != nil && c.Description != nil { - return true - } - - return false -} - -// SetDescription allocates a new c.Description and returns the pointer to it. -func (c *createUpdateServiceLevelObjective) SetDescription(v string) { - c.Description = &v -} - -// GetMonitorSearch returns the MonitorSearch field if non-nil, zero value otherwise. -func (c *createUpdateServiceLevelObjective) GetMonitorSearch() string { - if c == nil || c.MonitorSearch == nil { - return "" - } - return *c.MonitorSearch -} - -// GetMonitorSearchOk returns a tuple with the MonitorSearch field if it's non-nil, zero value otherwise -// and a boolean to check if the value has been set. -func (c *createUpdateServiceLevelObjective) GetMonitorSearchOk() (string, bool) { - if c == nil || c.MonitorSearch == nil { - return "", false - } - return *c.MonitorSearch, true -} - -// HasMonitorSearch returns a boolean if a field has been set. -func (c *createUpdateServiceLevelObjective) HasMonitorSearch() bool { - if c != nil && c.MonitorSearch != nil { - return true - } - - return false -} - -// SetMonitorSearch allocates a new c.MonitorSearch and returns the pointer to it. -func (c *createUpdateServiceLevelObjective) SetMonitorSearch(v string) { - c.MonitorSearch = &v -} - -// GetName returns the Name field if non-nil, zero value otherwise. -func (c *createUpdateServiceLevelObjective) GetName() string { - if c == nil || c.Name == nil { - return "" - } - return *c.Name -} - -// GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise -// and a boolean to check if the value has been set. -func (c *createUpdateServiceLevelObjective) GetNameOk() (string, bool) { - if c == nil || c.Name == nil { - return "", false - } - return *c.Name, true -} - -// HasName returns a boolean if a field has been set. -func (c *createUpdateServiceLevelObjective) HasName() bool { - if c != nil && c.Name != nil { - return true - } - - return false -} - -// SetName allocates a new c.Name and returns the pointer to it. -func (c *createUpdateServiceLevelObjective) SetName(v string) { - c.Name = &v -} - -// GetQuery returns the Query field if non-nil, zero value otherwise. -func (c *createUpdateServiceLevelObjective) GetQuery() ServiceLevelObjectiveMetricQuery { - if c == nil || c.Query == nil { - return ServiceLevelObjectiveMetricQuery{} - } - return *c.Query -} - -// GetQueryOk returns a tuple with the Query field if it's non-nil, zero value otherwise -// and a boolean to check if the value has been set. -func (c *createUpdateServiceLevelObjective) GetQueryOk() (ServiceLevelObjectiveMetricQuery, bool) { - if c == nil || c.Query == nil { - return ServiceLevelObjectiveMetricQuery{}, false - } - return *c.Query, true -} - -// HasQuery returns a boolean if a field has been set. -func (c *createUpdateServiceLevelObjective) HasQuery() bool { - if c != nil && c.Query != nil { - return true - } - - return false -} - -// SetQuery allocates a new c.Query and returns the pointer to it. -func (c *createUpdateServiceLevelObjective) SetQuery(v ServiceLevelObjectiveMetricQuery) { - c.Query = &v -} - -// GetType returns the Type field if non-nil, zero value otherwise. -func (c *createUpdateServiceLevelObjective) GetType() string { - if c == nil || c.Type == nil { - return "" - } - return *c.Type -} - -// GetTypeOk returns a tuple with the Type field if it's non-nil, zero value otherwise -// and a boolean to check if the value has been set. -func (c *createUpdateServiceLevelObjective) GetTypeOk() (string, bool) { - if c == nil || c.Type == nil { - return "", false - } - return *c.Type, true -} - -// HasType returns a boolean if a field has been set. -func (c *createUpdateServiceLevelObjective) HasType() bool { - if c != nil && c.Type != nil { - return true - } - - return false -} - -// SetType allocates a new c.Type and returns the pointer to it. -func (c *createUpdateServiceLevelObjective) SetType(v string) { - c.Type = &v -} - // GetEmail returns the Email field if non-nil, zero value otherwise. func (c *Creator) GetEmail() string { if c == nil || c.Email == nil { @@ -15235,66 +15018,66 @@ func (s *ServiceLevelObjectiveMetricQuery) SetNumerator(v string) { s.Numerator = &v } -// GetSLO returns the SLO field if non-nil, zero value otherwise. -func (s *ServiceLevelObjectiveThreshold) GetSLO() float64 { - if s == nil || s.SLO == nil { +// GetTarget returns the Target field if non-nil, zero value otherwise. +func (s *ServiceLevelObjectiveThreshold) GetTarget() float64 { + if s == nil || s.Target == nil { return 0 } - return *s.SLO + return *s.Target } -// GetSLOOk returns a tuple with the SLO field if it's non-nil, zero value otherwise +// GetTargetOk returns a tuple with the Target field if it's non-nil, zero value otherwise // and a boolean to check if the value has been set. -func (s *ServiceLevelObjectiveThreshold) GetSLOOk() (float64, bool) { - if s == nil || s.SLO == nil { +func (s *ServiceLevelObjectiveThreshold) GetTargetOk() (float64, bool) { + if s == nil || s.Target == nil { return 0, false } - return *s.SLO, true + return *s.Target, true } -// HasSLO returns a boolean if a field has been set. -func (s *ServiceLevelObjectiveThreshold) HasSLO() bool { - if s != nil && s.SLO != nil { +// HasTarget returns a boolean if a field has been set. +func (s *ServiceLevelObjectiveThreshold) HasTarget() bool { + if s != nil && s.Target != nil { return true } return false } -// SetSLO allocates a new s.SLO and returns the pointer to it. -func (s *ServiceLevelObjectiveThreshold) SetSLO(v float64) { - s.SLO = &v +// SetTarget allocates a new s.Target and returns the pointer to it. +func (s *ServiceLevelObjectiveThreshold) SetTarget(v float64) { + s.Target = &v } -// GetSLODisplay returns the SLODisplay field if non-nil, zero value otherwise. -func (s *ServiceLevelObjectiveThreshold) GetSLODisplay() string { - if s == nil || s.SLODisplay == nil { +// GetTargetDisplay returns the TargetDisplay field if non-nil, zero value otherwise. +func (s *ServiceLevelObjectiveThreshold) GetTargetDisplay() string { + if s == nil || s.TargetDisplay == nil { return "" } - return *s.SLODisplay + return *s.TargetDisplay } -// GetSLODisplayOk returns a tuple with the SLODisplay field if it's non-nil, zero value otherwise +// GetTargetDisplayOk returns a tuple with the TargetDisplay field if it's non-nil, zero value otherwise // and a boolean to check if the value has been set. -func (s *ServiceLevelObjectiveThreshold) GetSLODisplayOk() (string, bool) { - if s == nil || s.SLODisplay == nil { +func (s *ServiceLevelObjectiveThreshold) GetTargetDisplayOk() (string, bool) { + if s == nil || s.TargetDisplay == nil { return "", false } - return *s.SLODisplay, true + return *s.TargetDisplay, true } -// HasSLODisplay returns a boolean if a field has been set. -func (s *ServiceLevelObjectiveThreshold) HasSLODisplay() bool { - if s != nil && s.SLODisplay != nil { +// HasTargetDisplay returns a boolean if a field has been set. +func (s *ServiceLevelObjectiveThreshold) HasTargetDisplay() bool { + if s != nil && s.TargetDisplay != nil { return true } return false } -// SetSLODisplay allocates a new s.SLODisplay and returns the pointer to it. -func (s *ServiceLevelObjectiveThreshold) SetSLODisplay(v string) { - s.SLODisplay = &v +// SetTargetDisplay allocates a new s.TargetDisplay and returns the pointer to it. +func (s *ServiceLevelObjectiveThreshold) SetTargetDisplay(v string) { + s.TargetDisplay = &v } // GetTimeFrame returns the TimeFrame field if non-nil, zero value otherwise. diff --git a/integration/service_level_objectives_test.go b/integration/service_level_objectives_test.go index 948150b..e510bfc 100644 --- a/integration/service_level_objectives_test.go +++ b/integration/service_level_objectives_test.go @@ -2,6 +2,7 @@ package integration import ( "testing" + "time" "github.com/stretchr/testify/assert" "github.com/zorkian/go-datadog-api" @@ -15,7 +16,7 @@ func TestServiceLevelObjectivesCreateGetUpdateAndDelete(t *testing.T) { Thresholds: datadog.ServiceLevelObjectiveThresholds{ { TimeFrame: datadog.String("7d"), - SLO: datadog.Float64(99), + Target: datadog.Float64(99), Warning: datadog.Float64(99.5), }, }, @@ -34,32 +35,38 @@ func TestServiceLevelObjectivesCreateGetUpdateAndDelete(t *testing.T) { assert.Equal(t, expected.Description, actual.Description) assert.True(t, expected.Thresholds.Equal(actual.Thresholds)) + time.Sleep(time.Second) + // Get found, err := client.GetServiceLevelObjective(actual.GetID()) assert.NoError(t, err) assert.Equal(t, actual.GetID(), found.GetID()) + time.Sleep(time.Second) + // Update actual.SetDescription("Integration test for SLOs - updated") actual.Thresholds = datadog.ServiceLevelObjectiveThresholds{ { TimeFrame: datadog.String("7d"), - SLO: datadog.Float64(99), + Target: datadog.Float64(99), Warning: datadog.Float64(99.5), }, { TimeFrame: datadog.String("30d"), - SLO: datadog.Float64(99), + Target: datadog.Float64(99), Warning: datadog.Float64(99.5), }, } - actual, err = client.UpdateServiceLevelObjective(actual) + updated, err := client.UpdateServiceLevelObjective(actual) assert.NoError(t, err) - assert.Equal(t, "Integration test for SLOs - updated", actual.GetDescription()) - assert.Len(t, actual.Thresholds, 2) + assert.Equal(t, "Integration test for SLOs - updated", updated.GetDescription()) + assert.Len(t, updated.Thresholds, 2) + + time.Sleep(time.Second) // Delete - err = client.DeleteServiceLevelObjective(actual.GetID()) + err = client.DeleteServiceLevelObjective(updated.GetID()) assert.NoError(t, err) } @@ -71,17 +78,17 @@ func TestServiceLevelObjectivesBulkTimeFrameDelete(t *testing.T) { Thresholds: datadog.ServiceLevelObjectiveThresholds{ { TimeFrame: datadog.String("7d"), - SLO: datadog.Float64(99), + Target: datadog.Float64(99), Warning: datadog.Float64(99.5), }, { TimeFrame: datadog.String("30d"), - SLO: datadog.Float64(99), + Target: datadog.Float64(99), Warning: datadog.Float64(99.5), }, { TimeFrame: datadog.String("90d"), - SLO: datadog.Float64(99), + Target: datadog.Float64(99), Warning: datadog.Float64(99.5), }, }, @@ -98,7 +105,7 @@ func TestServiceLevelObjectivesBulkTimeFrameDelete(t *testing.T) { Thresholds: datadog.ServiceLevelObjectiveThresholds{ { TimeFrame: datadog.String("7d"), - SLO: datadog.Float64(99), + Target: datadog.Float64(99), Warning: datadog.Float64(99.5), }, }, @@ -117,6 +124,8 @@ func TestServiceLevelObjectivesBulkTimeFrameDelete(t *testing.T) { assert.NoError(t, err) assert.NotEmpty(t, actual2.GetID()) + time.Sleep(time.Second) + // Do multi-timeframe delete timeframesToDelete := map[string][]string{ // delete only 2 of 3 timeframes from 1 @@ -133,6 +142,8 @@ func TestServiceLevelObjectivesBulkTimeFrameDelete(t *testing.T) { assert.EqualValues(t, []string{actual2.GetID()}, resp.DeletedIDs) assert.EqualValues(t, []string{actual1.GetID()}, resp.UpdatedIDs) + time.Sleep(time.Second) + // Delete err = client.DeleteServiceLevelObjective(actual1.GetID()) assert.NoError(t, err) diff --git a/service_level_objectives.go b/service_level_objectives.go index fa0bbdd..a284a6b 100644 --- a/service_level_objectives.go +++ b/service_level_objectives.go @@ -45,8 +45,8 @@ var ServiceLevelObjectiveTypeToID = map[string]int{ // For example it's the ` of within type ServiceLevelObjectiveThreshold struct { TimeFrame *string `json:"timeframe,omitempty"` - SLO *float64 `json:"slo,omitempty"` - SLODisplay *string `json:"slo_display,omitempty"` // Read-Only for monitor type + Target *float64 `json:"target,omitempty"` + TargetDisplay *string `json:"target_display,omitempty"` // Read-Only for monitor type Warning *float64 `json:"warning,omitempty"` WarningDisplay *string `json:"warning_display,omitempty"` // Read-Only for monitor type } @@ -61,14 +61,14 @@ func (s *ServiceLevelObjectiveThreshold) Equal(o interface{}) bool { } return s.GetTimeFrame() == other.GetTimeFrame() && - Float64AlmostEqual(s.GetSLO(), other.GetSLO(), thresholdTolerance) && + Float64AlmostEqual(s.GetTarget(), other.GetTarget(), thresholdTolerance) && Float64AlmostEqual(s.GetWarning(), other.GetWarning(), thresholdTolerance) } // String implements Stringer func (s ServiceLevelObjectiveThreshold) String() string { - return fmt.Sprintf("Threshold{timeframe=%s slo=%f slo_display=%s warning=%f warning_display=%s", - s.GetTimeFrame(), s.GetSLO(), s.GetSLODisplay(), s.GetWarning(), s.GetWarningDisplay()) + return fmt.Sprintf("Threshold{timeframe=%s target=%f target_display=%s warning=%f warning_display=%s", + s.GetTimeFrame(), s.GetTarget(), s.GetTargetDisplay(), s.GetWarning(), s.GetWarningDisplay()) } // ServiceLevelObjectiveMetricQuery represents a metric-based SLO definition query @@ -161,8 +161,37 @@ type ServiceLevelObjective struct { // Informational MonitorTags []string `json:"monitor_tags,omitempty"` // Read-Only Creator *Creator `json:"creator,omitempty"` // Read-Only - CreatedAt *int `json:"created_at"` // Read-Only - ModifiedAt *int `json:"modified_at"` // Read-Only + CreatedAt *int `json:"created_at,omitempty"` // Read-Only + ModifiedAt *int `json:"modified_at,omitempty"` // Read-Only +} + +// implements custom marshaler to ignore some fields +func (s *ServiceLevelObjective) MarshalJSON() ([]byte, error) { + var output struct { + ID *string `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + Tags []string `json:"tags,omitempty"` + Thresholds ServiceLevelObjectiveThresholds `json:"thresholds,omitempty"` + Type *string `json:"type,omitempty"` + // SLI definition + Query *ServiceLevelObjectiveMetricQuery `json:"query,omitempty"` + MonitorIDs []int `json:"monitor_ids,omitempty"` + MonitorSearch *string `json:"monitor_search,omitempty"` + Groups []string `json:"groups,omitempty"` + } + + output.ID = s.ID + output.Name = s.Name + output.Description = s.Description + output.Tags = s.Tags + output.Thresholds = s.Thresholds + output.Type = s.Type + output.Query = s.Query + output.MonitorIDs = s.MonitorIDs + output.MonitorSearch = s.MonitorSearch + output.Groups = s.Groups + return json.Marshal(&output) } var sloTimeFrameToDurationRegex = regexp.MustCompile(`(?P\d+)(?P(d))`) @@ -195,47 +224,6 @@ func ServiceLevelObjectiveTimeFrameToDuration(timeframe string) (time.Duration, } } -type createSLOThreshold struct { - SLO *float64 `json:"slo,omitempty"` - Warning *float64 `json:"warning,omitempty"` -} - -// createServiceLevelObjective is the appropriate model for creation/update -// note that thresholds is a map of timeframe: -type createUpdateServiceLevelObjective struct { - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - Tags []string `json:"tags,omitempty"` - Thresholds map[string]*createSLOThreshold `json:"thresholds,omitempty"` - Type *string `json:"type,omitempty"` - Query *ServiceLevelObjectiveMetricQuery `json:"query,omitempty"` - MonitorIDs []int `json:"monitor_ids,omitempty"` - MonitorSearch *string `json:"monitor_search,omitempty"` - Groups []string `json:"groups,omitempty"` -} - -func (slo *ServiceLevelObjective) toCreateUpdate() *createUpdateServiceLevelObjective { - thresholds := make(map[string]*createSLOThreshold, 0) - for _, threshold := range slo.Thresholds { - thresholds[threshold.GetTimeFrame()] = &createSLOThreshold{ - SLO: threshold.SLO, - Warning: threshold.Warning, - } - } - - return &createUpdateServiceLevelObjective{ - Name: slo.Name, - Description: slo.Description, - Tags: slo.Tags, - Thresholds: thresholds, - Type: slo.Type, - Query: slo.Query, - MonitorIDs: slo.MonitorIDs, - MonitorSearch: slo.MonitorSearch, - Groups: slo.Groups, - } -} - // CreateServiceLevelObjective adds a new service level objective to the system. This returns a pointer // to the service level objective so you can pass that to UpdateServiceLevelObjective or DeleteServiceLevelObjective // later if needed. @@ -246,7 +234,7 @@ func (client *Client) CreateServiceLevelObjective(slo *ServiceLevelObjective) (* return nil, fmt.Errorf("no SLO specified") } - if err := client.doJsonRequest("POST", "/v1/slo", slo.toCreateUpdate(), &out); err != nil { + if err := client.doJsonRequest("POST", "/v1/slo", slo, &out); err != nil { return nil, err } if out.Error != "" { @@ -265,7 +253,11 @@ func (client *Client) UpdateServiceLevelObjective(slo *ServiceLevelObjective) (* return nil, fmt.Errorf("no SLO specified") } - if err := client.doJsonRequest("PUT", fmt.Sprintf("/v1/slo/%s", slo.GetID()), slo.toCreateUpdate(), &out); err != nil { + if _, ok := slo.GetIDOk(); !ok { + return nil, fmt.Errorf("SLO must be created first") + } + + if err := client.doJsonRequest("PUT", fmt.Sprintf("/v1/slo/%s", slo.GetID()), slo, &out); err != nil { return nil, err } @@ -294,7 +286,7 @@ func (client *Client) SearchServiceLevelObjectives(limit int, offset int, query uriValues.Set("offset", fmt.Sprintf("%d", offset)) } // Either use `query` or use `ids` - hasQuery := query != "" + hasQuery := strings.TrimSpace(query) != "" hasIDs := len(ids) > 0 if hasQuery && hasIDs { return nil, fmt.Errorf("invalid search: must specify either ids OR query, not both") @@ -349,24 +341,6 @@ func (client *Client) GetServiceLevelObjective(id string) (*ServiceLevelObjectiv return out.Data, nil } -// GetServiceLevelObjectives retrieves an service level objective by identifier. -func (client *Client) GetServiceLevelObjectives(ids []string) ([]*ServiceLevelObjective, error) { - var out reqServiceLevelObjectives - - if len(ids) == 0 { - return nil, fmt.Errorf("no SLO IDs specified") - } - - if err := client.doJsonRequest("GET", "/v1/slo", ids, &out); err != nil { - return nil, err - } - if out.Error != "" { - return nil, fmt.Errorf(out.Error) - } - - return out.Data, nil -} - type reqDeleteResp struct { Data []string `json:"data"` Error string `json:"error"` diff --git a/service_level_objectives_test.go b/service_level_objectives_test.go index baf2fd6..7359092 100644 --- a/service_level_objectives_test.go +++ b/service_level_objectives_test.go @@ -24,7 +24,7 @@ func TestServiceLevelObjectiveSerialization(t *testing.T) { Thresholds: []*ServiceLevelObjectiveThreshold{ { TimeFrame: String("7d"), - SLO: Float64(99), + Target: Float64(99), Warning: Float64(99.5), }, }, @@ -50,8 +50,48 @@ func TestServiceLevelObjectiveSerialization(t *testing.T) { assert.Nil(t, deserializedSLO.Groups) } -func testSLOGetMock(t *testing.T, fixturePath string) (*httptest.Server, *Client) { +const sloTestFixturePrefix = "./tests/fixtures/service_level_objectives/" + +func testSLOGetMock(t *testing.T, expectedInputFixturePath, fixturePath string) (*httptest.Server, *Client) { + + if expectedInputFixturePath != "" { + expectedInputFixturePath = sloTestFixturePrefix + expectedInputFixturePath + } + fixturePath = sloTestFixturePrefix + fixturePath + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if expectedInputFixturePath != "" && r != nil { + body := r.Body + if body == nil { + t.Fatal("nil body received") + } + defer body.Close() + payload, err := ioutil.ReadAll(body) + if err != nil { + t.Fatal(err) + } + + var payloadContent interface{} + err = json.Unmarshal(payload, &payloadContent) + if err != nil { + t.Fatal(err) + } + + expectedPayload, err := ioutil.ReadFile(expectedInputFixturePath) + if err != nil { + t.Fatal(err) + } + var expectedPayloadContent interface{} + err = json.Unmarshal(expectedPayload, &expectedPayloadContent) + if err != nil { + t.Fatal(err) + } + + if !assert.Equal(t, expectedPayloadContent, payloadContent) { + t.Fatalf("expected input did not match actual input") + } + } + response, err := ioutil.ReadFile(fixturePath) if err != nil { t.Fatal(err) @@ -67,60 +107,71 @@ func testSLOGetMock(t *testing.T, fixturePath string) (*httptest.Server, *Client } func getMockSLO(id string) *ServiceLevelObjective { + var sloID *string = nil + if id != "" { + sloID = &id + } return &ServiceLevelObjective{ - ID: &id, + ID: sloID, Name: sptr("Test SLO"), - Description: sptr("Test Description"), + Description: sptr("test slo description"), Tags: []string{"product:foo"}, Thresholds: []*ServiceLevelObjectiveThreshold{ { TimeFrame: String("7d"), - SLO: Float64(99), + Target: Float64(99), Warning: Float64(99.5), }, { TimeFrame: String("30d"), - SLO: Float64(98), + Target: Float64(98), Warning: Float64(99), }, { TimeFrame: String("90d"), - SLO: Float64(98), + Target: Float64(98), Warning: Float64(99), }, }, - Type: &ServiceLevelObjectiveTypeMonitor, - MonitorIDs: []int{1}, } } func TestServiceLevelObjectiveIntegration(t *testing.T) { t.Run("CreateMonitor", func(t2 *testing.T) { - ts, c := testSLOGetMock(t2, "./tests/fixtures/service_level_objectives/create_response.json") + ts, c := testSLOGetMock(t2, "create_request_monitor.json", "create_response_monitor.json") defer ts.Close() slo := getMockSLO("") + slo.SetType(ServiceLevelObjectiveTypeMonitor) + slo.MonitorIDs = []int{1} created, err := c.CreateServiceLevelObjective(slo) assert.NoError(t2, err) assert.Equal(t2, "12345678901234567890123456789012", created.GetID()) }) t.Run("CreateMetric", func(t2 *testing.T) { - ts, c := testSLOGetMock(t2, "./tests/fixtures/service_level_objectives/create_response_metric.json") + ts, c := testSLOGetMock(t2, "create_request_metric.json", "create_response_metric.json") defer ts.Close() slo := getMockSLO("") + slo.SetType(ServiceLevelObjectiveTypeMetric) + slo.SetQuery(ServiceLevelObjectiveMetricQuery{ + Numerator: String("sum:my.metric{type:good}.as_count()"), + Denominator: String("sum:my.metric{*}.as_count()"), + }) created, err := c.CreateServiceLevelObjective(slo) assert.NoError(t2, err) assert.Equal(t2, "abcdefabcdefabcdefabcdefabcdefab", created.GetID()) }) t.Run("Update", func(t2 *testing.T) { - ts, c := testSLOGetMock(t2, "./tests/fixtures/service_level_objectives/update_response.json") + ts, c := testSLOGetMock(t2, "update_request.json", "update_response.json") defer ts.Close() slo := getMockSLO("12345678901234567890123456789012") + slo.SetType(ServiceLevelObjectiveTypeMonitor) + slo.MonitorIDs = []int{1} slo, err := c.UpdateServiceLevelObjective(slo) assert.NoError(t2, err) assert.Equal(t2, "12345678901234567890123456789012", slo.GetID()) @@ -128,7 +179,7 @@ func TestServiceLevelObjectiveIntegration(t *testing.T) { }) t.Run("Delete", func(t2 *testing.T) { - ts, c := testSLOGetMock(t2, "./tests/fixtures/service_level_objectives/delete_response.json") + ts, c := testSLOGetMock(t2, "", "delete_response.json") defer ts.Close() slo := getMockSLO("12345678901234567890123456789012") @@ -137,7 +188,7 @@ func TestServiceLevelObjectiveIntegration(t *testing.T) { }) t.Run("DeleteMany", func(t2 *testing.T) { - ts, c := testSLOGetMock(t2, "./tests/fixtures/service_level_objectives/delete_many_response.json") + ts, c := testSLOGetMock(t2, "delete_many_request.json", "delete_many_response.json") defer ts.Close() err := c.DeleteServiceLevelObjectives( @@ -147,7 +198,7 @@ func TestServiceLevelObjectiveIntegration(t *testing.T) { }) t.Run("DeleteByTimeframe", func(t2 *testing.T) { - ts, c := testSLOGetMock(t2, "./tests/fixtures/service_level_objectives/delete_by_timeframe_response.json") + ts, c := testSLOGetMock(t2, "delete_by_timeframe_request.json", "delete_by_timeframe_response.json") defer ts.Close() /* Some Context for this test case: This is useful for doing individual time-frame deletes across different SLOs (used by the web list view bulk delete) @@ -169,7 +220,7 @@ func TestServiceLevelObjectiveIntegration(t *testing.T) { }) t.Run("GetByID", func(t2 *testing.T) { - ts, c := testSLOGetMock(t2, "./tests/fixtures/service_level_objectives/get_by_id_response.json") + ts, c := testSLOGetMock(t2, "", "get_by_id_response.json") defer ts.Close() slo, err := c.GetServiceLevelObjective("12345678901234567890123456789012") @@ -177,11 +228,11 @@ func TestServiceLevelObjectiveIntegration(t *testing.T) { assert.Equal(t2, "12345678901234567890123456789012", slo.GetID()) }) - t.Run("GetManyWithIDs", func(t2 *testing.T) { - ts, c := testSLOGetMock(t2, "./tests/fixtures/service_level_objectives/get_many_response.json") + t.Run("SearchWithIDs", func(t2 *testing.T) { + ts, c := testSLOGetMock(t2, "", "get_many_response.json") defer ts.Close() - slos, err := c.GetServiceLevelObjectives([]string{"12345678901234567890123456789012", "abcdefabcdefabcdefabcdefabcdefab"}) + slos, err := c.SearchServiceLevelObjectives(1000, 0, "", []string{"12345678901234567890123456789012", "abcdefabcdefabcdefabcdefabcdefab"}) assert.NoError(t2, err) assert.Len(t2, slos, 2) @@ -197,8 +248,8 @@ func TestServiceLevelObjectiveIntegration(t *testing.T) { assert.True(t2, contains(slos, "abcdefabcdefabcdefabcdefabcdefab")) }) - t.Run("Search", func(t2 *testing.T) { - ts, c := testSLOGetMock(t2, "./tests/fixtures/service_level_objectives/search_response.json") + t.Run("SearchWithQuery", func(t2 *testing.T) { + ts, c := testSLOGetMock(t2, "", "search_response.json") defer ts.Close() slos, err := c.SearchServiceLevelObjectives(1000, 0, "service:foo AND team:a", nil) @@ -211,15 +262,15 @@ func TestServiceLevelObjectiveIntegration(t *testing.T) { thresholds := ServiceLevelObjectiveThresholds{ { TimeFrame: String("30d"), - SLO: Float64(99.9), + Target: Float64(99.9), }, { TimeFrame: String("7d"), - SLO: Float64(98.9), + Target: Float64(98.9), }, { TimeFrame: String("90d"), - SLO: Float64(97.9), + Target: Float64(97.9), }, } @@ -232,23 +283,23 @@ func TestServiceLevelObjectiveIntegration(t *testing.T) { t.Run("thresholds are comparable", func(t2 *testing.T) { threshold1 := &ServiceLevelObjectiveThreshold{ TimeFrame: String("30d"), - SLO: Float64(99.9), + Target: Float64(99.9), } threshold2 := &ServiceLevelObjectiveThreshold{ TimeFrame: String("30d"), - SLO: Float64(99.9), + Target: Float64(99.9), } assert.True(t2, threshold1.Equal(threshold2)) threshold3 := &ServiceLevelObjectiveThreshold{ TimeFrame: String("30d"), - SLO: Float64(0.9), + Target: Float64(0.9), } assert.False(t2, threshold3.Equal(threshold2)) threshold4 := &ServiceLevelObjectiveThreshold{ TimeFrame: String("7d"), - SLO: Float64(99.9), + Target: Float64(99.9), } assert.False(t2, threshold2.Equal(threshold4)) }) diff --git a/tests/fixtures/service_level_objectives/create_request_metric.json b/tests/fixtures/service_level_objectives/create_request_metric.json new file mode 100644 index 0000000..2283608 --- /dev/null +++ b/tests/fixtures/service_level_objectives/create_request_metric.json @@ -0,0 +1,27 @@ +{ + "name": "Test SLO", + "tags": ["product:foo"], + "type": "metric", + "description": "test slo description", + "query": { + "numerator": "sum:my.metric{type:good}.as_count()", + "denominator": "sum:my.metric{*}.as_count()" + }, + "thresholds": [ + { + "timeframe": "7d", + "target": 99.0, + "warning": 99.5 + }, + { + "timeframe": "30d", + "target": 98, + "warning": 99 + }, + { + "timeframe": "90d", + "target": 98, + "warning": 99 + } + ] +} \ No newline at end of file diff --git a/tests/fixtures/service_level_objectives/create_request_monitor.json b/tests/fixtures/service_level_objectives/create_request_monitor.json new file mode 100644 index 0000000..ab97a5c --- /dev/null +++ b/tests/fixtures/service_level_objectives/create_request_monitor.json @@ -0,0 +1,24 @@ +{ + "name": "Test SLO", + "tags": ["product:foo"], + "type": "monitor", + "description": "test slo description", + "monitor_ids": [1], + "thresholds": [ + { + "timeframe": "7d", + "target": 99.0, + "warning": 99.5 + }, + { + "timeframe": "30d", + "target": 98, + "warning": 99 + }, + { + "timeframe": "90d", + "target": 98, + "warning": 99 + } + ] +} \ No newline at end of file diff --git a/tests/fixtures/service_level_objectives/create_response_metric.json b/tests/fixtures/service_level_objectives/create_response_metric.json index fefbf3a..411c5eb 100644 --- a/tests/fixtures/service_level_objectives/create_response_metric.json +++ b/tests/fixtures/service_level_objectives/create_response_metric.json @@ -15,15 +15,15 @@ "thresholds": [ { "timeframe": "7d", - "slo": 99.0, - "slo_display": "99.0", + "target": 99.0, + "target_display": "99.0", "warning": 99.5, "warning_display": "99.5" }, { "timeframe": "30d", - "slo": 98, - "slo_display": "98.0", + "target": 98, + "target_display": "98.0", "warning": 99, "warning_display": "99.0" } diff --git a/tests/fixtures/service_level_objectives/create_response.json b/tests/fixtures/service_level_objectives/create_response_monitor.json similarity index 86% rename from tests/fixtures/service_level_objectives/create_response.json rename to tests/fixtures/service_level_objectives/create_response_monitor.json index 918f7a7..ba0aec7 100644 --- a/tests/fixtures/service_level_objectives/create_response.json +++ b/tests/fixtures/service_level_objectives/create_response_monitor.json @@ -12,15 +12,15 @@ "thresholds": [ { "timeframe": "7d", - "slo": 99.0, - "slo_display": "99.0", + "target": 99.0, + "target_display": "99.0", "warning": 99.5, "warning_display": "99.5" }, { "timeframe": "30d", - "slo": 98, - "slo_display": "98.0", + "target": 98, + "target_display": "98.0", "warning": 99, "warning_display": "99.0" } diff --git a/tests/fixtures/service_level_objectives/delete_by_timeframe_request.json b/tests/fixtures/service_level_objectives/delete_by_timeframe_request.json new file mode 100644 index 0000000..65e1cf0 --- /dev/null +++ b/tests/fixtures/service_level_objectives/delete_by_timeframe_request.json @@ -0,0 +1,4 @@ +{ + "12345678901234567890123456789012": ["7d"], + "abcdefabcdefabcdefabcdefabcdefab": ["30d", "90d"] +} \ No newline at end of file diff --git a/tests/fixtures/service_level_objectives/delete_many_request.json b/tests/fixtures/service_level_objectives/delete_many_request.json new file mode 100644 index 0000000..7e01a23 --- /dev/null +++ b/tests/fixtures/service_level_objectives/delete_many_request.json @@ -0,0 +1,4 @@ +[ + "12345678901234567890123456789012", + "abcdefabcdefabcdefabcdefabcdefab" +] \ No newline at end of file diff --git a/tests/fixtures/service_level_objectives/get_by_id_response.json b/tests/fixtures/service_level_objectives/get_by_id_response.json index 64a70fd..16034c4 100644 --- a/tests/fixtures/service_level_objectives/get_by_id_response.json +++ b/tests/fixtures/service_level_objectives/get_by_id_response.json @@ -11,15 +11,15 @@ "thresholds": [ { "timeframe": "7d", - "slo": 99.0, - "slo_display": "99.0", + "target": 99.0, + "target_display": "99.0", "warning": 99.5, "warning_display": "99.5" }, { "timeframe": "30d", - "slo": 98, - "slo_display": "98.0", + "target": 98, + "target_display": "98.0", "warning": 99, "warning_display": "99.0" } diff --git a/tests/fixtures/service_level_objectives/get_many_response.json b/tests/fixtures/service_level_objectives/get_many_response.json index c1eb9dd..50d1d04 100644 --- a/tests/fixtures/service_level_objectives/get_many_response.json +++ b/tests/fixtures/service_level_objectives/get_many_response.json @@ -12,15 +12,15 @@ "thresholds": [ { "timeframe": "7d", - "slo": 99.0, - "slo_display": "99.0", + "target": 99.0, + "target_display": "99.0", "warning": 99.5, "warning_display": "99.5" }, { "timeframe": "30d", - "slo": 98, - "slo_display": "98.0", + "target": 98, + "target_display": "98.0", "warning": 99, "warning_display": "99.0" } @@ -47,15 +47,15 @@ "thresholds": [ { "timeframe": "7d", - "slo": 99.0, - "slo_display": "99.0", + "target": 99.0, + "target_display": "99.0", "warning": 99.5, "warning_display": "99.5" }, { "timeframe": "30d", - "slo": 98, - "slo_display": "98.0", + "target": 98, + "target_display": "98.0", "warning": 99, "warning_display": "99.0" } diff --git a/tests/fixtures/service_level_objectives/search_response.json b/tests/fixtures/service_level_objectives/search_response.json index 918f7a7..ba0aec7 100644 --- a/tests/fixtures/service_level_objectives/search_response.json +++ b/tests/fixtures/service_level_objectives/search_response.json @@ -12,15 +12,15 @@ "thresholds": [ { "timeframe": "7d", - "slo": 99.0, - "slo_display": "99.0", + "target": 99.0, + "target_display": "99.0", "warning": 99.5, "warning_display": "99.5" }, { "timeframe": "30d", - "slo": 98, - "slo_display": "98.0", + "target": 98, + "target_display": "98.0", "warning": 99, "warning_display": "99.0" } diff --git a/tests/fixtures/service_level_objectives/update_request.json b/tests/fixtures/service_level_objectives/update_request.json new file mode 100644 index 0000000..4304ded --- /dev/null +++ b/tests/fixtures/service_level_objectives/update_request.json @@ -0,0 +1,25 @@ +{ + "id": "12345678901234567890123456789012", + "name": "Test SLO", + "tags": ["product:foo"], + "type": "monitor", + "description": "test slo description", + "monitor_ids": [1], + "thresholds": [ + { + "timeframe": "7d", + "target": 99.0, + "warning": 99.5 + }, + { + "timeframe": "30d", + "target": 98, + "warning": 99 + }, + { + "timeframe": "90d", + "target": 98, + "warning": 99 + } + ] +} \ No newline at end of file diff --git a/tests/fixtures/service_level_objectives/update_response.json b/tests/fixtures/service_level_objectives/update_response.json index 671c784..f040117 100644 --- a/tests/fixtures/service_level_objectives/update_response.json +++ b/tests/fixtures/service_level_objectives/update_response.json @@ -12,15 +12,15 @@ "thresholds": [ { "timeframe": "7d", - "slo": 99.0, - "slo_display": "99.0", + "target": 99.0, + "target_display": "99.0", "warning": 99.5, "warning_display": "99.5" }, { "timeframe": "30d", - "slo": 98, - "slo_display": "98.0", + "target": 98, + "target_display": "98.0", "warning": 99, "warning_display": "99.0" }