use reflection

This commit is contained in:
Ryan McKinley 2024-06-12 02:21:05 +03:00
parent 0118c7666a
commit df148ca9ea
6 changed files with 311 additions and 0 deletions

View File

@ -0,0 +1,30 @@
package resource
import (
"github.com/fullstorydev/grpchan"
"github.com/fullstorydev/grpchan/inprocgrpc"
grpcAuth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
"google.golang.org/grpc"
grpcUtils "github.com/grafana/grafana/pkg/services/store/entity/grpc"
)
func NewResourceStoreClientLocal(server ResourceStoreServer) ResourceStoreClient {
channel := &inprocgrpc.Channel{}
auth := &grpcUtils.Authenticator{}
channel.RegisterService(
grpchan.InterceptServer(
&ResourceStore_ServiceDesc,
grpcAuth.UnaryServerInterceptor(auth.Authenticate),
grpcAuth.StreamServerInterceptor(auth.Authenticate),
),
server,
)
return NewResourceStoreClient(grpchan.InterceptClientConn(channel, grpcUtils.UnaryClientInterceptor, grpcUtils.StreamClientInterceptor))
}
func NewEntityStoreClientGRPC(channel *grpc.ClientConn) ResourceStoreClient {
return NewResourceStoreClient(grpchan.InterceptClientConn(channel, grpcUtils.UnaryClientInterceptor, grpcUtils.StreamClientInterceptor))
}

View File

@ -0,0 +1,105 @@
package resource_server_tests
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/components/satokengen"
"github.com/grafana/grafana/pkg/infra/appcontext"
"github.com/grafana/grafana/pkg/server"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/org"
saAPI "github.com/grafana/grafana/pkg/services/serviceaccounts/api"
saTests "github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
"github.com/grafana/grafana/pkg/services/store/entity/db/dbimpl"
"github.com/grafana/grafana/pkg/services/store/resource"
"github.com/grafana/grafana/pkg/services/store/resource/sqlstash"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/tests/testinfra"
"github.com/grafana/grafana/pkg/tests/testsuite"
)
func TestMain(m *testing.M) {
testsuite.Run(m)
}
func createServiceAccountAdminToken(t *testing.T, env *server.TestEnv) (string, *user.SignedInUser) {
t.Helper()
account := saTests.SetupUserServiceAccount(t, env.SQLStore, env.Cfg, saTests.TestUser{
Name: "grpc-server-sa",
Role: string(org.RoleAdmin),
Login: "grpc-server-sa",
IsServiceAccount: true,
})
keyGen, err := satokengen.New(saAPI.ServiceID)
require.NoError(t, err)
_ = saTests.SetupApiKey(t, env.SQLStore, env.Cfg, saTests.TestApiKey{
Name: "grpc-server-test",
Role: org.RoleAdmin,
OrgId: account.OrgID,
Key: keyGen.HashedKey,
ServiceAccountID: &account.ID,
})
return keyGen.ClientSecret, &user.SignedInUser{
UserID: account.ID,
Email: account.Email,
Name: account.Name,
Login: account.Login,
OrgID: account.OrgID,
IsServiceAccount: account.IsServiceAccount,
}
}
type testContext struct {
authToken string
client resource.ResourceStoreClient
user *user.SignedInUser
ctx context.Context
}
func createTestContext(t *testing.T) testContext {
t.Helper()
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
EnableFeatureToggles: []string{
featuremgmt.FlagGrpcServer,
featuremgmt.FlagUnifiedStorage,
},
AppModeProduction: false, // required for migrations to run
GRPCServerAddress: "127.0.0.1:0", // :0 for choosing the port automatically
})
_, env := testinfra.StartGrafanaEnv(t, dir, path)
authToken, serviceAccountUser := createServiceAccountAdminToken(t, env)
eDB, err := dbimpl.ProvideEntityDB(env.SQLStore, env.Cfg, env.FeatureToggles, nil)
require.NoError(t, err)
err = eDB.Init()
require.NoError(t, err)
traceConfig, err := tracing.ParseTracingConfig(env.Cfg)
require.NoError(t, err)
tracer, err := tracing.ProvideService(traceConfig)
require.NoError(t, err)
store, err := sqlstash.ProvideSQLResourceServer(eDB, tracer)
require.NoError(t, err)
client := resource.NewResourceStoreClientLocal(store)
return testContext{
authToken: authToken,
client: client,
user: serviceAccountUser,
ctx: appcontext.WithUser(context.Background(), serviceAccountUser),
}
}

