Skip to content

Commit ae96693

Browse files
authored
API versioning (#60)
1) Enhanced REST server to accept the client version through new request header 'Accept-Version'. This is an optional header. If specified, it should be of Translib's yang bundle version format "Major.Minor.Patch". Server returns 400 status if Accept-Version value is invalid. 2) Accept-Version header value is passed as "ClientVersion" value to the translib APIs. Translib version check errors are mapped to 400 status with error-type "protocol", error-tag "invalid-value" and an error-info json object indicating allowed version range (server version and server base version). Sameple error response payload: { "ietf-restconf:errors" : { "error" : [ { "error-type" : "protocol", "error-tag" : "operation-not-supported", "error-message" : "Unsupported client version 0.0.1", "error-info" : { "version-error" : { "ServerBaseVersion" : "1.0.0", "ServerVersion" : "2.1.3", "ClientVersion" : "0.0.1" } } }]}} 3) Translib version checks are not performed if client did not send the Accept-Version header. Signed-off-by: Sachin Holla <sachin.holla@broadcom.com>
1 parent 7b93bfc commit ae96693

File tree

6 files changed

+160
-16
lines changed

6 files changed

+160
-16
lines changed

go.sum

+42
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ github.com/antchfx/xmlquery v1.2.1 h1:wE4xjHrqOScP440wdv23Xkg0Gr8JryW0ptqodPH+y2
88
github.com/antchfx/xmlquery v1.2.1/go.mod h1:/+CnyD/DzHRnv2eRxrVbieRU/FIF6N0C+7oTtyUtCKk=
99
github.com/antchfx/xpath v1.1.2 h1:YziPrtM0gEJBnhdUGxYcIVYXZ8FXbtbovxOi+UW/yWQ=
1010
github.com/antchfx/xpath v1.1.2/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
11+
github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
1112
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
1213
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
14+
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
1315
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1416
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
17+
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
18+
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
1519
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
1620
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
1721
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
@@ -29,7 +33,20 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
2933
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
3034
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
3135
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
36+
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
37+
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
38+
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
39+
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
40+
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
41+
github.com/golang/protobuf v1.4.0-rc.4/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
42+
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0 h1:aRz0NBceriICVtjhCgKkDvl+RudKu1CT6h0ZvUTrNfE=
43+
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
3244
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
45+
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
46+
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
47+
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
48+
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
49+
github.com/google/protobuf v3.11.4+incompatible/go.mod h1:lUQ9D1ePzbH2PrIS7ob/bjm9HXyH5WHB0Akwh7URreM=
3350
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
3451
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
3552
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@@ -42,10 +59,19 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
4259
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
4360
github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c h1:a380JP+B7xlMbEQOlha1buKhzBPXFqgFXplyWCEIGEY=
4461
github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc=
62+
github.com/openconfig/gnmi v0.0.0-20200307010808-e7106f7f5493/go.mod h1:jMSUQIR4z9WTtM58/QBHbElXAwbUnomFdty1aund1uY=
63+
github.com/openconfig/gnmi v0.0.0-20200617225440-d2b4e6a45802 h1:WXFwJlWOJINlwlyAZuNo4GdYZS6qPX36+rRUncLmN8Q=
64+
github.com/openconfig/gnmi v0.0.0-20200617225440-d2b4e6a45802/go.mod h1:M/EcuapNQgvzxo1DDXHK4tx3QpYM/uG4l591v33jG2A=
4565
github.com/openconfig/goyang v0.0.0-20190924211109-064f9690516f h1:BaekRUaWpfaRBP3mShDZaNi4+EHbdli7D6YXc/TP3lo=
4666
github.com/openconfig/goyang v0.0.0-20190924211109-064f9690516f/go.mod h1:dhXaV0JgHJzdrHi2l+w0fZrwArtXL7jEFoiqLEdmkvU=
67+
github.com/openconfig/goyang v0.0.0-20200115183954-d0a48929f0ea/go.mod h1:dhXaV0JgHJzdrHi2l+w0fZrwArtXL7jEFoiqLEdmkvU=
68+
github.com/openconfig/goyang v0.0.0-20200309174518-a00bece872fc h1:W6XYKuH3mxF5WFhsSQOPPN9DRDba1xz9lbUbQR3uHkg=
69+
github.com/openconfig/goyang v0.0.0-20200309174518-a00bece872fc/go.mod h1:dhXaV0JgHJzdrHi2l+w0fZrwArtXL7jEFoiqLEdmkvU=
70+
github.com/openconfig/ygot v0.6.0/go.mod h1:o30svNf7O0xK+R35tlx95odkDmZWS9JyWWQSmIhqwAs=
4771
github.com/openconfig/ygot v0.6.1-0.20190723223108-724a6b18a922 h1:zBLb75mrLMxabjsAhPk/2qxbht+BwHKFWBvRAB4Fd2U=
4872
github.com/openconfig/ygot v0.6.1-0.20190723223108-724a6b18a922/go.mod h1:o30svNf7O0xK+R35tlx95odkDmZWS9JyWWQSmIhqwAs=
73+
github.com/openconfig/ygot v0.7.1 h1:kqDRYQpowXTr7EhGwr2BBDKJzqs+H8aFYjffYQ8lBsw=
74+
github.com/openconfig/ygot v0.7.1/go.mod h1:5MwNX6DMP1QMf2eQjW+aJN/KNslVqRJtbfSL3SO6Urk=
4975
github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
5076
github.com/pkg/profile v1.4.0 h1:uCmaf4vVbWAOZz36k1hrQD7ijGRzLwaME8Am/7a4jZI=
5177
github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE=
@@ -67,6 +93,8 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
6793
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
6894
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
6995
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
96+
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
97+
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
7098
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
7199
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
72100
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -85,15 +113,29 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
85113
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
86114
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
87115
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
116+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
88117
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
89118
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
90119
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
91120
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
92121
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
122+
google.golang.org/genproto v0.0.0-20200319113533-08878b785e9c h1:5aI3/f/3eCZps9xwoEnmgfDJDhMbnJpfqeGpjVNgVEI=
123+
google.golang.org/genproto v0.0.0-20200319113533-08878b785e9c/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
93124
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
94125
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
95126
google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0=
96127
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
128+
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
129+
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
130+
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
131+
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
132+
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
133+
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
134+
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
135+
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
136+
google.golang.org/protobuf v1.20.1/go.mod h1:KqelGeouBkcbcuB3HCk4/YH2tmNLk6YSWA5LIWeI/lY=
137+
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
138+
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
97139
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
98140
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
99141
gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M=

