This is an automated email from the ASF dual-hosted git repository.

bzp2010 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git


The following commit(s) were added to refs/heads/master by this push:
     new edeed6b  feat: storage grafana path in to etcd (#2362)
edeed6b is described below

commit edeed6ba5097f8d715dbc2c400c051bdb7de1dea
Author: LetsGO <[email protected]>
AuthorDate: Thu Mar 17 14:12:10 2022 +0800

    feat: storage grafana path in to etcd (#2362)
---
 api/go.mod                                         |   1 -
 api/go.sum                                         |   3 -
 api/internal/core/entity/entity.go                 |   9 +
 api/internal/core/store/storehub.go                |  13 ++
 .../handler/system_config/system_config.go         | 132 +++++++++++
 .../handler/system_config/system_config_test.go    | 258 +++++++++++++++++++++
 api/internal/route.go                              |   4 +-
 api/test/e2enew/go.mod                             |  32 ---
 api/test/e2enew/go.sum                             |   2 -
 .../system_config/system_config_suite_test.go      |  28 +++
 .../e2enew/system_config/system_config_test.go     | 126 ++++++++++
 11 files changed, 569 insertions(+), 39 deletions(-)

diff --git a/api/go.mod b/api/go.mod
index 257f9b7..691ecfc 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -15,7 +15,6 @@ require (
        github.com/evanphx/json-patch/v5 v5.1.0
        github.com/getkin/kin-openapi v0.33.0
        github.com/gin-contrib/gzip v0.0.3
-       github.com/gin-contrib/pprof v1.3.0
        github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e
        github.com/gin-gonic/gin v1.6.3
        github.com/golang-jwt/jwt v3.2.2+incompatible
diff --git a/api/go.sum b/api/go.sum
index a3be366..19d50c6 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -120,14 +120,11 @@ github.com/ghodss/yaml v1.0.0 
h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gin-contrib/gzip v0.0.3 
h1:etUaeesHhEORpZMp18zoOhepboiWnFtXrBZxszWUn4k=
 github.com/gin-contrib/gzip v0.0.3/go.mod 
h1:YxxswVZIqOvcHEQpsSn+QF5guQtO1dCfy0shBPy4jFc=
-github.com/gin-contrib/pprof v1.3.0 
h1:G9eK6HnbkSqDZBYbzG4wrjCsA4e+cvYAHUZw6W+W9K0=
-github.com/gin-contrib/pprof v1.3.0/go.mod 
h1:waMjT1H9b179t3CxuG1cV3DHpga6ybizwfBaM5OXaB0=
 github.com/gin-contrib/sse v0.1.0 
h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
 github.com/gin-contrib/sse v0.1.0/go.mod 
h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e 
h1:8bZpGwoPxkaivQPrAbWl+7zjjUcbFUnYp7yQcx2r2N0=
 github.com/gin-contrib/static v0.0.0-20200916080430-d45d9a37d28e/go.mod 
h1:VhW/Ch/3FhimwZb8Oj+qJmdMmoB8r7lmJ5auRjm50oQ=
 github.com/gin-gonic/gin v1.5.0/go.mod 
h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
-github.com/gin-gonic/gin v1.6.2/go.mod 
h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
 github.com/gin-gonic/gin v1.6.3/go.mod 
h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod 
h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
diff --git a/api/internal/core/entity/entity.go 
b/api/internal/core/entity/entity.go
index f7d4857..4161696 100644
--- a/api/internal/core/entity/entity.go
+++ b/api/internal/core/entity/entity.go
@@ -304,3 +304,12 @@ type StreamRoute struct {
        UpstreamID interface{}            `json:"upstream_id,omitempty"`
        Plugins    map[string]interface{} `json:"plugins,omitempty"`
 }
+
+// swagger:model SystemConfig
+type SystemConfig struct {
+       ConfigName string                 `json:"config_name"`
+       Desc       string                 `json:"desc,omitempty"`
+       Payload    map[string]interface{} `json:"payload,omitempty"`
+       CreateTime int64                  `json:"create_time,omitempty"`
+       UpdateTime int64                  `json:"update_time,omitempty"`
+}
diff --git a/api/internal/core/store/storehub.go 
b/api/internal/core/store/storehub.go
index 1184a3f..76d15fe 100644
--- a/api/internal/core/store/storehub.go
+++ b/api/internal/core/store/storehub.go
@@ -40,6 +40,7 @@ const (
        HubKeyPluginConfig HubKey = "plugin_config"
        HubKeyProto        HubKey = "proto"
        HubKeyStreamRoute  HubKey = "stream_route"
+       HubKeySystemConfig HubKey = "system_config"
 )
 
 var (
@@ -229,5 +230,17 @@ func InitStores() error {
                return err
        }
 
+       err = InitStore(HubKeySystemConfig, GenericStoreOption{
+               BasePath: conf.ETCDConfig.Prefix + "/system_config",
+               ObjType:  reflect.TypeOf(entity.SystemConfig{}),
+               KeyFunc: func(obj interface{}) string {
+                       r := obj.(*entity.SystemConfig)
+                       return r.ConfigName
+               },
+       })
+       if err != nil {
+               return err
+       }
+
        return nil
 }
diff --git a/api/internal/handler/system_config/system_config.go 
b/api/internal/handler/system_config/system_config.go
new file mode 100644
index 0000000..b74acb3
--- /dev/null
+++ b/api/internal/handler/system_config/system_config.go
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package system_config
+
+import (
+       "errors"
+       "reflect"
+       "time"
+
+       "github.com/gin-gonic/gin"
+       "github.com/shiningrush/droplet"
+       "github.com/shiningrush/droplet/wrapper"
+       wgin "github.com/shiningrush/droplet/wrapper/gin"
+
+       "github.com/apisix/manager-api/internal/core/entity"
+       "github.com/apisix/manager-api/internal/core/store"
+       "github.com/apisix/manager-api/internal/handler"
+)
+
+type Handler struct {
+       systemConfig store.Interface
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+       return &Handler{
+               systemConfig: store.GetStore(store.HubKeySystemConfig),
+       }, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+       r.GET("/apisix/admin/system_config/:config_name", wgin.Wraps(h.Get,
+               wrapper.InputType(reflect.TypeOf(GetInput{}))))
+       r.POST("/apisix/admin/system_config", wgin.Wraps(h.Post,
+               wrapper.InputType(reflect.TypeOf(entity.SystemConfig{}))))
+       r.PUT("/apisix/admin/system_config", wgin.Wraps(h.Put,
+               wrapper.InputType(reflect.TypeOf(entity.SystemConfig{}))))
+       r.DELETE("/apisix/admin/system_config/:config_name", 
wgin.Wraps(h.Delete,
+               wrapper.InputType(reflect.TypeOf(DeleteInput{}))))
+}
+
+type GetInput struct {
+       ConfigName string `auto_read:"config_name,path" validate:"required"`
+}
+
+func (h *Handler) Get(c droplet.Context) (interface{}, error) {
+       input := c.Input().(*GetInput)
+       r, err := h.systemConfig.Get(c.Context(), input.ConfigName)
+
+       if err != nil {
+               return handler.SpecCodeResponse(err), err
+       }
+
+       return r, nil
+}
+
+func (h *Handler) Post(c droplet.Context) (interface{}, error) {
+       input := c.Input().(*entity.SystemConfig)
+       input.CreateTime = time.Now().Unix()
+       input.UpdateTime = time.Now().Unix()
+
+       // TODO use json schema to do it
+       if err := h.checkSystemConfig(input); err != nil {
+               return handler.SpecCodeResponse(err), err
+       }
+
+       // create
+       res, err := h.systemConfig.Create(c.Context(), input)
+       if err != nil {
+               return handler.SpecCodeResponse(err), err
+       }
+
+       return res, nil
+}
+
+func (h *Handler) Put(c droplet.Context) (interface{}, error) {
+       input := c.Input().(*entity.SystemConfig)
+       input.UpdateTime = time.Now().Unix()
+
+       // TODO use json schema to do it
+       if err := h.checkSystemConfig(input); err != nil {
+               return handler.SpecCodeResponse(err), err
+       }
+
+       // update
+       res, err := h.systemConfig.Update(c.Context(), input, false)
+       if err != nil {
+               return handler.SpecCodeResponse(err), err
+       }
+
+       return res, nil
+}
+
+type DeleteInput struct {
+       ConfigName string `auto_read:"config_name,path" validate:"required"`
+}
+
+func (h *Handler) Delete(c droplet.Context) (interface{}, error) {
+       input := c.Input().(*DeleteInput)
+       err := h.systemConfig.BatchDelete(c.Context(), 
[]string{input.ConfigName})
+
+       if err != nil {
+               return handler.SpecCodeResponse(err), err
+       }
+
+       return nil, nil
+}
+
+func (h *Handler) checkSystemConfig(input *entity.SystemConfig) error {
+       if len(input.ConfigName) < 1 || len(input.ConfigName) > 100 {
+               return errors.New("invalid params: config_name length must be 
between 1 and 100")
+       }
+
+       if len(input.Payload) < 1 {
+               return errors.New("invalid params: payload is required")
+       }
+
+       return nil
+}
diff --git a/api/internal/handler/system_config/system_config_test.go 
b/api/internal/handler/system_config/system_config_test.go
new file mode 100644
index 0000000..ca5d6ac
--- /dev/null
+++ b/api/internal/handler/system_config/system_config_test.go
@@ -0,0 +1,258 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package system_config
+
+import (
+       "errors"
+       "testing"
+
+       "github.com/shiningrush/droplet"
+       "github.com/shiningrush/droplet/data"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/mock"
+
+       "github.com/apisix/manager-api/internal/core/entity"
+       "github.com/apisix/manager-api/internal/core/store"
+)
+
+func TestSystem_Get(t *testing.T) {
+       t.Parallel()
+       type testCase struct {
+               caseDesc  string
+               giveInput *GetInput
+               wantErr   error
+               wantRet   interface{}
+               mockStore store.Interface
+               mockFunc  func(tc *testCase)
+       }
+
+       cases := []*testCase{
+               {
+                       caseDesc:  "system config not found",
+                       giveInput: &GetInput{ConfigName: "grafana"},
+                       wantErr:   data.ErrNotFound,
+                       mockFunc: func(tc *testCase) {
+                               mockStore := &store.MockInterface{}
+                               mockStore.On("Get", mock.Anything, 
mock.Anything).Return(nil, tc.wantErr)
+                               tc.mockStore = mockStore
+                       },
+               },
+               {
+                       caseDesc:  "get system config success",
+                       giveInput: &GetInput{ConfigName: "grafana"},
+                       wantErr:   nil,
+                       wantRet: entity.SystemConfig{
+                               ConfigName: "grafana",
+                               Payload: map[string]interface{}{
+                                       "url": "http://127.0.0.1:3000";,
+                               },
+                       },
+                       mockFunc: func(tc *testCase) {
+                               mockStore := &store.MockInterface{}
+                               mockStore.On("Get", mock.Anything, 
mock.Anything).Return(tc.wantRet, nil)
+                               tc.mockStore = mockStore
+                       },
+               },
+       }
+
+       for _, tc := range cases {
+               t.Run(tc.caseDesc, func(t *testing.T) {
+                       tc.mockFunc(tc)
+                       h := Handler{tc.mockStore}
+                       ctx := droplet.NewContext()
+                       ctx.SetInput(tc.giveInput)
+                       ret, err := h.Get(ctx)
+                       assert.Equal(t, err, tc.wantErr)
+                       if err == nil {
+                               assert.Equal(t, ret, tc.wantRet)
+                       }
+               })
+       }
+}
+
+func TestSystem_Post(t *testing.T) {
+       t.Parallel()
+       type testCase struct {
+               caseDesc  string
+               giveInput *entity.SystemConfig
+               wantErr   error
+               wantRet   interface{}
+               mockStore store.Interface
+               mockFunc  func(tc *testCase)
+       }
+
+       systemConfig := entity.SystemConfig{
+               ConfigName: "grafana",
+               Payload: map[string]interface{}{
+                       "url": "http://127.0.0.1:3000";,
+               },
+       }
+
+       cases := []*testCase{
+               {
+                       caseDesc:  "create system config error",
+                       giveInput: &systemConfig,
+                       wantErr:   errors.New("mock error"),
+                       mockFunc: func(tc *testCase) {
+                               mockStore := &store.MockInterface{}
+                               mockStore.On("Create", mock.Anything, 
mock.Anything).Return(nil, tc.wantErr)
+                               tc.mockStore = mockStore
+                       },
+               },
+               {
+                       caseDesc:  "create system config success",
+                       giveInput: &systemConfig,
+                       wantErr:   nil,
+                       wantRet: entity.SystemConfig{
+                               ConfigName: "grafana",
+                               Payload: map[string]interface{}{
+                                       "url": "http://127.0.0.1:3000";,
+                               },
+                       },
+                       mockFunc: func(tc *testCase) {
+                               mockStore := &store.MockInterface{}
+                               mockStore.On("Create", mock.Anything, 
mock.Anything).Return(tc.wantRet, nil)
+                               tc.mockStore = mockStore
+                       },
+               },
+       }
+
+       for _, tc := range cases {
+               t.Run(tc.caseDesc, func(t *testing.T) {
+                       tc.mockFunc(tc)
+                       h := Handler{tc.mockStore}
+                       ctx := droplet.NewContext()
+                       ctx.SetInput(tc.giveInput)
+                       ret, err := h.Post(ctx)
+                       assert.Equal(t, err, tc.wantErr)
+                       if err == nil {
+                               assert.Equal(t, ret, tc.wantRet)
+                       }
+               })
+       }
+}
+
+func TestSystem_Put(t *testing.T) {
+       t.Parallel()
+       type testCase struct {
+               caseDesc  string
+               giveInput *entity.SystemConfig
+               wantErr   error
+               wantRet   interface{}
+               mockStore store.Interface
+               mockFunc  func(tc *testCase)
+       }
+
+       systemConfig := entity.SystemConfig{
+               ConfigName: "grafana",
+               Payload: map[string]interface{}{
+                       "url": "http://127.0.0.1:3000";,
+               },
+       }
+
+       cases := []*testCase{
+               {
+                       caseDesc:  "update system config error",
+                       giveInput: &systemConfig,
+                       wantErr:   errors.New("mock error"),
+                       mockFunc: func(tc *testCase) {
+                               mockStore := &store.MockInterface{}
+                               mockStore.On("Update", mock.Anything, 
mock.Anything, mock.Anything).Return(nil, tc.wantErr)
+                               tc.mockStore = mockStore
+                       },
+               },
+               {
+                       caseDesc:  "update system config success",
+                       giveInput: &systemConfig,
+                       wantErr:   nil,
+                       wantRet: entity.SystemConfig{
+                               ConfigName: "grafana",
+                               Payload: map[string]interface{}{
+                                       "url": "http://127.0.0.1:3000";,
+                               },
+                       },
+                       mockFunc: func(tc *testCase) {
+                               mockStore := &store.MockInterface{}
+                               mockStore.On("Update", mock.Anything, 
mock.Anything, mock.Anything).Return(tc.wantRet, nil)
+                               tc.mockStore = mockStore
+                       },
+               },
+       }
+
+       for _, tc := range cases {
+               t.Run(tc.caseDesc, func(t *testing.T) {
+                       tc.mockFunc(tc)
+                       h := Handler{tc.mockStore}
+                       ctx := droplet.NewContext()
+                       ctx.SetInput(tc.giveInput)
+                       ret, err := h.Put(ctx)
+                       assert.Equal(t, err, tc.wantErr)
+                       if err == nil {
+                               assert.Equal(t, ret, tc.wantRet)
+                       }
+               })
+       }
+}
+
+func TestSystem_Delete(t *testing.T) {
+       t.Parallel()
+       type testCase struct {
+               caseDesc  string
+               giveInput *DeleteInput
+               wantErr   error
+               wantRet   interface{}
+               mockStore store.Interface
+               mockFunc  func(tc *testCase)
+       }
+
+       cases := []*testCase{
+               {
+                       caseDesc:  "delete system config error",
+                       giveInput: &DeleteInput{ConfigName: "grafana"},
+                       wantErr:   errors.New("mock error"),
+                       mockFunc: func(tc *testCase) {
+                               mockStore := &store.MockInterface{}
+                               mockStore.On("BatchDelete", mock.Anything, 
mock.Anything).Return(tc.wantErr)
+                               tc.mockStore = mockStore
+                       },
+               },
+               {
+                       caseDesc:  "delete system config success",
+                       giveInput: &DeleteInput{ConfigName: "grafana"},
+                       wantErr:   nil,
+                       mockFunc: func(tc *testCase) {
+                               mockStore := &store.MockInterface{}
+                               mockStore.On("BatchDelete", mock.Anything, 
mock.Anything).Return(tc.wantRet)
+                               tc.mockStore = mockStore
+                       },
+               },
+       }
+
+       for _, tc := range cases {
+               t.Run(tc.caseDesc, func(t *testing.T) {
+                       tc.mockFunc(tc)
+                       h := Handler{tc.mockStore}
+                       ctx := droplet.NewContext()
+                       ctx.SetInput(tc.giveInput)
+                       ret, err := h.Delete(ctx)
+                       assert.Equal(t, err, tc.wantErr)
+                       if err == nil {
+                               assert.Equal(t, ret, tc.wantRet)
+                       }
+               })
+       }
+}
diff --git a/api/internal/route.go b/api/internal/route.go
index 5ece4e3..7eddc9c 100644
--- a/api/internal/route.go
+++ b/api/internal/route.go
@@ -21,6 +21,7 @@ import (
        "path/filepath"
 
        // "github.com/gin-contrib/pprof"
+       "github.com/gin-contrib/gzip"
        "github.com/gin-contrib/static"
        "github.com/gin-gonic/gin"
 
@@ -42,10 +43,10 @@ import (
        "github.com/apisix/manager-api/internal/handler/service"
        "github.com/apisix/manager-api/internal/handler/ssl"
        "github.com/apisix/manager-api/internal/handler/stream_route"
+       "github.com/apisix/manager-api/internal/handler/system_config"
        "github.com/apisix/manager-api/internal/handler/tool"
        "github.com/apisix/manager-api/internal/handler/upstream"
        "github.com/apisix/manager-api/internal/log"
-       "github.com/gin-contrib/gzip"
 )
 
 func SetUpRouter() *gin.Engine {
@@ -83,6 +84,7 @@ func SetUpRouter() *gin.Engine {
                migrate.NewHandler,
                proto.NewHandler,
                stream_route.NewHandler,
+               system_config.NewHandler,
        }
 
        for i := range factories {
diff --git a/api/test/e2enew/go.mod b/api/test/e2enew/go.mod
index 94fdd65..0d6c7fb 100644
--- a/api/test/e2enew/go.mod
+++ b/api/test/e2enew/go.mod
@@ -9,35 +9,3 @@ require (
        github.com/stretchr/testify v1.7.0
        github.com/tidwall/gjson v1.11.0
 )
-
-require (
-       github.com/ajg/form v1.5.1 // indirect
-       github.com/andybalholm/brotli v1.0.2 // indirect
-       github.com/davecgh/go-spew v1.1.1 // indirect
-       github.com/fatih/structs v1.0.0 // indirect
-       github.com/fsnotify/fsnotify v1.4.9 // indirect
-       github.com/google/go-querystring v1.0.0 // indirect
-       github.com/gorilla/websocket v1.4.2 // indirect
-       github.com/imkira/go-interpol v1.0.0 // indirect
-       github.com/klauspost/compress v1.12.2 // indirect
-       github.com/nxadm/tail v1.4.8 // indirect
-       github.com/pmezard/go-difflib v1.0.0 // indirect
-       github.com/sergi/go-diff v1.0.0 // indirect
-       github.com/tidwall/match v1.1.1 // indirect
-       github.com/tidwall/pretty v1.2.0 // indirect
-       github.com/valyala/bytebufferpool v1.0.0 // indirect
-       github.com/valyala/fasthttp v1.27.0 // indirect
-       github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // 
indirect
-       github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 
// indirect
-       github.com/xeipuuv/gojsonschema v1.1.0 // indirect
-       github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect
-       github.com/yudai/gojsondiff v1.0.0 // indirect
-       github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
-       golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
-       golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
-       golang.org/x/text v0.3.6 // indirect
-       gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
-       gopkg.in/yaml.v2 v2.4.0 // indirect
-       gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
-       moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e // indirect
-)
diff --git a/api/test/e2enew/go.sum b/api/test/e2enew/go.sum
index b0dbf1b..b6d85c7 100644
--- a/api/test/e2enew/go.sum
+++ b/api/test/e2enew/go.sum
@@ -14,7 +14,6 @@ github.com/fsnotify/fsnotify v1.4.9 
h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
 github.com/fsnotify/fsnotify v1.4.9/go.mod 
h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/gavv/httpexpect/v2 v2.3.1 
h1:sGLlKMn8AuHS9ztK9Sb7AJ7OxIL8v2PcLdyxfKt1Fo4=
 github.com/gavv/httpexpect/v2 v2.3.1/go.mod 
h1:yOE8m/aqFYQDNrgprMeXgq4YynfN9h1NgcE1+1suV64=
-github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 
h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod 
h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/golang/protobuf v1.2.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod 
h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
@@ -137,7 +136,6 @@ golang.org/x/text v0.3.6 
h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod 
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e 
h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=
 golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod 
h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/api/test/e2enew/system_config/system_config_suite_test.go 
b/api/test/e2enew/system_config/system_config_suite_test.go
new file mode 100644
index 0000000..122ca1f
--- /dev/null
+++ b/api/test/e2enew/system_config/system_config_suite_test.go
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package system_config
+
+import (
+       "github.com/onsi/ginkgo"
+       "github.com/onsi/gomega"
+       "testing"
+)
+
+func TestSystemConfig(t *testing.T) {
+       gomega.RegisterFailHandler(ginkgo.Fail)
+       ginkgo.RunSpecs(t, "system config suite")
+}
diff --git a/api/test/e2enew/system_config/system_config_test.go 
b/api/test/e2enew/system_config/system_config_test.go
new file mode 100644
index 0000000..7fc2166
--- /dev/null
+++ b/api/test/e2enew/system_config/system_config_test.go
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package system_config
+
+import (
+       "net/http"
+
+       . "github.com/onsi/ginkgo"
+       . "github.com/onsi/ginkgo/extensions/table"
+
+       "github.com/apisix/manager-api/test/e2enew/base"
+)
+
+var _ = Describe("system config", func() {
+       DescribeTable("test system config data CURD",
+               func(tc base.HttpTestCase) {
+                       base.RunTestCase(tc)
+               },
+
+               Entry("get system config should get not found error", 
base.HttpTestCase{
+                       Object:       base.ManagerApiExpect(),
+                       Method:       http.MethodGet,
+                       Path:         "/apisix/admin/system_config/grafana",
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusNotFound,
+               }),
+
+               Entry("create system config should get schema validate failed 
error", base.HttpTestCase{
+                       Object: base.ManagerApiExpect(),
+                       Method: http.MethodPost,
+                       Path:   "/apisix/admin/system_config",
+                       Body: `{
+                               "config_name": "",
+                               "payload": {"url":"http://127.0.0.1:3000"}
+                       }`,
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusBadRequest,
+               }),
+
+               Entry("create system config should success", base.HttpTestCase{
+                       Object: base.ManagerApiExpect(),
+                       Method: http.MethodPost,
+                       Path:   "/apisix/admin/system_config",
+                       Body: `{
+                               "config_name": "grafana",
+                               "payload": {"url":"http://127.0.0.1:3000"}
+                       }`,
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusOK,
+                       ExpectBody:   
"\"config_name\":\"grafana\",\"payload\":{\"url\":\"http://127.0.0.1:3000\"}";,
+               }),
+
+               Entry("after create system config get config should succeed", 
base.HttpTestCase{
+                       Object:       base.ManagerApiExpect(),
+                       Method:       http.MethodGet,
+                       Path:         "/apisix/admin/system_config/grafana",
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusOK,
+                       ExpectBody:   
"\"config_name\":\"grafana\",\"payload\":{\"url\":\"http://127.0.0.1:3000\"}";,
+               }),
+
+               Entry("update system config should get schema validate failed 
error", base.HttpTestCase{
+                       Object: base.ManagerApiExpect(),
+                       Method: http.MethodPut,
+                       Path:   "/apisix/admin/system_config",
+                       Body: `{
+                               "config_name": "",
+                               "payload": {"url":"http://127.0.0.1:2000"}
+                       }`,
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusBadRequest,
+               }),
+
+               Entry("update system config should success", base.HttpTestCase{
+                       Object: base.ManagerApiExpect(),
+                       Method: http.MethodPut,
+                       Path:   "/apisix/admin/system_config",
+                       Body: `{
+                               "config_name": "grafana",
+                               "payload": {"url":"http://127.0.0.1:2000"}
+                       }`,
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusOK,
+                       ExpectBody:   
"\"config_name\":\"grafana\",\"payload\":{\"url\":\"http://127.0.0.1:2000\"}";,
+               }),
+
+               Entry("after update system config get config should succeed", 
base.HttpTestCase{
+                       Object:       base.ManagerApiExpect(),
+                       Method:       http.MethodGet,
+                       Path:         "/apisix/admin/system_config/grafana",
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusOK,
+                       ExpectBody:   
"\"config_name\":\"grafana\",\"payload\":{\"url\":\"http://127.0.0.1:2000\"}";,
+               }),
+
+               Entry("delete system config should success", base.HttpTestCase{
+                       Object:       base.ManagerApiExpect(),
+                       Method:       http.MethodDelete,
+                       Path:         "/apisix/admin/system_config/grafana",
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusOK,
+               }),
+
+               Entry("get system config should get not found error", 
base.HttpTestCase{
+                       Object:       base.ManagerApiExpect(),
+                       Method:       http.MethodGet,
+                       Path:         "/apisix/admin/system_config/grafana",
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusNotFound,
+               }),
+       )
+})

Reply via email to