You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ti...@apache.org on 2019/12/31 10:13:35 UTC

[servicecomb-kie] branch master updated: SCB-1699 support match pattern (#60)

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

tianxiaoliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git


The following commit(s) were added to refs/heads/master by this push:
     new f35cbba  SCB-1699 support match pattern (#60)
f35cbba is described below

commit f35cbba3fe4c94072a4067bea6194bdae299033d
Author: Shawn <xi...@gmail.com>
AuthorDate: Tue Dec 31 18:13:29 2019 +0800

    SCB-1699 support match pattern (#60)
---
 pkg/common/common.go                        |   1 +
 server/resource/v1/common.go                |  19 +++-
 server/resource/v1/doc_struct.go            |  10 ++
 server/resource/v1/history_resource_test.go |   2 +-
 server/resource/v1/kv_resource.go           |   5 +-
 server/resource/v1/kv_resource_test.go      | 159 +++++++++++++++-------------
 server/resource/v1/v1_suite_test.go         |  34 ------
 server/service/mongo/kv/kv_dao.go           |   3 -
 server/service/mongo/kv/kv_service.go       |   5 +
 9 files changed, 124 insertions(+), 114 deletions(-)

diff --git a/pkg/common/common.go b/pkg/common/common.go
index 05b7ae3..22ab5a3 100644
--- a/pkg/common/common.go
+++ b/pkg/common/common.go
@@ -22,6 +22,7 @@ const (
 	QueryParamQ      = "q"
 	QueryByLabelsCon = "&"
 	QueryParamWait   = "wait"
+	QueryParamMatch  = "match"
 )
 
 //http headers
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index 4cd6d1a..2db72c9 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -40,6 +40,7 @@ import (
 
 //const of server
 const (
+	PatternExact            = "exact"
 	MsgDomainMustNotBeEmpty = "domain must not be empty"
 	MsgIllegalLabels        = "label value can not be empty, " +
 		"label can not be duplicated, please check query parameters"
@@ -155,6 +156,14 @@ func getWaitDuration(rctx *restful.Context) string {
 	}
 	return wait
 }
+func getMatchPattern(rctx *restful.Context) string {
+	m := rctx.ReadQueryParameter(common.QueryParamMatch)
+
+	if m != "" && m != PatternExact {
+		return ""
+	}
+	return m
+}
 func wait(d time.Duration, rctx *restful.Context, topic *pubsub.Topic) bool {
 	changed := true
 	if d != 0 {
@@ -197,9 +206,15 @@ func checkPagination(limitStr, offsetStr string) (int64, int64, error) {
 	}
 	return limit, offset, err
 }
-func queryAndResponse(rctx *restful.Context, domain interface{}, project string, key string, labels map[string]string, limit, offset int) {
+func queryAndResponse(rctx *restful.Context,
+	domain interface{}, project string, key string, labels map[string]string, limit, offset int) {
+	m := getMatchPattern(rctx)
+	opts := []service.FindOption{service.WithKey(key), service.WithLabels(labels)}
+	if m == PatternExact {
+		opts = append(opts, service.WithExactLabels())
+	}
 	kv, err := service.KVService.List(rctx.Ctx, domain.(string), project,
-		limit, offset, service.WithKey(key), service.WithLabels(labels))
+		limit, offset, opts...)
 	if err != nil {
 		if err == service.ErrKeyNotExists {
 			WriteErrResponse(rctx, http.StatusNotFound, err.Error(), common.ContentTypeText)
diff --git a/server/resource/v1/doc_struct.go b/server/resource/v1/doc_struct.go
index 9b6ecf4..6a00529 100644
--- a/server/resource/v1/doc_struct.go
+++ b/server/resource/v1/doc_struct.go
@@ -48,10 +48,20 @@ var (
 		DataType:  "string",
 		Name:      common.QueryParamWait,
 		ParamType: goRestful.QueryParameterKind,
+		Required:  false,
 		Desc: "wait until any kv changed. " +
 			"for example wait=5s, server will not response until 5 seconds during that time window, " +
 			"if any kv changed, server will return 200 and kv list, otherwise return 304 and empty body",
 	}
+	DocQueryMatch = &restful.Parameters{
+		DataType:  "string",
+		Name:      common.QueryParamMatch,
+		ParamType: goRestful.QueryParameterKind,
+		Required:  false,
+		Desc: "match works with label query param, it specifies label match pattern. " +
+			"if it is empty, server will return kv which's labels partial match the label query param. " +
+			"uf it is exact, server will return kv which's labels exact match the label query param",
+	}
 	DocQueryKVIDParameters = &restful.Parameters{
 		DataType:  "string",
 		Name:      "kvID",
diff --git a/server/resource/v1/history_resource_test.go b/server/resource/v1/history_resource_test.go
index c431614..c088f09 100644
--- a/server/resource/v1/history_resource_test.go
+++ b/server/resource/v1/history_resource_test.go
@@ -77,7 +77,7 @@ var _ = Describe("v1 history resource", func() {
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
 			})
-			data := []*model.LabelRevisionDoc{}
+			data := make([]*model.LabelRevisionDoc, 0)
 			err = json.Unmarshal(body, &data)
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
index 0ac5751..c56b356 100644
--- a/server/resource/v1/kv_resource.go
+++ b/server/resource/v1/kv_resource.go
@@ -279,8 +279,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			ResourceFunc: r.GetByKey,
 			FuncDesc:     "get key values by key and labels",
 			Parameters: []*restful.Parameters{
-				DocPathProject, DocPathKey,
-				DocQueryLabelParameters,
+				DocPathProject, DocPathKey, DocQueryLabelParameters, DocQueryMatch,
 			},
 			Returns: []*restful.Returns{
 				{
@@ -316,7 +315,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			ResourceFunc: r.List,
 			FuncDesc:     "list key values by labels and key",
 			Parameters: []*restful.Parameters{
-				DocPathProject, DocQueryLabelParameters, DocQueryWait,
+				DocPathProject, DocQueryLabelParameters, DocQueryWait, DocQueryMatch,
 			},
 			Returns: []*restful.Returns{
 				{
diff --git a/server/resource/v1/kv_resource_test.go b/server/resource/v1/kv_resource_test.go
index dc1de85..4787753 100644
--- a/server/resource/v1/kv_resource_test.go
+++ b/server/resource/v1/kv_resource_test.go
@@ -20,34 +20,32 @@ package v1_test
 import (
 	"bytes"
 	"encoding/json"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/apache/servicecomb-kie/server/config"
+	handler2 "github.com/apache/servicecomb-kie/server/handler"
 	"github.com/apache/servicecomb-kie/server/pubsub"
+	v1 "github.com/apache/servicecomb-kie/server/resource/v1"
 	"github.com/apache/servicecomb-kie/server/service"
+	"github.com/go-chassis/go-chassis/core/common"
+	"github.com/go-chassis/go-chassis/core/handler"
+	"github.com/go-chassis/go-chassis/server/restful/restfultest"
 	log "github.com/go-chassis/paas-lager"
 	"github.com/go-mesh/openlogging"
+	"github.com/stretchr/testify/assert"
 	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
+	"testing"
 
-	"github.com/go-chassis/go-chassis/core/common"
-	"github.com/go-chassis/go-chassis/core/handler"
-	"github.com/go-chassis/go-chassis/server/restful/restfultest"
-	. "github.com/onsi/ginkgo"
-	. "github.com/onsi/gomega"
-
-	"github.com/apache/servicecomb-kie/pkg/model"
-	"github.com/apache/servicecomb-kie/server/config"
-	noop "github.com/apache/servicecomb-kie/server/handler"
-	v1 "github.com/apache/servicecomb-kie/server/resource/v1"
 	_ "github.com/apache/servicecomb-kie/server/service/mongo"
 )
 
-var _ = Describe("v1 kv resource", func() {
+func TestKVResource_List(t *testing.T) {
 	log.Init(log.Config{
 		Writers:       []string{"stdout"},
 		LoggerLevel:   "DEBUG",
 		LogFormatText: false,
 	})
-
 	logger := log.NewLogger("ut")
 	openlogging.SetLogger(logger)
 	//for UT
@@ -63,66 +61,85 @@ var _ = Describe("v1 kv resource", func() {
 	}
 	pubsub.Init()
 	pubsub.Start()
-	Describe("put kv", func() {
-		Context("valid param", func() {
-			kv := &model.KVDoc{
-				Value:  "1s",
-				Labels: map[string]string{"service": "tester"},
-			}
-			j, _ := json.Marshal(kv)
-			r, _ := http.NewRequest("PUT", "/v1/test/kie/kv/timeout", bytes.NewBuffer(j))
-			noopH := &noop.NoopAuthHandler{}
-			chain, _ := handler.CreateChain(common.Provider, "testchain1", noopH.Name())
-			r.Header.Set("Content-Type", "application/json")
-			kvr := &v1.KVResource{}
-			c, _ := restfultest.New(kvr, chain)
-			resp := httptest.NewRecorder()
-			c.ServeHTTP(resp, r)
-
-			body, err := ioutil.ReadAll(resp.Body)
-			It("should not return err", func() {
-				Expect(err).Should(BeNil())
-			})
+	t.Run("put kv, label is service", func(t *testing.T) {
+		kv := &model.KVDoc{
+			Value:  "1s",
+			Labels: map[string]string{"service": "utService"},
+		}
+		j, _ := json.Marshal(kv)
+		r, _ := http.NewRequest("PUT", "/v1/test/kie/kv/timeout", bytes.NewBuffer(j))
+		noopH := &handler2.NoopAuthHandler{}
+		chain, _ := handler.CreateChain(common.Provider, "testchain1", noopH.Name())
+		r.Header.Set("Content-Type", "application/json")
+		kvr := &v1.KVResource{}
+		c, _ := restfultest.New(kvr, chain)
+		resp := httptest.NewRecorder()
+		c.ServeHTTP(resp, r)
 
-			data := &model.KVDoc{}
-			err = json.Unmarshal(body, data)
-			It("should not return err", func() {
-				Expect(err).Should(BeNil())
-			})
-
-			It("should return created or updated kv", func() {
-				Expect(data.Value).Should(Equal(kv.Value))
-				Expect(data.Labels).Should(Equal(kv.Labels))
-			})
-		})
+		body, err := ioutil.ReadAll(resp.Body)
+		assert.NoError(t, err)
+		data := &model.KVDoc{}
+		err = json.Unmarshal(body, data)
+		assert.NoError(t, err)
+		assert.NotEmpty(t, data.ID)
+		assert.Equal(t, kv.Value, data.Value)
+		assert.Equal(t, kv.Labels, data.Labels)
 	})
-	Describe("list kv", func() {
-		Context("with no label", func() {
-			r, _ := http.NewRequest("GET", "/v1/test/kie/kv?label=service:tester", nil)
-			noopH := &noop.NoopAuthHandler{}
-			chain, _ := handler.CreateChain(common.Provider, "testchain1", noopH.Name())
-			r.Header.Set("Content-Type", "application/json")
-			kvr := &v1.KVResource{}
-			c, err := restfultest.New(kvr, chain)
-			It("should not return error", func() {
-				Expect(err).Should(BeNil())
-			})
-			resp := httptest.NewRecorder()
-			c.ServeHTTP(resp, r)
-
-			body, err := ioutil.ReadAll(resp.Body)
-			It("should not return err", func() {
-				Expect(err).Should(BeNil())
-			})
-			result := &model.KVResponse{}
-			err = json.Unmarshal(body, result)
-			It("should not return err", func() {
-				Expect(err).Should(BeNil())
-			})
+	t.Run("put kv,label is service and version", func(t *testing.T) {
+		kv := &model.KVDoc{
+			Value: "1s",
+			Labels: map[string]string{"service": "utService",
+				"version": "1.0.0"},
+		}
+		j, _ := json.Marshal(kv)
+		r, _ := http.NewRequest("PUT", "/v1/test/kie/kv/timeout", bytes.NewBuffer(j))
+		noopH := &handler2.NoopAuthHandler{}
+		chain, _ := handler.CreateChain(common.Provider, "testchain1", noopH.Name())
+		r.Header.Set("Content-Type", "application/json")
+		kvr := &v1.KVResource{}
+		c, _ := restfultest.New(kvr, chain)
+		resp := httptest.NewRecorder()
+		c.ServeHTTP(resp, r)
 
-			It("should longer than 1", func() {
-				Expect(len(result.Data)).NotTo(Equal(0))
-			})
-		})
+		body, err := ioutil.ReadAll(resp.Body)
+		assert.NoError(t, err)
+		data := &model.KVDoc{}
+		err = json.Unmarshal(body, data)
+		assert.NoError(t, err)
+		assert.NotEmpty(t, data.ID)
+	})
+	t.Run("list kv by service label, should return 2 kvs", func(t *testing.T) {
+		r, _ := http.NewRequest("GET", "/v1/test/kie/kv?label=service:utService", nil)
+		noopH := &handler2.NoopAuthHandler{}
+		chain, _ := handler.CreateChain(common.Provider, "testchain1", noopH.Name())
+		r.Header.Set("Content-Type", "application/json")
+		kvr := &v1.KVResource{}
+		c, err := restfultest.New(kvr, chain)
+		assert.NoError(t, err)
+		resp := httptest.NewRecorder()
+		c.ServeHTTP(resp, r)
+		body, err := ioutil.ReadAll(resp.Body)
+		assert.NoError(t, err)
+		result := &model.KVResponse{}
+		err = json.Unmarshal(body, result)
+		assert.NoError(t, err)
+		assert.Equal(t, 2, len(result.Data))
+	})
+	t.Run("list kv by service label, exact match,should return 1 kv", func(t *testing.T) {
+		r, _ := http.NewRequest("GET", "/v1/test/kie/kv?label=service:utService&match=exact", nil)
+		noopH := &handler2.NoopAuthHandler{}
+		chain, _ := handler.CreateChain(common.Provider, "testchain1", noopH.Name())
+		r.Header.Set("Content-Type", "application/json")
+		kvr := &v1.KVResource{}
+		c, err := restfultest.New(kvr, chain)
+		assert.NoError(t, err)
+		resp := httptest.NewRecorder()
+		c.ServeHTTP(resp, r)
+		body, err := ioutil.ReadAll(resp.Body)
+		assert.NoError(t, err)
+		result := &model.KVResponse{}
+		err = json.Unmarshal(body, result)
+		assert.NoError(t, err)
+		assert.Equal(t, 1, len(result.Data))
 	})
-})
+}
diff --git a/server/resource/v1/v1_suite_test.go b/server/resource/v1/v1_suite_test.go
deleted file mode 100644
index 31569b8..0000000
--- a/server/resource/v1/v1_suite_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 v1_test
-
-import (
-	"testing"
-
-	. "github.com/onsi/ginkgo"
-	. "github.com/onsi/gomega"
-
-	_ "github.com/apache/servicecomb-kie/server/service/mongo"
-)
-
-func TestV1(t *testing.T) {
-
-	RegisterFailHandler(Fail)
-	RunSpecs(t, "V1 Suite")
-
-}
diff --git a/server/service/mongo/kv/kv_dao.go b/server/service/mongo/kv/kv_dao.go
index 207ac8a..b61b88b 100644
--- a/server/service/mongo/kv/kv_dao.go
+++ b/server/service/mongo/kv/kv_dao.go
@@ -121,10 +121,7 @@ func findKV(ctx context.Context, domain string, project string, opts service.Fin
 		for k, v := range opts.Labels {
 			filter["labels."+k] = v
 		}
-	} else {
-		filter["labels"] = ""
 	}
-
 	cur, err := collection.Find(ctx, filter)
 	if err != nil {
 		if err.Error() == context.DeadlineExceeded.Error() {
diff --git a/server/service/mongo/kv/kv_service.go b/server/service/mongo/kv/kv_service.go
index 8cc6b8c..1be9160 100644
--- a/server/service/mongo/kv/kv_service.go
+++ b/server/service/mongo/kv/kv_service.go
@@ -205,6 +205,11 @@ func (s *Service) List(ctx context.Context, domain, project string, limit, offse
 			openlogging.Error("decode to KVs error: " + err.Error())
 			return nil, err
 		}
+		if opts.ExactLabels {
+			if !reflect.DeepEqual(opts.Labels, curKV.Labels) {
+				continue
+			}
+		}
 		clearPart(curKV)
 		result.Data = append(result.Data, curKV)
 	}