You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by st...@apache.org on 2021/02/05 04:05:28 UTC
[apisix-dashboard] branch master updated: feat: remove the etcd
dependency in the service unit test
This is an automated email from the ASF dual-hosted git repository.
starsz 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 661e48f feat: remove the etcd dependency in the service unit test
661e48f is described below
commit 661e48fb8cd1035429bd4d14919f7b8ea910d5ad
Author: Peter Zhu <st...@gmail.com>
AuthorDate: Fri Feb 5 12:05:22 2021 +0800
feat: remove the etcd dependency in the service unit test
---
api/internal/handler/service/service_test.go | 1037 ++++++++++++++++++++------
1 file changed, 801 insertions(+), 236 deletions(-)
diff --git a/api/internal/handler/service/service_test.go b/api/internal/handler/service/service_test.go
index 4f469af..40da731 100644
--- a/api/internal/handler/service/service_test.go
+++ b/api/internal/handler/service/service_test.go
@@ -18,274 +18,839 @@
package service
import (
- "encoding/json"
- "strings"
+ "fmt"
+ "net/http"
"testing"
- "time"
"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/conf"
"github.com/apisix/manager-api/internal/core/entity"
- "github.com/apisix/manager-api/internal/core/storage"
"github.com/apisix/manager-api/internal/core/store"
+ "github.com/apisix/manager-api/internal/handler"
)
-func TestService(t *testing.T) {
- // init
- err := storage.InitETCDClient(conf.ETCDConfig)
- assert.Nil(t, err)
- err = store.InitStores()
- assert.Nil(t, err)
-
- handler := &Handler{
- serviceStore: store.GetStore(store.HubKeyService),
+func TestService_Get(t *testing.T) {
+ tests := []struct {
+ caseDesc string
+ giveInput *GetInput
+ giveRet *entity.Service
+ giveErr error
+ wantErr error
+ wantGetKey string
+ wantRet interface{}
+ }{
+ {
+ caseDesc: "normal",
+ giveInput: &GetInput{ID: "s1"},
+ wantGetKey: "s1",
+ giveRet: &entity.Service{
+ BaseInfo: entity.BaseInfo{
+ ID: "s1",
+ },
+ Plugins: map[string]interface{}{
+ "limit-count": map[string]interface{}{
+ "count": 2,
+ "time_window": 60,
+ "rejected_code": 503,
+ "key": "remote_addr",
+ },
+ },
+ },
+ wantRet: &entity.Service{
+ BaseInfo: entity.BaseInfo{
+ ID: "s1",
+ },
+ Plugins: map[string]interface{}{
+ "limit-count": map[string]interface{}{
+ "count": 2,
+ "time_window": 60,
+ "rejected_code": 503,
+ "key": "remote_addr",
+ },
+ },
+ },
+ },
+ {
+ caseDesc: "store get failed",
+ giveInput: &GetInput{ID: "failed_key"},
+ wantGetKey: "failed_key",
+ giveErr: fmt.Errorf("get failed"),
+ wantErr: fmt.Errorf("get failed"),
+ wantRet: &data.SpecCodeResponse{
+ StatusCode: http.StatusInternalServerError,
+ },
+ },
}
- assert.NotNil(t, handler)
- //create
- ctx := droplet.NewContext()
- service := &entity.Service{}
- reqBody := `{
- "id": "1",
- "plugins": {
- "limit-count": {
- "count": 2,
- "time_window": 60,
- "rejected_code": 503,
- "key": "remote_addr"
- }
- },
- "upstream": {
- "type": "roundrobin",
- "nodes": [{
- "host": "39.97.63.215",
- "port": 80,
- "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, "1", objRet.ID)
+ for _, tc := range tests {
+ t.Run(tc.caseDesc, func(t *testing.T) {
+ getCalled := true
+ mStore := &store.MockInterface{}
+ mStore.On("Get", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ getCalled = true
+ assert.Equal(t, tc.wantGetKey, args.Get(0))
+ }).Return(tc.giveRet, tc.giveErr)
- //sleep
- time.Sleep(time.Duration(100) * time.Millisecond)
-
- //get
- input := &GetInput{}
- input.ID = "1"
- ctx.SetInput(input)
- ret, err = handler.Get(ctx)
- stored := ret.(*entity.Service)
- assert.Nil(t, err)
- assert.Equal(t, stored.ID, service.ID)
+ h := Handler{serviceStore: mStore}
+ ctx := droplet.NewContext()
+ ctx.SetInput(tc.giveInput)
+ ret, err := h.Get(ctx)
+ assert.True(t, getCalled)
+ assert.Equal(t, tc.wantRet, ret)
+ assert.Equal(t, tc.wantErr, err)
+ })
+ }
+}
- //update
- service2 := &UpdateInput{}
- service2.ID = "1"
- reqBody = `{
- "name": "test-service",
- "plugins": {
- "limit-count": {
- "count": 2,
- "time_window": 60,
- "rejected_code": 503,
- "key": "remote_addr"
- }
+func TestService_List(t *testing.T) {
+ tests := []struct {
+ caseDesc string
+ giveInput *ListInput
+ giveData []*entity.Service
+ giveErr error
+ wantErr error
+ wantInput store.ListInput
+ wantRet interface{}
+ }{
+ {
+ caseDesc: "list all service",
+ giveInput: &ListInput{
+ Pagination: store.Pagination{
+ PageSize: 10,
+ PageNumber: 10,
+ },
+ },
+ wantInput: store.ListInput{
+ PageSize: 10,
+ PageNumber: 10,
+ },
+ giveData: []*entity.Service{
+ {Name: "s1"},
+ {Name: "s2"},
+ {Name: "test_service"},
+ {Name: "service_test"},
+ },
+ wantRet: &store.ListOutput{
+ Rows: []interface{}{
+ &entity.Service{Name: "s1"},
+ &entity.Service{Name: "s2"},
+ &entity.Service{Name: "test_service"},
+ &entity.Service{Name: "service_test"},
+ },
+ TotalSize: 4,
+ },
},
- "enable_websocket": true,
- "upstream": {
- "type": "roundrobin",
- "nodes": [{
- "host": "39.97.63.215",
- "port": 80,
- "weight": 1
- }]
- }
- }`
- err = json.Unmarshal([]byte(reqBody), service2)
- assert.Nil(t, err)
- ctx.SetInput(service2)
- ret, err = handler.Update(ctx)
- assert.Nil(t, err)
- // Check the returned value
- objRet, ok = ret.(*entity.Service)
- assert.True(t, ok)
- assert.Equal(t, service2.ID, objRet.ID)
- assert.Equal(t, service2.Name, objRet.Name)
+ {
+ caseDesc: "list service with 'service'",
+ giveInput: &ListInput{
+ Name: "service",
+ Pagination: store.Pagination{
+ PageSize: 10,
+ PageNumber: 10,
+ },
+ },
+ wantInput: store.ListInput{
+ PageSize: 10,
+ PageNumber: 10,
+ },
+ giveData: []*entity.Service{
+ {BaseInfo: entity.BaseInfo{CreateTime: 1609376661}, Name: "s1"},
+ {BaseInfo: entity.BaseInfo{CreateTime: 1609376662}, Name: "s2"},
+ {BaseInfo: entity.BaseInfo{CreateTime: 1609376663}, Name: "test_service"},
+ {BaseInfo: entity.BaseInfo{CreateTime: 1609376664}, Name: "service_test"},
+ },
+ wantRet: &store.ListOutput{
+ Rows: []interface{}{
+ &entity.Service{BaseInfo: entity.BaseInfo{CreateTime: 1609376663}, Name: "test_service"},
+ &entity.Service{BaseInfo: entity.BaseInfo{CreateTime: 1609376664}, Name: "service_test"},
+ },
+ TotalSize: 2,
+ },
+ },
+ {
+ caseDesc: "list service with key s1",
+ giveInput: &ListInput{
+ Name: "s1",
+ Pagination: store.Pagination{
+ PageSize: 10,
+ PageNumber: 10,
+ },
+ },
+ wantInput: store.ListInput{
+ PageSize: 10,
+ PageNumber: 10,
+ },
+ giveData: []*entity.Service{
+ {Name: "s1"},
+ {Name: "s2"},
+ {Name: "test_service"},
+ {Name: "service_test"},
+ },
+ wantRet: &store.ListOutput{
+ Rows: []interface{}{
+ &entity.Service{Name: "s1"},
+ },
+ TotalSize: 1,
+ },
+ },
+ {
+ caseDesc: "list service and format",
+ giveInput: &ListInput{
+ Pagination: store.Pagination{
+ PageSize: 10,
+ PageNumber: 10,
+ },
+ },
+ wantInput: store.ListInput{
+ PageSize: 10,
+ PageNumber: 10,
+ },
+ giveData: []*entity.Service{
+ {
+ Name: "s1",
+ Upstream: &entity.UpstreamDef{
+ Nodes: []interface{}{
+ map[string]interface{}{
+ "host": "39.97.63.215",
+ "port": float64(80),
+ "weight": float64(1),
+ },
+ },
+ },
+ },
+ {Name: "s2"},
+ {Name: "test_service"},
+ {Name: "service_test"},
+ },
+ wantRet: &store.ListOutput{
+ Rows: []interface{}{
+ &entity.Service{Name: "s1", Upstream: &entity.UpstreamDef{
+ Nodes: []*entity.Node{
+ {
+ Host: "39.97.63.215",
+ Port: 80,
+ Weight: 1,
+ },
+ },
+ }},
+ &entity.Service{Name: "s2"},
+ &entity.Service{Name: "test_service"},
+ &entity.Service{Name: "service_test"},
+ },
+ TotalSize: 4,
+ },
+ },
+ }
- //sleep
- time.Sleep(time.Duration(100) * time.Millisecond)
+ for _, tc := range tests {
+ t.Run(tc.caseDesc, func(t *testing.T) {
+ getCalled := true
+ mStore := &store.MockInterface{}
+ mStore.On("List", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ getCalled = true
+ input := args.Get(0).(store.ListInput)
+ assert.Equal(t, tc.wantInput.PageSize, input.PageSize)
+ assert.Equal(t, tc.wantInput.PageNumber, input.PageNumber)
+ }).Return(func(input store.ListInput) *store.ListOutput {
+ var returnData []interface{}
+ for _, c := range tc.giveData {
+ if input.Predicate(c) {
+ if input.Format == nil {
+ returnData = append(returnData, c)
+ continue
+ }
- //list
- listInput := &ListInput{}
- reqBody = `{"page_size": 1, "page": 1}`
- err = json.Unmarshal([]byte(reqBody), listInput)
- assert.Nil(t, err)
- ctx.SetInput(listInput)
- retPage, err := handler.List(ctx)
- assert.Nil(t, err)
- dataPage := retPage.(*store.ListOutput)
- assert.Equal(t, len(dataPage.Rows), 1)
+ returnData = append(returnData, input.Format(c))
+ }
+ }
+ return &store.ListOutput{
+ Rows: returnData,
+ TotalSize: len(returnData),
+ }
+ }, tc.giveErr)
- //list search match
- listInput2 := &ListInput{}
- reqBody = `{"page_size": 1, "page": 1, "name": "test"}`
- err = json.Unmarshal([]byte(reqBody), listInput2)
- assert.Nil(t, err)
- ctx.SetInput(listInput2)
- retPage, err = handler.List(ctx)
- assert.Nil(t, err)
- dataPage = retPage.(*store.ListOutput)
- assert.Equal(t, len(dataPage.Rows), 1)
+ h := Handler{serviceStore: mStore}
+ ctx := droplet.NewContext()
+ ctx.SetInput(tc.giveInput)
+ ret, err := h.List(ctx)
+ assert.True(t, getCalled)
+ assert.Equal(t, tc.wantRet, ret)
+ assert.Equal(t, tc.wantErr, err)
+ })
+ }
+}
- //list search not match
- listInput3 := &ListInput{}
- reqBody = `{"page_size": 1, "page": 1, "name": "not-exists"}`
- err = json.Unmarshal([]byte(reqBody), listInput3)
- assert.Nil(t, err)
- ctx.SetInput(listInput3)
- retPage, err = handler.List(ctx)
- assert.Nil(t, err)
- dataPage = retPage.(*store.ListOutput)
- assert.Equal(t, len(dataPage.Rows), 0)
+func TestService_Create(t *testing.T) {
+ tests := []struct {
+ caseDesc string
+ getCalled bool
+ giveInput *entity.Service
+ giveRet interface{}
+ giveErr error
+ wantInput *entity.Service
+ wantErr error
+ wantRet interface{}
+ upstreamInput string
+ upstreamRet interface{}
+ upstreamErr interface{}
+ }{
+ {
+ caseDesc: "create success",
+ getCalled: true,
+ giveInput: &entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ wantInput: &entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ upstreamInput: "u1",
+ upstreamRet: entity.Upstream{
+ BaseInfo: entity.BaseInfo{
+ ID: "u1",
+ },
+ },
+ },
+ {
+ caseDesc: "create failed, upstream not found",
+ getCalled: false,
+ giveInput: &entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ wantInput: &entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ wantErr: fmt.Errorf("upstream id: u1 not found"),
+ wantRet: &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+ upstreamInput: "u1",
+ upstreamErr: data.ErrNotFound,
+ },
+ {
+ caseDesc: "create failed, upstream return error",
+ getCalled: false,
+ giveInput: &entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ wantInput: &entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ wantErr: fmt.Errorf("unknown error"),
+ wantRet: &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+ upstreamInput: "u1",
+ upstreamErr: fmt.Errorf("unknown error"),
+ },
+ {
+ caseDesc: "create failed, create return error",
+ getCalled: true,
+ giveInput: &entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ giveErr: fmt.Errorf("create failed"),
+ wantInput: &entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ upstreamInput: "u1",
+ upstreamRet: entity.Upstream{
+ BaseInfo: entity.BaseInfo{
+ ID: "u1",
+ },
+ },
+ wantErr: fmt.Errorf("create failed"),
+ wantRet: handler.SpecCodeResponse(fmt.Errorf("create failed")),
+ },
+ }
- //delete test data
- inputDel := &BatchDelete{}
- reqBody = `{"ids": "1"}`
- err = json.Unmarshal([]byte(reqBody), inputDel)
- assert.Nil(t, err)
- ctx.SetInput(inputDel)
- _, err = handler.BatchDelete(ctx)
- assert.Nil(t, err)
+ for _, tc := range tests {
+ t.Run(tc.caseDesc, func(t *testing.T) {
+ getCalled := false
+ serviceStore := &store.MockInterface{}
+ serviceStore.On("Create", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ getCalled = true
+ input := args.Get(1).(*entity.Service)
+ assert.Equal(t, tc.wantInput, input)
+ }).Return(tc.giveRet, tc.giveErr)
- //create without upstream
- service11 := &entity.Service{}
- reqBody = `{
- "id": "11",
- "plugins": {
- "limit-count": {
- "count": 2,
- "time_window": 60,
- "rejected_code": 503,
- "key": "remote_addr"
- }
- }
- }`
- err = json.Unmarshal([]byte(reqBody), service11)
- assert.Nil(t, err)
- ctx.SetInput(service11)
- ret, err = handler.Create(ctx)
- assert.Nil(t, err)
- objRet, ok = ret.(*entity.Service)
- assert.True(t, ok)
- assert.Equal(t, "11", objRet.ID)
+ upstreamStore := &store.MockInterface{}
+ upstreamStore.On("Get", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ id := args.Get(0).(string)
+ assert.Equal(t, tc.upstreamInput, id)
+ }).Return(tc.upstreamRet, tc.upstreamErr)
- //sleep
- time.Sleep(time.Duration(100) * time.Millisecond)
+ h := Handler{serviceStore: serviceStore, upstreamStore: upstreamStore}
+ ctx := droplet.NewContext()
+ ctx.SetInput(tc.giveInput)
+ ret, err := h.Create(ctx)
+ assert.Equal(t, tc.getCalled, getCalled)
+ assert.Equal(t, tc.wantRet, ret)
+ assert.Equal(t, tc.wantErr, err)
+ })
+ }
+}
- //get
- input11 := &GetInput{}
- input11.ID = "11"
- ctx.SetInput(input11)
- ret, err = handler.Get(ctx)
- stored = ret.(*entity.Service)
- assert.Nil(t, err)
- assert.Equal(t, "11", stored.ID)
+func TestService_Update(t *testing.T) {
+ tests := []struct {
+ caseDesc string
+ getCalled bool
+ giveInput *UpdateInput
+ giveErr error
+ giveRet interface{}
+ wantInput *entity.Service
+ wantErr error
+ wantRet interface{}
+ upstreamInput string
+ upstreamRet interface{}
+ upstreamErr interface{}
+ }{
+ {
+ caseDesc: "create success",
+ getCalled: true,
+ giveInput: &UpdateInput{
+ ID: "s1",
+ Service: entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ },
+ wantInput: &entity.Service{
+ BaseInfo: entity.BaseInfo{
+ ID: "s1",
+ },
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ upstreamInput: "u1",
+ upstreamRet: entity.Upstream{
+ BaseInfo: entity.BaseInfo{
+ ID: "u1",
+ },
+ },
+ },
+ {
+ caseDesc: "create failed, different id",
+ giveInput: &UpdateInput{
+ ID: "s1",
+ Service: entity.Service{
+ BaseInfo: entity.BaseInfo{
+ ID: "s2",
+ },
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ },
+ wantRet: &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+ wantErr: fmt.Errorf("ID on path (s1) doesn't match ID on body (s2)"),
+ },
+ {
+ caseDesc: "update failed, upstream not found",
+ giveInput: &UpdateInput{
+ ID: "s1",
+ Service: entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ },
+ wantInput: &entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ wantErr: fmt.Errorf("upstream id: u1 not found"),
+ wantRet: &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+ upstreamInput: "u1",
+ upstreamErr: data.ErrNotFound,
+ },
+ {
+ caseDesc: "update failed, upstream return error",
+ giveInput: &UpdateInput{
+ ID: "s1",
+ Service: entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ },
+ wantInput: &entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ wantErr: fmt.Errorf("unknown error"),
+ wantRet: &data.SpecCodeResponse{StatusCode: http.StatusBadRequest},
+ upstreamInput: "u1",
+ upstreamErr: fmt.Errorf("unknown error"),
+ },
+ {
+ caseDesc: "update failed, update return error",
+ getCalled: true,
+ giveInput: &UpdateInput{
+ ID: "s1",
+ Service: entity.Service{
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ },
+ giveErr: fmt.Errorf("update failed"),
+ upstreamInput: "u1",
+ upstreamRet: entity.Upstream{
+ BaseInfo: entity.BaseInfo{
+ ID: "u1",
+ },
+ },
+ wantInput: &entity.Service{
+ BaseInfo: entity.BaseInfo{ID: "s1"},
+ Name: "s1",
+ UpstreamID: "u1",
+ Desc: "test service",
+ },
+ wantErr: fmt.Errorf("update failed"),
+ wantRet: handler.SpecCodeResponse(fmt.Errorf("update failed")),
+ },
+ }
- //list
- listInput11 := &ListInput{}
- reqBody = `{"page_size": 10, "page": 1}`
- err = json.Unmarshal([]byte(reqBody), listInput11)
- assert.Nil(t, err)
- ctx.SetInput(listInput11)
- _, err = handler.List(ctx)
- assert.Nil(t, err)
+ for _, tc := range tests {
+ t.Run(tc.caseDesc, func(t *testing.T) {
+ getCalled := false
+ serviceStore := &store.MockInterface{}
+ serviceStore.On("Update", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ getCalled = true
+ input := args.Get(1).(*entity.Service)
+ createIfNotExist := args.Get(2).(bool)
+ assert.Equal(t, tc.wantInput, input)
+ assert.True(t, createIfNotExist)
+ }).Return(tc.giveRet, tc.giveErr)
- //delete test data
- inputDel11 := &BatchDelete{}
- reqBody = `{"ids": "11"}`
- err = json.Unmarshal([]byte(reqBody), inputDel11)
- assert.Nil(t, err)
- ctx.SetInput(inputDel11)
- _, err = handler.BatchDelete(ctx)
- assert.Nil(t, err)
+ upstreamStore := &store.MockInterface{}
+ upstreamStore.On("Get", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ id := args.Get(0).(string)
+ assert.Equal(t, tc.upstreamInput, id)
+ }).Return(tc.upstreamRet, tc.upstreamErr)
+ h := Handler{serviceStore: serviceStore, upstreamStore: upstreamStore}
+ ctx := droplet.NewContext()
+ ctx.SetInput(tc.giveInput)
+ ret, err := h.Update(ctx)
+ assert.Equal(t, tc.getCalled, getCalled)
+ assert.Equal(t, tc.wantRet, ret)
+ assert.Equal(t, tc.wantErr, err)
+ })
+ }
}
-func TestService_Patch_Update(t *testing.T) {
- //create
- handler := &Handler{
- serviceStore: store.GetStore(store.HubKeyService),
+func TestService_Patch(t *testing.T) {
+ existService := &entity.Service{
+ BaseInfo: entity.BaseInfo{
+ ID: "s1",
+ CreateTime: 1609340491,
+ UpdateTime: 1609340491,
+ },
+ Name: "exist_service",
+ UpstreamID: "u1",
+ EnableWebsocket: false,
+ Labels: map[string]string{
+ "version": "v1",
+ },
+ Plugins: map[string]interface{}{
+ "limit-count": map[string]interface{}{
+ "count": 2,
+ "time_window": 60,
+ "rejected_code": 503,
+ "key": "remote_addr",
+ },
+ },
+ }
+
+ tests := []struct {
+ caseDesc string
+ giveInput *PatchInput
+ giveErr error
+ giveRet interface{}
+ wantInput *entity.Service
+ wantErr error
+ wantRet interface{}
+ serviceInput string
+ serviceRet *entity.Service
+ serviceErr error
+ called bool
+ }{
+ {
+ caseDesc: "patch all success",
+ giveInput: &PatchInput{
+ ID: "s1",
+ SubPath: "",
+ Body: []byte(`{
+ "name":"patched",
+ "upstream_id":"u2",
+ "enable_websocket":true,
+ "labels":{
+ "version":"v1",
+ "build":"16"
+ },
+ "plugins":{
+ "limit-count":{
+ "count":2,
+ "time_window":60,
+ "rejected_code": 504,
+ "key":"remote_addr"
+ },
+ "key-auth":{
+ "key":"auth-one"
+ }
+ }
+ }`),
+ },
+ wantInput: &entity.Service{
+ BaseInfo: entity.BaseInfo{
+ ID: "s1",
+ CreateTime: 1609340491,
+ UpdateTime: 1609340491,
+ },
+ Name: "patched",
+ UpstreamID: "u2",
+ EnableWebsocket: true,
+ Labels: map[string]string{
+ "version": "v1",
+ "build": "16",
+ },
+ Plugins: map[string]interface{}{
+ "limit-count": map[string]interface{}{
+ "count": float64(2),
+ "time_window": float64(60),
+ "rejected_code": float64(504),
+ "key": "remote_addr",
+ },
+ "key-auth": map[string]interface{}{
+ "key": "auth-one",
+ },
+ },
+ },
+ serviceInput: "s1",
+ serviceRet: existService,
+ called: true,
+ },
+ {
+ caseDesc: "patch part of service success",
+ giveInput: &PatchInput{
+ ID: "s1",
+ SubPath: "",
+ Body: []byte(`{
+ "name":"patched",
+ "upstream_id":"u2",
+ "enable_websocket":true,
+ "labels":{
+ "version":"v1",
+ "build":"16"
+ }
+ }`),
+ },
+ wantInput: &entity.Service{
+ BaseInfo: entity.BaseInfo{
+ ID: "s1",
+ CreateTime: 1609340491,
+ UpdateTime: 1609340491,
+ },
+ Name: "patched",
+ UpstreamID: "u2",
+ EnableWebsocket: true,
+ Labels: map[string]string{
+ "version": "v1",
+ "build": "16",
+ },
+ Plugins: map[string]interface{}{
+ "limit-count": map[string]interface{}{
+ "count": float64(2),
+ "time_window": float64(60),
+ "rejected_code": float64(503),
+ "key": "remote_addr",
+ },
+ },
+ },
+ serviceInput: "s1",
+ serviceRet: existService,
+ called: true,
+ },
+ {
+ caseDesc: "patch name success with sub path",
+ giveInput: &PatchInput{
+ ID: "s1",
+ SubPath: "/upstream_id",
+ Body: []byte(`{"upstream_id":"u3"}`),
+ },
+ wantInput: &entity.Service{
+ BaseInfo: entity.BaseInfo{
+ ID: "s1",
+ CreateTime: 1609340491,
+ UpdateTime: 1609340491,
+ },
+ Name: "exist_service",
+ UpstreamID: map[string]interface{}{
+ "upstream_id": "u3",
+ },
+ EnableWebsocket: false,
+ Labels: map[string]string{
+ "version": "v1",
+ },
+ Plugins: map[string]interface{}{
+ "limit-count": map[string]interface{}{
+ "count": float64(2),
+ "time_window": float64(60),
+ "rejected_code": float64(503),
+ "key": "remote_addr",
+ },
+ },
+ },
+ serviceInput: "s1",
+ serviceRet: existService,
+ called: true,
+ },
+ {
+ caseDesc: "patch labels success",
+ giveInput: &PatchInput{
+ ID: "s1",
+ SubPath: "/labels",
+ Body: []byte(`{"version": "v3"}`),
+ },
+ wantInput: &entity.Service{
+ BaseInfo: entity.BaseInfo{
+ ID: "s1",
+ CreateTime: 1609340491,
+ UpdateTime: 1609340491,
+ },
+ Name: "exist_service",
+ EnableWebsocket: false,
+ Labels: map[string]string{
+ "version": "v3",
+ },
+ UpstreamID: "u1",
+ Plugins: map[string]interface{}{
+ "limit-count": map[string]interface{}{
+ "count": float64(2),
+ "time_window": float64(60),
+ "rejected_code": float64(503),
+ "key": "remote_addr",
+ },
+ },
+ },
+ serviceInput: "s1",
+ serviceRet: existService,
+ called: true,
+ },
+ {
+ caseDesc: "patch failed, service store get error",
+ giveInput: &PatchInput{
+ ID: "s1",
+ Body: []byte{},
+ },
+ serviceInput: "s1",
+ serviceErr: fmt.Errorf("get error"),
+ wantRet: handler.SpecCodeResponse(fmt.Errorf("get error")),
+ wantErr: fmt.Errorf("get error"),
+ called: false,
+ },
}
- 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)
+ for _, tc := range tests {
+ t.Run(tc.caseDesc, func(t *testing.T) {
+ getCalled := false
+ serviceStore := &store.MockInterface{}
+ serviceStore.On("Update", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ getCalled = true
+ input := args.Get(1).(*entity.Service)
+ createIfNotExist := args.Get(2).(bool)
+ assert.Equal(t, tc.wantInput, input)
+ assert.False(t, createIfNotExist)
+ }).Return(tc.giveRet, tc.giveErr)
- 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"}`
+ serviceStore.On("Get", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ input := args.Get(0).(string)
+ assert.Equal(t, tc.serviceInput, input)
+ }).Return(tc.serviceRet, tc.serviceErr)
- input2 := &PatchInput{}
- input2.ID = "3"
- input2.SubPath = ""
- input2.Body = []byte(reqBody1)
- ctx.SetInput(input2)
+ h := Handler{serviceStore: serviceStore}
+ ctx := droplet.NewContext()
+ ctx.SetInput(tc.giveInput)
+ ret, err := h.Patch(ctx)
+ assert.Equal(t, tc.called, getCalled)
+ assert.Equal(t, tc.wantRet, ret)
+ assert.Equal(t, tc.wantErr, err)
+ })
+ }
+}
- 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)
+func TestServices_Delete(t *testing.T) {
+ tests := []struct {
+ caseDesc string
+ giveInput *BatchDelete
+ giveErr error
+ wantInput []string
+ wantErr error
+ wantRet interface{}
+ }{
+ {
+ caseDesc: "delete success",
+ giveInput: &BatchDelete{
+ IDs: "s1",
+ },
+ wantInput: []string{"s1"},
+ },
+ {
+ caseDesc: "batch delete success",
+ giveInput: &BatchDelete{
+ IDs: "s1,s2",
+ },
+ wantInput: []string{"s1", "s2"},
+ },
+ {
+ caseDesc: "delete failed",
+ giveInput: &BatchDelete{
+ IDs: "s1",
+ },
+ giveErr: fmt.Errorf("delete error"),
+ wantInput: []string{"s1"},
+ wantRet: handler.SpecCodeResponse(fmt.Errorf("delete error")),
+ wantErr: fmt.Errorf("delete error"),
+ },
+ }
- //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)
+ for _, tc := range tests {
+ t.Run(tc.caseDesc, func(t *testing.T) {
+ getCalled := false
+ serviceStore := &store.MockInterface{}
+ serviceStore.On("BatchDelete", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ getCalled = true
+ input := args.Get(1).([]string)
+ assert.Equal(t, tc.wantInput, input)
+ }).Return(tc.giveErr)
+ h := Handler{serviceStore: serviceStore}
+ ctx := droplet.NewContext()
+ ctx.SetInput(tc.giveInput)
+ ret, err := h.BatchDelete(ctx)
+ assert.True(t, getCalled)
+ assert.Equal(t, tc.wantRet, ret)
+ assert.Equal(t, tc.wantErr, err)
+ })
+ }
}
-