rest/server/error.go

+13-5
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,12 @@ type errorResponse struct {
3939
// errorEntry defines the RESTCONF compilant error information
4040
// payload.
4141
type errorEntry struct {
42-
Type errtype `json:"error-type"`
43-
Tag errtag `json:"error-tag"`
44-
AppTag string `json:"error-app-tag,omitempty"`
45-
Path string `json:"error-path,omitempty"`
46-
Message string `json:"error-message,omitempty"`
42+
Type errtype `json:"error-type"`
43+
Tag errtag `json:"error-tag"`
44+
AppTag string `json:"error-app-tag,omitempty"`
45+
Path string `json:"error-path,omitempty"`
46+
Message string `json:"error-message,omitempty"`
47+
ErrInfo interface{} `json:"error-info,omitempty"`
4748
}
4849

4950
type errtype string
@@ -139,6 +140,13 @@ func toErrorEntry(err error, r *http.Request) (status int, errInfo errorEntry) {
139140
errInfo.Tag = errtagInvalidValue
140141
errInfo.Message = e.ErrorStr.Error()
141142

143+
case tlerr.TranslibUnsupportedClientVersion:
144+
status = http.StatusBadRequest
145+
errInfo.Type = errtypeProtocol
146+
errInfo.Tag = errtagOperationNotSupported
147+
errInfo.Message = e.Error()
148+
errInfo.ErrInfo = map[string]interface{}{"version-error": e}
149+
142150
case tlerr.TranslibRedisClientEntryNotExist:
143151
status = http.StatusNotFound
144152
errInfo.Tag = errtagInvalidValue

rest/server/error_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ func TestErrorEntry(t *testing.T) {
161161
tlerr.TranslibSyntaxValidationError{ErrorStr: errors.New("ygot")},
162162
400, "protocol", "invalid-value", "", "ygot"))
163163

164+
t.Run("Version_err", testErrorEntry(
165+
tlerr.TranslibUnsupportedClientVersion{
166+
ClientVersion: "1.2.3", ServerVersion: "1.2.0", ServerBaseVersion: "1.0.0"},
167+
400, "protocol", "operation-not-supported", "", "Unsupported client version 1.2.3"))
168+
164169
}
165170

