@ -1,9 +1,11 @@
package api
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"
@ -12,11 +14,17 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/query"
"github.com/grafana/grafana/pkg/web/webtest"
fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes"
)
func TestAPIGetPublicDashboard ( t * testing . T ) {
@ -238,3 +246,262 @@ func TestApiSavePublicDashboardConfig(t *testing.T) {
} )
}
}
// `/public/dashboards/:uid/query`` endpoint test
func TestAPIQueryPublicDashboard ( t * testing . T ) {
queryReturnsError := false
qds := query . ProvideService (
nil ,
& fakeDatasources . FakeCacheService {
DataSources : [ ] * models . DataSource {
{ Uid : "mysqlds" } ,
{ Uid : "promds" } ,
{ Uid : "promds2" } ,
} ,
} ,
nil ,
& fakePluginRequestValidator { } ,
& fakeDatasources . FakeDataSourceService { } ,
& fakePluginClient {
QueryDataHandlerFunc : func ( ctx context . Context , req * backend . QueryDataRequest ) ( * backend . QueryDataResponse , error ) {
if queryReturnsError {
return nil , errors . New ( "error" )
}
resp := backend . Responses { }
for _ , query := range req . Queries {
resp [ query . RefID ] = backend . DataResponse {
Frames : [ ] * data . Frame {
{
RefID : query . RefID ,
Name : "query-" + query . RefID ,
} ,
} ,
}
}
return & backend . QueryDataResponse { Responses : resp } , nil
} ,
} ,
& fakeOAuthTokenService { } ,
)
setup := func ( enabled bool ) ( * webtest . Server , * dashboards . FakeDashboardService ) {
fakeDashboardService := & dashboards . FakeDashboardService { }
return SetupAPITestServer ( t , func ( hs * HTTPServer ) {
hs . queryDataService = qds
hs . Features = featuremgmt . WithFeatures ( featuremgmt . FlagPublicDashboards , enabled )
hs . dashboardService = fakeDashboardService
} ) , fakeDashboardService
}
t . Run ( "Status code is 404 when feature toggle is disabled" , func ( t * testing . T ) {
server , _ := setup ( false )
req := server . NewPostRequest (
"/api/public/dashboards/abc123/panels/2/query" ,
strings . NewReader ( "{}" ) ,
)
resp , err := server . SendJSON ( req )
require . NoError ( t , err )
require . NoError ( t , resp . Body . Close ( ) )
require . Equal ( t , http . StatusNotFound , resp . StatusCode )
} )
t . Run ( "Status code is 400 when the panel ID is invalid" , func ( t * testing . T ) {
server , _ := setup ( true )
req := server . NewPostRequest (
"/api/public/dashboards/abc123/panels/notanumber/query" ,
strings . NewReader ( "{}" ) ,
)
resp , err := server . SendJSON ( req )
require . NoError ( t , err )
require . NoError ( t , resp . Body . Close ( ) )
require . Equal ( t , http . StatusBadRequest , resp . StatusCode )
} )
t . Run ( "Returns query data when feature toggle is enabled" , func ( t * testing . T ) {
server , fakeDashboardService := setup ( true )
fakeDashboardService . On (
"BuildPublicDashboardMetricRequest" ,
mock . Anything ,
"abc123" ,
int64 ( 2 ) ,
) . Return ( dtos . MetricRequest {
Queries : [ ] * simplejson . Json {
simplejson . MustJson ( [ ] byte ( `
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds"
} ,
"exemplar" : true ,
"expr" : "query_2_A" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
}
` ) ) ,
} ,
} , nil )
req := server . NewPostRequest (
"/api/public/dashboards/abc123/panels/2/query" ,
strings . NewReader ( "{}" ) ,
)
resp , err := server . SendJSON ( req )
require . NoError ( t , err )
bodyBytes , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
require . JSONEq (
t ,
` {
"results" : {
"A" : {
"frames" : [
{
"data" : {
"values" : [ ]
} ,
"schema" : {
"fields" : [ ] ,
"refId" : "A" ,
"name" : "query-A"
}
}
]
}
}
} ` ,
string ( bodyBytes ) ,
)
require . NoError ( t , resp . Body . Close ( ) )
require . Equal ( t , http . StatusOK , resp . StatusCode )
} )
t . Run ( "Status code is 500 when the query fails" , func ( t * testing . T ) {
server , fakeDashboardService := setup ( true )
fakeDashboardService . On (
"BuildPublicDashboardMetricRequest" ,
mock . Anything ,
"abc123" ,
int64 ( 2 ) ,
) . Return ( dtos . MetricRequest {
Queries : [ ] * simplejson . Json {
simplejson . MustJson ( [ ] byte ( `
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds"
} ,
"exemplar" : true ,
"expr" : "query_2_A" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
}
` ) ) ,
} ,
} , nil )
req := server . NewPostRequest (
"/api/public/dashboards/abc123/panels/2/query" ,
strings . NewReader ( "{}" ) ,
)
queryReturnsError = true
resp , err := server . SendJSON ( req )
require . NoError ( t , err )
require . NoError ( t , resp . Body . Close ( ) )
require . Equal ( t , http . StatusInternalServerError , resp . StatusCode )
queryReturnsError = false
} )
t . Run ( "Status code is 200 when a panel has queries from multiple datasources" , func ( t * testing . T ) {
server , fakeDashboardService := setup ( true )
fakeDashboardService . On (
"BuildPublicDashboardMetricRequest" ,
mock . Anything ,
"abc123" ,
int64 ( 2 ) ,
) . Return ( dtos . MetricRequest {
Queries : [ ] * simplejson . Json {
simplejson . MustJson ( [ ] byte ( `
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds"
} ,
"exemplar" : true ,
"expr" : "query_2_A" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
}
` ) ) ,
simplejson . MustJson ( [ ] byte ( `
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds2"
} ,
"exemplar" : true ,
"expr" : "query_2_B" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "B"
}
` ) ) ,
} ,
} , nil )
req := server . NewPostRequest (
"/api/public/dashboards/abc123/panels/2/query" ,
strings . NewReader ( "{}" ) ,
)
resp , err := server . SendJSON ( req )
require . NoError ( t , err )
bodyBytes , err := ioutil . ReadAll ( resp . Body )
require . NoError ( t , err )
require . JSONEq (
t ,
` {
"results" : {
"A" : {
"frames" : [
{
"data" : {
"values" : [ ]
} ,
"schema" : {
"fields" : [ ] ,
"refId" : "A" ,
"name" : "query-A"
}
}
]
} ,
"B" : {
"frames" : [
{
"data" : {
"values" : [ ]
} ,
"schema" : {
"fields" : [ ] ,
"refId" : "B" ,
"name" : "query-B"
}
}
]
}
}
} ` ,
string ( bodyBytes ) ,
)
require . NoError ( t , resp . Body . Close ( ) )
require . Equal ( t , http . StatusOK , resp . StatusCode )
} )
}