blob: f9bed0732b168d7aadab54af4a5c213069fee24c [file] [log] [blame]
Scott Bakere7144bc2019-10-01 14:16:47 -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 "fmt"
21 "github.com/golang/protobuf/proto"
22 "github.com/opencord/voltha-go/common/log"
23 common_pb "github.com/opencord/voltha-protos/go/common"
24 "github.com/stretchr/testify/assert"
25 "google.golang.org/grpc"
26 "testing"
27)
28
29const (
30 ROUND_ROBIN_ROUTER_PROTOFILE = "../../../vendor/github.com/opencord/voltha-protos/go/voltha.pb"
31)
32
33func init() {
34 log.SetDefaultLogger(log.JSON, log.DebugLevel, nil)
35 log.AddPackage(log.JSON, log.WarnLevel, nil)
36}
37
38func MakeRoundRobinTestConfig(numBackends int, numConnections int) (*RouteConfig, *RouterConfig) {
39
40 var backends []BackendConfig
41 for backendIndex := 0; backendIndex < numBackends; backendIndex++ {
42 var connections []ConnectionConfig
43 for connectionIndex := 0; connectionIndex < numConnections; connectionIndex++ {
44 connectionConfig := ConnectionConfig{
45 Name: fmt.Sprintf("ro_vcore%d%d", backendIndex, connectionIndex+1),
46 Addr: "foo",
47 Port: "123",
48 }
49 connections = append(connections, connectionConfig)
50 }
51
52 backendConfig := BackendConfig{
53 Name: fmt.Sprintf("ro_vcore%d", backendIndex),
54 Type: BackendSingleServer,
55 Connections: connections,
56 }
57
58 backends = append(backends, backendConfig)
59 }
60
61 backendClusterConfig := BackendClusterConfig{
62 Name: "ro_vcore",
63 Backends: backends,
64 }
65
66 routeConfig := RouteConfig{
67 Name: "read_only",
68 Type: RouteTypeRoundRobin,
69 Association: AssociationRoundRobin,
70 BackendCluster: "ro_vcore",
71 backendCluster: &backendClusterConfig,
72 Methods: []string{"ListDevicePorts"},
73 }
74
75 routerConfig := RouterConfig{
76 Name: "vcore",
77 ProtoService: "VolthaService",
78 ProtoPackage: "voltha",
79 Routes: []RouteConfig{routeConfig},
80 ProtoFile: ROUND_ROBIN_ROUTER_PROTOFILE,
81 }
82 return &routeConfig, &routerConfig
83}
84
85// Route() requires an open connection, so pretend we have one.
86func PretendRoundRobinOpenConnection(router Router, clusterName string, backendIndex int, connectionName string) {
87 cluster := router.FindBackendCluster(clusterName)
88
89 // Route Method expects an open connection
90 conn := cluster.backends[backendIndex].connections[connectionName]
91 cluster.backends[backendIndex].openConns[conn] = &grpc.ClientConn{}
92}
93
94// Common setup to run before each unit test
95func RoundRobinTestSetup() {
96 // reset globals that need to be clean for each unit test
97
98 clusters = make(map[string]*cluster)
99}
100
101// Test creation of a new RoundRobinRouter, and the Service(), Name(), FindBackendCluster(), and
102// ReplyHandler() methods.
103func TestRoundRobinRouterInit(t *testing.T) {
104 RoundRobinTestSetup()
105
106 routeConfig, routerConfig := MakeRoundRobinTestConfig(1, 1)
107
108 router, err := newRoundRobinRouter(routerConfig, routeConfig)
109
110 assert.NotNil(t, router)
111 assert.Nil(t, err)
112
113 assert.Equal(t, router.Service(), "VolthaService")
114 assert.Equal(t, router.Name(), "read_only")
115
116 cluster, err := router.BackendCluster("foo", "bar")
117 assert.Equal(t, cluster, clusters["ro_vcore"])
118 assert.Nil(t, err)
119
120 assert.Equal(t, router.FindBackendCluster("ro_vcore"), clusters["ro_vcore"])
121 assert.Nil(t, router.ReplyHandler("foo"))
122}
123
124func TestRoundRobinRouterInitNoName(t *testing.T) {
125 RoundRobinTestSetup()
126
127 routeConfig, routerConfig := MakeRoundRobinTestConfig(1, 1)
128 routeConfig.Name = ""
129
130 _, err := newRoundRobinRouter(routerConfig, routeConfig)
131
132 assert.EqualError(t, err, "Failed to create a new router ''")
133}
134
135func TestRoundRobinRouterInitNoProtoPackage(t *testing.T) {
136 RoundRobinTestSetup()
137
138 routeConfig, routerConfig := MakeRoundRobinTestConfig(1, 1)
139 routerConfig.ProtoPackage = ""
140
141 _, err := newRoundRobinRouter(routerConfig, routeConfig)
142
143 assert.EqualError(t, err, "Failed to create a new router 'read_only'")
144}
145
146func TestRoundRobinRouterInitNoProtoService(t *testing.T) {
147 RoundRobinTestSetup()
148
149 routeConfig, routerConfig := MakeRoundRobinTestConfig(1, 1)
150 routerConfig.ProtoService = ""
151
152 _, err := newRoundRobinRouter(routerConfig, routeConfig)
153
154 assert.EqualError(t, err, "Failed to create a new router 'read_only'")
155}
156
157// Tests a cluster with no backends
158func TestRoundRobinRouteZero(t *testing.T) {
159 RoundRobinTestSetup()
160
161 routeConfig, routerConfig := MakeRoundRobinTestConfig(1, 1)
162
163 router, err := newRoundRobinRouter(routerConfig, routeConfig)
164 assert.Nil(t, err)
165
166 idMessage := &common_pb.ID{Id: "1234"}
167
168 idData, err := proto.Marshal(idMessage)
169 assert.Nil(t, err)
170
171 sel := &requestFrame{payload: idData,
172 err: nil,
173 methodInfo: newMethodDetails("/voltha.VolthaService/ListDevicePorts")}
174
175 backend, connection := router.Route(sel)
176
177 assert.EqualError(t, sel.err, "No backend with open connections found")
178 assert.Nil(t, backend)
179 assert.Nil(t, connection)
180}
181
182// Tests a cluster with only one Backend
183func TestRoundRobinRouteOne(t *testing.T) {
184 RoundRobinTestSetup()
185
186 routeConfig, routerConfig := MakeRoundRobinTestConfig(1, 1)
187
188 router, err := newRoundRobinRouter(routerConfig, routeConfig)
189 assert.Nil(t, err)
190
191 PretendRoundRobinOpenConnection(router, "ro_vcore", 0, "ro_vcore01")
192
193 idMessage := &common_pb.ID{Id: "1234"}
194
195 idData, err := proto.Marshal(idMessage)
196 assert.Nil(t, err)
197
198 sel := &requestFrame{payload: idData,
199 err: nil,
200 methodInfo: newMethodDetails("/voltha.VolthaService/ListDevicePorts")}
201
202 backend, connection := router.Route(sel)
203
204 assert.Nil(t, sel.err)
205 assert.NotNil(t, backend)
206 assert.Equal(t, "ro_vcore0", backend.name)
207 assert.Nil(t, connection)
208
209 // Since we only have one backend, calling Route a second time should return the same one
210
211 backend, connection = router.Route(sel)
212
213 assert.Nil(t, sel.err)
214 assert.NotNil(t, backend)
215 assert.Equal(t, "ro_vcore0", backend.name)
216 assert.Nil(t, connection)
217}
218
219// Tests a cluster with two Backends
220func TestRoundRobinRouteTwo(t *testing.T) {
221 RoundRobinTestSetup()
222
223 routeConfig, routerConfig := MakeRoundRobinTestConfig(2, 1)
224
225 router, err := newRoundRobinRouter(routerConfig, routeConfig)
226 assert.Nil(t, err)
227
228 PretendRoundRobinOpenConnection(router, "ro_vcore", 0, "ro_vcore01")
229 PretendRoundRobinOpenConnection(router, "ro_vcore", 1, "ro_vcore11")
230
231 idMessage := &common_pb.ID{Id: "1234"}
232
233 idData, err := proto.Marshal(idMessage)
234 assert.Nil(t, err)
235
236 sel := &requestFrame{payload: idData,
237 err: nil,
238 methodInfo: newMethodDetails("/voltha.VolthaService/ListDevicePorts")}
239
240 backend, connection := router.Route(sel)
241
242 assert.Nil(t, sel.err)
243 assert.NotNil(t, backend)
244 assert.Equal(t, "ro_vcore0", backend.name)
245 assert.Nil(t, connection)
246
247 // Since we have two backends, calling Route a second time should return the second
248
249 backend, connection = router.Route(sel)
250
251 assert.Nil(t, sel.err)
252 assert.NotNil(t, backend)
253 assert.Equal(t, "ro_vcore1", backend.name)
254 assert.Nil(t, connection)
255
256 // Calling Route a third time should return the first again
257
258 backend, connection = router.Route(sel)
259
260 assert.Nil(t, sel.err)
261 assert.NotNil(t, backend)
262 assert.Equal(t, "ro_vcore0", backend.name)
263 assert.Nil(t, connection)
264}
265
266// Tests a cluster with one backend but no open connections
267func TestRoundRobinRouteOneNoOpenConnection(t *testing.T) {
268 RoundRobinTestSetup()
269
270 routeConfig, routerConfig := MakeRoundRobinTestConfig(1, 1)
271
272 router, err := newRoundRobinRouter(routerConfig, routeConfig)
273 assert.Nil(t, err)
274
275 idMessage := &common_pb.ID{Id: "1234"}
276
277 idData, err := proto.Marshal(idMessage)
278 assert.Nil(t, err)
279
280 sel := &requestFrame{payload: idData,
281 err: nil,
282 methodInfo: newMethodDetails("/voltha.VolthaService/ListDevicePorts")}
283
284 backend, connection := router.Route(sel)
285
286 assert.EqualError(t, sel.err, "No backend with open connections found")
287 assert.Nil(t, backend)
288 assert.Nil(t, connection)
289}