This is an automated email from the ASF dual-hosted git repository.
chenjunxu 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 4b894cf feat: support labels list (#1072)
4b894cf is described below
commit 4b894cfd3fb7280b500249b9f6457d04867c42d9
Author: Peter Zhu <[email protected]>
AuthorDate: Mon Dec 21 16:49:11 2020 +0800
feat: support labels list (#1072)
* feat: support labels list
---
api/internal/handler/label/label.go | 261 ++++++++++++++++++++++++
api/internal/handler/label/label_test.go | 336 +++++++++++++++++++++++++++++++
api/internal/route.go | 2 +
api/test/e2e/label_test.go | 269 +++++++++++++++++++++++++
4 files changed, 868 insertions(+)
diff --git a/api/internal/handler/label/label.go
b/api/internal/handler/label/label.go
new file mode 100644
index 0000000..93ff0de
--- /dev/null
+++ b/api/internal/handler/label/label.go
@@ -0,0 +1,261 @@
+/*
+ * 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 label
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+
+ "github.com/gin-gonic/gin"
+ "github.com/shiningrush/droplet"
+ "github.com/shiningrush/droplet/data"
+ "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"
+ "github.com/apisix/manager-api/internal/utils"
+)
+
+type Handler struct {
+ routeStore store.Interface
+ serviceStore store.Interface
+ upstreamStore store.Interface
+ sslStore store.Interface
+ consumerStore store.Interface
+}
+
+var _ json.Marshaler = Pair{}
+
+type Pair struct {
+ Key string
+ Val string
+}
+
+func (p Pair) MarshalJSON() ([]byte, error) {
+ res := fmt.Sprintf("{%s:%s}", strconv.Quote(p.Key),
strconv.Quote(p.Val))
+ return []byte(res), nil
+}
+
+func NewHandler() (handler.RouteRegister, error) {
+ return &Handler{
+ routeStore: store.GetStore(store.HubKeyRoute),
+ serviceStore: store.GetStore(store.HubKeyService),
+ upstreamStore: store.GetStore(store.HubKeyUpstream),
+ sslStore: store.GetStore(store.HubKeySsl),
+ consumerStore: store.GetStore(store.HubKeyConsumer),
+ }, nil
+}
+
+func (h *Handler) ApplyRoute(r *gin.Engine) {
+ r.GET("/apisix/admin/labels/:type", wgin.Wraps(h.List,
+ wrapper.InputType(reflect.TypeOf(ListInput{}))))
+}
+
+type ListInput struct {
+ store.Pagination
+ Type string `auto_read:"type,path" validate:"required"`
+ Label string `auto_read:"label,query"`
+}
+
+func subsetOf(reqLabels, labels map[string]string) map[string]string {
+ if len(reqLabels) == 0 {
+ return labels
+ }
+
+ var res = make(map[string]string)
+ for k, v := range labels {
+ l, exist := reqLabels[k]
+ if exist && ((l == "") || v == l) {
+ res[k] = v
+ }
+ }
+
+ return res
+}
+
+// swagger:operation GET /api/labels getLabelsList
+//
+// Return the labels list among `route,ssl,consumer,upstream,service`
+// according to the specified page number and page size, and can search labels
by label.
+//
+// ---
+// produces:
+// - application/json
+// parameters:
+// - name: page
+// in: query
+// description: page number
+// required: false
+// type: integer
+// - name: page_size
+// in: query
+// description: page size
+// required: false
+// type: integer
+// - name: label
+// in: query
+// description: label filter of labels
+// required: false
+// type: string
+// responses:
+// '0':
+// description: list response
+// schema:
+// type: array
+// items:
+// "$ref": "#/definitions/service"
+// default:
+// description: unexpected error
+// schema:
+// "$ref": "#/definitions/ApiError"
+func (h *Handler) List(c droplet.Context) (interface{}, error) {
+ input := c.Input().(*ListInput)
+
+ typ := input.Type
+ reqLabels, err := utils.GenLabelMap(input.Label)
+ if err != nil {
+ return &data.SpecCodeResponse{StatusCode:
http.StatusBadRequest},
+ fmt.Errorf("%s: \"%s\"", err.Error(), input.Label)
+ }
+
+ var items []interface{}
+ switch typ {
+ case "route":
+ items = append(items, h.routeStore)
+ case "service":
+ items = append(items, h.serviceStore)
+ case "consumer":
+ items = append(items, h.consumerStore)
+ case "ssl":
+ items = append(items, h.sslStore)
+ case "upstream":
+ items = append(items, h.upstreamStore)
+ case "all":
+ items = append(items, h.routeStore, h.serviceStore,
h.upstreamStore,
+ h.sslStore, h.consumerStore)
+ }
+
+ predicate := func(obj interface{}) bool {
+ var ls map[string]string
+
+ switch obj := obj.(type) {
+ case *entity.Route:
+ ls = obj.Labels
+ case *entity.Consumer:
+ ls = obj.Labels
+ case *entity.SSL:
+ ls = obj.Labels
+ case *entity.Service:
+ ls = obj.Labels
+ case *entity.Upstream:
+ ls = obj.Labels
+ default:
+ return false
+ }
+
+ return utils.LabelContains(ls, reqLabels)
+ }
+
+ format := func(obj interface{}) interface{} {
+ val := reflect.ValueOf(obj).Elem()
+ l := val.FieldByName("Labels")
+ if l.IsNil() {
+ return nil
+ }
+
+ ls := l.Interface().(map[string]string)
+ return subsetOf(reqLabels, ls)
+ }
+
+ var totalRet = new(store.ListOutput)
+ var existMap = make(map[string]struct{})
+ for _, item := range items {
+ ret, err := item.(store.Interface).List(
+ store.ListInput{
+ Predicate: predicate,
+ Format: format,
+ // Sort it later.
+ PageSize: 0,
+ PageNumber: 0,
+ Less: func(i, j interface{}) bool {
+ return true
+ },
+ },
+ )
+
+ if err != nil {
+ return nil, err
+ }
+
+ for _, r := range ret.Rows {
+ if r == nil {
+ continue
+ }
+
+ for k, v := range r.(map[string]string) {
+ key := fmt.Sprintf("%s:%s", k, v)
+ if _, exist := existMap[key]; exist {
+ continue
+ }
+
+ existMap[key] = struct{}{}
+ p := Pair{Key: k, Val: v}
+ totalRet.Rows = append(totalRet.Rows, p)
+ }
+ }
+ }
+ totalRet.TotalSize = len(totalRet.Rows)
+
+ sort.Slice(totalRet.Rows, func(i, j int) bool {
+ p1 := totalRet.Rows[i].(Pair)
+ p2 := totalRet.Rows[j].(Pair)
+
+ if strings.Compare(p1.Key, p2.Key) == 0 {
+ return strings.Compare(p1.Val, p2.Val) < 0
+ }
+
+ return strings.Compare(p1.Key, p2.Key) < 0
+ })
+
+ /* There are more than one store items,
+ So we need sort after getting all of labels.
+ */
+ if input.PageSize > 0 && input.PageNumber > 0 {
+ skipCount := (input.PageNumber - 1) * input.PageSize
+ if skipCount > totalRet.TotalSize {
+ totalRet.Rows = []interface{}{}
+ return totalRet, nil
+ }
+
+ endIdx := skipCount + input.PageSize
+ if endIdx >= totalRet.TotalSize {
+ totalRet.Rows = totalRet.Rows[skipCount:]
+ return totalRet, nil
+ }
+
+ totalRet.Rows = totalRet.Rows[skipCount:endIdx]
+ }
+
+ return totalRet, nil
+}
diff --git a/api/internal/handler/label/label_test.go
b/api/internal/handler/label/label_test.go
new file mode 100644
index 0000000..1d0205b
--- /dev/null
+++ b/api/internal/handler/label/label_test.go
@@ -0,0 +1,336 @@
+/*
+ * 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 label
+
+import (
+ "encoding/json"
+ "math/rand"
+ "testing"
+
+ "github.com/shiningrush/droplet"
+ "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"
+)
+
+type testCase struct {
+ giveInput *ListInput
+ giveData []interface{}
+ wantRet interface{}
+}
+
+func TestPair_MarshalJSON(t *testing.T) {
+ type tempStruct struct {
+ Val string `json:"test_key"`
+ }
+
+ temp := tempStruct{Val: "test_val"}
+ expect, err := json.Marshal(temp)
+ assert.Nil(t, err)
+
+ p := Pair{Key: "test_key", Val: `test_val`}
+ content, err := json.Marshal(p)
+ assert.Nil(t, err, nil)
+ assert.Equal(t, expect, content)
+
+ mp := make(map[string]string)
+ err = json.Unmarshal(content, &mp)
+ assert.Nil(t, err)
+ assert.Equal(t, mp["test_key"], "test_val")
+
+ // Because the quote in json key is not allowed.
+ // So we only test the quote in json value.
+ temp = tempStruct{Val: "test_val\""}
+ expect, err = json.Marshal(temp)
+ assert.Nil(t, err)
+
+ p = Pair{Key: "test_key", Val: `test_val"`}
+ content, err = json.Marshal(p)
+ assert.Nil(t, err, nil)
+ assert.Equal(t, expect, content)
+
+ mp = make(map[string]string)
+ err = json.Unmarshal(content, &mp)
+ assert.Nil(t, err)
+ assert.Equal(t, mp["test_key"], "test_val\"")
+}
+
+func genMockStore(t *testing.T, giveData []interface{}) *store.MockInterface {
+ mStore := &store.MockInterface{}
+ mStore.On("List", mock.Anything).Run(func(args mock.Arguments) {
+ input := args.Get(0).(store.ListInput)
+ assert.Equal(t, 0, input.PageSize)
+ assert.Equal(t, 0, input.PageNumber)
+ }).Return(func(input store.ListInput) *store.ListOutput {
+ var returnData []interface{}
+ for _, c := range giveData {
+ if input.Predicate(c) {
+ returnData = append(returnData, input.Format(c))
+ }
+ }
+ return &store.ListOutput{
+ Rows: returnData,
+ TotalSize: len(returnData),
+ }
+ }, nil)
+
+ return mStore
+}
+
+func newCase(giveData []interface{}, ret []interface{}) *testCase {
+ t := testCase{}
+ t.giveInput = &ListInput{
+ Pagination: store.Pagination{
+ PageSize: 10,
+ PageNumber: 1,
+ },
+ }
+
+ t.giveData = giveData
+ t.wantRet = &store.ListOutput{
+ Rows: ret,
+ TotalSize: len(ret),
+ }
+
+ return &t
+}
+
+func genRoute(labels map[string]string) *entity.Route {
+ r := entity.Route{
+ BaseInfo: entity.BaseInfo{
+ ID: rand.Int(),
+ CreateTime: rand.Int63(),
+ },
+ Host: "test.com",
+ URI: "/test/route",
+ Labels: labels,
+ }
+
+ return &r
+}
+
+func genService(labels map[string]string) *entity.Service {
+ r := entity.Service{
+ BaseInfo: entity.BaseInfo{
+ ID: rand.Int(),
+ CreateTime: rand.Int63(),
+ },
+ EnableWebsocket: true,
+ Labels: labels,
+ }
+
+ return &r
+}
+
+func genSSL(labels map[string]string) *entity.SSL {
+ r := entity.SSL{
+ BaseInfo: entity.BaseInfo{
+ ID: rand.Int(),
+ CreateTime: rand.Int63(),
+ },
+ Labels: labels,
+ }
+
+ return &r
+}
+
+func genUpstream(labels map[string]string) *entity.Upstream {
+ r := entity.Upstream{
+ BaseInfo: entity.BaseInfo{
+ ID: rand.Int(),
+ CreateTime: rand.Int63(),
+ },
+ UpstreamDef: entity.UpstreamDef{
+ Labels: labels,
+ },
+ }
+
+ return &r
+}
+
+func genConsumer(labels map[string]string) *entity.Consumer {
+ r := entity.Consumer{
+ BaseInfo: entity.BaseInfo{
+ ID: rand.Int(),
+ CreateTime: rand.Int63(),
+ },
+ Username: "test",
+ Labels: labels,
+ }
+
+ return &r
+}
+
+func TestLabel(t *testing.T) {
+ m1 := map[string]string{
+ "label1": "value1",
+ "label2": "value2",
+ }
+
+ m2 := map[string]string{
+ "label1": "value2",
+ }
+
+ // TODO: Test SSL after the ssl config bug fixed
+ types := []string{"route", "service", "upstream", "consumer"}
+
+ var giveData []interface{}
+ for _, typ := range types {
+ switch typ {
+ case "route":
+ giveData = []interface{}{
+ genRoute(m1),
+ genRoute(m2),
+ }
+ case "service":
+ giveData = []interface{}{
+ genService(m1),
+ genService(m2),
+ }
+ case "ssl":
+ giveData = []interface{}{
+ genSSL(m1),
+ genSSL(m2),
+ }
+ case "upstream":
+ giveData = []interface{}{
+ genUpstream(m1),
+ genUpstream(m2),
+ }
+ case "consumer":
+ giveData = []interface{}{
+ genConsumer(m1),
+ genConsumer(m2),
+ }
+ }
+
+ expect := []interface{}{
+ Pair{"label1", "value1"},
+ Pair{"label1", "value2"},
+ Pair{"label2", "value2"},
+ }
+ case1 := newCase(giveData, expect)
+ case1.giveInput.Type = typ
+
+ expect = []interface{}{
+ Pair{"label1", "value1"},
+ Pair{"label1", "value2"},
+ }
+ case2 := newCase(giveData, expect)
+ case2.giveInput.Type = typ
+ case2.giveInput.Label = "label1"
+
+ expect = []interface{}{
+ Pair{"label1", "value2"},
+ }
+ case3 := newCase(giveData, expect)
+ case3.giveInput.Type = typ
+ case3.giveInput.Label = "label1:value2"
+
+ testCases := []*testCase{case1, case2, case3}
+ handler := Handler{}
+ for _, tc := range testCases {
+ switch typ {
+ case "route":
+ handler.routeStore = genMockStore(t,
tc.giveData)
+ case "service":
+ handler.serviceStore = genMockStore(t,
tc.giveData)
+ case "ssl":
+ handler.sslStore = genMockStore(t, tc.giveData)
+ case "upstream":
+ handler.upstreamStore = genMockStore(t,
tc.giveData)
+ case "consumer":
+ handler.consumerStore = genMockStore(t,
tc.giveData)
+ }
+
+ ctx := droplet.NewContext()
+ ctx.SetInput(tc.giveInput)
+ ret, err := handler.List(ctx)
+ assert.Nil(t, err)
+ assert.Equal(t, tc.wantRet, ret)
+ }
+ }
+
+ // test all
+ m3 := map[string]string{
+ "label3": "value3",
+ }
+
+ m4 := map[string]string{
+ "label4": "value4",
+ }
+
+ m5 := map[string]string{
+ "label4": "value4",
+ "label5": "value5",
+ }
+
+ handler := Handler{
+ routeStore: genMockStore(t, []interface{}{genRoute(m1)}),
+ sslStore: genMockStore(t, []interface{}{genSSL(m2)}),
+ upstreamStore: genMockStore(t, []interface{}{genUpstream(m3)}),
+ consumerStore: genMockStore(t, []interface{}{genConsumer(m4)}),
+ serviceStore: genMockStore(t, []interface{}{genService(m5)}),
+ }
+
+ expect := []interface{}{
+ Pair{"label1", "value1"},
+ Pair{"label1", "value2"},
+ Pair{"label2", "value2"},
+ Pair{"label3", "value3"},
+ Pair{"label4", "value4"},
+ Pair{"label5", "value5"},
+ }
+ case1 := newCase(nil, expect)
+ case1.giveInput.Type = "all"
+
+ expect = []interface{}{
+ Pair{"label1", "value1"},
+ Pair{"label1", "value2"},
+ }
+ case2 := newCase(nil, expect)
+ case2.giveInput.Type = "all"
+ case2.giveInput.Label = "label1"
+
+ expect = []interface{}{
+ Pair{"label1", "value2"},
+ }
+ case3 := newCase(nil, expect)
+ case3.giveInput.Type = "all"
+ case3.giveInput.Label = "label1:value2"
+
+ expect = []interface{}{
+ Pair{"label1", "value1"},
+ Pair{"label1", "value2"},
+ Pair{"label5", "value5"},
+ }
+ case4 := newCase(nil, expect)
+ case4.giveInput.Type = "all"
+ case4.giveInput.Label = "label1,label5:value5"
+
+ testcase := []*testCase{case1, case2, case3, case4}
+ for _, tc := range testcase {
+ ctx := droplet.NewContext()
+ ctx.SetInput(tc.giveInput)
+ ret, err := handler.List(ctx)
+ assert.Nil(t, err)
+ assert.Equal(t, tc.wantRet, ret)
+ }
+}
diff --git a/api/internal/route.go b/api/internal/route.go
index 801f369..3e38ea1 100644
--- a/api/internal/route.go
+++ b/api/internal/route.go
@@ -32,6 +32,7 @@ import (
"github.com/apisix/manager-api/internal/handler/authentication"
"github.com/apisix/manager-api/internal/handler/consumer"
"github.com/apisix/manager-api/internal/handler/healthz"
+ "github.com/apisix/manager-api/internal/handler/label"
"github.com/apisix/manager-api/internal/handler/plugin"
"github.com/apisix/manager-api/internal/handler/route"
"github.com/apisix/manager-api/internal/handler/route_online_debug"
@@ -69,6 +70,7 @@ func SetUpRouter() *gin.Engine {
authentication.NewHandler,
route_online_debug.NewHandler,
server_info.NewHandler,
+ label.NewHandler,
}
for i := range factories {
diff --git a/api/test/e2e/label_test.go b/api/test/e2e/label_test.go
new file mode 100644
index 0000000..4fe5713
--- /dev/null
+++ b/api/test/e2e/label_test.go
@@ -0,0 +1,269 @@
+/*
+ * 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 e2e
+
+import (
+ "net/http"
+ "testing"
+)
+
+func TestLabel(t *testing.T) {
+ // Todo: test ssl after ssl bug fixed
+ tests := []HttpTestCase{
+ {
+ caseDesc: "config route",
+ Object: ManagerApiExpect(t),
+ Path: "/apisix/admin/routes/r1",
+ Method: http.MethodPut,
+ Body: `{
+ "uri": "/hello",
+ "labels": {
+ "build":"16",
+ "env":"production",
+ "version":"v2"
+ },
+ "upstream": {
+ "type": "roundrobin",
+ "nodes": [{
+ "host": "172.16.238.20",
+ "port": 1980,
+ "weight": 1
+ }]
+ }
+ }`,
+ Headers: map[string]string{"Authorization": token},
+ ExpectStatus: http.StatusOK,
+ },
+ {
+ caseDesc: "create consumer",
+ Object: ManagerApiExpect(t),
+ Path: "/apisix/admin/consumers/c1",
+ Method: http.MethodPut,
+ Body: `{
+ "username": "jack",
+ "plugins": {
+ "key-auth": {
+ "key": "auth-one"
+ }
+ },
+ "labels": {
+ "build":"16",
+ "env":"production",
+ "version":"v3"
+ },
+ "desc": "test description"
+ }`,
+ Headers: map[string]string{"Authorization": token},
+ ExpectStatus: http.StatusOK,
+ },
+ {
+ caseDesc: "create upstream",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodPut,
+ Path: "/apisix/admin/upstreams/u1",
+ Body: `{
+ "nodes": [{
+ "host": "172.16.238.20",
+ "port": 1980,
+ "weight": 1
+ }],
+ "labels": {
+ "build":"17",
+ "env":"production",
+ "version":"v2"
+ },
+ "type": "roundrobin"
+ }`,
+ Headers: map[string]string{"Authorization": token},
+ ExpectStatus: http.StatusOK,
+ },
+ {
+ caseDesc: "create service",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodPost,
+ Path: "/apisix/admin/services",
+ Body: `{
+ "id": "s1",
+ "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
+ }]
+ },
+ "labels": {
+ "build":"16",
+ "env":"production",
+ "version":"v2",
+ "extra": "test"
+ }
+ }`,
+ Headers: map[string]string{"Authorization": token},
+ ExpectStatus: http.StatusOK,
+ },
+ {
+ caseDesc: "get route label",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Headers: map[string]string{"Authorization": token},
+ Path: "/apisix/admin/labels/route",
+ ExpectStatus: http.StatusOK,
+ ExpectBody:
"{\"build\":\"16\"},{\"env\":\"production\"},{\"version\":\"v2\"}",
+ },
+ {
+ caseDesc: "get consumer label",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Headers: map[string]string{"Authorization": token},
+ Path: "/apisix/admin/labels/consumer",
+ ExpectStatus: http.StatusOK,
+ ExpectBody:
"{\"build\":\"16\"},{\"env\":\"production\"},{\"version\":\"v3\"}",
+ },
+ {
+ caseDesc: "get upstream label",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Headers: map[string]string{"Authorization": token},
+ Path: "/apisix/admin/labels/upstream",
+ ExpectStatus: http.StatusOK,
+ ExpectBody:
"{\"build\":\"17\"},{\"env\":\"production\"},{\"version\":\"v2\"}",
+ },
+ {
+ caseDesc: "get service label",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Headers: map[string]string{"Authorization": token},
+ Path: "/apisix/admin/labels/service",
+ ExpectStatus: http.StatusOK,
+ ExpectBody:
"{\"build\":\"16\"},{\"env\":\"production\"},{\"extra\":\"test\"},{\"version\":\"v2\"}",
+ },
+ {
+ caseDesc: "get all label",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Headers: map[string]string{"Authorization": token},
+ Path: "/apisix/admin/labels/all",
+ ExpectStatus: http.StatusOK,
+ ExpectBody:
"{\"build\":\"16\"},{\"build\":\"17\"},{\"env\":\"production\"},{\"extra\":\"test\"},{\"version\":\"v2\"},{\"version\":\"v3\"}",
+ },
+ {
+ caseDesc: "get label with page",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Query: "page=1&page_size=1",
+ Headers: map[string]string{"Authorization": token},
+ Path: "/apisix/admin/labels/all",
+ ExpectStatus: http.StatusOK,
+ ExpectBody: "{\"build\":\"16\"}",
+ },
+ {
+ caseDesc: "get label with page",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Query: "page=3&page_size=1",
+ Headers: map[string]string{"Authorization": token},
+ Path: "/apisix/admin/labels/all",
+ ExpectStatus: http.StatusOK,
+ ExpectBody: "{\"env\":\"production\"}",
+ },
+ {
+ caseDesc: "get labels (key = build)",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Headers: map[string]string{"Authorization": token},
+ Query: "label=build",
+ Path: "/apisix/admin/labels/all",
+ ExpectStatus: http.StatusOK,
+ ExpectBody: "{\"build\":\"16\"},{\"build\":\"17\"}",
+ },
+ {
+ caseDesc: "get labels (key = build) with page",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Headers: map[string]string{"Authorization": token},
+ Query: "label=build&page=2&page_size=1",
+ Path: "/apisix/admin/labels/all",
+ ExpectStatus: http.StatusOK,
+ ExpectBody: "{\"build\":\"17\"}",
+ },
+ {
+ caseDesc: "get labels (key = build && env =
production)",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Headers: map[string]string{"Authorization": token},
+ Query: "label=build,env:production",
+ Path: "/apisix/admin/labels/all",
+ ExpectStatus: http.StatusOK,
+ ExpectBody:
"{\"build\":\"16\"},{\"build\":\"17\"},{\"env\":\"production\"}",
+ },
+ {
+ caseDesc: "get labels (key = build && env =
production) with page",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodGet,
+ Headers: map[string]string{"Authorization": token},
+ Query:
"label=build,env:production&page=3&page_size=1",
+ Path: "/apisix/admin/labels/all",
+ ExpectStatus: http.StatusOK,
+ ExpectBody: "{\"env\":\"production\"}",
+ },
+ {
+ caseDesc: "delete route",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodDelete,
+ Path: "/apisix/admin/routes/r1",
+ Headers: map[string]string{"Authorization": token},
+ ExpectStatus: http.StatusOK,
+ },
+ {
+ caseDesc: "delete consumer",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodDelete,
+ Path: "/apisix/admin/consumers/c1",
+ Headers: map[string]string{"Authorization": token},
+ ExpectStatus: http.StatusOK,
+ },
+ {
+ caseDesc: "delete service",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodDelete,
+ Path: "/apisix/admin/services/s1",
+ Headers: map[string]string{"Authorization": token},
+ ExpectStatus: http.StatusOK,
+ },
+ {
+ caseDesc: "delete upstream",
+ Object: ManagerApiExpect(t),
+ Method: http.MethodDelete,
+ Path: "/apisix/admin/upstreams/u1",
+ Headers: map[string]string{"Authorization": token},
+ ExpectStatus: http.StatusOK,
+ },
+ }
+
+ for _, tc := range tests {
+ testCaseCheck(tc)
+ }
+}