reorganize packages and add tests for zabbix datasource instance methods
This commit is contained in:
4
go.mod
4
go.mod
@@ -7,8 +7,8 @@ require (
|
|||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
||||||
github.com/google/go-cmp v0.3.1 // indirect
|
github.com/google/go-cmp v0.3.1 // indirect
|
||||||
github.com/grafana/grafana-plugin-sdk-go v0.65.0
|
github.com/grafana/grafana-plugin-sdk-go v0.65.0
|
||||||
github.com/grafana/grafana_plugin_model v0.0.0-20180518082423-84176c64269d
|
github.com/grafana/grafana_plugin_model v0.0.0-20180518082423-84176c64269d // indirect
|
||||||
github.com/hashicorp/go-hclog v0.9.2
|
github.com/hashicorp/go-hclog v0.9.2 // indirect
|
||||||
github.com/hashicorp/go-plugin v1.2.2 // indirect
|
github.com/hashicorp/go-plugin v1.2.2 // indirect
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/kr/pretty v0.1.0 // indirect
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package datasource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -31,6 +31,13 @@ type ZabbixDatasourceInstance struct {
|
|||||||
logger log.Logger
|
logger log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewZabbixDatasource() *ZabbixDatasource {
|
||||||
|
return &ZabbixDatasource{
|
||||||
|
datasourceCache: cache.NewCache(10*time.Minute, 10*time.Minute),
|
||||||
|
logger: log.New(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewZabbixDatasourceInstance returns an initialized zabbix datasource instance
|
// NewZabbixDatasourceInstance returns an initialized zabbix datasource instance
|
||||||
func NewZabbixDatasourceInstance(dsInfo *backend.DataSourceInstanceSettings) (*ZabbixDatasourceInstance, error) {
|
func NewZabbixDatasourceInstance(dsInfo *backend.DataSourceInstanceSettings) (*ZabbixDatasourceInstance, error) {
|
||||||
zabbixAPI, err := zabbixapi.New(dsInfo.URL)
|
zabbixAPI, err := zabbixapi.New(dsInfo.URL)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package datasource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package datasource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -39,17 +39,17 @@ type ZabbixAPIRequest struct {
|
|||||||
Params ZabbixAPIParams `json:"params,omitempty"`
|
Params ZabbixAPIParams `json:"params,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ZabbixAPIRequest) String() string {
|
||||||
|
jsonRequest, _ := json.Marshal(r.Params)
|
||||||
|
return r.Method + string(jsonRequest)
|
||||||
|
}
|
||||||
|
|
||||||
type ZabbixAPIParams = map[string]interface{}
|
type ZabbixAPIParams = map[string]interface{}
|
||||||
|
|
||||||
type ZabbixAPIResourceResponse struct {
|
type ZabbixAPIResourceResponse struct {
|
||||||
Result interface{} `json:"result,omitempty"`
|
Result interface{} `json:"result,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ZabbixAPIRequest) String() string {
|
|
||||||
jsonRequest, _ := json.Marshal(r.Params)
|
|
||||||
return r.Method + string(jsonRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryModel model
|
// QueryModel model
|
||||||
type QueryModel struct {
|
type QueryModel struct {
|
||||||
Mode int64 `json:"mode"`
|
Mode int64 `json:"mode"`
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package datasource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -8,14 +8,14 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ds *ZabbixDatasource) rootHandler(rw http.ResponseWriter, req *http.Request) {
|
func (ds *ZabbixDatasource) RootHandler(rw http.ResponseWriter, req *http.Request) {
|
||||||
ds.logger.Debug("Received resource call", "url", req.URL.String(), "method", req.Method)
|
ds.logger.Debug("Received resource call", "url", req.URL.String(), "method", req.Method)
|
||||||
|
|
||||||
rw.Write([]byte("Hello from Zabbix data source!"))
|
rw.Write([]byte("Hello from Zabbix data source!"))
|
||||||
rw.WriteHeader(http.StatusOK)
|
rw.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *ZabbixDatasource) zabbixAPIHandler(rw http.ResponseWriter, req *http.Request) {
|
func (ds *ZabbixDatasource) ZabbixAPIHandler(rw http.ResponseWriter, req *http.Request) {
|
||||||
if req.Method != http.MethodPost {
|
if req.Method != http.MethodPost {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ func (ds *ZabbixDatasource) zabbixAPIHandler(rw http.ResponseWriter, req *http.R
|
|||||||
body, err := ioutil.ReadAll(req.Body)
|
body, err := ioutil.ReadAll(req.Body)
|
||||||
defer req.Body.Close()
|
defer req.Body.Close()
|
||||||
if err != nil || len(body) == 0 {
|
if err != nil || len(body) == 0 {
|
||||||
WriteError(rw, http.StatusBadRequest, err)
|
writeError(rw, http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ func (ds *ZabbixDatasource) zabbixAPIHandler(rw http.ResponseWriter, req *http.R
|
|||||||
err = json.Unmarshal(body, &reqData)
|
err = json.Unmarshal(body, &reqData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ds.logger.Error("Cannot unmarshal request", "error", err.Error())
|
ds.logger.Error("Cannot unmarshal request", "error", err.Error())
|
||||||
WriteError(rw, http.StatusInternalServerError, err)
|
writeError(rw, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ func (ds *ZabbixDatasource) zabbixAPIHandler(rw http.ResponseWriter, req *http.R
|
|||||||
dsInstance, err := ds.GetDatasource(pluginCxt)
|
dsInstance, err := ds.GetDatasource(pluginCxt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ds.logger.Error("Error loading datasource", "error", err)
|
ds.logger.Error("Error loading datasource", "error", err)
|
||||||
WriteError(rw, http.StatusInternalServerError, err)
|
writeError(rw, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,17 +48,17 @@ func (ds *ZabbixDatasource) zabbixAPIHandler(rw http.ResponseWriter, req *http.R
|
|||||||
result, err := dsInstance.ZabbixAPIQuery(req.Context(), apiReq)
|
result, err := dsInstance.ZabbixAPIQuery(req.Context(), apiReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ds.logger.Error("Zabbix API request error", "error", err)
|
ds.logger.Error("Zabbix API request error", "error", err)
|
||||||
WriteError(rw, http.StatusInternalServerError, err)
|
writeError(rw, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteResponse(rw, result)
|
writeResponse(rw, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WriteResponse(rw http.ResponseWriter, result *ZabbixAPIResourceResponse) {
|
func writeResponse(rw http.ResponseWriter, result *ZabbixAPIResourceResponse) {
|
||||||
resultJson, err := json.Marshal(*result)
|
resultJson, err := json.Marshal(*result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
WriteError(rw, http.StatusInternalServerError, err)
|
writeError(rw, http.StatusInternalServerError, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rw.Header().Add("Content-Type", "application/json")
|
rw.Header().Add("Content-Type", "application/json")
|
||||||
@@ -66,7 +66,7 @@ func WriteResponse(rw http.ResponseWriter, result *ZabbixAPIResourceResponse) {
|
|||||||
rw.Write(resultJson)
|
rw.Write(resultJson)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WriteError(rw http.ResponseWriter, statusCode int, err error) {
|
func writeError(rw http.ResponseWriter, statusCode int, err error) {
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
|
|
||||||
data["error"] = "Internal Server Error"
|
data["error"] = "Internal Server Error"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package zabbix
|
package datasource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package datasource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/cache"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/cache"
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix"
|
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbixapi"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbixapi"
|
||||||
simplejson "github.com/bitly/go-simplejson"
|
simplejson "github.com/bitly/go-simplejson"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
@@ -156,7 +155,7 @@ func (ds *ZabbixDatasourceInstance) queryNumericItems(ctx context.Context, query
|
|||||||
return frames, nil
|
return frames, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *ZabbixDatasourceInstance) getItems(ctx context.Context, groupFilter string, hostFilter string, appFilter string, itemFilter string, itemType string) (zabbix.Items, error) {
|
func (ds *ZabbixDatasourceInstance) getItems(ctx context.Context, groupFilter string, hostFilter string, appFilter string, itemFilter string, itemType string) (Items, error) {
|
||||||
hosts, err := ds.getHosts(ctx, groupFilter, hostFilter)
|
hosts, err := ds.getHosts(ctx, groupFilter, hostFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -182,10 +181,10 @@ func (ds *ZabbixDatasourceInstance) getItems(ctx context.Context, groupFilter st
|
|||||||
allItems, err = ds.getAllItems(ctx, nil, appids, itemType)
|
allItems, err = ds.getAllItems(ctx, nil, appids, itemType)
|
||||||
}
|
}
|
||||||
|
|
||||||
var items zabbix.Items
|
var items Items
|
||||||
|
|
||||||
if allItems == nil {
|
if allItems == nil {
|
||||||
items = zabbix.Items{}
|
items = Items{}
|
||||||
} else {
|
} else {
|
||||||
itemsJSON, err := allItems.MarshalJSON()
|
itemsJSON, err := allItems.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -203,7 +202,7 @@ func (ds *ZabbixDatasourceInstance) getItems(ctx context.Context, groupFilter st
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
filteredItems := zabbix.Items{}
|
filteredItems := Items{}
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
itemName := item.ExpandItem()
|
itemName := item.ExpandItem()
|
||||||
if item.Status == "0" {
|
if item.Status == "0" {
|
||||||
@@ -361,7 +360,7 @@ func (ds *ZabbixDatasourceInstance) getAllGroups(ctx context.Context) (*simplejs
|
|||||||
return ds.ZabbixQuery(ctx, &ZabbixAPIRequest{Method: "hostgroup.get", Params: params})
|
return ds.ZabbixQuery(ctx, &ZabbixAPIRequest{Method: "hostgroup.get", Params: params})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *ZabbixDatasourceInstance) queryNumericDataForItems(ctx context.Context, query *QueryModel, items zabbix.Items) (*data.Frame, error) {
|
func (ds *ZabbixDatasourceInstance) queryNumericDataForItems(ctx context.Context, query *QueryModel, items Items) (*data.Frame, error) {
|
||||||
valueType := ds.getTrendValueType(query)
|
valueType := ds.getTrendValueType(query)
|
||||||
consolidateBy := ds.getConsolidateBy(query)
|
consolidateBy := ds.getConsolidateBy(query)
|
||||||
|
|
||||||
@@ -400,12 +399,12 @@ func (ds *ZabbixDatasourceInstance) getConsolidateBy(query *QueryModel) string {
|
|||||||
return consolidateBy
|
return consolidateBy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *ZabbixDatasourceInstance) getHistotyOrTrend(ctx context.Context, query *QueryModel, items zabbix.Items) (zabbix.History, error) {
|
func (ds *ZabbixDatasourceInstance) getHistotyOrTrend(ctx context.Context, query *QueryModel, items Items) (History, error) {
|
||||||
timeRange := query.TimeRange
|
timeRange := query.TimeRange
|
||||||
useTrend := ds.isUseTrend(timeRange)
|
useTrend := ds.isUseTrend(timeRange)
|
||||||
allHistory := zabbix.History{}
|
allHistory := History{}
|
||||||
|
|
||||||
groupedItems := map[int]zabbix.Items{}
|
groupedItems := map[int]Items{}
|
||||||
|
|
||||||
for _, j := range items {
|
for _, j := range items {
|
||||||
groupedItems[j.ValueType] = append(groupedItems[j.ValueType], j)
|
groupedItems[j.ValueType] = append(groupedItems[j.ValueType], j)
|
||||||
@@ -444,7 +443,7 @@ func (ds *ZabbixDatasourceInstance) getHistotyOrTrend(ctx context.Context, query
|
|||||||
return nil, fmt.Errorf("Internal error parsing response JSON: %w", err)
|
return nil, fmt.Errorf("Internal error parsing response JSON: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
history := zabbix.History{}
|
history := History{}
|
||||||
err = json.Unmarshal(pointJSON, &history)
|
err = json.Unmarshal(pointJSON, &history)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ds.logger.Warn(fmt.Sprintf("Could not map Zabbix response to History: %s", err.Error()))
|
ds.logger.Warn(fmt.Sprintf("Could not map Zabbix response to History: %s", err.Error()))
|
||||||
@@ -472,7 +471,7 @@ func (ds *ZabbixDatasourceInstance) isUseTrend(timeRange backend.TimeRange) bool
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertHistory(history zabbix.History, items zabbix.Items) *data.Frame {
|
func convertHistory(history History, items Items) *data.Frame {
|
||||||
timeFileld := data.NewFieldFromFieldType(data.FieldTypeTime, 0)
|
timeFileld := data.NewFieldFromFieldType(data.FieldTypeTime, 0)
|
||||||
timeFileld.Name = "time"
|
timeFileld.Name = "time"
|
||||||
frame := data.NewFrame("History", timeFileld)
|
frame := data.NewFrame("History", timeFileld)
|
||||||
134
pkg/datasource/zabbix_test.go
Normal file
134
pkg/datasource/zabbix_test.go
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package datasource
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/cache"
|
||||||
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbixapi"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var emptyParams = map[string]interface{}{}
|
||||||
|
|
||||||
|
type RoundTripFunc func(req *http.Request) *http.Response
|
||||||
|
|
||||||
|
func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
return f(req), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewTestClient returns *http.Client with Transport replaced to avoid making real calls
|
||||||
|
func NewTestClient(fn RoundTripFunc) *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: RoundTripFunc(fn),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var basicDatasourceInfo = &backend.DataSourceInstanceSettings{
|
||||||
|
ID: 1,
|
||||||
|
Name: "TestDatasource",
|
||||||
|
URL: "http://zabbix.org/zabbix",
|
||||||
|
JSONData: []byte(`{"username":"username", "password":"password"}}`),
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockZabbixQuery(method string, params ZabbixAPIParams) *ZabbixAPIRequest {
|
||||||
|
return &ZabbixAPIRequest{
|
||||||
|
Method: method,
|
||||||
|
Params: params,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MockZabbixDataSource(body string, statusCode int) *ZabbixDatasourceInstance {
|
||||||
|
zabbixAPI, _ := zabbixapi.MockZabbixAPI(body, statusCode)
|
||||||
|
zabbixSettings, _ := readZabbixSettings(basicDatasourceInfo)
|
||||||
|
|
||||||
|
return &ZabbixDatasourceInstance{
|
||||||
|
dsInfo: basicDatasourceInfo,
|
||||||
|
zabbixAPI: zabbixAPI,
|
||||||
|
Settings: zabbixSettings,
|
||||||
|
queryCache: cache.NewCache(cache.NoExpiration, 10*time.Minute),
|
||||||
|
logger: log.New(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MockZabbixDataSourceResponse(dsInstance *ZabbixDatasourceInstance, body string, statusCode int) *ZabbixDatasourceInstance {
|
||||||
|
zabbixAPI, _ := zabbixapi.MockZabbixAPI(body, statusCode)
|
||||||
|
dsInstance.zabbixAPI = zabbixAPI
|
||||||
|
|
||||||
|
return dsInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogin(t *testing.T) {
|
||||||
|
dsInstance := MockZabbixDataSource(`{"result":"secretauth"}`, 200)
|
||||||
|
err := dsInstance.login(context.Background())
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, "secretauth", dsInstance.zabbixAPI.GetAuth())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoginError(t *testing.T) {
|
||||||
|
dsInstance := MockZabbixDataSource(`{"result":""}`, 500)
|
||||||
|
err := dsInstance.login(context.Background())
|
||||||
|
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, "", dsInstance.zabbixAPI.GetAuth())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestZabbixAPIQuery(t *testing.T) {
|
||||||
|
dsInstance := MockZabbixDataSource(`{"result":"test"}`, 200)
|
||||||
|
resp, err := dsInstance.ZabbixAPIQuery(context.Background(), mockZabbixQuery("test.get", emptyParams))
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
result, ok := resp.Result.(string)
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, "test", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCachedQuery(t *testing.T) {
|
||||||
|
// Using methods with caching enabled
|
||||||
|
query := mockZabbixQuery("host.get", emptyParams)
|
||||||
|
dsInstance := MockZabbixDataSource(`{"result":"testOld"}`, 200)
|
||||||
|
|
||||||
|
// Run query first time
|
||||||
|
resp, err := dsInstance.ZabbixAPIQuery(context.Background(), query)
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
result, _ := resp.Result.(string)
|
||||||
|
assert.Equal(t, "testOld", result)
|
||||||
|
|
||||||
|
// Mock request with new value
|
||||||
|
dsInstance = MockZabbixDataSourceResponse(dsInstance, `{"result":"testNew"}`, 200)
|
||||||
|
// Should not run actual API query and return first result
|
||||||
|
resp, err = dsInstance.ZabbixAPIQuery(context.Background(), query)
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
result, _ = resp.Result.(string)
|
||||||
|
assert.Equal(t, "testOld", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNonCachedQuery(t *testing.T) {
|
||||||
|
// Using methods with caching disabled
|
||||||
|
query := mockZabbixQuery("history.get", emptyParams)
|
||||||
|
dsInstance := MockZabbixDataSource(`{"result":"testOld"}`, 200)
|
||||||
|
|
||||||
|
// Run query first time
|
||||||
|
resp, err := dsInstance.ZabbixAPIQuery(context.Background(), query)
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
result, _ := resp.Result.(string)
|
||||||
|
assert.Equal(t, "testOld", result)
|
||||||
|
|
||||||
|
// Mock request with new value
|
||||||
|
dsInstance = MockZabbixDataSourceResponse(dsInstance, `{"result":"testNew"}`, 200)
|
||||||
|
// Should not run actual API query and return first result
|
||||||
|
resp, err = dsInstance.ZabbixAPIQuery(context.Background(), query)
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
result, _ = resp.Result.(string)
|
||||||
|
assert.Equal(t, "testNew", result)
|
||||||
|
}
|
||||||
@@ -3,9 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/cache"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/datasource"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
|
||||||
@@ -33,7 +32,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Init(logger log.Logger, mux *http.ServeMux) *ZabbixDatasource {
|
func Init(logger log.Logger, mux *http.ServeMux) *datasource.ZabbixDatasource {
|
||||||
variableName := "GFX_ZABBIX_DATA_PATH"
|
variableName := "GFX_ZABBIX_DATA_PATH"
|
||||||
path, exist := os.LookupEnv(variableName)
|
path, exist := os.LookupEnv(variableName)
|
||||||
if !exist {
|
if !exist {
|
||||||
@@ -42,13 +41,10 @@ func Init(logger log.Logger, mux *http.ServeMux) *ZabbixDatasource {
|
|||||||
logger.Debug("environment variable for storage found", "variable", variableName, "value", path)
|
logger.Debug("environment variable for storage found", "variable", variableName, "value", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
ds := &ZabbixDatasource{
|
ds := datasource.NewZabbixDatasource()
|
||||||
logger: logger,
|
|
||||||
datasourceCache: cache.NewCache(10*time.Minute, 10*time.Minute),
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.HandleFunc("/", ds.rootHandler)
|
mux.HandleFunc("/", ds.RootHandler)
|
||||||
mux.HandleFunc("/zabbix-api", ds.zabbixAPIHandler)
|
mux.HandleFunc("/zabbix-api", ds.ZabbixAPIHandler)
|
||||||
// mux.Handle("/scenarios", getScenariosHandler(logger))
|
// mux.Handle("/scenarios", getScenariosHandler(logger))
|
||||||
|
|
||||||
return ds
|
return ds
|
||||||
|
|||||||
@@ -1,446 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"regexp"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
simplejson "github.com/bitly/go-simplejson"
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
||||||
"github.com/grafana/grafana_plugin_model/go/datasource"
|
|
||||||
hclog "github.com/hashicorp/go-hclog"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RoundTripFunc func(req *http.Request) *http.Response
|
|
||||||
|
|
||||||
func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
return f(req), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewTestClient returns *http.Client with Transport replaced to avoid making real calls
|
|
||||||
func NewTestClient(fn RoundTripFunc) *http.Client {
|
|
||||||
return &http.Client{
|
|
||||||
Transport: RoundTripFunc(fn),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var basicDatasourceInfo = &backend.DataSourceInstanceSettings{
|
|
||||||
ID: 1,
|
|
||||||
Name: "TestDatasource",
|
|
||||||
URL: "http://zabbix.org/zabbix",
|
|
||||||
JSONData: []byte(`{"username":"username", "password":"password"}}`),
|
|
||||||
}
|
|
||||||
|
|
||||||
func mockDataSourceRequest(modelJSON string) *datasource.DatasourceRequest {
|
|
||||||
return &datasource.DatasourceRequest{
|
|
||||||
Datasource: basicDatasourceInfo,
|
|
||||||
Queries: []*datasource.Query{
|
|
||||||
{
|
|
||||||
ModelJson: modelJSON,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mockZabbixDataSource(body string, statusCode int) ZabbixDatasourceInstance {
|
|
||||||
apiUrl, _ := url.Parse(basicDatasourceInfo.Url)
|
|
||||||
return ZabbixDatasourceInstance{
|
|
||||||
url: apiUrl,
|
|
||||||
dsInfo: basicDatasourceInfo,
|
|
||||||
queryCache: NewCache(10*time.Minute, 10*time.Minute),
|
|
||||||
httpClient: NewTestClient(func(req *http.Request) *http.Response {
|
|
||||||
return &http.Response{
|
|
||||||
StatusCode: statusCode,
|
|
||||||
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
|
|
||||||
Header: make(http.Header),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
authToken: "sampleAuthToken",
|
|
||||||
logger: hclog.Default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZabbixAPIQuery(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 200)
|
|
||||||
resp, err := zabbixDatasource.ZabbixAPIQuery(context.Background(), mockDataSourceRequest(`{"target":{"method":"Method","params":{"param1" : "Param1"}}}`))
|
|
||||||
|
|
||||||
assert.Equal(t, "\"sampleResult\"", resp.GetResults()[0].GetMetaJson())
|
|
||||||
assert.Equal(t, "zabbixAPI", resp.GetResults()[0].GetRefId())
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZabbixAPIQueryEmptyQuery(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 200)
|
|
||||||
resp, err := zabbixDatasource.ZabbixAPIQuery(context.Background(), mockDataSourceRequest(``))
|
|
||||||
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZabbixAPIQueryNoQueries(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 200)
|
|
||||||
basicDatasourceRequest := &datasource.DatasourceRequest{
|
|
||||||
Datasource: &datasource.DatasourceInfo{
|
|
||||||
Id: 1,
|
|
||||||
Name: "TestDatasource",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
resp, err := zabbixDatasource.ZabbixAPIQuery(context.Background(), basicDatasourceRequest)
|
|
||||||
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
assert.Equal(t, "At least one query should be provided", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZabbixAPIQueryError(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 500)
|
|
||||||
resp, err := zabbixDatasource.ZabbixAPIQuery(context.Background(), mockDataSourceRequest(`{"target":{"method":"Method","params":{"param1" : "Param1"}}}`))
|
|
||||||
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
assert.Equal(t, "ZabbixAPIQuery is not implemented yet", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLogin(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 200)
|
|
||||||
resp, err := zabbixDatasource.login(context.Background(), "username", "password")
|
|
||||||
|
|
||||||
assert.Equal(t, "sampleResult", resp)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLoginError(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 500)
|
|
||||||
resp, err := zabbixDatasource.login(context.Background(), "username", "password")
|
|
||||||
|
|
||||||
assert.Equal(t, "", resp)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLoginWithDs(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 200)
|
|
||||||
err := zabbixDatasource.login(context.Background())
|
|
||||||
|
|
||||||
assert.Equal(t, "sampleResult", zabbixDatasource.authToken)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLoginWithDsError(t *testing.T) {
|
|
||||||
errResponse := `{"error":{"code":-32500,"message":"Application error.","data":"Login name or password is incorrect."}}`
|
|
||||||
zabbixDatasource := mockZabbixDataSource(errResponse, 200)
|
|
||||||
err := zabbixDatasource.login(context.Background())
|
|
||||||
|
|
||||||
assert.Equal(t, "", zabbixDatasource.authToken)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZabbixRequest(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 200)
|
|
||||||
resp, err := zabbixDatasource.ZabbixRequest(context.Background(), "method", ZabbixAPIParams{})
|
|
||||||
assert.Equal(t, "sampleResult", resp.MustString())
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZabbixRequestWithNoAuthToken(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"auth"}`, 200)
|
|
||||||
resp, err := zabbixDatasource.ZabbixRequest(context.Background(), "method", ZabbixAPIParams{})
|
|
||||||
assert.Equal(t, "auth", resp.MustString())
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZabbixRequestError(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 500)
|
|
||||||
resp, err := zabbixDatasource.ZabbixRequest(context.Background(), "method", ZabbixAPIParams{})
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZabbixAPIRequest(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 200)
|
|
||||||
resp, err := zabbixDatasource.ZabbixAPIRequest(context.Background(), "item.get", ZabbixAPIParams{}, "auth")
|
|
||||||
|
|
||||||
assert.Equal(t, "sampleResult", resp.MustString())
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZabbixAPIRequestError(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 500)
|
|
||||||
resp, err := zabbixDatasource.ZabbixAPIRequest(context.Background(), "item.get", ZabbixAPIParams{}, "auth")
|
|
||||||
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTestConnection(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 200)
|
|
||||||
resp, err := zabbixDatasource.TestConnection(context.Background(), mockDataSourceRequest(``))
|
|
||||||
|
|
||||||
assert.Equal(t, "{\"zabbixVersion\":\"sampleResult\",\"dbConnectorStatus\":null}", resp.Results[0].GetMetaJson())
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTestConnectionError(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 500)
|
|
||||||
resp, err := zabbixDatasource.TestConnection(context.Background(), mockDataSourceRequest(``))
|
|
||||||
|
|
||||||
assert.Equal(t, "", resp.Results[0].GetMetaJson())
|
|
||||||
assert.NotNil(t, resp.Results[0].GetError())
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsNotAuthorized(t *testing.T) {
|
|
||||||
testPositive := isNotAuthorized("Not authorised.")
|
|
||||||
assert.True(t, testPositive)
|
|
||||||
|
|
||||||
testNegative := isNotAuthorized("testNegative")
|
|
||||||
assert.False(t, testNegative)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHandleAPIResult(t *testing.T) {
|
|
||||||
expectedResponse, err := handleAPIResult([]byte(`{"result":"sampleResult"}`))
|
|
||||||
|
|
||||||
assert.Equal(t, "sampleResult", expectedResponse.MustString())
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHandleAPIResultFormatError(t *testing.T) {
|
|
||||||
expectedResponse, err := handleAPIResult([]byte(`{"result"::"sampleResult"}`))
|
|
||||||
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
assert.Nil(t, expectedResponse)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHandleAPIResultError(t *testing.T) {
|
|
||||||
expectedResponse, err := handleAPIResult([]byte(`{"result":"sampleResult", "error":{"message":"Message", "data":"Data"}}`))
|
|
||||||
|
|
||||||
assert.Equal(t, "Message Data", err.Error())
|
|
||||||
assert.Nil(t, expectedResponse)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAllGroups(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"groupid": "46489126", "name": "name1"},{"groupid": "46489127", "name":"name2"}]}`, 200)
|
|
||||||
resp, err := zabbixDatasource.getAllGroups(context.Background(), basicDatasourceInfo)
|
|
||||||
|
|
||||||
assert.Equal(t, "46489126", resp.MustArray()[0].(map[string]interface{})["groupid"])
|
|
||||||
assert.Equal(t, "46489127", resp.MustArray()[1].(map[string]interface{})["groupid"])
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAllHosts(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"hostid": "46489126", "name": "hostname1"},{"hostid": "46489127", "name":"hostname2"}]}`, 200)
|
|
||||||
resp, err := zabbixDatasource.getAllHosts(context.Background(), basicDatasourceInfo, []string{"46489127", "46489127"})
|
|
||||||
|
|
||||||
assert.Equal(t, "46489126", resp.MustArray()[0].(map[string]interface{})["hostid"])
|
|
||||||
assert.Equal(t, "46489127", resp.MustArray()[1].(map[string]interface{})["hostid"])
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAllApps(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"applicationid": "46489126", "name": "hostname1"},{"applicationid": "46489127", "name":"hostname2"}]}`, 200)
|
|
||||||
resp, err := zabbixDatasource.getAllApps(context.Background(), basicDatasourceInfo, []string{"46489127", "46489127"})
|
|
||||||
|
|
||||||
assert.Equal(t, "46489126", resp.MustArray()[0].(map[string]interface{})["applicationid"])
|
|
||||||
assert.Equal(t, "46489127", resp.MustArray()[1].(map[string]interface{})["applicationid"])
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAllItems(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"itemid": "46489126", "name": "hostname1"},{"itemid": "46489127", "name":"hostname2"}]}`, 200)
|
|
||||||
resp, err := zabbixDatasource.getAllItems(context.Background(), basicDatasourceInfo, []string{"46489127", "46489127"}, []string{"7947934", "9182763"}, "num")
|
|
||||||
|
|
||||||
assert.Equal(t, "46489126", resp.MustArray()[0].(map[string]interface{})["itemid"])
|
|
||||||
assert.Equal(t, "46489127", resp.MustArray()[1].(map[string]interface{})["itemid"])
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGroups(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"groupid": "46489126", "name": "name1"},{"groupid": "46489127", "name":"name2"}]}`, 200)
|
|
||||||
resp, err := zabbixDatasource.getGroups(context.Background(), basicDatasourceInfo, "name1")
|
|
||||||
|
|
||||||
assert.Equal(t, "46489126", resp[0]["groupid"])
|
|
||||||
assert.Equal(t, "name1", resp[0]["name"])
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetGroupsError(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"groupid": "46489126", "name": "name1"},{"groupid": "46489127", "name":"name2"}]}`, 500)
|
|
||||||
resp, err := zabbixDatasource.getGroups(context.Background(), basicDatasourceInfo, "name1")
|
|
||||||
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetHosts(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"groupid": "46489126", "hostid": "7468763", "name": "hostname1"},{"groupid": "46489127","hostid": "846586", "name":"hostname2"}]}`, 200)
|
|
||||||
resp, err := zabbixDatasource.getHosts(context.Background(), basicDatasourceInfo, "nam", "hostname1")
|
|
||||||
|
|
||||||
assert.Equal(t, "7468763", resp[0]["hostid"])
|
|
||||||
assert.Equal(t, "hostname1", resp[0]["name"])
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetHostsError(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"groupid": "46489126", "hostid": "7468763", "name": "hostname1"},{"groupid": "46489127","hostid": "846586", "name":"hostname2"}]}`, 500)
|
|
||||||
resp, err := zabbixDatasource.getHosts(context.Background(), basicDatasourceInfo, "nam", "hostna")
|
|
||||||
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetApps(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"groupid": "46489126", "hostid": "7468763", "applicationid": "7947934", "name": "appname1"},
|
|
||||||
{"groupid": "46489127","hostid": "846586", "applicationid": "9182763", "name": "appname2"}]}`, 200)
|
|
||||||
resp, err := zabbixDatasource.getApps(context.Background(), basicDatasourceInfo, "nam", "hostnam", "appname1")
|
|
||||||
|
|
||||||
assert.Equal(t, "7947934", resp[0]["applicationid"])
|
|
||||||
assert.Equal(t, "appname1", resp[0]["name"])
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAppsError(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"groupid": "46489126", "hostid": "7468763", "applicationid": "7947934", "name": "appname1"},
|
|
||||||
{"groupid": "46489127","hostid": "846586", "applicationid": "9182763", "name": "appname2"}]}`, 500)
|
|
||||||
resp, err := zabbixDatasource.getApps(context.Background(), basicDatasourceInfo, "nam", "hostnam", "appname1")
|
|
||||||
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetItems(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"groupid": "46489126", "hostid": "7468763", "applicationid": "7947934", "itemid": "837465", "name": "itemname1", "status": "0"},
|
|
||||||
{"groupid": "46489127","hostid": "846586", "applicationid": "9182763", "itemid" : "0288374", "name": "itemname2", "status": "0"}]}`, 200)
|
|
||||||
resp, err := zabbixDatasource.getItems(context.Background(), basicDatasourceInfo, "itemname1", "itemname1", "itemname1", "itemname1", "num")
|
|
||||||
|
|
||||||
assert.Equal(t, "837465", resp[0].ID)
|
|
||||||
assert.Equal(t, "itemname1", resp[0].Name)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetItemsError(t *testing.T) {
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":[{"groupid": "46489126", "hostid": "7468763", "applicationid": "7947934", "itemid": "837465", "name": "itemname1", "status": "0"},
|
|
||||||
{"groupid": "46489127","hostid": "846586", "applicationid": "9182763", "itemid" : "0288374", "name": "itemname2", "status": "0"}]}`, 500)
|
|
||||||
resp, err := zabbixDatasource.getItems(context.Background(), basicDatasourceInfo, "name", "name", "name", "name", "num")
|
|
||||||
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetTrendValueType(t *testing.T) {
|
|
||||||
json1, _ := simplejson.NewJson([]byte(`{"functions":[{"def":{"name":"name1"}},{"def":{"name":"name2"}}]}`))
|
|
||||||
json2, _ := simplejson.NewJson([]byte(`{"functions":[{"def":{"name":"name1"}},{"def":{"name":"name2"}}]}`))
|
|
||||||
jsonQueries := []*simplejson.Json{json1, json2}
|
|
||||||
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 200)
|
|
||||||
resp := zabbixDatasource.getTrendValueType(jsonQueries)
|
|
||||||
|
|
||||||
assert.Equal(t, "avg", resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetConsolidateBy(t *testing.T) {
|
|
||||||
json1, _ := simplejson.NewJson([]byte(`{"functions":[{"def":{"name":"consolidateBy", "params":["sum"]}},{"def":{"name":"name2"}}]}`))
|
|
||||||
json2, _ := simplejson.NewJson([]byte(`{"functions":[{"def":{"name":"name1"}},{"def":{"name":"name2"}}]}`))
|
|
||||||
jsonQueries := []*simplejson.Json{json1, json2}
|
|
||||||
|
|
||||||
zabbixDatasource := mockZabbixDataSource(`{"result":"sampleResult"}`, 200)
|
|
||||||
resp := zabbixDatasource.getConsolidateBy(jsonQueries)
|
|
||||||
|
|
||||||
assert.Equal(t, "sum", resp)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_isUseTrend(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
timeRange *datasource.TimeRange
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "History time",
|
|
||||||
timeRange: &datasource.TimeRange{
|
|
||||||
FromEpochMs: time.Now().Add(-time.Hour*48).Unix() * 1000,
|
|
||||||
ToEpochMs: time.Now().Add(-time.Hour*12).Unix() * 1000,
|
|
||||||
},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Trend time (past 7 days)",
|
|
||||||
timeRange: &datasource.TimeRange{
|
|
||||||
FromEpochMs: time.Now().Add(-time.Hour*24*14).Unix() * 1000,
|
|
||||||
ToEpochMs: time.Now().Add(-time.Hour*24*13).Unix() * 1000,
|
|
||||||
},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Trend time (longer than 4 days)",
|
|
||||||
timeRange: &datasource.TimeRange{
|
|
||||||
FromEpochMs: time.Now().Add(-time.Hour*24*8).Unix() * 1000,
|
|
||||||
ToEpochMs: time.Now().Add(-time.Hour*24*1).Unix() * 1000,
|
|
||||||
},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
got := isUseTrend(tt.timeRange)
|
|
||||||
assert.Equal(t, tt.want, got, tt.name, tt.timeRange)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_parseFilter(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
filter string
|
|
||||||
want *regexp.Regexp
|
|
||||||
wantErr string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Non-regex filter",
|
|
||||||
filter: "foobar",
|
|
||||||
want: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Non-regex filter (would-be invalid regex)",
|
|
||||||
filter: "fooba(r",
|
|
||||||
want: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Regex filter",
|
|
||||||
filter: "/^foo.+/",
|
|
||||||
want: regexp.MustCompile("^foo.+"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Regex filter with flags",
|
|
||||||
filter: "/^foo.+/s",
|
|
||||||
want: regexp.MustCompile("(?s)^foo.+"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Invalid regex",
|
|
||||||
filter: "/fooba(r/",
|
|
||||||
wantErr: "error parsing regexp: missing closing ): `fooba(r`",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Unsupported flag",
|
|
||||||
filter: "/foo.+/z",
|
|
||||||
wantErr: "error parsing regexp: unsupported flags `z` (expected [imsU])",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
got, err := parseFilter(tt.filter)
|
|
||||||
|
|
||||||
if tt.wantErr != "" {
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.EqualError(t, err, tt.wantErr)
|
|
||||||
assert.Nil(t, got)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
44
pkg/zabbixapi/testing.go
Normal file
44
pkg/zabbixapi/testing.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package zabbixapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RoundTripFunc func(req *http.Request) *http.Response
|
||||||
|
|
||||||
|
func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
return f(req), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewTestClient returns *http.Client with Transport replaced to avoid making real calls
|
||||||
|
func NewTestClient(fn RoundTripFunc) *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: RoundTripFunc(fn),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MockZabbixAPI(body string, statusCode int) (*ZabbixAPI, error) {
|
||||||
|
apiLogger := log.New()
|
||||||
|
zabbixURL, err := url.Parse("http://zabbix.org/zabbix")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ZabbixAPI{
|
||||||
|
url: zabbixURL,
|
||||||
|
logger: apiLogger,
|
||||||
|
|
||||||
|
httpClient: NewTestClient(func(req *http.Request) *http.Response {
|
||||||
|
return &http.Response{
|
||||||
|
StatusCode: statusCode,
|
||||||
|
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
|
||||||
|
Header: make(http.Header),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -81,6 +81,11 @@ func (api *ZabbixAPI) SetUrl(api_url string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAuth returns API authentication token
|
||||||
|
func (api *ZabbixAPI) GetAuth() string {
|
||||||
|
return api.auth
|
||||||
|
}
|
||||||
|
|
||||||
// SetAuth sets API authentication token
|
// SetAuth sets API authentication token
|
||||||
func (api *ZabbixAPI) SetAuth(auth string) {
|
func (api *ZabbixAPI) SetAuth(auth string) {
|
||||||
api.auth = auth
|
api.auth = auth
|
||||||
|
|||||||
@@ -1,53 +1,14 @@
|
|||||||
package zabbixapi
|
package zabbixapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RoundTripFunc func(req *http.Request) *http.Response
|
|
||||||
|
|
||||||
func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
return f(req), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//NewTestClient returns *http.Client with Transport replaced to avoid making real calls
|
|
||||||
func NewTestClient(fn RoundTripFunc) *http.Client {
|
|
||||||
return &http.Client{
|
|
||||||
Transport: RoundTripFunc(fn),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mockZabbixAPI(body string, statusCode int) (*ZabbixAPI, error) {
|
|
||||||
apiLogger := log.New()
|
|
||||||
zabbixURL, err := url.Parse("http://zabbix.org/zabbix")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ZabbixAPI{
|
|
||||||
url: zabbixURL,
|
|
||||||
logger: apiLogger,
|
|
||||||
|
|
||||||
httpClient: NewTestClient(func(req *http.Request) *http.Response {
|
|
||||||
return &http.Response{
|
|
||||||
StatusCode: statusCode,
|
|
||||||
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
|
|
||||||
Header: make(http.Header),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZabbixAPIUnauthenticatedQuery(t *testing.T) {
|
func TestZabbixAPIUnauthenticatedQuery(t *testing.T) {
|
||||||
zabbixApi, _ := mockZabbixAPI(`{"result":"sampleResult"}`, 200)
|
zabbixApi, _ := MockZabbixAPI(`{"result":"sampleResult"}`, 200)
|
||||||
resp, err := zabbixApi.RequestUnauthenticated(context.Background(), "test.get", map[string]interface{}{})
|
resp, err := zabbixApi.RequestUnauthenticated(context.Background(), "test.get", map[string]interface{}{})
|
||||||
|
|
||||||
assert.Equal(t, "sampleResult", resp.MustString())
|
assert.Equal(t, "sampleResult", resp.MustString())
|
||||||
@@ -55,7 +16,7 @@ func TestZabbixAPIUnauthenticatedQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLogin(t *testing.T) {
|
func TestLogin(t *testing.T) {
|
||||||
zabbixApi, _ := mockZabbixAPI(`{"result":"secretauth"}`, 200)
|
zabbixApi, _ := MockZabbixAPI(`{"result":"secretauth"}`, 200)
|
||||||
err := zabbixApi.Authenticate(context.Background(), "user", "password")
|
err := zabbixApi.Authenticate(context.Background(), "user", "password")
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
@@ -91,7 +52,7 @@ func TestZabbixAPI(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
zabbixApi, _ := mockZabbixAPI(tt.mockApiResponse, tt.mockApiResponseCode)
|
zabbixApi, _ := MockZabbixAPI(tt.mockApiResponse, tt.mockApiResponseCode)
|
||||||
zabbixApi.auth = tt.auth
|
zabbixApi.auth = tt.auth
|
||||||
resp, err := zabbixApi.Request(context.Background(), "test.get", map[string]interface{}{})
|
resp, err := zabbixApi.Request(context.Background(), "test.get", map[string]interface{}{})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user