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