166171
func testErrorEntry(err error,

rest/server/handler.go

+33-10
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ func Process(w http.ResponseWriter, r *http.Request) {
4646

4747
glog.Infof("[%s] %s %s; content-len=%d", reqID, r.Method, r.URL.Path, r.ContentLength)
4848
_, args.data, err = getRequestBody(r, rc)
49+
50+
if err == nil {
51+
err = args.parseClientVersion(r, rc)
52+
}
53+
4954
if err != nil {
5055
status, data, rtype = prepareErrorResponse(err, r)
5156
goto write_resp
@@ -219,8 +224,21 @@ func trimRestconfPrefix(path string) string {
219224

220225
// translibArgs holds arguments for invoking translib APIs.
221226
type translibArgs struct {
222-
path string // Translib path
223-
data []byte // payload
227+
path string // Translib path
228+
data []byte // payload
229+
version translib.Version // client version
230+
}
231+
232+
// parseClientVersion parses the Accept-Version request header value
233+
func (args *translibArgs) parseClientVersion(r *http.Request, rc *RequestContext) error {
234+
if v := r.Header.Get("Accept-Version"); len(v) != 0 {
235+
if err := args.version.Set(v); err != nil {
236+
return httpBadRequest("Invalid Accept-Version \"%s\"", v)
237+
}
238+
}
239+
240+
glog.V(1).Infof("[%s] Client version = \"%s\"", rc.ID, args.version)
241+
return nil
224242
}
225243

226244
// invokeTranslib calls appropriate TransLib API for the given HTTP
@@ -233,7 +251,8 @@ func invokeTranslib(args *translibArgs, r *http.Request, rc *RequestContext) (in
233251
switch r.Method {
234252
case "GET", "HEAD":
235253
req := translib.GetRequest{
236-
Path: args.path,
254+
Path: args.path,
255+
ClientVersion: args.version,
237256
}
238257
resp, err1 := translib.Get(req)
239258
if err1 == nil {
@@ -247,32 +266,36 @@ func invokeTranslib(args *translibArgs, r *http.Request, rc *RequestContext) (in
247266
//TODO return 200 for operations request
248267
status = 201
249268
req := translib.SetRequest{
250-
Path: args.path,
251-
Payload: args.data,
269+
Path: args.path,
270+
Payload: args.data,
271+
ClientVersion: args.version,
252272
}
253273
_, err = translib.Create(req)
254274

255275
case "PUT":
256276
//TODO send 201 if PUT resulted in creation
257277
status = 204
258278
req := translib.SetRequest{
259-
Path: args.path,
260-
Payload: args.data,
279+
Path: args.path,
280+
Payload: args.data,
281+
ClientVersion: args.version,
261282
}
262283
_, err = translib.Replace(req)
263284

264285
case "PATCH":
265286
status = 204
266287
req := translib.SetRequest{
267-
Path: args.path,
268-
Payload: args.data,
288+
Path: args.path,
289+
Payload: args.data,
290+
ClientVersion: args.version,
269291
}
270292
_, err = translib.Update(req)
271293

272294
case "DELETE":
273295
status = 204
274296
req := translib.SetRequest{
275-
Path: args.path,
297+
Path: args.path,
298+
ClientVersion: args.version,
276299
}
277300
_, err = translib.Delete(req)
278301

rest/server/handler_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import (
2828
"sort"
2929
"strings"
3030
"testing"
31+
32+
"github.com/Azure/sonic-mgmt-common/translib"
3133
)
3234

3335
var testRouter *Router
@@ -501,6 +503,52 @@ func testRespData(r *http.Request, rc *RequestContext, data []byte, expType stri
501503
}
502504
}
503505

506+
func TestVersion_none(t *testing.T) {
507+
r := httptest.NewRequest("GET", "/test", nil)
508+
verifyParseVersion(t, r, true, translib.Version{})
509+
}
510+
511+
func TestVersion_empty(t *testing.T) {
512+
r := httptest.NewRequest("GET", "/test", nil)
513+
r.Header.Set("Accept-Version", "")
514+
verifyParseVersion(t, r, true, translib.Version{})
515+
}
516+
517+
func TestVersion_000(t *testing.T) {
518+
r := httptest.NewRequest("GET", "/test", nil)
519+
r.Header.Set("Accept-Version", "0.0.0")
520+
verifyParseVersion(t, r, false, translib.Version{})
521+
}
522+
523+
func TestVersion_123(t *testing.T) {
524+
r := httptest.NewRequest("GET", "/test", nil)
525+
r.Header.Set("Accept-Version", "1.2.3")
526+
verifyParseVersion(t, r, true, translib.Version{Major: 1, Minor: 2, Patch: 3})
527+
}
528+
529+
func TestVersion_bad(t *testing.T) {
530+
r := httptest.NewRequest("GET", "/test", nil)
531+
r.Header.Set("Accept-Version", "bad")
532+
verifyParseVersion(t, r, false, translib.Version{})
533+
}
534+
535+
func verifyParseVersion(t *testing.T, r *http.Request, expSuccess bool, expVer translib.Version) {
536+
var args translibArgs
537+
rc, r := GetContext(r)
538+
err := args.parseClientVersion(r, rc)
539+
ver := r.Header.Get("Accept-Version")
540+
541+
if expSuccess && err != nil {
542+
t.Fatalf("Unexpected error parsing AcceptVersion \"%s\"; err=%v", ver, err)
543+
}
544+
if !expSuccess && err == nil {
545+
t.Fatalf("Expected error parsing AcceptVersion \"%s\"", ver)
546+
}
547+
if expSuccess && args.version != expVer {
548+
t.Fatalf("Failed to parse AcceptVersion \"%s\"; expected=%s, found=%s", ver, expVer, args.version)
549+
}
550+
}
551+
504552
func TestProcessGET(t *testing.T) {
505553
w := httptest.NewRecorder()
506554
Process(w, prepareRequest(t, "GET", "/api-tests:sample", ""))

tools/test/rest-server.sh

+19-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
set -e
2323

24-
TOPDIR=$PWD
24+
TOPDIR=$(git rev-parse --show-toplevel || echo ${PWD})
2525
BUILD_DIR=$TOPDIR/build
2626
SERVER_DIR=$TOPDIR/build/rest_server
2727
MGMT_COMMON_DIR=$(realpath $TOPDIR/../sonic-mgmt-common)
@@ -32,6 +32,11 @@ if [[ ! -f $SERVER_DIR/rest_server ]]; then
3232
exit 1
3333
fi
3434

35+
# Setup database config file path
36+
if [[ -z ${DB_CONFIG_PATH} ]]; then
37+
export DB_CONFIG_PATH=${MGMT_COMMON_DIR}/tools/test/database_config.json
38+
fi
39+
3540
# LD_LIBRARY_PATH for CVL
3641
[ -z $LD_LIBRARY_PATH ] && export LD_LIBRARY_PATH=/usr/local/lib
3742

@@ -55,6 +60,19 @@ if [[ -z $CVL_CFG_FILE ]]; then
5560
fi
5661
fi
5762

63+
# Prepare yang files directiry for transformer
64+
if [[ -z ${YANG_MODELS_PATH} ]]; then
65+
export YANG_MODELS_PATH=${BUILD_DIR}/all_yangs
66+
mkdir -p ${YANG_MODELS_PATH}
67+
pushd ${YANG_MODELS_PATH} > /dev/null
68+
MGMT_COMN=$(realpath --relative-to=${PWD} ${MGMT_COMMON_DIR})
69+
rm -f *
70+
find ${MGMT_COMN}/models/yang -name "*.yang" -not -path "*/testdata/*" -exec ln -sf {} \;
71+
ln -sf ${MGMT_COMN}/models/yang/version.xml
72+
ln -sf ${MGMT_COMN}/config/transformer/models_list
73+
popd > /dev/null
74+
fi
75+
5876
EXTRA_ARGS="-rest_ui $SERVER_DIR/dist/ui -logtostderr"
5977

6078
for V in $@; do

0 commit comments

Comments
 (0)