From 46552d1c156e5ee33c5549a59381785707fe7171 Mon Sep 17 00:00:00 2001 From: Rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:06:38 +0800 Subject: [PATCH] feat: support verify the store (#157) --- .github/testing/core.yaml | 31 ++- .github/workflows/build.yaml | 1 + LICENSE | 2 +- console/atest-ui/src/App.vue | 4 +- console/atest-ui/src/views/TestSuite.vue | 2 + extensions/store-orm/cmd/root.go | 71 ++++++ extensions/store-orm/cmd/root_test.go | 55 +++++ extensions/store-orm/main.go | 249 +-------------------- extensions/store-orm/pkg/server.go | 251 ++++++++++++++++++++++ extensions/store-orm/pkg/server_test.go | 95 ++++++++ extensions/store-s3/cmd/root.go | 6 +- extensions/store-s3/pkg/s3_server.go | 38 ++-- extensions/store-s3/pkg/s3_server_test.go | 5 + pkg/server/remote_server.go | 47 ++-- pkg/server/remote_server_test.go | 18 +- pkg/server/server.pb.go | 245 +++++++++++---------- pkg/server/server.proto | 1 + pkg/testing/loader.go | 2 + pkg/testing/loader_file.go | 5 + pkg/testing/remote/grpc.go | 11 + pkg/testing/remote/loader.pb.go | 56 ++--- pkg/testing/remote/loader.proto | 2 + pkg/testing/remote/loader_grpc.pb.go | 36 ++++ pkg/testing/store.go | 4 + pkg/testing/store_test.go | 6 + pkg/util/error.go | 33 +++ pkg/util/error_test.go | 38 ++++ 27 files changed, 889 insertions(+), 425 deletions(-) create mode 100644 extensions/store-orm/cmd/root.go create mode 100644 extensions/store-orm/cmd/root_test.go create mode 100644 extensions/store-orm/pkg/server.go create mode 100644 extensions/store-orm/pkg/server_test.go create mode 100644 pkg/util/error.go create mode 100644 pkg/util/error_test.go diff --git a/.github/testing/core.yaml b/.github/testing/core.yaml index 232835a..ca73e0b 100644 --- a/.github/testing/core.yaml +++ b/.github/testing/core.yaml @@ -13,7 +13,7 @@ items: api: /GetTestSuite method: POST body: | - {"name": "texst"} + {"name": "test"} expect: bodyFieldsExpect: name: "" @@ -23,7 +23,7 @@ items: api: /GetTestCase method: POST body: | - {"name": "texst"} + {"name": "test"} expect: statusCode: 500 bodyFieldsExpect: @@ -33,7 +33,7 @@ items: api: /GetTestCase method: POST body: | - {"name": "texst"} + {"name": "test"} expect: statusCode: 500 bodyFieldsExpect: @@ -42,3 +42,28 @@ items: request: api: /PopularHeaders method: POST +- name: list-code-generators + request: + api: /ListCodeGenerator + method: POST + expect: + verify: + - len(data) == 1 +- name: list-stores + request: + api: /GetStores + method: POST + expect: + verify: + - len(data) >= 1 +- name: query-funcs + request: + api: /FunctionsQuery + method: POST + expect: + verify: + - len(data) == 1 +- name: version + request: + api: /GetVersion + method: POST diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index d35ae0c..3633e88 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -30,6 +30,7 @@ jobs: make build copy sudo atest service install sudo atest service restart + sudo atest service status atest run -p .github/testing/core.yaml Build: diff --git a/LICENSE b/LICENSE index 34ee84c..82c552e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Rick +Copyright (c) 2023 API Testing Authors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/console/atest-ui/src/App.vue b/console/atest-ui/src/App.vue index 88c43aa..4ebf964 100644 --- a/console/atest-ui/src/App.vue +++ b/console/atest-ui/src/App.vue @@ -126,7 +126,9 @@ function loadStores() { data.value = [] as Tree[] d.data.forEach((item: any) => { - loadTestSuites(item.name) + if (item.ready) { + loadTestSuites(item.name) + } }) }) } diff --git a/console/atest-ui/src/views/TestSuite.vue b/console/atest-ui/src/views/TestSuite.vue index 4450e52..1314073 100644 --- a/console/atest-ui/src/views/TestSuite.vue +++ b/console/atest-ui/src/views/TestSuite.vue @@ -23,6 +23,8 @@ const suite = ref({ } } as Suite) function load() { + if (!props.name || props.store === "") return + const requestOptions = { method: 'POST', headers: { diff --git a/extensions/store-orm/cmd/root.go b/extensions/store-orm/cmd/root.go new file mode 100644 index 0000000..f832710 --- /dev/null +++ b/extensions/store-orm/cmd/root.go @@ -0,0 +1,71 @@ +/** +MIT License + +Copyright (c) 2023 API Testing Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +package cmd + +import ( + "fmt" + "net" + + "github.com/linuxsuren/api-testing/extensions/store-orm/pkg" + "github.com/linuxsuren/api-testing/pkg/testing/remote" + "github.com/spf13/cobra" + "google.golang.org/grpc" +) + +func NewRootCommand() (c *cobra.Command) { + opt := &option{} + c = &cobra.Command{ + Use: "store-orm", + Short: "Storage extension of api-testing", + RunE: opt.runE, + } + flags := c.Flags() + flags.IntVarP(&opt.port, "port", "p", 7071, "The port of gRPC server") + return +} + +func (o *option) runE(cmd *cobra.Command, args []string) (err error) { + removeServer := pkg.NewRemoteServer() + + var lis net.Listener + lis, err = net.Listen("tcp", fmt.Sprintf(":%d", o.port)) + if err != nil { + return + } + + gRPCServer := grpc.NewServer() + remote.RegisterLoaderServer(gRPCServer, removeServer) + + go func() { + <-cmd.Context().Done() + gRPCServer.Stop() + }() + cmd.Println("ORM storage extension is running at port", o.port) + err = gRPCServer.Serve(lis) + return +} + +type option struct { + port int +} diff --git a/extensions/store-orm/cmd/root_test.go b/extensions/store-orm/cmd/root_test.go new file mode 100644 index 0000000..2df00d3 --- /dev/null +++ b/extensions/store-orm/cmd/root_test.go @@ -0,0 +1,55 @@ +/** +MIT License + +Copyright (c) 2023 API Testing Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +package cmd + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestRootCommand(t *testing.T) { + t.Run("invalid port", func(t *testing.T) { + c := NewRootCommand() + assert.Equal(t, "store-orm", c.Use) + + c.SetArgs([]string{"--port", "abc"}) + err := c.Execute() + assert.Error(t, err) + }) + + t.Run("a random port", func(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + c := NewRootCommand() + c.SetContext(ctx) + + c.SetArgs([]string{"--port", "0"}) + err := c.Execute() + assert.NoError(t, err) + }) +} diff --git a/extensions/store-orm/main.go b/extensions/store-orm/main.go index c11ce9b..4598919 100644 --- a/extensions/store-orm/main.go +++ b/extensions/store-orm/main.go @@ -1,258 +1,13 @@ package main import ( - "context" - "errors" - "fmt" - "net" "os" - "github.com/linuxsuren/api-testing/extensions/store-orm/pkg" - "github.com/linuxsuren/api-testing/pkg/server" - "github.com/linuxsuren/api-testing/pkg/testing/remote" - "github.com/spf13/cobra" - "google.golang.org/grpc" - "gorm.io/driver/mysql" - "gorm.io/gorm" - "gorm.io/gorm/logger" + "github.com/linuxsuren/api-testing/extensions/store-orm/cmd" ) func main() { - opt := &option{} - cmd := &cobra.Command{ - Use: "store-orm", - Short: "Storage extension of api-testing", - RunE: opt.runE, - } - flags := cmd.Flags() - flags.IntVarP(&opt.port, "port", "p", 7071, "The port of gRPC server") - if err := cmd.Execute(); err != nil { + if err := cmd.NewRootCommand().Execute(); err != nil { os.Exit(1) } } - -func (o *option) runE(cmd *cobra.Command, args []string) (err error) { - var removeServer remote.LoaderServer - if removeServer, err = NewRemoteServer(); err != nil { - return - } - - var lis net.Listener - lis, err = net.Listen("tcp", fmt.Sprintf(":%d", o.port)) - if err != nil { - return - } - - gRPCServer := grpc.NewServer() - remote.RegisterLoaderServer(gRPCServer, removeServer) - err = gRPCServer.Serve(lis) - return -} - -type option struct { - port int -} - -type dbserver struct { - remote.UnimplementedLoaderServer -} - -// NewRemoteServer creates a remote server instance -func NewRemoteServer() (s remote.LoaderServer, err error) { - s = &dbserver{} - return -} - -func createDB(user, address, database string) (db *gorm.DB, err error) { - dsn := fmt.Sprintf("%s:@tcp(%s)/%s?charset=utf8mb4", user, address, database) - fmt.Println("try to connect to", dsn) - db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{ - Logger: logger.Default.LogMode(logger.Info), - }) - if err != nil { - err = fmt.Errorf("failed to connect to %s, %v", dsn, err) - return - } - - db.AutoMigrate(&pkg.TestCase{}) - db.AutoMigrate(&pkg.TestSuite{}) - return -} - -var dbCache map[string]*gorm.DB = make(map[string]*gorm.DB) - -func (s *dbserver) getClient(ctx context.Context) (db *gorm.DB, err error) { - store := remote.GetStoreFromContext(ctx) - if store == nil { - err = errors.New("no connect to database") - } else { - var ok bool - if db, ok = dbCache[store.Name]; ok && db != nil { - return - } - - database := "atest" - for key, val := range store.Properties { - if key == "database" { - database = val - } - } - - db, err = createDB(store.Username, store.URL, database) - dbCache[store.Name] = db - } - return -} - -func (s *dbserver) ListTestSuite(ctx context.Context, _ *server.Empty) (suites *remote.TestSuites, err error) { - items := make([]*pkg.TestSuite, 0) - - var db *gorm.DB - if db, err = s.getClient(ctx); err != nil { - return - } - - db.Find(&items) - suites = &remote.TestSuites{} - for i := range items { - suites.Data = append(suites.Data, pkg.ConvertToGRPCTestSuite(items[i])) - } - return -} - -func (s *dbserver) CreateTestSuite(ctx context.Context, testSuite *remote.TestSuite) (reply *server.Empty, err error) { - reply = &server.Empty{} - var db *gorm.DB - if db, err = s.getClient(ctx); err != nil { - return - } - - db.Create(pkg.ConvertToDBTestSuite(testSuite)) - return -} - -const nameQuery = `name = ?` - -func (s *dbserver) GetTestSuite(ctx context.Context, suite *remote.TestSuite) (reply *remote.TestSuite, err error) { - query := &pkg.TestSuite{} - var db *gorm.DB - if db, err = s.getClient(ctx); err != nil { - return - } - - db.Find(&query, nameQuery, suite.Name) - - reply = pkg.ConvertToGRPCTestSuite(query) - if suite.Full { - var testcases *server.TestCases - if testcases, err = s.ListTestCases(ctx, &remote.TestSuite{ - Name: suite.Name, - }); err == nil && testcases != nil { - reply.Items = testcases.Data - } - } - return -} - -func (s *dbserver) UpdateTestSuite(ctx context.Context, suite *remote.TestSuite) (reply *remote.TestSuite, err error) { - reply = &remote.TestSuite{} - input := pkg.ConvertToDBTestSuite(suite) - var db *gorm.DB - if db, err = s.getClient(ctx); err != nil { - return - } - - testSuiteIdentity(db, input).Updates(input) - return -} - -func testSuiteIdentity(db *gorm.DB, suite *pkg.TestSuite) *gorm.DB { - return db.Model(suite).Where(nameQuery, suite.Name) -} - -func (s *dbserver) DeleteTestSuite(ctx context.Context, suite *remote.TestSuite) (reply *server.Empty, err error) { - reply = &server.Empty{} - var db *gorm.DB - if db, err = s.getClient(ctx); err != nil { - return - } - - db.Delete(suite, nameQuery, suite.Name) - return -} - -func (s *dbserver) ListTestCases(ctx context.Context, suite *remote.TestSuite) (result *server.TestCases, err error) { - items := make([]*pkg.TestCase, 0) - var db *gorm.DB - if db, err = s.getClient(ctx); err != nil { - return - } - db.Find(&items, "suite_name = ?", suite.Name) - - result = &server.TestCases{} - for i := range items { - result.Data = append(result.Data, pkg.ConvertToRemoteTestCase(items[i])) - } - return -} - -func (s *dbserver) CreateTestCase(ctx context.Context, testcase *server.TestCase) (reply *server.Empty, err error) { - payload := pkg.ConverToDBTestCase(testcase) - var db *gorm.DB - if db, err = s.getClient(ctx); err != nil { - return - } - reply = &server.Empty{} - db.Create(&payload) - return -} - -func (s *dbserver) GetTestCase(ctx context.Context, testcase *server.TestCase) (result *server.TestCase, err error) { - item := &pkg.TestCase{} - var db *gorm.DB - if db, err = s.getClient(ctx); err != nil { - return - } - db.Find(&item, "suite_name = ? AND name = ?", testcase.SuiteName, testcase.Name) - - result = pkg.ConvertToRemoteTestCase(item) - return -} - -func (s *dbserver) UpdateTestCase(ctx context.Context, testcase *server.TestCase) (reply *server.TestCase, err error) { - reply = &server.TestCase{} - input := pkg.ConverToDBTestCase(testcase) - var db *gorm.DB - if db, err = s.getClient(ctx); err != nil { - return - } - testCaseIdentiy(db, input).Updates(input) - - data := make(map[string]interface{}) - if input.ExpectBody == "" { - data["expect_body"] = "" - } - if input.ExpectSchema == "" { - data["expect_schema"] = "" - } - - if len(data) > 0 { - testCaseIdentiy(db, input).Updates(data) - } - return -} - -func (s *dbserver) DeleteTestCase(ctx context.Context, testcase *server.TestCase) (reply *server.Empty, err error) { - reply = &server.Empty{} - input := pkg.ConverToDBTestCase(testcase) - var db *gorm.DB - if db, err = s.getClient(ctx); err != nil { - return - } - testCaseIdentiy(db, input).Delete(input) - return -} - -func testCaseIdentiy(db *gorm.DB, testcase *pkg.TestCase) *gorm.DB { - return db.Model(testcase).Where(fmt.Sprintf("suite_name = '%s' AND name = '%s'", testcase.SuiteName, testcase.Name)) -} diff --git a/extensions/store-orm/pkg/server.go b/extensions/store-orm/pkg/server.go new file mode 100644 index 0000000..b1bf152 --- /dev/null +++ b/extensions/store-orm/pkg/server.go @@ -0,0 +1,251 @@ +/** +MIT License + +Copyright (c) 2023 API Testing Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +package pkg + +import ( + "context" + "errors" + "fmt" + + "github.com/linuxsuren/api-testing/pkg/server" + "github.com/linuxsuren/api-testing/pkg/testing/remote" + "github.com/linuxsuren/api-testing/pkg/util" + "gorm.io/driver/mysql" + "gorm.io/gorm" + "gorm.io/gorm/logger" +) + +type dbserver struct { + remote.UnimplementedLoaderServer +} + +// NewRemoteServer creates a remote server instance +func NewRemoteServer() (s remote.LoaderServer) { + s = &dbserver{} + return +} + +func createDB(user, address, database string) (db *gorm.DB, err error) { + dsn := fmt.Sprintf("%s:@tcp(%s)/%s?charset=utf8mb4", user, address, database) + fmt.Println("try to connect to", dsn) + db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{ + Logger: logger.Default.LogMode(logger.Info), + }) + if err != nil { + err = fmt.Errorf("failed to connect to %s, %v", dsn, err) + return + } + + db.AutoMigrate(&TestCase{}) + db.AutoMigrate(&TestSuite{}) + return +} + +var dbCache map[string]*gorm.DB = make(map[string]*gorm.DB) + +func (s *dbserver) getClient(ctx context.Context) (db *gorm.DB, err error) { + store := remote.GetStoreFromContext(ctx) + if store == nil { + err = errors.New("no connect to database") + } else { + var ok bool + if db, ok = dbCache[store.Name]; ok && db != nil { + return + } + + database := "atest" + for key, val := range store.Properties { + if key == "database" { + database = val + } + } + + if db, err = createDB(store.Username, store.URL, database); err == nil { + dbCache[store.Name] = db + } + } + return +} + +func (s *dbserver) ListTestSuite(ctx context.Context, _ *server.Empty) (suites *remote.TestSuites, err error) { + items := make([]*TestSuite, 0) + + var db *gorm.DB + if db, err = s.getClient(ctx); err != nil { + return + } + + db.Find(&items) + suites = &remote.TestSuites{} + for i := range items { + suites.Data = append(suites.Data, ConvertToGRPCTestSuite(items[i])) + } + return +} + +func (s *dbserver) CreateTestSuite(ctx context.Context, testSuite *remote.TestSuite) (reply *server.Empty, err error) { + reply = &server.Empty{} + var db *gorm.DB + if db, err = s.getClient(ctx); err != nil { + return + } + + db.Create(ConvertToDBTestSuite(testSuite)) + return +} + +const nameQuery = `name = ?` + +func (s *dbserver) GetTestSuite(ctx context.Context, suite *remote.TestSuite) (reply *remote.TestSuite, err error) { + query := &TestSuite{} + var db *gorm.DB + if db, err = s.getClient(ctx); err != nil { + return + } + + db.Find(&query, nameQuery, suite.Name) + + reply = ConvertToGRPCTestSuite(query) + if suite.Full { + var testcases *server.TestCases + if testcases, err = s.ListTestCases(ctx, &remote.TestSuite{ + Name: suite.Name, + }); err == nil && testcases != nil { + reply.Items = testcases.Data + } + } + return +} + +func (s *dbserver) UpdateTestSuite(ctx context.Context, suite *remote.TestSuite) (reply *remote.TestSuite, err error) { + reply = &remote.TestSuite{} + input := ConvertToDBTestSuite(suite) + var db *gorm.DB + if db, err = s.getClient(ctx); err != nil { + return + } + + testSuiteIdentity(db, input).Updates(input) + return +} + +func testSuiteIdentity(db *gorm.DB, suite *TestSuite) *gorm.DB { + return db.Model(suite).Where(nameQuery, suite.Name) +} + +func (s *dbserver) DeleteTestSuite(ctx context.Context, suite *remote.TestSuite) (reply *server.Empty, err error) { + reply = &server.Empty{} + var db *gorm.DB + if db, err = s.getClient(ctx); err != nil { + return + } + + db.Delete(suite, nameQuery, suite.Name) + return +} + +func (s *dbserver) ListTestCases(ctx context.Context, suite *remote.TestSuite) (result *server.TestCases, err error) { + items := make([]*TestCase, 0) + var db *gorm.DB + if db, err = s.getClient(ctx); err != nil { + return + } + db.Find(&items, "suite_name = ?", suite.Name) + + result = &server.TestCases{} + for i := range items { + result.Data = append(result.Data, ConvertToRemoteTestCase(items[i])) + } + return +} + +func (s *dbserver) CreateTestCase(ctx context.Context, testcase *server.TestCase) (reply *server.Empty, err error) { + payload := ConverToDBTestCase(testcase) + var db *gorm.DB + if db, err = s.getClient(ctx); err != nil { + return + } + reply = &server.Empty{} + db.Create(&payload) + return +} + +func (s *dbserver) GetTestCase(ctx context.Context, testcase *server.TestCase) (result *server.TestCase, err error) { + item := &TestCase{} + var db *gorm.DB + if db, err = s.getClient(ctx); err != nil { + return + } + db.Find(&item, "suite_name = ? AND name = ?", testcase.SuiteName, testcase.Name) + + result = ConvertToRemoteTestCase(item) + return +} + +func (s *dbserver) UpdateTestCase(ctx context.Context, testcase *server.TestCase) (reply *server.TestCase, err error) { + reply = &server.TestCase{} + input := ConverToDBTestCase(testcase) + var db *gorm.DB + if db, err = s.getClient(ctx); err != nil { + return + } + testCaseIdentiy(db, input).Updates(input) + + data := make(map[string]interface{}) + if input.ExpectBody == "" { + data["expect_body"] = "" + } + if input.ExpectSchema == "" { + data["expect_schema"] = "" + } + + if len(data) > 0 { + testCaseIdentiy(db, input).Updates(data) + } + return +} + +func (s *dbserver) DeleteTestCase(ctx context.Context, testcase *server.TestCase) (reply *server.Empty, err error) { + reply = &server.Empty{} + input := ConverToDBTestCase(testcase) + var db *gorm.DB + if db, err = s.getClient(ctx); err != nil { + return + } + testCaseIdentiy(db, input).Delete(input) + return +} + +func (s *dbserver) Verify(ctx context.Context, in *server.Empty) (reply *server.CommonResult, err error) { + db, clientErr := s.getClient(ctx) + reply = &server.CommonResult{ + Success: err == nil && db != nil, + Message: util.OKOrErrorMessage(clientErr), + } + return +} + +func testCaseIdentiy(db *gorm.DB, testcase *TestCase) *gorm.DB { + return db.Model(testcase).Where(fmt.Sprintf("suite_name = '%s' AND name = '%s'", testcase.SuiteName, testcase.Name)) +} diff --git a/extensions/store-orm/pkg/server_test.go b/extensions/store-orm/pkg/server_test.go new file mode 100644 index 0000000..e631bae --- /dev/null +++ b/extensions/store-orm/pkg/server_test.go @@ -0,0 +1,95 @@ +/** +MIT License + +Copyright (c) 2023 API Testing Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +package pkg + +import ( + "context" + "testing" + + "github.com/linuxsuren/api-testing/pkg/server" + "github.com/linuxsuren/api-testing/pkg/testing/remote" + "github.com/stretchr/testify/assert" +) + +func TestNewRemoteServer(t *testing.T) { + remoteServer := NewRemoteServer() + assert.NotNil(t, remoteServer) + defaultCtx := context.Background() + + t.Run("ListTestSuite", func(t *testing.T) { + _, err := remoteServer.ListTestSuite(defaultCtx, nil) + assert.Error(t, err) + }) + + t.Run("CreateTestSuite", func(t *testing.T) { + _, err := remoteServer.CreateTestSuite(defaultCtx, nil) + assert.Error(t, err) + }) + + t.Run("GetTestSuite", func(t *testing.T) { + _, err := remoteServer.GetTestSuite(defaultCtx, nil) + assert.Error(t, err) + }) + + t.Run("UpdateTestSuite", func(t *testing.T) { + _, err := remoteServer.UpdateTestSuite(defaultCtx, &remote.TestSuite{}) + assert.Error(t, err) + }) + + t.Run("DeleteTestSuite", func(t *testing.T) { + _, err := remoteServer.DeleteTestSuite(defaultCtx, nil) + assert.Error(t, err) + }) + + t.Run("ListTestCases", func(t *testing.T) { + _, err := remoteServer.ListTestCases(defaultCtx, nil) + assert.Error(t, err) + }) + + t.Run("CreateTestCase", func(t *testing.T) { + _, err := remoteServer.CreateTestCase(defaultCtx, &server.TestCase{}) + assert.Error(t, err) + }) + + t.Run("GetTestCase", func(t *testing.T) { + _, err := remoteServer.GetTestCase(defaultCtx, nil) + assert.Error(t, err) + }) + + t.Run("UpdateTestCase", func(t *testing.T) { + _, err := remoteServer.UpdateTestCase(defaultCtx, &server.TestCase{}) + assert.Error(t, err) + }) + + t.Run("DeleteTestCase", func(t *testing.T) { + _, err := remoteServer.DeleteTestCase(defaultCtx, &server.TestCase{}) + assert.Error(t, err) + }) + + t.Run("Verify", func(t *testing.T) { + reply, err := remoteServer.Verify(defaultCtx, nil) + assert.NoError(t, err) + assert.False(t, reply.Success) + }) +} diff --git a/extensions/store-s3/cmd/root.go b/extensions/store-s3/cmd/root.go index df808da..832e8cf 100644 --- a/extensions/store-s3/cmd/root.go +++ b/extensions/store-s3/cmd/root.go @@ -12,7 +12,7 @@ import ( func NewRootCmd(s3Creator pkg.S3Creator) (cmd *cobra.Command) { opt := &option{ - S3Creator: s3Creator, + s3Creator: s3Creator, } cmd = &cobra.Command{ Use: "store-s3", @@ -25,7 +25,7 @@ func NewRootCmd(s3Creator pkg.S3Creator) (cmd *cobra.Command) { } func (o *option) runE(cmd *cobra.Command, args []string) (err error) { - removeServer := pkg.NewRemoteServer(o.S3Creator) + removeServer := pkg.NewRemoteServer(o.s3Creator) var lis net.Listener lis, err = net.Listen("tcp", fmt.Sprintf(":%d", o.port)) @@ -50,5 +50,5 @@ type option struct { port int // inner fields - S3Creator pkg.S3Creator + s3Creator pkg.S3Creator } diff --git a/extensions/store-s3/pkg/s3_server.go b/extensions/store-s3/pkg/s3_server.go index aaa57d6..2cb133f 100644 --- a/extensions/store-s3/pkg/s3_server.go +++ b/extensions/store-s3/pkg/s3_server.go @@ -13,6 +13,7 @@ import ( "github.com/linuxsuren/api-testing/pkg/server" "github.com/linuxsuren/api-testing/pkg/testing" "github.com/linuxsuren/api-testing/pkg/testing/remote" + "github.com/linuxsuren/api-testing/pkg/util" "gopkg.in/yaml.v3" ) @@ -21,8 +22,8 @@ type s3Client struct { remote.UnimplementedLoaderServer } -func NewRemoteServer(S3Creator S3Creator) remote.LoaderServer { - return &s3Client{S3Creator: S3Creator} +func NewRemoteServer(s3Creator S3Creator) remote.LoaderServer { + return &s3Client{S3Creator: s3Creator} } func (s *s3Client) ListTestSuite(ctx context.Context, _ *server.Empty) (suites *remote.TestSuites, err error) { @@ -169,6 +170,14 @@ func (s *s3Client) DeleteTestCase(ctx context.Context, testcase *server.TestCase } return } +func (s *s3Client) Verify(ctx context.Context, in *server.Empty) (reply *server.CommonResult, err error) { + _, clientErr := s.ListTestSuite(ctx, in) + reply = &server.CommonResult{ + Success: err == nil, + Message: util.OKOrErrorMessage(clientErr), + } + return +} func (s *s3Client) getClient(ctx context.Context) (db *s3WithBucket, err error) { store := remote.GetStoreFromContext(ctx) if store == nil { @@ -180,18 +189,9 @@ func (s *s3Client) getClient(ctx context.Context) (db *s3WithBucket, err error) } options := mapToS3Options(store.Properties) - cred := credentials.NewStaticCredentials(options.AccessKeyID, options.SecretAccessKey, options.SessionToken) - - config := aws.Config{ - Region: aws.String(options.Region), - Endpoint: aws.String(store.URL), - DisableSSL: aws.Bool(options.DisableSSL), - S3ForcePathStyle: aws.Bool(options.ForcePathStyle), - Credentials: cred, - } var sess *session.Session - sess, err = session.NewSession(&config) + sess, err = createClientFromSs3Options(options, store.URL) if err == nil { svc := s.S3Creator.New(sess) // s3.New(sess) db = &s3WithBucket{S3API: svc, bucket: options.Bucket} @@ -200,6 +200,20 @@ func (s *s3Client) getClient(ctx context.Context) (db *s3WithBucket, err error) } return } +func createClientFromSs3Options(options s3Options, storeURL string) (sess *session.Session, err error) { + cred := credentials.NewStaticCredentials(options.AccessKeyID, options.SecretAccessKey, options.SessionToken) + + config := aws.Config{ + Region: aws.String(options.Region), + Endpoint: aws.String(storeURL), + DisableSSL: aws.Bool(options.DisableSSL), + S3ForcePathStyle: aws.Bool(options.ForcePathStyle), + Credentials: cred, + } + + sess, err = session.NewSession(&config) + return +} func mapToS3Options(data map[string]string) (opt s3Options) { opt.AccessKeyID = data["accesskeyid"] diff --git a/extensions/store-s3/pkg/s3_server_test.go b/extensions/store-s3/pkg/s3_server_test.go index ba97f68..d8215c3 100644 --- a/extensions/store-s3/pkg/s3_server_test.go +++ b/extensions/store-s3/pkg/s3_server_test.go @@ -31,6 +31,11 @@ func TestNewRemoteServer(t *testing.T) { t.Run("ListTestSuite", func(t *testing.T) { _, err := newRemoteServer(t).ListTestSuite(defaultCtx, nil) assert.NoError(t, err) + + var result *server.CommonResult + result, err = newRemoteServer(t).Verify(defaultCtx, &server.Empty{}) + assert.NoError(t, err) + assert.True(t, result.Success) }) t.Run("CreateTestSuite", func(t *testing.T) { diff --git a/pkg/server/remote_server.go b/pkg/server/remote_server.go index 0e829ab..7325c96 100644 --- a/pkg/server/remote_server.go +++ b/pkg/server/remote_server.go @@ -19,6 +19,7 @@ import ( "github.com/linuxsuren/api-testing/pkg/render" "github.com/linuxsuren/api-testing/pkg/runner" "github.com/linuxsuren/api-testing/pkg/testing" + "github.com/linuxsuren/api-testing/pkg/util" "github.com/linuxsuren/api-testing/pkg/version" "github.com/linuxsuren/api-testing/sample" "google.golang.org/grpc/metadata" @@ -110,19 +111,11 @@ func (s *server) getLoader(ctx context.Context) (loader testing.Writer) { storeNameMeta := mdd.Get(HeaderKeyStoreName) if len(storeNameMeta) > 0 { storeName := storeNameMeta[0] - if storeName == "local" { + if storeName == "local" || storeName == "" { return } - store, err := testing.NewStoreFactory(s.configDir).GetStore(storeName) - if err == nil && store != nil { - loader, err = s.storeWriterFactory.NewInstance(*store) - if err != nil { - fmt.Println("failed to new grpc loader from store", store.Name, err) - } - } else { - fmt.Println("failed to get store", storeName, err) - } + loader, _ = s.getLoaderByStoreName(storeName) } } return @@ -530,7 +523,7 @@ func (s *server) GetSuggestedAPIs(ctx context.Context, in *TestSuiteIdentity) (r return } - fmt.Println(in.Name, suite) + fmt.Println("Finding APIs from", in.Name, "with loader", reflect.TypeOf(loader)) var swaggerAPI *apispec.Swagger if swaggerAPI, err = apispec.ParseURLToSwagger(suite.Spec.URL); err == nil && swaggerAPI != nil { for api, item := range swaggerAPI.Paths { @@ -607,7 +600,16 @@ func (s *server) GetStores(ctx context.Context, in *Empty) (reply *Stores, err e Data: make([]*Store, 0), } for _, item := range stores { - reply.Data = append(reply.Data, ToGRPCStore(item)) + 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 + } + + reply.Data = append(reply.Data, grpcStore) } } return @@ -622,6 +624,27 @@ func (s *server) DeleteStore(ctx context.Context, in *Store) (reply *Store, err } func (s *server) VerifyStore(ctx context.Context, in *SimpleQuery) (reply *CommonResult, err error) { // TODO need to implement + reply = &CommonResult{} + var loader testing.Writer + if loader, err = s.getLoaderByStoreName(in.Name); err == nil && loader != nil { + verifyErr := loader.Verify() + reply.Success = verifyErr == nil + reply.Message = util.OKOrErrorMessage(verifyErr) + } + return +} + +func (s *server) getLoaderByStoreName(storeName string) (loader testing.Writer, err error) { + var store *testing.Store + store, err = testing.NewStoreFactory(s.configDir).GetStore(storeName) + if err == nil && store != nil { + loader, err = s.storeWriterFactory.NewInstance(*store) + if err != nil { + err = fmt.Errorf("failed to new grpc loader from store %s, err: %v", store.Name, err) + } + } else { + err = fmt.Errorf("failed to get store %s, err: %v", storeName, err) + } return } diff --git a/pkg/server/remote_server_test.go b/pkg/server/remote_server_test.go index 02c2b57..dc7951e 100644 --- a/pkg/server/remote_server_test.go +++ b/pkg/server/remote_server_test.go @@ -663,8 +663,8 @@ func TestStoreManager(t *testing.T) { defer clean() reply, err := server.VerifyStore(ctx, &SimpleQuery{}) - assert.NoError(t, err) - assert.Nil(t, reply) + assert.Error(t, err) + assert.NotNil(t, reply) }) } @@ -673,7 +673,19 @@ func getRemoteServerInTempDir() (server RunnerServer, call func()) { call = func() { os.RemoveAll(dir) } writer := atesting.NewFileWriter(dir) - server = NewRemoteServer(writer, nil, "") + server = NewRemoteServer(writer, newLocalloaderFromStore(), "") + return +} + +type fakeLocalLoaderFactory struct { +} + +func newLocalloaderFromStore() atesting.StoreWriterFactory { + return &fakeLocalLoaderFactory{} +} + +func (l *fakeLocalLoaderFactory) NewInstance(store atesting.Store) (writer atesting.Writer, err error) { + writer = atesting.NewFileWriter("") return } diff --git a/pkg/server/server.pb.go b/pkg/server/server.pb.go index 38853db..544af07 100644 --- a/pkg/server/server.pb.go +++ b/pkg/server/server.pb.go @@ -1252,6 +1252,7 @@ type Store struct { Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password,omitempty"` Properties []*Pair `protobuf:"bytes,6,rep,name=properties,proto3" json:"properties,omitempty"` Kind *StoreKind `protobuf:"bytes,7,opt,name=kind,proto3" json:"kind,omitempty"` + Ready bool `protobuf:"varint,8,opt,name=ready,proto3" json:"ready,omitempty"` } func (x *Store) Reset() { @@ -1335,6 +1336,13 @@ func (x *Store) GetKind() *StoreKind { return nil } +func (x *Store) GetReady() bool { + if x != nil { + return x.Ready + } + return false +} + type StoreKinds struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1814,7 +1822,7 @@ var file_pkg_server_server_proto_rawDesc = []byte{ 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2b, 0x0a, 0x06, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xdc, 0x01, 0x0a, + 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf2, 0x01, 0x0a, 0x05, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, @@ -1828,126 +1836,127 @@ var file_pkg_server_server_proto_rawDesc = []byte{ 0x76, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, - 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x33, 0x0a, 0x0a, 0x53, - 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x25, 0x0a, 0x04, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, - 0x22, 0x31, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x75, 0x72, 0x6c, 0x22, 0x42, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2e, 0x0a, 0x0a, 0x53, 0x69, 0x6d, 0x70, 0x6c, - 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x69, - 0x72, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x20, 0x0a, 0x0a, 0x53, 0x69, 0x6d, 0x70, 0x6c, - 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x6d, 0x0a, 0x13, 0x43, 0x6f, 0x64, - 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 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, 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, 0x00, 0x12, 0x2c, 0x0a, 0x09, 0x47, - 0x65, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x0f, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3e, 0x0a, - 0x0c, 0x47, 0x65, 0x74, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x19, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a, - 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, - 0x12, 0x11, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, - 0x69, 0x74, 0x65, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, - 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x0f, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, - 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x53, 0x75, 0x69, 0x74, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x10, 0x47, 0x65, 0x74, - 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x41, 0x50, 0x49, 0x73, 0x12, 0x19, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, - 0x0b, 0x52, 0x75, 0x6e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, 0x18, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, - 0x12, 0x3b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, - 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, - 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, - 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, - 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, - 0x65, 0x57, 0x69, 0x74, 0x68, 0x53, 0x75, 0x69, 0x74, 0x65, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, - 0x12, 0x41, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, - 0x73, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, - 0x43, 0x61, 0x73, 0x65, 0x57, 0x69, 0x74, 0x68, 0x53, 0x75, 0x69, 0x74, 0x65, 0x1a, 0x12, 0x2e, + 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x72, + 0x65, 0x61, 0x64, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x61, 0x64, + 0x79, 0x22, 0x33, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x12, + 0x25, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x31, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, + 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x42, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2e, 0x0a, + 0x0a, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x20, 0x0a, + 0x0a, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0x6d, 0x0a, 0x13, 0x43, 0x6f, 0x64, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, + 0x69, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x54, 0x65, 0x73, 0x74, 0x53, + 0x75, 0x69, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, + 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, + 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, + 0x00, 0x12, 0x2c, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x12, 0x0d, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0e, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x22, 0x00, 0x12, + 0x42, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, + 0x74, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, + 0x53, 0x75, 0x69, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x65, 0x73, + 0x79, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, + 0x69, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, + 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x11, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, + 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x65, 0x73, + 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x11, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, + 0x42, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, + 0x74, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, + 0x53, 0x75, 0x69, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x12, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x73, 0x74, 0x43, + 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, + 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0d, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x69, 0x74, 0x65, 0x22, 0x00, 0x12, + 0x42, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x41, + 0x50, 0x49, 0x73, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, + 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x11, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, + 0x73, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0b, 0x52, 0x75, 0x6e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, + 0x73, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, + 0x43, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, - 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x64, - 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x12, - 0x43, 0x0a, 0x0c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, - 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x47, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x22, 0x00, 0x12, 0x30, 0x0a, 0x0e, 0x50, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x72, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, - 0x61, 0x69, 0x72, 0x73, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0d, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x22, 0x00, 0x12, 0x40, - 0x0a, 0x14, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x13, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, - 0x12, 0x31, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0d, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x06, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x0d, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x00, 0x12, 0x34, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, - 0x6e, 0x64, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, - 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x22, 0x00, 0x12, 0x2c, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, - 0x74, 0x6f, 0x72, 0x65, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0e, 0x2e, 0x73, 0x65, 0x72, 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, 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, + 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x65, 0x73, + 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, + 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x57, 0x69, 0x74, 0x68, 0x53, 0x75, 0x69, 0x74, 0x65, + 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x57, 0x69, 0x74, 0x68, 0x53, 0x75, + 0x69, 0x74, 0x65, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, + 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, + 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x11, 0x4c, + 0x69, 0x73, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4c, + 0x69, 0x73, 0x74, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0c, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, + 0x6f, 0x64, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x30, 0x0a, 0x0e, 0x50, 0x6f, + 0x70, 0x75, 0x6c, 0x61, 0x72, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x0d, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x0e, + 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x13, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x69, + 0x72, 0x73, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x14, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x13, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x73, + 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x31, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, + 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x06, 0x53, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x6c, 0x6c, + 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x34, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x53, + 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x73, 0x22, 0x00, 0x12, 0x2c, + 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0e, 0x2e, 0x73, 0x65, 0x72, + 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, 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 ( diff --git a/pkg/server/server.proto b/pkg/server/server.proto index 4bd8ecf..3c6c9e2 100644 --- a/pkg/server/server.proto +++ b/pkg/server/server.proto @@ -165,6 +165,7 @@ message Store { string password = 5; repeated Pair properties = 6; StoreKind kind = 7; + bool ready = 8; } message StoreKinds { diff --git a/pkg/testing/loader.go b/pkg/testing/loader.go index 87af233..65b6bd1 100644 --- a/pkg/testing/loader.go +++ b/pkg/testing/loader.go @@ -25,4 +25,6 @@ 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.go b/pkg/testing/loader_file.go index a1a27c2..12bf149 100644 --- a/pkg/testing/loader_file.go +++ b/pkg/testing/loader_file.go @@ -304,3 +304,8 @@ func (l *fileLoader) DeleteTestCase(suiteName, testcase string) (err error) { } return } + +func (l *fileLoader) Verify() (err error) { + // always be okay + return +} diff --git a/pkg/testing/remote/grpc.go b/pkg/testing/remote/grpc.go index 6c87725..b036b12 100644 --- a/pkg/testing/remote/grpc.go +++ b/pkg/testing/remote/grpc.go @@ -2,6 +2,7 @@ package remote import ( context "context" + "errors" server "github.com/linuxsuren/api-testing/pkg/server" "github.com/linuxsuren/api-testing/pkg/testing" @@ -170,3 +171,13 @@ func (g *gRPCLoader) DeleteSuite(name string) (err error) { }) return } + +func (g *gRPCLoader) Verify() (err error) { + var result *server.CommonResult + if result, err = g.client.Verify(g.ctx, &server.Empty{}); err == nil { + if !result.Success { + err = errors.New(result.Message) + } + } + return +} diff --git a/pkg/testing/remote/loader.pb.go b/pkg/testing/remote/loader.pb.go index 0c2e36e..81cca70 100644 --- a/pkg/testing/remote/loader.pb.go +++ b/pkg/testing/remote/loader.pb.go @@ -177,7 +177,7 @@ var file_pkg_testing_remote_loader_proto_rawDesc = []byte{ 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x75, 0x6c, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x66, 0x75, 0x6c, 0x6c, - 0x32, 0xaf, 0x04, 0x0a, 0x06, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x0d, 0x4c, + 0x32, 0xe0, 0x04, 0x0a, 0x06, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x12, 0x34, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x22, @@ -212,11 +212,14 @@ var file_pkg_testing_remote_loader_proto_rawDesc = []byte{ 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, 0x10, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x1a, 0x0d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x22, 0x00, 0x42, 0x36, 0x5a, 0x34, 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, 0x74, 0x65, 0x73, 0x74, - 0x69, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x06, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x12, 0x0d, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 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, 0x36, 0x5a, 0x34, 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, 0x74, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -233,13 +236,14 @@ func file_pkg_testing_remote_loader_proto_rawDescGZIP() []byte { var file_pkg_testing_remote_loader_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_pkg_testing_remote_loader_proto_goTypes = []interface{}{ - (*TestSuites)(nil), // 0: remote.TestSuites - (*TestSuite)(nil), // 1: remote.TestSuite - (*server.Pair)(nil), // 2: server.Pair - (*server.APISpec)(nil), // 3: server.APISpec - (*server.TestCase)(nil), // 4: server.TestCase - (*server.Empty)(nil), // 5: server.Empty - (*server.TestCases)(nil), // 6: server.TestCases + (*TestSuites)(nil), // 0: remote.TestSuites + (*TestSuite)(nil), // 1: remote.TestSuite + (*server.Pair)(nil), // 2: server.Pair + (*server.APISpec)(nil), // 3: server.APISpec + (*server.TestCase)(nil), // 4: server.TestCase + (*server.Empty)(nil), // 5: server.Empty + (*server.TestCases)(nil), // 6: server.TestCases + (*server.CommonResult)(nil), // 7: server.CommonResult } var file_pkg_testing_remote_loader_proto_depIdxs = []int32{ 1, // 0: remote.TestSuites.data:type_name -> remote.TestSuite @@ -256,18 +260,20 @@ var file_pkg_testing_remote_loader_proto_depIdxs = []int32{ 4, // 11: remote.Loader.GetTestCase:input_type -> server.TestCase 4, // 12: remote.Loader.UpdateTestCase:input_type -> server.TestCase 4, // 13: remote.Loader.DeleteTestCase:input_type -> server.TestCase - 0, // 14: remote.Loader.ListTestSuite:output_type -> remote.TestSuites - 5, // 15: remote.Loader.CreateTestSuite:output_type -> server.Empty - 1, // 16: remote.Loader.GetTestSuite:output_type -> remote.TestSuite - 1, // 17: remote.Loader.UpdateTestSuite:output_type -> remote.TestSuite - 5, // 18: remote.Loader.DeleteTestSuite:output_type -> server.Empty - 6, // 19: remote.Loader.ListTestCases:output_type -> server.TestCases - 5, // 20: remote.Loader.CreateTestCase:output_type -> server.Empty - 4, // 21: remote.Loader.GetTestCase:output_type -> server.TestCase - 4, // 22: remote.Loader.UpdateTestCase:output_type -> server.TestCase - 5, // 23: remote.Loader.DeleteTestCase:output_type -> server.Empty - 14, // [14:24] is the sub-list for method output_type - 4, // [4:14] is the sub-list for method input_type + 5, // 14: remote.Loader.Verify:input_type -> server.Empty + 0, // 15: remote.Loader.ListTestSuite:output_type -> remote.TestSuites + 5, // 16: remote.Loader.CreateTestSuite:output_type -> server.Empty + 1, // 17: remote.Loader.GetTestSuite:output_type -> remote.TestSuite + 1, // 18: remote.Loader.UpdateTestSuite:output_type -> remote.TestSuite + 5, // 19: remote.Loader.DeleteTestSuite:output_type -> server.Empty + 6, // 20: remote.Loader.ListTestCases:output_type -> server.TestCases + 5, // 21: remote.Loader.CreateTestCase:output_type -> server.Empty + 4, // 22: remote.Loader.GetTestCase:output_type -> server.TestCase + 4, // 23: remote.Loader.UpdateTestCase:output_type -> server.TestCase + 5, // 24: remote.Loader.DeleteTestCase:output_type -> server.Empty + 7, // 25: remote.Loader.Verify:output_type -> server.CommonResult + 15, // [15:26] is the sub-list for method output_type + 4, // [4:15] is the sub-list for method input_type 4, // [4:4] is the sub-list for extension type_name 4, // [4:4] is the sub-list for extension extendee 0, // [0:4] is the sub-list for field type_name diff --git a/pkg/testing/remote/loader.proto b/pkg/testing/remote/loader.proto index d07e08d..6844630 100644 --- a/pkg/testing/remote/loader.proto +++ b/pkg/testing/remote/loader.proto @@ -18,6 +18,8 @@ service Loader { rpc GetTestCase(server.TestCase) returns (server.TestCase) {} rpc UpdateTestCase(server.TestCase) returns (server.TestCase) {} rpc DeleteTestCase(server.TestCase) returns (server.Empty) {} + + rpc Verify(server.Empty) returns (server.CommonResult) {} } message TestSuites { diff --git a/pkg/testing/remote/loader_grpc.pb.go b/pkg/testing/remote/loader_grpc.pb.go index 3b8b1f4..372c17f 100644 --- a/pkg/testing/remote/loader_grpc.pb.go +++ b/pkg/testing/remote/loader_grpc.pb.go @@ -33,6 +33,7 @@ type LoaderClient interface { GetTestCase(ctx context.Context, in *server.TestCase, opts ...grpc.CallOption) (*server.TestCase, error) UpdateTestCase(ctx context.Context, in *server.TestCase, opts ...grpc.CallOption) (*server.TestCase, error) DeleteTestCase(ctx context.Context, in *server.TestCase, opts ...grpc.CallOption) (*server.Empty, error) + Verify(ctx context.Context, in *server.Empty, opts ...grpc.CallOption) (*server.CommonResult, error) } type loaderClient struct { @@ -133,6 +134,15 @@ func (c *loaderClient) DeleteTestCase(ctx context.Context, in *server.TestCase, return out, nil } +func (c *loaderClient) Verify(ctx context.Context, in *server.Empty, opts ...grpc.CallOption) (*server.CommonResult, error) { + out := new(server.CommonResult) + err := c.cc.Invoke(ctx, "/remote.Loader/Verify", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // LoaderServer is the server API for Loader service. // All implementations must embed UnimplementedLoaderServer // for forward compatibility @@ -147,6 +157,7 @@ type LoaderServer interface { GetTestCase(context.Context, *server.TestCase) (*server.TestCase, error) UpdateTestCase(context.Context, *server.TestCase) (*server.TestCase, error) DeleteTestCase(context.Context, *server.TestCase) (*server.Empty, error) + Verify(context.Context, *server.Empty) (*server.CommonResult, error) mustEmbedUnimplementedLoaderServer() } @@ -184,6 +195,9 @@ func (UnimplementedLoaderServer) UpdateTestCase(context.Context, *server.TestCas func (UnimplementedLoaderServer) DeleteTestCase(context.Context, *server.TestCase) (*server.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteTestCase not implemented") } +func (UnimplementedLoaderServer) Verify(context.Context, *server.Empty) (*server.CommonResult, error) { + return nil, status.Errorf(codes.Unimplemented, "method Verify not implemented") +} func (UnimplementedLoaderServer) mustEmbedUnimplementedLoaderServer() {} // UnsafeLoaderServer may be embedded to opt out of forward compatibility for this service. @@ -377,6 +391,24 @@ func _Loader_DeleteTestCase_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Loader_Verify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(server.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LoaderServer).Verify(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/remote.Loader/Verify", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LoaderServer).Verify(ctx, req.(*server.Empty)) + } + return interceptor(ctx, in, info, handler) +} + // Loader_ServiceDesc is the grpc.ServiceDesc for Loader service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -424,6 +456,10 @@ var Loader_ServiceDesc = grpc.ServiceDesc{ MethodName: "DeleteTestCase", Handler: _Loader_DeleteTestCase_Handler, }, + { + MethodName: "Verify", + Handler: _Loader_Verify_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "pkg/testing/remote/loader.proto", diff --git a/pkg/testing/store.go b/pkg/testing/store.go index f6e254b..938b943 100644 --- a/pkg/testing/store.go +++ b/pkg/testing/store.go @@ -58,6 +58,10 @@ 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"], diff --git a/pkg/testing/store_test.go b/pkg/testing/store_test.go index b9faf44..7e8599e 100644 --- a/pkg/testing/store_test.go +++ b/pkg/testing/store_test.go @@ -70,6 +70,7 @@ func TestStoreFactory(t *testing.T) { "database": "test", }, }, store) + assert.False(t, store.IsLocal()) }) t.Run("GetAllStores", func(t *testing.T) { @@ -97,6 +98,11 @@ func TestStoreFactory(t *testing.T) { Name: "local", }}, stores) }) + + t.Run("local store", func(t *testing.T) { + store := Store{Name: "local"} + assert.True(t, store.IsLocal()) + }) } var sampleStoreMap = map[string]string{ diff --git a/pkg/util/error.go b/pkg/util/error.go new file mode 100644 index 0000000..6402ede --- /dev/null +++ b/pkg/util/error.go @@ -0,0 +1,33 @@ +/** +MIT License + +Copyright (c) 2023 API Testing Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +package util + +// OKOrErrorMessage returns OK or error message +func OKOrErrorMessage(err error) string { + if err != nil { + return err.Error() + } + return "OK" +} diff --git a/pkg/util/error_test.go b/pkg/util/error_test.go new file mode 100644 index 0000000..74e8795 --- /dev/null +++ b/pkg/util/error_test.go @@ -0,0 +1,38 @@ +/** +MIT License + +Copyright (c) 2023 API Testing Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +package util_test + +import ( + "errors" + "testing" + + "github.com/linuxsuren/api-testing/pkg/util" + "github.com/stretchr/testify/assert" +) + +func TestOkOrErrorMessage(t *testing.T) { + assert.Equal(t, "OK", util.OKOrErrorMessage(nil)) + assert.Equal(t, "test", util.OKOrErrorMessage(errors.New("test"))) +}