diff --git a/Dockerfile b/Dockerfile index b84ffe6..1b4713d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -58,4 +58,8 @@ RUN mkdir -p /var/www/data COPY --from=builder /workspace/sample /var/www/sample COPY --from=ui /workspace/dist /var/www/html +RUN apt update -y && \ + # required for atest-store-git + apt install -y --no-install-recommends ssh-client ca-certificates + CMD ["atest", "server", "--console-path=/var/www/html", "--local-storage=/var/www/sample/*.yaml", "--local-storage=/var/www/data/*.yaml"] diff --git a/cmd/service.go b/cmd/service.go index f22c5b3..6f70da1 100644 --- a/cmd/service.go +++ b/cmd/service.go @@ -400,6 +400,7 @@ func (s *containerService) getStartArgs() []string { "--pull=always", "--network=host", "-v", s.localStorage + ":/var/www/data", + "-v", "/root/.config/atest:/root/.config/atest", s.image + ":" + s.tag} } diff --git a/extensions/store-git/pkg/server.go b/extensions/store-git/pkg/server.go index 540bf12..fe52ae4 100644 --- a/extensions/store-git/pkg/server.go +++ b/extensions/store-git/pkg/server.go @@ -28,6 +28,7 @@ import ( "context" "errors" "fmt" + "io" "os" "path" "time" @@ -43,11 +44,13 @@ import ( ) type gitClient struct { + writer io.Writer remote.UnimplementedLoaderServer } +// NewRemoteServer returns a new remote server func NewRemoteServer() remote.LoaderServer { - return &gitClient{} + return &gitClient{writer: os.Stdout} } func (s *gitClient) loadCache(ctx context.Context) (opt *gitOptions, err error) { if opt, err = s.getClient(ctx); err != nil { @@ -105,38 +108,33 @@ func (s *gitClient) pushCache(ctx context.Context) (err error) { var wd *git.Worktree if wd, err = repo.Worktree(); err == nil { - _, err = wd.Add(".") + if _, err = wd.Add("."); err != nil { + return + } if _, err = wd.Commit(`auto commit by api-testing See also https://github.com/LinuxSuRen/api-testing `, &git.CommitOptions{ Author: &object.Signature{ - Name: "LinuxSuRen", - Email: "LinuxSuRen@users.noreply.github.com", + Name: opt.name, + Email: opt.email, When: time.Now(), }, - }); err != nil { - return + }); err == nil { + err = repo.Push(opt.pushOptions) } - - err = repo.Push(opt.pushOptions) } } return } func (s *gitClient) ListTestSuite(ctx context.Context, _ *server.Empty) (reply *remote.TestSuites, err error) { reply = &remote.TestSuites{} - - var opt *gitOptions - if opt, err = s.loadCache(ctx); err != nil { + var loader testing.Writer + if loader, err = s.newLoader(ctx); err != nil { return } - parentDir := path.Join(opt.cache, opt.targetPath) - loader := testing.NewFileWriter(parentDir) - loader.Put(parentDir + "/*.yaml") - var suites []testing.TestSuite if suites, err = loader.ListTestSuite(); err == nil { for _, item := range suites { @@ -147,18 +145,11 @@ func (s *gitClient) ListTestSuite(ctx context.Context, _ *server.Empty) (reply * } func (s *gitClient) CreateTestSuite(ctx context.Context, testSuite *remote.TestSuite) (reply *server.Empty, err error) { reply = &server.Empty{} - - var opt *gitOptions - if opt, err = s.loadCache(ctx); err != nil { + var loader testing.Writer + if loader, err = s.newLoader(ctx); err != nil { return } - parentDir := path.Join(opt.cache, opt.targetPath) - if err = os.MkdirAll(parentDir, 0755); err != nil { - return - } - loader := testing.NewFileWriter(parentDir) - if err = loader.CreateSuite(testSuite.Name, testSuite.Api); err == nil { s.pushCache(ctx) } @@ -166,16 +157,11 @@ func (s *gitClient) CreateTestSuite(ctx context.Context, testSuite *remote.TestS } func (s *gitClient) GetTestSuite(ctx context.Context, suite *remote.TestSuite) (reply *remote.TestSuite, err error) { reply = &remote.TestSuite{} - - var opt *gitOptions - if opt, err = s.loadCache(ctx); err != nil { + var loader testing.Writer + if loader, err = s.newLoader(ctx); err != nil { return } - parentDir := path.Join(opt.cache, opt.targetPath) - loader := testing.NewFileWriter(parentDir) - loader.Put(parentDir + "/*.yaml") - var normalSuite testing.TestSuite if normalSuite, err = loader.GetTestSuite(suite.Name, true); err == nil { reply = remote.ConvertToGRPCTestSuite(&normalSuite) @@ -184,16 +170,11 @@ func (s *gitClient) GetTestSuite(ctx context.Context, suite *remote.TestSuite) ( } func (s *gitClient) UpdateTestSuite(ctx context.Context, suite *remote.TestSuite) (reply *remote.TestSuite, err error) { reply = &remote.TestSuite{} - - var opt *gitOptions - if opt, err = s.loadCache(ctx); err != nil { + var loader testing.Writer + if loader, err = s.newLoader(ctx); err != nil { return } - parentDir := path.Join(opt.cache, opt.targetPath) - loader := testing.NewFileWriter(parentDir) - loader.Put(parentDir + "/*.yaml") - if err = loader.UpdateSuite(*remote.ConvertToNormalTestSuite(suite)); err == nil { err = s.pushCache(ctx) } @@ -201,16 +182,11 @@ func (s *gitClient) UpdateTestSuite(ctx context.Context, suite *remote.TestSuite } func (s *gitClient) DeleteTestSuite(ctx context.Context, suite *remote.TestSuite) (reply *server.Empty, err error) { reply = &server.Empty{} - - var opt *gitOptions - if opt, err = s.loadCache(ctx); err != nil { + var loader testing.Writer + if loader, err = s.newLoader(ctx); err != nil { return } - parentDir := path.Join(opt.cache, opt.targetPath) - loader := testing.NewFileWriter(parentDir) - loader.Put(parentDir + "/*.yaml") - if err = loader.DeleteSuite(suite.Name); err == nil { err = s.pushCache(ctx) } @@ -226,16 +202,11 @@ func (s *gitClient) ListTestCases(ctx context.Context, suite *remote.TestSuite) } func (s *gitClient) CreateTestCase(ctx context.Context, testcase *server.TestCase) (reply *server.Empty, err error) { reply = &server.Empty{} - - var opt *gitOptions - if opt, err = s.loadCache(ctx); err != nil { + var loader testing.Writer + if loader, err = s.newLoader(ctx); err != nil { return } - parentDir := path.Join(opt.cache, opt.targetPath) - loader := testing.NewFileWriter(parentDir) - loader.Put(parentDir + "/*.yaml") - if err = loader.CreateTestCase(testcase.SuiteName, remote.ConvertToNormalTestCase(testcase)); err == nil { err = s.pushCache(ctx) } @@ -257,16 +228,11 @@ func (s *gitClient) GetTestCase(ctx context.Context, testcase *server.TestCase) } func (s *gitClient) UpdateTestCase(ctx context.Context, testcase *server.TestCase) (reply *server.TestCase, err error) { reply = &server.TestCase{} - - var opt *gitOptions - if opt, err = s.loadCache(ctx); err != nil { + var loader testing.Writer + if loader, err = s.newLoader(ctx); err != nil { return } - parentDir := path.Join(opt.cache, opt.targetPath) - loader := testing.NewFileWriter(parentDir) - loader.Put(parentDir + "/*.yaml") - if err = loader.UpdateTestCase(testcase.SuiteName, remote.ConvertToNormalTestCase(testcase)); err == nil { err = s.pushCache(ctx) } @@ -274,16 +240,11 @@ func (s *gitClient) UpdateTestCase(ctx context.Context, testcase *server.TestCas } func (s *gitClient) DeleteTestCase(ctx context.Context, testcase *server.TestCase) (reply *server.Empty, err error) { reply = &server.Empty{} - - var opt *gitOptions - if opt, err = s.loadCache(ctx); err != nil { + var loader testing.Writer + if loader, err = s.newLoader(ctx); err != nil { return } - parentDir := path.Join(opt.cache, opt.targetPath) - loader := testing.NewFileWriter(parentDir) - loader.Put(parentDir + "/*.yaml") - if err = loader.DeleteTestCase(testcase.SuiteName, testcase.Name); err == nil { err = s.pushCache(ctx) } @@ -292,7 +253,7 @@ func (s *gitClient) DeleteTestCase(ctx context.Context, testcase *server.TestCas func (s *gitClient) Verify(ctx context.Context, in *server.Empty) (reply *server.CommonResult, err error) { _, clientErr := s.ListTestSuite(ctx, in) reply = &server.CommonResult{ - Success: err == nil, + Success: clientErr == nil, Message: util.OKOrErrorMessage(clientErr), } return @@ -302,44 +263,69 @@ func (s *gitClient) getClient(ctx context.Context) (opt *gitOptions, err error) if store == nil { err = errors.New("no connect to git server") } else { - var ok bool - if opt, ok = clientCache[store.Name]; ok && opt != nil { - return - } - auth := &http.BasicAuth{ Username: store.Username, Password: store.Password, } + insecure := store.Properties["insecure"] == "true" + opt = &gitOptions{ - cache: "/tmp/" + store.Name, + cache: path.Join(os.TempDir(), store.Name), targetPath: store.Properties["targetpath"], + name: store.Properties["name"], + email: store.Properties["email"], cloneOptions: &git.CloneOptions{ - URL: store.URL, - Progress: os.Stdout, - Auth: auth, + URL: store.URL, + Progress: s.writer, + InsecureSkipTLS: insecure, + Auth: auth, }, pushOptions: &git.PushOptions{ - Progress: os.Stdout, - Auth: auth, + Progress: s.writer, + InsecureSkipTLS: insecure, + Auth: auth, }, fetchOptions: &git.FetchOptions{ - Progress: os.Stdout, - Auth: auth, + Progress: s.writer, + InsecureSkipTLS: insecure, + Auth: auth, }, } - clientCache[store.Name] = opt + + if opt.name == "" { + opt.name = "LinuxSuRen" + } + if opt.email == "" { + opt.email = "LinuxSuRen@users.noreply.github.com" + } } return } -var clientCache = map[string]*gitOptions{} +func (s *gitClient) newLoader(ctx context.Context) (loader testing.Writer, err error) { + var opt *gitOptions + if opt, err = s.loadCache(ctx); err == nil { + loader, err = opt.newLoader() + } + return +} type gitOptions struct { cache string targetPath string + name string + email string cloneOptions *git.CloneOptions pushOptions *git.PushOptions fetchOptions *git.FetchOptions } + +func (g *gitOptions) newLoader() (loader testing.Writer, err error) { + parentDir := path.Join(g.cache, g.targetPath) + if err = os.MkdirAll(parentDir, 0755); err == nil { + loader = testing.NewFileWriter(parentDir) + loader.Put(parentDir + "/*.yaml") + } + return +} diff --git a/extensions/store-git/pkg/server_test.go b/extensions/store-git/pkg/server_test.go new file mode 100644 index 0000000..39113de --- /dev/null +++ b/extensions/store-git/pkg/server_test.go @@ -0,0 +1,116 @@ +/** +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" + atest "github.com/linuxsuren/api-testing/pkg/testing" + "github.com/linuxsuren/api-testing/pkg/testing/remote" + "github.com/stretchr/testify/assert" +) + +func TestGetClient(t *testing.T) { + ctx := remote.WithIncomingStoreContext(context.Background(), &atest.Store{}) + defaultGitClient := &gitClient{} + t.Run("no context", func(t *testing.T) { + opt, err := defaultGitClient.getClient(context.TODO()) + assert.Nil(t, opt) + assert.Error(t, err) + + _, err = defaultGitClient.loadCache(context.TODO()) + assert.Error(t, err) + + err = defaultGitClient.pushCache(context.TODO()) + assert.Error(t, err) + }) + + t.Run("normal", func(t *testing.T) { + opt, err := defaultGitClient.getClient(ctx) + assert.NoError(t, err) + assert.NotNil(t, opt) + assert.False(t, opt.cloneOptions.InsecureSkipTLS) + }) + + t.Run("verify", func(t *testing.T) { + gitClient := NewRemoteServer() + + result, err := gitClient.Verify(ctx, &server.Empty{}) + assert.NoError(t, err) + assert.False(t, result.Success) + }) + + t.Run("ListTestSuite", func(t *testing.T) { + _, err := defaultGitClient.ListTestSuite(ctx, &server.Empty{}) + assert.Error(t, err) + }) + + t.Run("CreateTestSuite", func(t *testing.T) { + _, err := defaultGitClient.CreateTestSuite(ctx, &remote.TestSuite{}) + assert.Error(t, err) + }) + + t.Run("GetTestSuite", func(t *testing.T) { + _, err := defaultGitClient.GetTestSuite(ctx, &remote.TestSuite{}) + assert.Error(t, err) + }) + + t.Run("UpdateTestSuite", func(t *testing.T) { + _, err := defaultGitClient.UpdateTestSuite(ctx, &remote.TestSuite{}) + assert.Error(t, err) + }) + + t.Run("DeleteTestSuite", func(t *testing.T) { + _, err := defaultGitClient.DeleteTestSuite(ctx, &remote.TestSuite{}) + assert.Error(t, err) + }) + + t.Run("ListTestCases", func(t *testing.T) { + _, err := defaultGitClient.ListTestCases(ctx, &remote.TestSuite{}) + assert.Error(t, err) + }) + + t.Run("CreateTestCase", func(t *testing.T) { + _, err := defaultGitClient.CreateTestCase(ctx, &server.TestCase{}) + assert.Error(t, err) + }) + + t.Run("GetTestCase", func(t *testing.T) { + _, err := defaultGitClient.GetTestCase(ctx, &server.TestCase{}) + assert.Error(t, err) + }) + + t.Run("UpdateTestCase", func(t *testing.T) { + _, err := defaultGitClient.UpdateTestCase(ctx, &server.TestCase{}) + assert.Error(t, err) + }) + + t.Run("DeleteTestCase", func(t *testing.T) { + _, err := defaultGitClient.DeleteTestCase(ctx, &server.TestCase{}) + assert.Error(t, err) + }) +}