From e05262aae9cef3c14522f72a2b4d394919f35c34 Mon Sep 17 00:00:00 2001 From: Rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Wed, 9 Aug 2023 15:53:38 +0800 Subject: [PATCH] feat: support manager store on UI (#161) --- console/atest-ui/src/App.vue | 93 ++++---- console/atest-ui/src/views/StoreManager.vue | 234 ++++++++++++++++++++ pkg/server/convert.go | 20 ++ pkg/server/convert_test.go | 30 +++ pkg/server/remote_server.go | 27 ++- pkg/server/remote_server_test.go | 23 +- pkg/server/server.pb.go | 85 +++---- pkg/server/server.pb.gw.go | 85 +++++++ pkg/server/server.proto | 1 + pkg/server/server_grpc.pb.go | 36 +++ pkg/testing/loader.go | 4 +- pkg/testing/loader_file_test.go | 2 + pkg/testing/parser.go | 1 + pkg/testing/parser_test.go | 5 + pkg/testing/store.go | 69 +++++- pkg/testing/store_test.go | 43 +++- pkg/testing/testdata/stores.yaml | 2 + 17 files changed, 650 insertions(+), 110 deletions(-) create mode 100644 console/atest-ui/src/views/StoreManager.vue diff --git a/console/atest-ui/src/App.vue b/console/atest-ui/src/App.vue index 4ebf964b..96ac1491 100644 --- a/console/atest-ui/src/App.vue +++ b/console/atest-ui/src/App.vue @@ -1,11 +1,12 @@ + + diff --git a/pkg/server/convert.go b/pkg/server/convert.go index caefd9d2..7d7f568d 100644 --- a/pkg/server/convert.go +++ b/pkg/server/convert.go @@ -26,6 +26,7 @@ package server import "github.com/linuxsuren/api-testing/pkg/testing" +// ToGRPCStore convert the normal store to GRPC store func ToGRPCStore(store testing.Store) (result *Store) { result = &Store{ Name: store.Name, @@ -41,3 +42,22 @@ func ToGRPCStore(store testing.Store) (result *Store) { } return } + +// ToNormalStore convert the GRPC store to normal store +func ToNormalStore(store *Store) (result testing.Store) { + result = testing.Store{ + Name: store.Name, + Description: store.Description, + URL: store.Url, + Username: store.Username, + Password: store.Password, + Properties: pairToMap(store.Properties), + } + if store.Kind != nil { + result.Kind = testing.StoreKind{ + Name: store.Kind.Name, + URL: store.Kind.Url, + } + } + return +} diff --git a/pkg/server/convert_test.go b/pkg/server/convert_test.go index 7e4ab7fe..506ba27b 100644 --- a/pkg/server/convert_test.go +++ b/pkg/server/convert_test.go @@ -60,3 +60,33 @@ func TestToGRPCStore(t *testing.T) { }, })) } + +func TestToNormalStore(t *testing.T) { + assert.Equal(t, atest.Store{ + Name: "test", + Description: "desc", + Kind: atest.StoreKind{ + Name: "test", + URL: urlFoo, + }, + URL: urlFoo, + Username: "user", + Password: "pass", + Properties: map[string]string{ + "foo": "bar", + }, + }, ToNormalStore(&Store{ + Name: "test", + Description: "desc", + Kind: &StoreKind{ + Name: "test", + Url: urlFoo, + }, + Url: urlFoo, + Username: "user", + Password: "pass", + Properties: []*Pair{{ + Key: "foo", Value: "bar", + }}, + })) +} diff --git a/pkg/server/remote_server.go b/pkg/server/remote_server.go index 7325c96a..13864330 100644 --- a/pkg/server/remote_server.go +++ b/pkg/server/remote_server.go @@ -602,24 +602,35 @@ func (s *server) GetStores(ctx context.Context, in *Empty) (reply *Stores, err e for _, item := range stores { grpcStore := ToGRPCStore(item) - if !item.IsLocal() { - storeStatus, sErr := s.VerifyStore(ctx, &SimpleQuery{Name: item.Name}) - grpcStore.Ready = sErr == nil && storeStatus.Success - } else { - grpcStore.Ready = true - } + storeStatus, sErr := s.VerifyStore(ctx, &SimpleQuery{Name: item.Name}) + grpcStore.Ready = sErr == nil && storeStatus.Success reply.Data = append(reply.Data, grpcStore) } + reply.Data = append(reply.Data, &Store{ + Name: "local", + Kind: &StoreKind{}, + Ready: true, + }) } return } func (s *server) CreateStore(ctx context.Context, in *Store) (reply *Store, err error) { - // TODO need to implement + reply = &Store{} + storeFactory := testing.NewStoreFactory(s.configDir) + err = storeFactory.CreateStore(ToNormalStore(in)) + return +} +func (s *server) UpdateStore(ctx context.Context, in *Store) (reply *Store, err error) { + reply = &Store{} + storeFactory := testing.NewStoreFactory(s.configDir) + err = storeFactory.UpdateStore(ToNormalStore(in)) return } func (s *server) DeleteStore(ctx context.Context, in *Store) (reply *Store, err error) { - // TODO need to implement + reply = &Store{} + storeFactory := testing.NewStoreFactory(s.configDir) + err = storeFactory.DeleteStore(in.Name) return } func (s *server) VerifyStore(ctx context.Context, in *SimpleQuery) (reply *CommonResult, err error) { diff --git a/pkg/server/remote_server_test.go b/pkg/server/remote_server_test.go index dc7951ee..056b1c91 100644 --- a/pkg/server/remote_server_test.go +++ b/pkg/server/remote_server_test.go @@ -645,9 +645,16 @@ func TestStoreManager(t *testing.T) { t.Run("CreateStore", func(t *testing.T) { server, clean := getRemoteServerInTempDir() defer clean() - reply, err := server.CreateStore(ctx, &Store{}) + reply, err := server.CreateStore(ctx, &Store{ + Name: "fake", + }) + assert.NoError(t, err) + assert.NotNil(t, reply) + + var stores *Stores + stores, err = server.GetStores(ctx, &Empty{}) assert.NoError(t, err) - assert.Nil(t, reply) + assert.Equal(t, 2, len(stores.Data)) }) t.Run("DeleteStore", func(t *testing.T) { @@ -655,7 +662,7 @@ func TestStoreManager(t *testing.T) { defer clean() reply, err := server.DeleteStore(ctx, &Store{}) assert.NoError(t, err) - assert.Nil(t, reply) + assert.NotNil(t, reply) }) t.Run("VerifyStore", func(t *testing.T) { @@ -666,6 +673,14 @@ func TestStoreManager(t *testing.T) { assert.Error(t, err) assert.NotNil(t, reply) }) + + t.Run("UpdateStore", func(t *testing.T) { + server, clean := getRemoteServerInTempDir() + defer clean() + + _, err := server.UpdateStore(ctx, &Store{}) + assert.Error(t, err) + }) } func getRemoteServerInTempDir() (server RunnerServer, call func()) { @@ -673,7 +688,7 @@ func getRemoteServerInTempDir() (server RunnerServer, call func()) { call = func() { os.RemoveAll(dir) } writer := atesting.NewFileWriter(dir) - server = NewRemoteServer(writer, newLocalloaderFromStore(), "") + server = NewRemoteServer(writer, newLocalloaderFromStore(), dir) return } diff --git a/pkg/server/server.pb.go b/pkg/server/server.pb.go index 544af07a..fdf28475 100644 --- a/pkg/server/server.pb.go +++ b/pkg/server/server.pb.go @@ -1861,7 +1861,7 @@ var file_pkg_server_server_proto_rawDesc = []byte{ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x07, - 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0xbc, 0x0b, 0x0a, 0x06, 0x52, 0x75, 0x6e, 0x6e, + 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0xeb, 0x0b, 0x0a, 0x06, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x2d, 0x0a, 0x03, 0x52, 0x75, 0x6e, 0x12, 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, @@ -1946,17 +1946,20 @@ var file_pkg_server_server_proto_rawDesc = []byte{ 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x0b, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x0b, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0b, 0x56, 0x65, - 0x72, 0x69, 0x66, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x14, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x73, 0x75, 0x72, 0x65, 0x6e, 0x2f, - 0x61, 0x70, 0x69, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x70, 0x6b, 0x67, 0x2f, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x0b, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0b, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x14, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x22, 0x00, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x73, 0x75, 0x72, 0x65, 0x6e, 0x2f, 0x61, + 0x70, 0x69, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2051,35 +2054,37 @@ var file_pkg_server_server_proto_depIdxs = []int32{ 27, // 43: server.Runner.GetStoreKinds:input_type -> server.Empty 27, // 44: server.Runner.GetStores:input_type -> server.Empty 20, // 45: server.Runner.CreateStore:input_type -> server.Store - 20, // 46: server.Runner.DeleteStore:input_type -> server.Store - 18, // 47: server.Runner.VerifyStore:input_type -> server.SimpleQuery - 7, // 48: server.Runner.Run:output_type -> server.TestResult - 0, // 49: server.Runner.GetSuites:output_type -> server.Suites - 8, // 50: server.Runner.CreateTestSuite:output_type -> server.HelloReply - 3, // 51: server.Runner.GetTestSuite:output_type -> server.TestSuite - 8, // 52: server.Runner.UpdateTestSuite:output_type -> server.HelloReply - 8, // 53: server.Runner.DeleteTestSuite:output_type -> server.HelloReply - 9, // 54: server.Runner.ListTestCase:output_type -> server.Suite - 11, // 55: server.Runner.GetSuggestedAPIs:output_type -> server.TestCases - 15, // 56: server.Runner.RunTestCase:output_type -> server.TestCaseResult - 12, // 57: server.Runner.GetTestCase:output_type -> server.TestCase - 8, // 58: server.Runner.CreateTestCase:output_type -> server.HelloReply - 8, // 59: server.Runner.UpdateTestCase:output_type -> server.HelloReply - 8, // 60: server.Runner.DeleteTestCase:output_type -> server.HelloReply - 24, // 61: server.Runner.ListCodeGenerator:output_type -> server.SimpleList - 23, // 62: server.Runner.GenerateCode:output_type -> server.CommonResult - 17, // 63: server.Runner.PopularHeaders:output_type -> server.Pairs - 17, // 64: server.Runner.FunctionsQuery:output_type -> server.Pairs - 17, // 65: server.Runner.FunctionsQueryStream:output_type -> server.Pairs - 8, // 66: server.Runner.GetVersion:output_type -> server.HelloReply - 8, // 67: server.Runner.Sample:output_type -> server.HelloReply - 21, // 68: server.Runner.GetStoreKinds:output_type -> server.StoreKinds - 19, // 69: server.Runner.GetStores:output_type -> server.Stores - 20, // 70: server.Runner.CreateStore:output_type -> server.Store - 20, // 71: server.Runner.DeleteStore:output_type -> server.Store - 23, // 72: server.Runner.VerifyStore:output_type -> server.CommonResult - 48, // [48:73] is the sub-list for method output_type - 23, // [23:48] is the sub-list for method input_type + 20, // 46: server.Runner.UpdateStore:input_type -> server.Store + 20, // 47: server.Runner.DeleteStore:input_type -> server.Store + 18, // 48: server.Runner.VerifyStore:input_type -> server.SimpleQuery + 7, // 49: server.Runner.Run:output_type -> server.TestResult + 0, // 50: server.Runner.GetSuites:output_type -> server.Suites + 8, // 51: server.Runner.CreateTestSuite:output_type -> server.HelloReply + 3, // 52: server.Runner.GetTestSuite:output_type -> server.TestSuite + 8, // 53: server.Runner.UpdateTestSuite:output_type -> server.HelloReply + 8, // 54: server.Runner.DeleteTestSuite:output_type -> server.HelloReply + 9, // 55: server.Runner.ListTestCase:output_type -> server.Suite + 11, // 56: server.Runner.GetSuggestedAPIs:output_type -> server.TestCases + 15, // 57: server.Runner.RunTestCase:output_type -> server.TestCaseResult + 12, // 58: server.Runner.GetTestCase:output_type -> server.TestCase + 8, // 59: server.Runner.CreateTestCase:output_type -> server.HelloReply + 8, // 60: server.Runner.UpdateTestCase:output_type -> server.HelloReply + 8, // 61: server.Runner.DeleteTestCase:output_type -> server.HelloReply + 24, // 62: server.Runner.ListCodeGenerator:output_type -> server.SimpleList + 23, // 63: server.Runner.GenerateCode:output_type -> server.CommonResult + 17, // 64: server.Runner.PopularHeaders:output_type -> server.Pairs + 17, // 65: server.Runner.FunctionsQuery:output_type -> server.Pairs + 17, // 66: server.Runner.FunctionsQueryStream:output_type -> server.Pairs + 8, // 67: server.Runner.GetVersion:output_type -> server.HelloReply + 8, // 68: server.Runner.Sample:output_type -> server.HelloReply + 21, // 69: server.Runner.GetStoreKinds:output_type -> server.StoreKinds + 19, // 70: server.Runner.GetStores:output_type -> server.Stores + 20, // 71: server.Runner.CreateStore:output_type -> server.Store + 20, // 72: server.Runner.UpdateStore:output_type -> server.Store + 20, // 73: server.Runner.DeleteStore:output_type -> server.Store + 23, // 74: server.Runner.VerifyStore:output_type -> server.CommonResult + 49, // [49:75] is the sub-list for method output_type + 23, // [23:49] is the sub-list for method input_type 23, // [23:23] is the sub-list for extension type_name 23, // [23:23] is the sub-list for extension extendee 0, // [0:23] is the sub-list for field type_name diff --git a/pkg/server/server.pb.gw.go b/pkg/server/server.pb.gw.go index ecfde7f0..f7a128d4 100644 --- a/pkg/server/server.pb.gw.go +++ b/pkg/server/server.pb.gw.go @@ -822,6 +822,40 @@ func local_request_Runner_CreateStore_0(ctx context.Context, marshaler runtime.M } +func request_Runner_UpdateStore_0(ctx context.Context, marshaler runtime.Marshaler, client RunnerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq Store + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateStore(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Runner_UpdateStore_0(ctx context.Context, marshaler runtime.Marshaler, server RunnerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq Store + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UpdateStore(ctx, &protoReq) + return msg, metadata, err + +} + func request_Runner_DeleteStore_0(ctx context.Context, marshaler runtime.Marshaler, client RunnerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq Store var metadata runtime.ServerMetadata @@ -1453,6 +1487,31 @@ func RegisterRunnerHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser }) + mux.Handle("POST", pattern_Runner_UpdateStore_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/server.Runner/UpdateStore", runtime.WithHTTPPathPattern("/server.Runner/UpdateStore")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Runner_UpdateStore_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_Runner_UpdateStore_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("POST", pattern_Runner_DeleteStore_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2050,6 +2109,28 @@ func RegisterRunnerHandlerClient(ctx context.Context, mux *runtime.ServeMux, cli }) + mux.Handle("POST", pattern_Runner_UpdateStore_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/server.Runner/UpdateStore", runtime.WithHTTPPathPattern("/server.Runner/UpdateStore")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Runner_UpdateStore_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_Runner_UpdateStore_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("POST", pattern_Runner_DeleteStore_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2144,6 +2225,8 @@ var ( pattern_Runner_CreateStore_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"server.Runner", "CreateStore"}, "")) + pattern_Runner_UpdateStore_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"server.Runner", "UpdateStore"}, "")) + pattern_Runner_DeleteStore_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"server.Runner", "DeleteStore"}, "")) pattern_Runner_VerifyStore_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"server.Runner", "VerifyStore"}, "")) @@ -2196,6 +2279,8 @@ var ( forward_Runner_CreateStore_0 = runtime.ForwardResponseMessage + forward_Runner_UpdateStore_0 = runtime.ForwardResponseMessage + forward_Runner_DeleteStore_0 = runtime.ForwardResponseMessage forward_Runner_VerifyStore_0 = runtime.ForwardResponseMessage diff --git a/pkg/server/server.proto b/pkg/server/server.proto index 3c6c9e25..37bdc9d8 100644 --- a/pkg/server/server.proto +++ b/pkg/server/server.proto @@ -38,6 +38,7 @@ service Runner { rpc GetStoreKinds(Empty) returns (StoreKinds) {} rpc GetStores(Empty) returns (Stores) {} rpc CreateStore(Store) returns (Store) {} + rpc UpdateStore(Store) returns (Store) {} rpc DeleteStore(Store) returns (Store) {} rpc VerifyStore(SimpleQuery) returns (CommonResult) {} } diff --git a/pkg/server/server_grpc.pb.go b/pkg/server/server_grpc.pb.go index 4d20c587..cfdb004a 100644 --- a/pkg/server/server_grpc.pb.go +++ b/pkg/server/server_grpc.pb.go @@ -50,6 +50,7 @@ type RunnerClient interface { GetStoreKinds(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*StoreKinds, error) GetStores(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Stores, error) CreateStore(ctx context.Context, in *Store, opts ...grpc.CallOption) (*Store, error) + UpdateStore(ctx context.Context, in *Store, opts ...grpc.CallOption) (*Store, error) DeleteStore(ctx context.Context, in *Store, opts ...grpc.CallOption) (*Store, error) VerifyStore(ctx context.Context, in *SimpleQuery, opts ...grpc.CallOption) (*CommonResult, error) } @@ -291,6 +292,15 @@ func (c *runnerClient) CreateStore(ctx context.Context, in *Store, opts ...grpc. return out, nil } +func (c *runnerClient) UpdateStore(ctx context.Context, in *Store, opts ...grpc.CallOption) (*Store, error) { + out := new(Store) + err := c.cc.Invoke(ctx, "/server.Runner/UpdateStore", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *runnerClient) DeleteStore(ctx context.Context, in *Store, opts ...grpc.CallOption) (*Store, error) { out := new(Store) err := c.cc.Invoke(ctx, "/server.Runner/DeleteStore", in, out, opts...) @@ -341,6 +351,7 @@ type RunnerServer interface { GetStoreKinds(context.Context, *Empty) (*StoreKinds, error) GetStores(context.Context, *Empty) (*Stores, error) CreateStore(context.Context, *Store) (*Store, error) + UpdateStore(context.Context, *Store) (*Store, error) DeleteStore(context.Context, *Store) (*Store, error) VerifyStore(context.Context, *SimpleQuery) (*CommonResult, error) mustEmbedUnimplementedRunnerServer() @@ -419,6 +430,9 @@ func (UnimplementedRunnerServer) GetStores(context.Context, *Empty) (*Stores, er func (UnimplementedRunnerServer) CreateStore(context.Context, *Store) (*Store, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateStore not implemented") } +func (UnimplementedRunnerServer) UpdateStore(context.Context, *Store) (*Store, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateStore not implemented") +} func (UnimplementedRunnerServer) DeleteStore(context.Context, *Store) (*Store, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteStore not implemented") } @@ -860,6 +874,24 @@ func _Runner_CreateStore_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _Runner_UpdateStore_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Store) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RunnerServer).UpdateStore(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/server.Runner/UpdateStore", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RunnerServer).UpdateStore(ctx, req.(*Store)) + } + return interceptor(ctx, in, info, handler) +} + func _Runner_DeleteStore_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Store) if err := dec(in); err != nil { @@ -991,6 +1023,10 @@ var Runner_ServiceDesc = grpc.ServiceDesc{ MethodName: "CreateStore", Handler: _Runner_CreateStore_Handler, }, + { + MethodName: "UpdateStore", + Handler: _Runner_UpdateStore_Handler, + }, { MethodName: "DeleteStore", Handler: _Runner_DeleteStore_Handler, diff --git a/pkg/testing/loader.go b/pkg/testing/loader.go index 65b6bd15..23d4dd7f 100644 --- a/pkg/testing/loader.go +++ b/pkg/testing/loader.go @@ -8,6 +8,8 @@ type Loader interface { GetContext() string GetCount() int Reset() + + Verify() (err error) } type Writer interface { @@ -25,6 +27,4 @@ type Writer interface { GetSuite(name string) (*TestSuite, string, error) UpdateSuite(TestSuite) (err error) DeleteSuite(name string) (err error) - - Verify() (err error) } diff --git a/pkg/testing/loader_file_test.go b/pkg/testing/loader_file_test.go index 1827b8fb..151be0c5 100644 --- a/pkg/testing/loader_file_test.go +++ b/pkg/testing/loader_file_test.go @@ -38,6 +38,8 @@ func TestFileLoader(t *testing.T) { loader.Put(item) } tt.verify(t, loader) + + assert.NoError(t, loader.Verify()) }) } } diff --git a/pkg/testing/parser.go b/pkg/testing/parser.go index 8d3a0db1..3faabb23 100644 --- a/pkg/testing/parser.go +++ b/pkg/testing/parser.go @@ -41,6 +41,7 @@ func Parse(data []byte) (testSuite *TestSuite, err error) { return } +// ParseFromStream parses the stream and returns the test suite func ParseFromStream(stream io.Reader) (testSuite *TestSuite, err error) { var data []byte if data, err = io.ReadAll(stream); err == nil { diff --git a/pkg/testing/parser_test.go b/pkg/testing/parser_test.go index 4635d17f..816aca1f 100644 --- a/pkg/testing/parser_test.go +++ b/pkg/testing/parser_test.go @@ -1,6 +1,7 @@ package testing_test import ( + "bytes" "io" "net/http" "os" @@ -54,6 +55,10 @@ func TestParse(t *testing.T) { assert.Equal(t, "https://gitlab.com/api/v4", suite.API) } + var anotherSuite *atest.TestSuite + anotherSuite, err = atest.ParseFromStream(bytes.NewBuffer(data)) + assert.Equal(t, suite, anotherSuite) + _, err = atest.Parse([]byte(invalidTestCaseContent)) assert.NotNil(t, err) } diff --git a/pkg/testing/store.go b/pkg/testing/store.go index 938b943e..c2bd023b 100644 --- a/pkg/testing/store.go +++ b/pkg/testing/store.go @@ -25,6 +25,7 @@ SOFTWARE. package testing import ( + "fmt" "os" "path" "strings" @@ -58,10 +59,6 @@ func (s *Store) ToMap() (result map[string]string) { return } -func (s *Store) IsLocal() bool { - return s.Name == "local" -} - func MapToStore(data map[string]string) (store Store) { store = Store{ Name: data["name"], @@ -94,6 +91,7 @@ type StoreGetterAndSetter interface { GetStore(name string) (store *Store, err error) DeleteStore(name string) (err error) UpdateStore(store Store) (err error) + CreateStore(store Store) (err error) GetStoreKinds() (kinds []StoreKind, err error) } @@ -106,12 +104,14 @@ type storeFactory struct { configDir string } +// NewStoreFactory creates a new store factory func NewStoreFactory(configDir string) StoreGetterAndSetter { return &storeFactory{ configDir: configDir, } } +// GetStores returns all stores func (s *storeFactory) GetStores() (stores []Store, err error) { var data []byte if data, err = os.ReadFile(path.Join(s.configDir, "stores.yaml")); err == nil { @@ -119,7 +119,6 @@ func (s *storeFactory) GetStores() (stores []Store, err error) { } else { err = nil } - stores = append(stores, Store{Name: "local"}) return } @@ -137,10 +136,70 @@ func (s *storeFactory) GetStore(name string) (store *Store, err error) { } func (s *storeFactory) DeleteStore(name string) (err error) { + var stores []Store + if stores, err = s.GetStores(); err == nil { + for i := range stores { + item := stores[i] + if item.Name == name { + stores = append(stores[:i], stores[i+1:]...) + break + } + } + var data []byte + if data, err = yaml.Marshal(stores); err == nil { + err = os.WriteFile(path.Join(s.configDir, "stores.yaml"), data, 0644) + } + } return } func (s *storeFactory) UpdateStore(store Store) (err error) { + var stores []Store + if stores, err = s.GetStores(); err == nil { + exist := false + for i := range stores { + item := stores[i] + if item.Name == store.Name { + stores[i] = store + exist = true + break + } + } + + if exist { + var data []byte + if data, err = yaml.Marshal(stores); err == nil { + err = os.WriteFile(path.Join(s.configDir, "stores.yaml"), data, 0644) + } + } else { + err = fmt.Errorf("store %s is not exists", store.Name) + } + } + return +} + +func (s *storeFactory) CreateStore(store Store) (err error) { + var stores []Store + if stores, err = s.GetStores(); err == nil { + exist := false + for i := range stores { + item := stores[i] + if item.Name == store.Name { + exist = true + break + } + } + + if !exist { + stores = append(stores, store) + var data []byte + if data, err = yaml.Marshal(stores); err == nil { + err = os.WriteFile(path.Join(s.configDir, "stores.yaml"), data, 0644) + } + } else { + err = fmt.Errorf("store %s already exists", store.Name) + } + } return } diff --git a/pkg/testing/store_test.go b/pkg/testing/store_test.go index 7e8599e1..b3fa5f51 100644 --- a/pkg/testing/store_test.go +++ b/pkg/testing/store_test.go @@ -25,6 +25,7 @@ SOFTWARE. package testing import ( + "os" "testing" "github.com/stretchr/testify/assert" @@ -70,14 +71,13 @@ func TestStoreFactory(t *testing.T) { "database": "test", }, }, store) - assert.False(t, store.IsLocal()) }) t.Run("GetAllStores", func(t *testing.T) { stores, err := factory.GetStores() assert.Nil(t, err) - assert.Equal(t, 2, len(stores)) - assert.Equal(t, "local", stores[1].Name) + assert.Equal(t, 1, len(stores)) + assert.Equal(t, "db", stores[0].Name) }) t.Run("DeleteStore", func(t *testing.T) { @@ -86,22 +86,43 @@ func TestStoreFactory(t *testing.T) { }) t.Run("UpdateStore", func(t *testing.T) { - err := factory.UpdateStore(Store{}) - assert.NoError(t, err) + err := factory.UpdateStore(Store{Name: "fake"}) + assert.Error(t, err) }) t.Run("no stores.yaml found", func(t *testing.T) { factory := NewStoreFactory("testdata-fake") stores, err := factory.GetStores() assert.NoError(t, err) - assert.Equal(t, []Store{{ - Name: "local", - }}, stores) + assert.Nil(t, stores) }) - t.Run("local store", func(t *testing.T) { - store := Store{Name: "local"} - assert.True(t, store.IsLocal()) + t.Run("CreateStore", func(t *testing.T) { + dir, err := os.MkdirTemp(os.TempDir(), "store") + assert.NoError(t, err) + defer os.RemoveAll(dir) + + factory := NewStoreFactory(dir) + err = factory.CreateStore(Store{Name: "fake"}) + assert.NoError(t, err) + + // create an existing store + err = factory.CreateStore(Store{Name: "fake"}) + assert.Error(t, err) + + // update an existing store + err = factory.UpdateStore(Store{Name: "fake"}) + assert.NoError(t, err) + + // delete an existing store + err = factory.DeleteStore("fake") + assert.NoError(t, err) + + // get all stores + var stores []Store + stores, err = factory.GetStores() + assert.NoError(t, err) + assert.Equal(t, 0, len(stores)) }) } diff --git a/pkg/testing/testdata/stores.yaml b/pkg/testing/testdata/stores.yaml index e9783a44..994b3944 100644 --- a/pkg/testing/testdata/stores.yaml +++ b/pkg/testing/testdata/stores.yaml @@ -2,7 +2,9 @@ kind: name: database url: localhost:7071 + description: "" url: localhost:4000 username: root + password: "" properties: database: test