View File

@ -0,0 +1,84 @@
package resource_server_tests
import (
_ "embed"
"encoding/json"
"fmt"
"net/http"
"testing"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/grafana/grafana/pkg/apis/playlist/v0alpha1"
"github.com/grafana/grafana/pkg/infra/appcontext"
"github.com/grafana/grafana/pkg/services/store/resource"
)
var (
//go:embed testdata/dashboard-with-tags-b-g.json
dashboardWithTagsBlueGreen string
//go:embed testdata/dashboard-with-tags-r-g.json
dashboardWithTagsRedGreen string
)
func TestIntegrationEntityServer(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
testCtx := createTestContext(t)
ctx := appcontext.WithUser(testCtx.ctx, testCtx.user)
t.Run("should not retrieve non-existent objects", func(t *testing.T) {
resp, err := testCtx.client.GetResource(ctx, &resource.GetResourceRequest{
Key: &resource.Key{
Group: "X",
Namespace: "X",
},
})
require.NoError(t, err)
require.NotNil(t, resp)
require.NotNil(t, resp.Status)
require.Nil(t, resp.Value)
require.Equal(t, int32(http.StatusBadRequest), resp.Status.Code)
})
t.Run("insert an object", func(t *testing.T) {
var err error
key := &resource.Key{
Namespace: "default",
Group: "playlists.grafana.app",
Resource: "Playlist",
Name: "x123",
}
sample := v0alpha1.Playlist{
ObjectMeta: metav1.ObjectMeta{
Name: key.Name,
Namespace: key.Namespace,
UID: types.UID("xyz"),
},
TypeMeta: metav1.TypeMeta{
Kind: key.Resource,
APIVersion: key.Group + "/v0alpha1",
},
Spec: v0alpha1.Spec{
Title: "hello",
},
}
req := &resource.CreateRequest{
Key: key,
}
req.Value, err = json.Marshal(sample)
require.NoError(t, err)
fmt.Printf("%s", string(req.Value))
resp, err := testCtx.client.Create(ctx, req)
require.NoError(t, err)
require.NotNil(t, resp)
require.Nil(t, resp.Status)
require.True(t, resp.ResourceVersion > 0) // that it has a positive resource version
})
}

View File

@ -0,0 +1,39 @@
{
"tags": [
"blue",
"green"
],
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 221,
"links": [],
"liveNow": false,
"panels": [
{
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 8
},
"id": 8,
"title": "Row title",
"type": "row"
}
],
"schemaVersion": 36,
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "special ds",
"uid": "mocpwtR4k",
"version": 1,
"weekStart": ""
}

View File

@ -0,0 +1,39 @@
{
"tags": [
"red",
"green"
],
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 221,
"links": [],
"liveNow": false,
"panels": [
{
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 8
},
"id": 8,
"title": "Row title",
"type": "row"
}
],
"schemaVersion": 36,
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "special ds",
"uid": "mocpwtR4k",
"version": 1,
"weekStart": ""
}

View File

@ -0,0 +1,14 @@
package resource
import (
"fmt"
"net/http"
)
func badRequest(format string, a ...any) *StatusResult {
return &StatusResult{
Status: "Failure",
Message: fmt.Sprintf(format, a...),
Code: http.StatusBadRequest,
}
}