Skip to content

Commit

Permalink
Add validation for viz objects (#228)
Browse files Browse the repository at this point in the history
* validating functions added for viz objects

* viz objects code refactored

* update slo to return error after decoding
  • Loading branch information
klisiecka-splunk authored Nov 21, 2024
1 parent 84ee8bb commit 24f90a2
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 194 deletions.
104 changes: 36 additions & 68 deletions chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"context"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
Expand All @@ -20,106 +19,75 @@ const UpdateSloChartAPIURL = ChartAPIURL + "/updateSloChart"

// CreateChart creates a chart.
func (c *Client) CreateChart(ctx context.Context, chartRequest *chart.CreateUpdateChartRequest) (*chart.Chart, error) {
return c.internalCreateChart(ctx, chartRequest, ChartAPIURL)
return c.executeChartRequest(ctx, ChartAPIURL, http.MethodPost, http.StatusOK, chartRequest)
}

// CreateSloChart creates a SLO chart.
func (c *Client) CreateSloChart(ctx context.Context, chartRequest *chart.CreateUpdateSloChartRequest) (*chart.Chart, error) {
return c.internalCreateChart(ctx, chartRequest, CreateSloChartAPIURL)
}

func (c *Client) internalCreateChart(ctx context.Context, chartRequest interface{}, url string) (*chart.Chart, error) {
payload, err := json.Marshal(chartRequest)
if err != nil {
return nil, err
}

resp, err := c.doRequest(ctx, "POST", url, nil, bytes.NewReader(payload))
if err != nil {
return nil, err
}
defer resp.Body.Close()

if err = newResponseError(resp, http.StatusOK); err != nil {
return nil, err
}

finalChart := &chart.Chart{}

err = json.NewDecoder(resp.Body).Decode(finalChart)
_, _ = io.Copy(ioutil.Discard, resp.Body)

return finalChart, err
return c.executeChartRequest(ctx, CreateSloChartAPIURL, http.MethodPost, http.StatusOK, chartRequest)
}

// DeleteChart deletes a chart.
func (c *Client) DeleteChart(ctx context.Context, id string) error {
resp, err := c.doRequest(ctx, "DELETE", ChartAPIURL+"/"+id, nil, nil)
if err != nil {
return err
}
defer resp.Body.Close()

if err = newResponseError(resp, http.StatusOK); err != nil {
return err
_, err := c.executeChartRequest(ctx, ChartAPIURL+"/"+id, http.MethodDelete, http.StatusOK, nil)
if err == io.EOF {
// Expected error as delete request returns status 200 instead of 204
return nil
}
_, _ = io.Copy(ioutil.Discard, resp.Body)

return nil
return err
}

// GetChart gets a chart.
func (c *Client) GetChart(ctx context.Context, id string) (*chart.Chart, error) {
resp, err := c.doRequest(ctx, "GET", ChartAPIURL+"/"+id, nil, nil)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if err = newResponseError(resp, http.StatusOK); err != nil {
return nil, err
}

finalChart := &chart.Chart{}

err = json.NewDecoder(resp.Body).Decode(finalChart)
_, _ = io.Copy(ioutil.Discard, resp.Body)

return finalChart, err
return c.executeChartRequest(ctx, ChartAPIURL+"/"+id, http.MethodGet, http.StatusOK, nil)
}

// UpdateChart updates a chart.
func (c *Client) UpdateChart(ctx context.Context, id string, chartRequest *chart.CreateUpdateChartRequest) (*chart.Chart, error) {
return c.internalUpdateChart(ctx, id, chartRequest, ChartAPIURL)
return c.executeChartRequest(ctx, ChartAPIURL+"/"+id, http.MethodPut, http.StatusOK, chartRequest)
}

// UpdateSloChart updates an SLO chart.
func (c *Client) UpdateSloChart(ctx context.Context, id string, chartRequest *chart.CreateUpdateSloChartRequest) (*chart.Chart, error) {
return c.internalUpdateChart(ctx, id, chartRequest, UpdateSloChartAPIURL)
return c.executeChartRequest(ctx, UpdateSloChartAPIURL+"/"+id, http.MethodPut, http.StatusOK, chartRequest)
}

func (c *Client) internalUpdateChart(ctx context.Context, id string, chartRequest interface{}, url string) (*chart.Chart, error) {
payload, err := json.Marshal(chartRequest)
if err != nil {
return nil, err
// ValidateChart validates a chart.
func (c *Client) ValidateChart(ctx context.Context, chartRequest *chart.CreateUpdateChartRequest) error {
_, err := c.executeChartRequest(ctx, ChartAPIURL+"/validate", http.MethodPost, http.StatusNoContent, chartRequest)
return err
}

func (c *Client) executeChartRequest(ctx context.Context, url string, method string, expectedValidStatus int, chartRequest interface{}) (*chart.Chart, error) {
var body io.Reader
if chartRequest != nil {
payload, err := json.Marshal(chartRequest)
if err != nil {
return nil, err
}

body = bytes.NewReader(payload)
}

resp, err := c.doRequest(ctx, "PUT", url+"/"+id, nil, bytes.NewReader(payload))
resp, err := c.doRequest(ctx, method, url, nil, body)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if err = newResponseError(resp, http.StatusOK); err != nil {
if err = newResponseError(resp, expectedValidStatus); err != nil {
return nil, err
}

finalChart := &chart.Chart{}

err = json.NewDecoder(resp.Body).Decode(finalChart)
_, _ = io.Copy(ioutil.Discard, resp.Body)
if expectedValidStatus == http.StatusNoContent {
_, _ = io.Copy(io.Discard, resp.Body)
return nil, nil
}

return finalChart, err
returnedChart := &chart.Chart{}
err = json.NewDecoder(resp.Body).Decode(returnedChart)
_, _ = io.Copy(io.Discard, resp.Body)
return returnedChart, err
}

// SearchCharts searches for charts, given a query string in `name`.
Expand Down Expand Up @@ -147,7 +115,7 @@ func (c *Client) SearchCharts(ctx context.Context, limit int, name string, offse
finalCharts := &chart.SearchResult{}

err = json.NewDecoder(resp.Body).Decode(finalCharts)
_, _ = io.Copy(ioutil.Discard, resp.Body)
_, _ = io.Copy(io.Discard, resp.Body)

return finalCharts, err
}
24 changes: 24 additions & 0 deletions chart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,27 @@ func TestUpdateMissingSloChart(t *testing.T) {
assert.Error(t, err, "Expected error updating chart")
assert.Nil(t, result, "Expected nil result updating chart")
}

func TestValidateChart(t *testing.T) {
teardown := setup()
defer teardown()

mux.HandleFunc("/v2/chart/validate", verifyRequest(t, "POST", true, http.StatusNoContent, nil, ""))

err := client.ValidateChart(context.Background(), &chart.CreateUpdateChartRequest{
Name: "string",
})
assert.NoError(t, err, "Unexpected error creating chart")
}

func TestBadValidateChart(t *testing.T) {
teardown := setup()
defer teardown()

mux.HandleFunc("/v2/chart/validate", verifyRequest(t, "POST", true, http.StatusBadRequest, nil, ""))

err := client.ValidateChart(context.Background(), &chart.CreateUpdateChartRequest{
Name: "string",
})
assert.Error(t, err, "Expected error creating bad chart")
}
96 changes: 36 additions & 60 deletions dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"context"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
Expand All @@ -20,88 +19,65 @@ const DashboardAPIURL = "/v2/dashboard"

// CreateDashboard creates a dashboard.
func (c *Client) CreateDashboard(ctx context.Context, dashboardRequest *dashboard.CreateUpdateDashboardRequest) (*dashboard.Dashboard, error) {
payload, err := json.Marshal(dashboardRequest)
if err != nil {
return nil, err
}

resp, err := c.doRequest(ctx, "POST", DashboardAPIURL, nil, bytes.NewReader(payload))
if err != nil {
return nil, err
}
defer resp.Body.Close()

if err = newResponseError(resp, http.StatusOK); err != nil {
return nil, err
}

finalDashboard := &dashboard.Dashboard{}

err = json.NewDecoder(resp.Body).Decode(finalDashboard)
_, _ = io.Copy(ioutil.Discard, resp.Body)

return finalDashboard, err
return c.executeDashboardRequest(ctx, DashboardAPIURL, http.MethodPost, http.StatusOK, dashboardRequest)
}

// DeleteDashboard deletes a dashboard.
func (c *Client) DeleteDashboard(ctx context.Context, id string) error {
resp, err := c.doRequest(ctx, "DELETE", DashboardAPIURL+"/"+id, nil, nil)
if err != nil {
return err
_, err := c.executeDashboardRequest(ctx, DashboardAPIURL+"/"+id, http.MethodDelete, http.StatusOK, nil)
if err == io.EOF {
// Expected error as delete request returns status 200 instead of 204
return nil
}
defer resp.Body.Close()

if err = newResponseError(resp, http.StatusOK); err != nil {
return err
}
_, _ = io.Copy(ioutil.Discard, resp.Body)

return nil
return err
}

// GetDashboard gets a dashboard.
func (c *Client) GetDashboard(ctx context.Context, id string) (*dashboard.Dashboard, error) {
resp, err := c.doRequest(ctx, "GET", DashboardAPIURL+"/"+id, nil, nil)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if err = newResponseError(resp, http.StatusOK); err != nil {
return nil, err
}

finalDashboard := &dashboard.Dashboard{}

err = json.NewDecoder(resp.Body).Decode(finalDashboard)
_, _ = io.Copy(ioutil.Discard, resp.Body)

return finalDashboard, err
return c.executeDashboardRequest(ctx, DashboardAPIURL+"/"+id, http.MethodGet, http.StatusOK, nil)
}

// UpdateDashboard updates a dashboard.
func (c *Client) UpdateDashboard(ctx context.Context, id string, dashboardRequest *dashboard.CreateUpdateDashboardRequest) (*dashboard.Dashboard, error) {
payload, err := json.Marshal(dashboardRequest)
if err != nil {
return nil, err
return c.executeDashboardRequest(ctx, DashboardAPIURL+"/"+id, http.MethodPut, http.StatusOK, dashboardRequest)
}

// ValidateDashboard validates a dashboard.
func (c *Client) ValidateDashboard(ctx context.Context, dashboardRequest *dashboard.CreateUpdateDashboardRequest) error {
_, err := c.executeDashboardRequest(ctx, DashboardAPIURL+"/validate", http.MethodPost, http.StatusNoContent, dashboardRequest)
return err
}

func (c *Client) executeDashboardRequest(ctx context.Context, url string, method string, expectedValidStatus int, dashboardRequest *dashboard.CreateUpdateDashboardRequest) (*dashboard.Dashboard, error) {
var body io.Reader
if dashboardRequest != nil {
payload, err := json.Marshal(dashboardRequest)
if err != nil {
return nil, err
}

body = bytes.NewReader(payload)
}

resp, err := c.doRequest(ctx, "PUT", DashboardAPIURL+"/"+id, nil, bytes.NewReader(payload))
resp, err := c.doRequest(ctx, method, url, nil, body)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if err = newResponseError(resp, http.StatusOK); err != nil {
if err := newResponseError(resp, expectedValidStatus); err != nil {
return nil, err
}

finalDashboard := &dashboard.Dashboard{}

err = json.NewDecoder(resp.Body).Decode(finalDashboard)
_, _ = io.Copy(ioutil.Discard, resp.Body)
if expectedValidStatus == http.StatusNoContent {
_, _ = io.Copy(io.Discard, resp.Body)
return nil, nil
}

return finalDashboard, err
returnedDashboard := &dashboard.Dashboard{}
err = json.NewDecoder(resp.Body).Decode(returnedDashboard)
_, _ = io.Copy(io.Discard, resp.Body)
return returnedDashboard, err
}

// SearchDashboard searches for dashboards, given a query string in `name`.
Expand All @@ -125,7 +101,7 @@ func (c *Client) SearchDashboard(ctx context.Context, limit int, name string, of
finalDashboards := &dashboard.SearchResult{}

err = json.NewDecoder(resp.Body).Decode(finalDashboards)
_, _ = io.Copy(ioutil.Discard, resp.Body)
_, _ = io.Copy(io.Discard, resp.Body)

return finalDashboards, err
}
24 changes: 24 additions & 0 deletions dashboard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,27 @@ func TestUpdateMissingDashboard(t *testing.T) {
assert.Error(t, err, "Should've gotten an error from a missing dashboard update")
assert.Nil(t, result, "Should've gotten a nil dashboard from a missing dashboard update")
}

func TestValidateDashboard(t *testing.T) {
teardown := setup()
defer teardown()

mux.HandleFunc("/v2/dashboard/validate", verifyRequest(t, "POST", true, http.StatusNoContent, nil, ""))

err := client.ValidateDashboard(context.Background(), &dashboard.CreateUpdateDashboardRequest{
Name: "string",
})
assert.NoError(t, err, "Unexpected error creating dashboard")
}

func TestValidateBadDashboard(t *testing.T) {
teardown := setup()
defer teardown()

mux.HandleFunc("/v2/dashboard/validate", verifyRequest(t, "POST", true, http.StatusBadRequest, nil, ""))

err := client.ValidateDashboard(context.Background(), &dashboard.CreateUpdateDashboardRequest{
Name: "string",
})
assert.Error(t, err, "Should have gotten an error code for a bad dashboard")
}
Loading

0 comments on commit 24f90a2

Please sign in to comment.