Skip to content
This repository has been archived by the owner on May 11, 2022. It is now read-only.

Commit

Permalink
#27: up coverage of provider (grafana)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilsk committed Aug 1, 2020
1 parent 455a876 commit 5af0c8a
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 19 deletions.
2 changes: 1 addition & 1 deletion internal/cmd/coverage.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func NewCoverageCommand(
return nil
})
g.Go(func() error {
provider, err := grafana.New(config.Grafana.URL, logger)
provider, err := grafana.New(config.Grafana.URL, &http.Client{Timeout: time.Second}, logger)
if err != nil {
return err
}
Expand Down
5 changes: 4 additions & 1 deletion internal/cmd/queries.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package cmd

import (
"net/http"
"time"

"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -53,7 +56,7 @@ func NewQueriesCommand(
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
provider, err := grafana.New(config.Grafana.URL, logger)
provider, err := grafana.New(config.Grafana.URL, &http.Client{Timeout: time.Second}, logger)
if err != nil {
return err
}
Expand Down
10 changes: 10 additions & 0 deletions internal/provider/grafana/contract.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package grafana

import "net/http"

//go:generate mockgen -source $GOFILE -destination mocks_test.go -package ${GOPACKAGE}_test

// Client defines HTTP client interface.
type Client interface {
Do(*http.Request) (*http.Response, error)
}
10 changes: 6 additions & 4 deletions internal/provider/grafana/dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package grafana
import "github.com/kamilsk/grafaman/internal/model"

type dashboard struct {
Panels []panel `json:"panels,omitempty"`
Templating struct {
List []variable `json:"list,omitempty"`
} `json:"templating,omitempty"`
Panels []panel `json:"panels,omitempty"`
Templating templating `json:"templating,omitempty"`
}

type panel struct {
Expand All @@ -17,6 +15,10 @@ type panel struct {
Targets []target `json:"targets,omitempty"`
}

type templating struct {
List []variable `json:"list,omitempty"`
}

type target struct {
Query string `json:"target,omitempty"`
}
Expand Down
71 changes: 68 additions & 3 deletions internal/provider/grafana/dto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,80 @@ func TestDumpStubs(t *testing.T) {
fs = afero.NewOsFs()
}

type payload struct {
Dashboard dashboard `json:"dashboard,omitempty"`
}

type response struct {
Code int `json:"code,omitempty"`
Body dashboard `json:"body,omitempty"`
Code int `json:"code,omitempty"`
Body payload `json:"body,omitempty"`
}

t.Run("success", func(t *testing.T) {
resp := response{
Code: http.StatusOK,
Body: dashboard{},
Body: payload{
Dashboard: dashboard{
Panels: []panel{
{
ID: 1,
Title: "Panel A",
Type: "singlestat",
Targets: []target{
{
Query: "sumSeriesWithWildcards(movingSum(apps.services.*.rpc.*, '1min'), 3, 5)",
},
},
},
{
ID: 2,
Title: "Error rate",
Type: "row",
Panels: []panel{
{
ID: 3,
Title: "Panel B",
Type: "graph",
Targets: []target{
{
Query: "aliasByNode(movingSum(apps.services.*.errors.*, '1min'), 3, 6, 5)",
},
},
},
},
},
},
Templating: templating{
List: []variable{
{
Name: "env",
Options: []option{},
Current: currentOption{
Text: "prod",
Value: "prod",
},
},
{
Name: "source",
Options: []option{
{
Text: "All",
Value: "$__all",
},
{
Text: "service",
Value: "service",
},
},
Current: currentOption{
Text: "All",
Value: []interface{}{"$__all"},
},
},
},
},
},
},
}

file, err := fs.Create("testdata/success.json")
Expand Down
50 changes: 50 additions & 0 deletions internal/provider/grafana/mocks_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions internal/provider/grafana/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@ import (
)

// New returns an instance of Grafana dashboard provider.
func New(endpoint string, logger *logrus.Logger) (*provider, error) {
func New(endpoint string, client Client, logger *logrus.Logger) (*provider, error) {
u, err := url.Parse(endpoint)
if err != nil {
return nil, errors.Wrap(err, "grafana: prepare dashboard provider endpoint URL")
}
return &provider{
client: &http.Client{Timeout: time.Second},
client: client,
endpoint: *u,
logger: logger,
}, nil
}

type provider struct {
client *http.Client
client Client
endpoint url.URL
logger *logrus.Logger
}
Expand Down
117 changes: 117 additions & 0 deletions internal/provider/grafana/provider_test.go
Original file line number Diff line number Diff line change
@@ -1 +1,118 @@
package grafana_test

import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"net/http"
"os"
"testing"

"github.com/golang/mock/gomock"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.octolab.org/safe"
"go.octolab.org/unsafe"

. "github.com/kamilsk/grafaman/internal/provider/grafana"
)

func TestProvider(t *testing.T) {
ctx := context.Background()
_ = ctx

logger := logrus.New()
logger.SetOutput(ioutil.Discard)

t.Run("success fetch", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

client := NewMockClient(ctrl)
client.EXPECT().
Do(gomock.Any()).
Return(response("testdata/success.json")) // nolint:bodyclose

provider, err := New("test", client, logger)
require.NoError(t, err)

dashboard, err := provider.Fetch(ctx, "dashboard")
assert.NoError(t, err)
assert.NotNil(t, dashboard)
})

t.Run("bad endpoint", func(t *testing.T) {
provider, err := New(":invalid", nil, logger)
assert.Error(t, err)
assert.Nil(t, provider)
})

t.Run("nil context", func(t *testing.T) {
provider, err := New("test", nil, logger)
require.NoError(t, err)

dashboard, err := provider.Fetch(nil, "dashboard") // nolint:staticcheck
assert.Error(t, err)
assert.Nil(t, dashboard)
})

t.Run("service unavailable", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

client := NewMockClient(ctrl)
client.EXPECT().
Do(gomock.Any()).
Return(nil, errors.New(http.StatusText(http.StatusServiceUnavailable)))

provider, err := New("test", client, logger)
require.NoError(t, err)

dashboard, err := provider.Fetch(ctx, "dashboard")
assert.Error(t, err)
assert.Nil(t, dashboard)
})

t.Run("bad response", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

client := NewMockClient(ctrl)
client.EXPECT().
Do(gomock.Any()).
Return(response("testdata/invalid.json")) // nolint:bodyclose

provider, err := New("test", client, logger)
require.NoError(t, err)

dashboard, err := provider.Fetch(ctx, "dashboard")
assert.Error(t, err)
assert.Nil(t, dashboard)
})
}

// helpers

func response(filename string) (*http.Response, error) {
resp := new(http.Response)
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer safe.Close(file, unsafe.Ignore)

var dto struct {
Code int `json:"code,omitempty"`
Body json.RawMessage `json:"body,omitempty"`
}
if err := json.NewDecoder(file).Decode(&dto); err != nil {
return nil, err
}

resp.StatusCode = dto.Code
resp.Body = ioutil.NopCloser(bytes.NewReader(dto.Body))
return resp, nil
}
1 change: 1 addition & 0 deletions internal/provider/grafana/testdata/invalid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"code":200,"body":"invalid"}
2 changes: 1 addition & 1 deletion internal/provider/grafana/testdata/success.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"code":200,"body":{"panels":null,"templating":{"list":null}}}
{"code":200,"body":{"dashboard":{"panels":[{"id":1,"title":"Panel A","type":"singlestat","targets":[{"target":"sumSeriesWithWildcards(movingSum(apps.services.*.rpc.*, '1min'), 3, 5)"}]},{"id":2,"title":"Error rate","type":"row","panels":[{"id":3,"title":"Panel B","type":"graph","targets":[{"target":"aliasByNode(movingSum(apps.services.*.errors.*, '1min'), 3, 6, 5)"}]}]}],"templating":{"list":[{"name":"env","current":{"text":"prod","value":"prod"}},{"name":"source","options":[{"text":"All","value":"$__all"},{"text":"service","value":"service"}],"current":{"text":"All","value":["$__all"]}}]}}}}
12 changes: 6 additions & 6 deletions internal/provider/graphite/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ func TestProvider(t *testing.T) {
logger := logrus.New()
logger.SetOutput(ioutil.Discard)

t.Run("bad endpoint", func(t *testing.T) {
provider, err := New(":invalid", nil, logger)
assert.Error(t, err)
assert.Nil(t, provider)
})

t.Run("success fetch", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
Expand Down Expand Up @@ -62,6 +56,12 @@ func TestProvider(t *testing.T) {
}, metrics)
})

t.Run("bad endpoint", func(t *testing.T) {
provider, err := New(":invalid", nil, logger)
assert.Error(t, err)
assert.Nil(t, provider)
})

t.Run("nil context", func(t *testing.T) {
provider, err := New("test", nil, logger)
require.NoError(t, err)
Expand Down

0 comments on commit 5af0c8a

Please sign in to comment.