blob: 08be2aec690eab5e695f8fc78b4e4280455d95ce [file] [log] [blame]
Scott Bakerb654c4d2019-10-21 17:33:06 -07001/*
2 * Portions copyright 2019-present Open Networking Foundation
3 * Original copyright 2019-present Ciena Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the"github.com/stretchr/testify/assert" "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package afrouter
18
19import (
20 "context"
21 "fmt"
22 "github.com/golang/protobuf/proto"
Scott Bakerb6de7a52019-11-04 09:13:37 -080023 voltha_pb "github.com/opencord/voltha-protos/v2/go/voltha"
Scott Bakerb654c4d2019-10-21 17:33:06 -070024 "github.com/stretchr/testify/assert"
25 "google.golang.org/grpc"
26 "google.golang.org/grpc/metadata"
27 "testing"
28 "time"
29)
30
31// MockContext, always returns the specified Metadata
32
33type MockContext struct {
34 metadata metadata.MD
35}
36
37func (mc MockContext) Deadline() (deadline time.Time, ok bool) { return time.Now(), true }
38func (mc MockContext) Done() <-chan struct{} { return nil }
39func (mc MockContext) Err() error { return nil }
40func (mc MockContext) Value(key interface{}) interface{} {
41 return mc.metadata
42}
43
44// MockServerStream, always returns a Context that returns the specified metadata
45
46type MockServerStream struct {
47 metadata metadata.MD
48}
49
50func (ms MockServerStream) SetHeader(_ metadata.MD) error { return nil }
51func (ms MockServerStream) SendHeader(_ metadata.MD) error { return nil }
52func (ms MockServerStream) SetTrailer(_ metadata.MD) {}
53func (ms MockServerStream) Context() context.Context { return MockContext(ms) }
54func (ms MockServerStream) SendMsg(_ interface{}) error { return nil }
55func (ms MockServerStream) RecvMsg(_ interface{}) error { return nil }
56
57// Build an method router configuration
58func MakeBindingTestConfig(numBackends int, numConnections int) (*RouteConfig, *RouterConfig) {
59 var backends []BackendConfig
60 for backendIndex := 0; backendIndex < numBackends; backendIndex++ {
61 var connections []ConnectionConfig
62 for connectionIndex := 0; connectionIndex < numConnections; connectionIndex++ {
63 connectionConfig := ConnectionConfig{
64 Name: fmt.Sprintf("rw_vcore%d%d", backendIndex, connectionIndex+1),
65 Addr: "foo",
66 Port: "123",
67 }
68 connections = append(connections, connectionConfig)
69 }
70
71 backendConfig := BackendConfig{
72 Name: fmt.Sprintf("rw_vcore%d", backendIndex),
73 Type: BackendSingleServer,
74 Connections: connections,
75 }
76
77 backends = append(backends, backendConfig)
78 }
79
80 backendClusterConfig := BackendClusterConfig{
81 Name: "vcore",
82 Backends: backends,
83 }
84
85 bindingConfig := BindingConfig{
86 Type: "header",
87 Field: "voltha_backend_name",
88 Method: "Subscribe",
89 Association: AssociationRoundRobin,
90 }
91
92 routeConfig := RouteConfig{
93 Name: "dev_manager_ofagent",
94 Type: RouteTypeRpcAffinityMessage,
95 Association: AssociationRoundRobin,
96 BackendCluster: "vcore",
97 backendCluster: &backendClusterConfig,
98 Binding: bindingConfig,
99 RouteField: "id",
100 Methods: []string{"CreateDevice", "EnableDevice"},
101 NbBindingMethods: []string{"CreateDevice"},
102 }
103
104 routerConfig := RouterConfig{
105 Name: "vcore",
106 ProtoService: "VolthaService",
107 ProtoPackage: "voltha",
108 Routes: []RouteConfig{routeConfig},
109 ProtoFile: TEST_PROTOFILE,
110 }
111 return &routeConfig, &routerConfig
112}
113
114// Route() requires an open connection, so pretend we have one.
115func PretendBindingOpenConnection(router Router, clusterName string, backendIndex int, connectionName string) {
116 cluster := router.FindBackendCluster(clusterName)
117
118 // Route Method expects an open connection
119 conn := cluster.backends[backendIndex].connections[connectionName]
120 cluster.backends[backendIndex].openConns[conn] = &grpc.ClientConn{}
121}
122
123// Common setup to run before each unit test
124func BindingTestSetup() {
125 // reset globals that need to be clean for each unit test
126
127 clusters = make(map[string]*cluster)
128 allRouters = make(map[string]Router)
129}
130
131// Test creation of a new AffinityRouter, and the Service(), Name(), FindBackendCluster(), and
132// methods.
133func TestBindingRouterInit(t *testing.T) {
134 BindingTestSetup()
135
136 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
137
138 router, err := newBindingRouter(routerConfig, routeConfig)
139
140 assert.NotNil(t, router)
141 assert.Nil(t, err)
142
143 assert.Equal(t, router.Service(), "VolthaService")
144 assert.Equal(t, router.Name(), "dev_manager_ofagent")
145
146 cluster, err := router.BackendCluster("EnableDevice", NoMeta)
147 assert.Equal(t, cluster, clusters["vcore"])
148 assert.Nil(t, err)
149
150 assert.Equal(t, router.FindBackendCluster("vcore"), clusters["vcore"])
151}
152
153// Passing no ProtoPackage should return an error
154func TestBindingRouterNoProtoPackage(t *testing.T) {
155 BindingTestSetup()
156
157 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
158
159 routerConfig.ProtoPackage = ""
160
161 router, err := newBindingRouter(routerConfig, routeConfig)
162
163 assert.NotNil(t, router)
164 assert.EqualError(t, err, "Failed to create a new router 'dev_manager_ofagent'")
165}
166
167// Passing no ProtoService should return an error
168func TestBindingRouterNoProtoService(t *testing.T) {
169 BindingTestSetup()
170
171 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
172
173 routerConfig.ProtoService = ""
174
175 router, err := newBindingRouter(routerConfig, routeConfig)
176
177 assert.NotNil(t, router)
178 assert.EqualError(t, err, "Failed to create a new router 'dev_manager_ofagent'")
179}
180
181// Passing no ProtoService should return an error
182func TestBindingRouterNoAssociation(t *testing.T) {
183 BindingTestSetup()
184
185 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
186
187 routeConfig.Binding.Association = AssociationUndefined
188
189 router, err := newBindingRouter(routerConfig, routeConfig)
190
191 assert.NotNil(t, router)
192 assert.EqualError(t, err, "Failed to create a new router 'dev_manager_ofagent'")
193}
194
195// Passing type other than "header" should return an error
196func TestBindingRouterInvalidType(t *testing.T) {
197 BindingTestSetup()
198
199 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
200
201 routeConfig.Binding.Type = "wrong"
202
203 router, err := newBindingRouter(routerConfig, routeConfig)
204
205 assert.NotNil(t, router)
206 assert.EqualError(t, err, "Failed to create a new router 'dev_manager_ofagent'")
207}
208
209// Passing no Method should return an error
210func TestBindingNoMethod(t *testing.T) {
211 BindingTestSetup()
212
213 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
214
215 routeConfig.Binding.Method = ""
216
217 router, err := newBindingRouter(routerConfig, routeConfig)
218
219 assert.NotNil(t, router)
220 assert.EqualError(t, err, "Failed to create a new router 'dev_manager_ofagent'")
221}
222
223// Passing no Field should return an error
224func TestBindingNoField(t *testing.T) {
225 BindingTestSetup()
226
227 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
228
229 routeConfig.Binding.Method = ""
230
231 router, err := newBindingRouter(routerConfig, routeConfig)
232
233 assert.NotNil(t, router)
234 assert.EqualError(t, err, "Failed to create a new router 'dev_manager_ofagent'")
235}
236
237func TestBindingRouterGetMetaKeyVal(t *testing.T) {
238 BindingTestSetup()
239
240 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
241
242 router, err := newBindingRouter(routerConfig, routeConfig)
243
244 assert.NotNil(t, router)
245 assert.Nil(t, err)
246
247 ms := MockServerStream{}
248 ms.metadata = make(map[string][]string)
249 ms.metadata["voltha_backend_name"] = []string{"some_backend"}
250
251 k, v, err := router.GetMetaKeyVal(ms)
252
253 assert.Nil(t, err)
254 assert.Equal(t, "voltha_backend_name", k)
255 assert.Equal(t, "some_backend", v)
256}
257
258// If metadata doesn't exist, return empty strings
259func TestBindingRouterGetMetaKeyValEmptyMetadata(t *testing.T) {
260 BindingTestSetup()
261
262 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
263
264 router, err := newBindingRouter(routerConfig, routeConfig)
265
266 assert.NotNil(t, router)
267 assert.Nil(t, err)
268
269 ms := MockServerStream{}
270 ms.metadata = nil
271
272 k, v, err := router.GetMetaKeyVal(ms)
273
274 assert.Nil(t, err)
275 assert.Equal(t, "", k)
276 assert.Equal(t, "", v)
277}
278
279func TestBindingRoute(t *testing.T) {
280 BindingTestSetup()
281
282 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
283
284 router, err := newBindingRouter(routerConfig, routeConfig)
285
286 assert.NotNil(t, router)
287 assert.Nil(t, err)
288
289 ms := MockServerStream{}
290 ms.metadata = nil
291
292 subscribeMessage := &voltha_pb.OfAgentSubscriber{OfagentId: "1234", VolthaId: "5678"}
293
294 subscribeData, err := proto.Marshal(subscribeMessage)
295 assert.Nil(t, err)
296
297 sel := &requestFrame{payload: subscribeData,
298 err: nil,
299 metaKey: "voltha_backend_name",
300 metaVal: "",
301 methodInfo: newMethodDetails("/voltha.VolthaService/Subscribe")}
302
303 PretendBindingOpenConnection(router, "vcore", 0, "rw_vcore01")
304
305 backend, connection := router.Route(sel)
306 assert.NotNil(t, backend)
307 assert.Nil(t, connection)
308
309 // now route it again with a metaVal, and we should find the existing binding
310
311 sel = &requestFrame{payload: subscribeData,
312 err: nil,
313 metaKey: "voltha_backend_name",
314 metaVal: "rw_vcore0",
315 methodInfo: newMethodDetails("/voltha.VolthaService/Subscribe")}
316
317 backend, connection = router.Route(sel)
318 assert.NotNil(t, backend)
319 assert.Nil(t, connection)
320}
321
322// Only "Subscribe" is a valid method
323func TestBindingRouteWrongMethod(t *testing.T) {
324 BindingTestSetup()
325
326 routeConfig, routerConfig := MakeBindingTestConfig(1, 1)
327
328 router, err := newBindingRouter(routerConfig, routeConfig)
329
330 assert.NotNil(t, router)
331 assert.Nil(t, err)
332
333 ms := MockServerStream{}
334 ms.metadata = nil
335
336 subscribeMessage := &voltha_pb.OfAgentSubscriber{OfagentId: "1234", VolthaId: "5678"}
337
338 subscribeData, err := proto.Marshal(subscribeMessage)
339 assert.Nil(t, err)
340
341 sel := &requestFrame{payload: subscribeData,
342 err: nil,
343 metaKey: "voltha_backend_name",
344 metaVal: "",
345 methodInfo: newMethodDetails("/voltha.VolthaService/EnableDevice")}
346
347 PretendBindingOpenConnection(router, "vcore", 0, "rw_vcore01")
348
349 backend, connection := router.Route(sel)
350 assert.Nil(t, backend)
351 assert.Nil(t, connection)
352}