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

majunjie 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 bff19b5  fix(be): Modify the service to use the new JSON patch package 
(#1396)
bff19b5 is described below

commit bff19b5336485e4ec62666cf518ec22bfbb6370d
Author: JinChen <[email protected]>
AuthorDate: Sat Jan 30 10:32:14 2021 +0800

    fix(be): Modify the service to use the new JSON patch package (#1396)
---
 api/internal/handler/service/service.go      | 47 ++++++++-------
 api/internal/handler/service/service_test.go | 71 +++++++++++++++++++++++
 api/test/e2e/service_test.go                 | 87 ++++++++++++++++++++++++++++
 3 files changed, 181 insertions(+), 24 deletions(-)

diff --git a/api/internal/handler/service/service.go 
b/api/internal/handler/service/service.go
index 240e416..15c4a76 100644
--- a/api/internal/handler/service/service.go
+++ b/api/internal/handler/service/service.go
@@ -17,12 +17,12 @@
 package service
 
 import (
+       "encoding/json"
        "fmt"
        "net/http"
        "reflect"
        "strings"
 
-       "github.com/api7/go-jsonpatch"
        "github.com/gin-gonic/gin"
        "github.com/shiningrush/droplet"
        "github.com/shiningrush/droplet/data"
@@ -59,7 +59,9 @@ func (h *Handler) ApplyRoute(r *gin.Engine) {
        r.PUT("/apisix/admin/services/:id", wgin.Wraps(h.Update,
                wrapper.InputType(reflect.TypeOf(UpdateInput{}))))
        r.PATCH("/apisix/admin/services/:id", wgin.Wraps(h.Patch,
-               wrapper.InputType(reflect.TypeOf(UpdateInput{}))))
+               wrapper.InputType(reflect.TypeOf(PatchInput{}))))
+       r.PATCH("/apisix/admin/services/:id/*path", wgin.Wraps(h.Patch,
+               wrapper.InputType(reflect.TypeOf(PatchInput{}))))
        r.DELETE("/apisix/admin/services/:ids", wgin.Wraps(h.BatchDelete,
                wrapper.InputType(reflect.TypeOf(BatchDelete{}))))
 }
@@ -224,42 +226,39 @@ func (h *Handler) BatchDelete(c droplet.Context) 
(interface{}, error) {
        return nil, nil
 }
 
+type PatchInput struct {
+       ID      string `auto_read:"id,path"`
+       SubPath string `auto_read:"path,path"`
+       Body    []byte `auto_read:"@body"`
+}
+
 func (h *Handler) Patch(c droplet.Context) (interface{}, error) {
-       input := c.Input().(*UpdateInput)
-       arr := strings.Split(input.ID, "/")
-       var subPath string
-       if len(arr) > 1 {
-               input.ID = arr[0]
-               subPath = arr[1]
-       }
+       input := c.Input().(*PatchInput)
+       reqBody := input.Body
+       ID := input.ID
+       subPath := input.SubPath
 
-       stored, err := h.serviceStore.Get(c.Context(), input.ID)
+       stored, err := h.serviceStore.Get(c.Context(), ID)
        if err != nil {
                return handler.SpecCodeResponse(err), err
        }
 
-       var patch jsonpatch.Patch
-       if subPath != "" {
-               patch = jsonpatch.Patch{
-                       Operations: []jsonpatch.PatchOperation{
-                               {Op: jsonpatch.Replace, Path: subPath, Value: 
c.Input()},
-                       },
-               }
-       } else {
-               patch, err = jsonpatch.MakePatch(stored, input.Service)
-               if err != nil {
-                       return handler.SpecCodeResponse(err), err
-               }
+       res, err := utils.MergePatch(stored, subPath, reqBody)
+       if err != nil {
+               return handler.SpecCodeResponse(err), err
        }
 
-       if err := patch.Apply(&stored); err != nil {
+       var service entity.Service
+       err = json.Unmarshal(res, &service)
+       if err != nil {
                return handler.SpecCodeResponse(err), err
        }
 
-       ret, err := h.serviceStore.Update(c.Context(), &stored, false)
+       ret, err := h.serviceStore.Update(c.Context(), &service, false)
        if err != nil {
                return handler.SpecCodeResponse(err), err
        }
 
        return ret, nil
 }
+
diff --git a/api/internal/handler/service/service_test.go 
b/api/internal/handler/service/service_test.go
index 88cd5c3..4f469af 100644
--- a/api/internal/handler/service/service_test.go
+++ b/api/internal/handler/service/service_test.go
@@ -19,6 +19,7 @@ package service
 
 import (
        "encoding/json"
+       "strings"
        "testing"
        "time"
 
@@ -218,3 +219,73 @@ func TestService(t *testing.T) {
        assert.Nil(t, err)
 
 }
+
+func TestService_Patch_Update(t *testing.T) {
+       //create
+       handler := &Handler{
+               serviceStore: store.GetStore(store.HubKeyService),
+       }
+       ctx := droplet.NewContext()
+       service := &entity.Service{}
+       reqBody := `{
+               "id": "3",
+               "name": "testservice",
+               "upstream": {
+                       "type": "roundrobin",
+                       "nodes": [{
+                               "host": "172.16.238.20",
+                               "port": 1980,
+                               "weight": 1
+                       }]
+               }
+       }`
+       err := json.Unmarshal([]byte(reqBody), service)
+       assert.Nil(t, err)
+       ctx.SetInput(service)
+       ret, err := handler.Create(ctx)
+       assert.Nil(t, err)
+       objRet, ok := ret.(*entity.Service)
+       assert.True(t, ok)
+       assert.Equal(t, "3", objRet.ID)
+
+       //sleep
+       time.Sleep(time.Duration(20) * time.Millisecond)
+
+       reqBody1 := `{
+               "id": "3",
+               "name": "testpatch",
+               "upstream": {
+                       "type": "roundrobin",
+                       "nodes": [{
+                               "host": "172.16.238.20",
+                               "port": 1981,
+                               "weight": 1
+                       }]
+               }
+       }`
+       responesBody := 
`"nodes":[{"host":"172.16.238.20","port":1981,"weight":1}],"type":"roundrobin"}`
+
+       input2 := &PatchInput{}
+       input2.ID = "3"
+       input2.SubPath = ""
+       input2.Body = []byte(reqBody1)
+       ctx.SetInput(input2)
+
+       ret2, err := handler.Patch(ctx)
+       assert.Nil(t, err)
+       _ret2, err := json.Marshal(ret2)
+       assert.Nil(t, err)
+       isContains := strings.Contains(string(_ret2), responesBody)
+       assert.True(t, isContains)
+
+       //delete test data
+       inputDel2 := &BatchDelete{}
+       reqBody = `{"ids": "3"}`
+       err = json.Unmarshal([]byte(reqBody), inputDel2)
+       assert.Nil(t, err)
+       ctx.SetInput(inputDel2)
+       _, err = handler.BatchDelete(ctx)
+       assert.Nil(t, err)
+
+}
+
diff --git a/api/test/e2e/service_test.go b/api/test/e2e/service_test.go
index 4d9ebe2..9a0cc43 100644
--- a/api/test/e2e/service_test.go
+++ b/api/test/e2e/service_test.go
@@ -269,3 +269,90 @@ func TestService_Teardown(t *testing.T) {
                testCaseCheck(tc, t)
        }
 }
+
+func TestService_Update_Use_Patch_Method(t *testing.T) {
+       tests := []HttpTestCase{
+               {
+                       Desc:    "create service without plugin",
+                       Object:  ManagerApiExpect(t),
+                       Method:  http.MethodPut,
+                       Path:    "/apisix/admin/services/s5",
+                       Headers: map[string]string{"Authorization": token},
+                       Body: `{
+                               "name": "testservice",
+                               "upstream": {
+                                       "type": "roundrobin",
+                                       "nodes": [{
+                                               "host": "172.16.238.20",
+                                               "port": 1980,
+                                               "weight": 1
+                                       }]
+                               }
+                       }`,
+                       ExpectStatus: http.StatusOK,
+                       ExpectBody:   
"\"name\":\"testservice\",\"upstream\":{\"nodes\":[{\"host\":\"172.16.238.20\",\"port\":1980,\"weight\":1}],\"type\":\"roundrobin\"}}",
+               },
+               {
+                       Desc:   "update service use patch method",
+                       Object: ManagerApiExpect(t),
+                       Method: http.MethodPatch,
+                       Path:   "/apisix/admin/services/s5",
+                       Body: `{
+                               "name": "testpatch",
+                               "upstream": {
+                                       "type": "roundrobin",
+                                       "nodes": [{
+                                               "host": "172.16.238.20",
+                                               "port": 1981,
+                                               "weight": 1
+                                       }]
+                               }
+                       }`,
+                       Headers:      map[string]string{"Authorization": token},
+                       ExpectStatus: http.StatusOK,
+               },
+               {
+                       Desc:       "get the service s5",
+                       Object:     ManagerApiExpect(t),
+                       Method:     http.MethodGet,
+                       Path:       "/apisix/admin/services/s5",
+                       Headers:    map[string]string{"Authorization": token},
+                       ExpectCode: http.StatusOK,
+                       ExpectBody: 
"\"name\":\"testpatch\",\"upstream\":{\"nodes\":[{\"host\":\"172.16.238.20\",\"port\":1981,\"weight\":1}],\"type\":\"roundrobin\"}}",
+               },
+               {
+                       Desc:   "Update service using path parameter patch 
method",
+                       Object: ManagerApiExpect(t),
+                       Method: http.MethodPatch,
+                       Path:   "/apisix/admin/services/s5/upstream",
+                       Body:   
`{"type":"roundrobin","nodes":[{"host":"172.16.238.20","port":1980,"weight":1}]}`,
+                       Headers: map[string]string{
+                               "Authorization": token,
+                               "Content-Type":  "text/plain",
+                       },
+                       ExpectStatus: http.StatusOK,
+               },
+               {
+                       Desc:         "get service data",
+                       Object:       ManagerApiExpect(t),
+                       Method:       http.MethodGet,
+                       Path:         "/apisix/admin/services/s5",
+                       Headers:      map[string]string{"Authorization": token},
+                       ExpectStatus: http.StatusOK,
+                       ExpectBody:   
"\"name\":\"testpatch\",\"upstream\":{\"nodes\":[{\"host\":\"172.16.238.20\",\"port\":1980,\"weight\":1}],\"type\":\"roundrobin\"}}",
+               },
+               {
+                       Desc:         "delete service",
+                       Object:       ManagerApiExpect(t),
+                       Method:       http.MethodDelete,
+                       Path:         "/apisix/admin/services/s5",
+                       Headers:      map[string]string{"Authorization": token},
+                       ExpectStatus: http.StatusOK,
+               },
+       }
+
+       for _, tc := range tests {
+               testCaseCheck(tc, t)
+       }
+}
+

Reply via email to