blob: 0fd08363bf917c3ff68cf93e5817a4894febee8b [file] [log] [blame]
khenaidoo820197c2020-02-13 16:35:33 -05001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package route
17
18import (
19 "context"
20 "errors"
21 "fmt"
khenaidoo820197c2020-02-13 16:35:33 -050022 "math/rand"
23 "reflect"
24 "strings"
25 "sync"
26 "testing"
27 "time"
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040028
29 "github.com/opencord/voltha-protos/v3/go/openflow_13"
30 "github.com/opencord/voltha-protos/v3/go/voltha"
31 "github.com/stretchr/testify/assert"
khenaidoo820197c2020-02-13 16:35:33 -050032)
33
34const (
35 logicalDeviceID = "ld"
36 oltDeviceID = "olt"
37)
38
khenaidoo0db4c812020-05-27 15:27:30 -040039const testSetupPhase contextKey = "testSetupPhase"
40
41type contextKey string
42
khenaidoo820197c2020-02-13 16:35:33 -050043//portRegistration is a message sent from an OLT device to a logical device to create a logical port
44type portRegistration struct {
45 port *voltha.Port
46 rootPort bool
47}
48
49//onuRegistration is a message sent from an ONU device to an OLT device to register an ONU
50type onuRegistration struct {
51 onu *voltha.Device
52 oltPonNo uint32
53 onuPonNo uint32
54}
55
56type logicalDeviceManager struct {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040057 logicalDeviceID string
58 ports map[uint32]*voltha.LogicalPort
khenaidoo820197c2020-02-13 16:35:33 -050059 deviceRoutes *DeviceRoutes
60 ldChnl chan portRegistration
61 numLogicalPorts int
62 done chan struct{}
63}
64
65func newLogicalDeviceManager(ld *voltha.LogicalDevice, ch chan portRegistration, totalLogicalPorts int, done chan struct{}) *logicalDeviceManager {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040066 ports := make(map[uint32]*voltha.LogicalPort)
67 for _, p := range ld.Ports {
68 ports[p.DevicePortNo] = p
69 }
70
khenaidoo820197c2020-02-13 16:35:33 -050071 return &logicalDeviceManager{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040072 logicalDeviceID: ld.Id,
73 ports: ports,
khenaidoo820197c2020-02-13 16:35:33 -050074 ldChnl: ch,
75 numLogicalPorts: totalLogicalPorts,
76 done: done,
77 }
78}
79
Rohan Agrawal31f21802020-06-12 05:38:46 +000080func (ldM *logicalDeviceManager) start(ctx context.Context, getDevice GetDeviceFunc, buildRoutes bool) {
81 ldM.deviceRoutes = NewDeviceRoutes(ctx, ldM.logicalDeviceID, getDevice)
khenaidoo820197c2020-02-13 16:35:33 -050082 ofpPortNo := uint32(1)
83 for portReg := range ldM.ldChnl {
84 if portReg.port == nil {
85 // End of registration - exit loop
86 break
87 }
88 lp := &voltha.LogicalPort{
89 Id: portReg.port.Label,
90 OfpPort: &openflow_13.OfpPort{PortNo: ofpPortNo},
91 DeviceId: portReg.port.DeviceId,
92 DevicePortNo: portReg.port.PortNo,
93 RootPort: portReg.rootPort,
94 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040095 ldM.ports[lp.DevicePortNo] = lp
khenaidoo820197c2020-02-13 16:35:33 -050096 if buildRoutes {
khenaidoo0db4c812020-05-27 15:27:30 -040097 device, err := getDevice(context.WithValue(context.Background(), testSetupPhase, true), lp.DeviceId)
98 if err != nil {
99 fmt.Println("Error when getting device:", lp.DeviceId, err)
100 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400101 if err := ldM.deviceRoutes.AddPort(context.Background(), lp, device, ldM.ports); err != nil && !strings.Contains(err.Error(), "code = FailedPrecondition") {
102 fmt.Println("(Error when adding port:", lp, len(ldM.ports), err)
khenaidoo820197c2020-02-13 16:35:33 -0500103 }
104 }
105 ofpPortNo++
106 }
107 // Inform the caller we are now done
108 ldM.done <- struct{}{}
109}
110
111type oltManager struct {
112 olt *voltha.Device
113 logicalDeviceMgr *logicalDeviceManager
114 numNNIPort int
115 numPonPortOnOlt int
116 oltChnl chan onuRegistration
117}
118
119func newOltManager(oltDeviceID string, ldMgr *logicalDeviceManager, numNNIPort int, numPonPortOnOlt int, ch chan onuRegistration) *oltManager {
120 return &oltManager{
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400121 olt: &voltha.Device{Id: oltDeviceID, ParentId: ldMgr.logicalDeviceID, Root: true},
khenaidoo820197c2020-02-13 16:35:33 -0500122 logicalDeviceMgr: ldMgr,
123 numNNIPort: numNNIPort,
124 numPonPortOnOlt: numPonPortOnOlt,
125 oltChnl: ch,
126 }
127}
128
129func (oltM *oltManager) start() {
130 oltM.olt.Ports = make([]*voltha.Port, 0)
131 // Setup the OLT nni ports and trigger the nni ports creation
132 for nniPort := 1; nniPort < oltM.numNNIPort+1; nniPort++ {
133 p := &voltha.Port{Label: fmt.Sprintf("nni-%d", nniPort), PortNo: uint32(nniPort), DeviceId: oltM.olt.Id, Type: voltha.Port_ETHERNET_NNI}
134 oltM.olt.Ports = append(oltM.olt.Ports, p)
135 oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: p, rootPort: true}
136 }
137
138 // Create OLT pon ports
139 for ponPort := oltM.numNNIPort + 1; ponPort < oltM.numPonPortOnOlt+oltM.numNNIPort+1; ponPort++ {
140 p := voltha.Port{PortNo: uint32(ponPort), DeviceId: oltM.olt.Id, Type: voltha.Port_PON_OLT}
141 oltM.olt.Ports = append(oltM.olt.Ports, &p)
142 }
143
144 // Wait for onu registration
145 for onuReg := range oltM.oltChnl {
146 if onuReg.onu == nil {
147 // All onu has registered - exit the loop
148 break
149 }
150 oltM.registerOnu(onuReg.onu, onuReg.oltPonNo, onuReg.onuPonNo)
151 }
152 // Inform the logical device manager we are done
153 oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: nil}
154}
155
156func (oltM *oltManager) registerOnu(onu *voltha.Device, oltPonNo uint32, onuPonNo uint32) {
157 // Update the olt pon peers
158 for _, port := range oltM.olt.Ports {
159 if port.Type == voltha.Port_PON_OLT && port.PortNo == oltPonNo {
160 port.Peers = append(port.Peers, &voltha.Port_PeerPort{DeviceId: onu.Id, PortNo: onuPonNo})
161 }
162 }
163 // For each uni port on the ONU trigger the creation of a logical port
164 for _, port := range onu.Ports {
165 if port.Type == voltha.Port_ETHERNET_UNI {
166 oltM.logicalDeviceMgr.ldChnl <- portRegistration{port: port, rootPort: false}
167 }
168 }
169}
170
171type onuManager struct {
172 oltMgr *oltManager
173 numOnus int
174 numUnisPerOnu int
175 startingUniPortNo int
176 numGetDeviceInvoked int
177 numGetDeviceInvokedLock sync.RWMutex
178 deviceLock sync.RWMutex
179 onus []*voltha.Device
180}
181
182func newOnuManager(oltMgr *oltManager, numOnus int, numUnisPerOnu int, startingUniPortNo int) *onuManager {
183 return &onuManager{
184 oltMgr: oltMgr,
185 numOnus: numOnus,
186 numUnisPerOnu: numUnisPerOnu,
187 startingUniPortNo: startingUniPortNo,
188 onus: make([]*voltha.Device, 0),
189 }
190}
191
192func (onuM *onuManager) start(startingOltPeerPortNo int, numPonPortOnOlt int) {
193 var wg sync.WaitGroup
194 for oltPonNo := startingOltPeerPortNo; oltPonNo < startingOltPeerPortNo+numPonPortOnOlt; oltPonNo++ {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400195 for onuID := 0; onuID < onuM.numOnus; onuID++ {
khenaidoo820197c2020-02-13 16:35:33 -0500196 wg.Add(1)
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400197 go func(onuID int, oltPonNum int) {
khenaidoo820197c2020-02-13 16:35:33 -0500198 var onu *voltha.Device
199 defer wg.Done()
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400200 id := fmt.Sprintf("%d-onu-%d", oltPonNum, onuID)
khenaidoo820197c2020-02-13 16:35:33 -0500201 onu = &voltha.Device{Id: id, ParentId: onuM.oltMgr.olt.Id, ParentPortNo: uint32(oltPonNum)}
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400202 ponPort := &voltha.Port{Label: fmt.Sprintf("%s:pon-%d", onu.Id, onuID), PortNo: 1, DeviceId: onu.Id, Type: voltha.Port_PON_ONU}
khenaidoo820197c2020-02-13 16:35:33 -0500203 ponPort.Peers = make([]*voltha.Port_PeerPort, 0)
204 peerPort := voltha.Port_PeerPort{DeviceId: onuM.oltMgr.olt.Id, PortNo: uint32(oltPonNum)}
205 ponPort.Peers = append(ponPort.Peers, &peerPort)
206 onu.Ports = make([]*voltha.Port, 0)
207 onu.Ports = append(onu.Ports, ponPort)
208 for j := onuM.startingUniPortNo; j < onuM.numUnisPerOnu+onuM.startingUniPortNo; j++ {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400209 uniPort := &voltha.Port{Label: fmt.Sprintf("%s:uni-%d", onu.Id, j), PortNo: uint32(oltPonNum)<<12 + uint32(onuID+1)<<4 + uint32(j), DeviceId: onu.Id, Type: voltha.Port_ETHERNET_UNI}
khenaidoo820197c2020-02-13 16:35:33 -0500210 onu.Ports = append(onu.Ports, uniPort)
211 }
212 onuM.deviceLock.Lock()
213 onuM.onus = append(onuM.onus, onu)
214 onuM.deviceLock.Unlock()
215 onuM.oltMgr.oltChnl <- onuRegistration{
216 onu: onu,
217 oltPonNo: uint32(oltPonNum),
218 onuPonNo: 1,
219 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400220 }(onuID, oltPonNo)
khenaidoo820197c2020-02-13 16:35:33 -0500221 }
222 }
223 wg.Wait()
224 //send an empty device to indicate the end of onu registration
225 onuM.oltMgr.oltChnl <- onuRegistration{
226 onu: nil,
227 oltPonNo: 0,
228 onuPonNo: 1,
229 }
230}
231
232func (onuM *onuManager) getOnu(deviceID string) *voltha.Device {
233 onuM.deviceLock.Lock()
234 defer onuM.deviceLock.Unlock()
235 for _, onu := range onuM.onus {
236 if onu.Id == deviceID {
237 return onu
238 }
239 }
240 return nil
241}
242
khenaidoo0db4c812020-05-27 15:27:30 -0400243func (onuM *onuManager) GetDeviceHelper(ctx context.Context, id string) (*voltha.Device, error) {
244 if ctx.Value(testSetupPhase) != true {
245 onuM.numGetDeviceInvokedLock.Lock()
246 onuM.numGetDeviceInvoked++
247 onuM.numGetDeviceInvokedLock.Unlock()
248 }
khenaidoo820197c2020-02-13 16:35:33 -0500249 if id == oltDeviceID {
250 return onuM.oltMgr.olt, nil
251 }
252 if onu := onuM.getOnu(id); onu != nil {
253 return onu, nil
254 }
255 return nil, errors.New("not-found")
256}
257
258func TestDeviceRoutes_ComputeRoutes(t *testing.T) {
259 numNNIPort := 2
260 numPonPortOnOlt := 8
khenaidoo0db4c812020-05-27 15:27:30 -0400261 numOnuPerOltPonPort := 256
khenaidoo820197c2020-02-13 16:35:33 -0500262 numUniPerOnu := 4
263 done := make(chan struct{})
264
265 fmt.Println(fmt.Sprintf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d",
266 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
267
268 // Create all the devices and logical device before computing the routes in one go
269 ld := &voltha.LogicalDevice{Id: logicalDeviceID}
270 ldMgrChnl := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
271 ldMgr := newLogicalDeviceManager(ld, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
272 oltMgrChnl := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
273 oltMgr := newOltManager(oltDeviceID, ldMgr, numNNIPort, numPonPortOnOlt, oltMgrChnl)
274 onuMgr := newOnuManager(oltMgr, numOnuPerOltPonPort, numUniPerOnu, 2)
275 getDevice := onuMgr.GetDeviceHelper
276 // Start the managers. Only the devices are created. No routes will be built.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000277 ctx := context.Background()
278 go ldMgr.start(ctx, getDevice, false)
khenaidoo820197c2020-02-13 16:35:33 -0500279 go oltMgr.start()
280 go onuMgr.start(numNNIPort+1, numPonPortOnOlt)
281
282 // Wait for all the devices to be created
283 <-done
284 close(oltMgrChnl)
285 close(ldMgrChnl)
286
287 // Computes the routes
288 start := time.Now()
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400289 err := ldMgr.deviceRoutes.ComputeRoutes(context.TODO(), ldMgr.ports)
khenaidoo820197c2020-02-13 16:35:33 -0500290 assert.Nil(t, err)
291
292 // Validate the routes are up to date
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400293 assert.True(t, ldMgr.deviceRoutes.isUpToDate(ldMgr.ports))
khenaidoo820197c2020-02-13 16:35:33 -0500294
295 // Validate the expected number of routes
296 assert.EqualValues(t, 2*numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, len(ldMgr.deviceRoutes.Routes))
297
298 // Validate the root ports
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400299 for _, port := range ldMgr.ports {
khenaidoo820197c2020-02-13 16:35:33 -0500300 assert.Equal(t, port.RootPort, ldMgr.deviceRoutes.IsRootPort(port.OfpPort.PortNo))
301 }
302 fmt.Println(fmt.Sprintf("Total Time:%dms, Total Routes:%d NumGetDeviceInvoked:%d", time.Since(start)/time.Millisecond, len(ldMgr.deviceRoutes.Routes), onuMgr.numGetDeviceInvoked))
303}
304
305func TestDeviceRoutes_AddPort(t *testing.T) {
306 numNNIPort := 2
khenaidoo0db4c812020-05-27 15:27:30 -0400307 numPonPortOnOlt := 16
308 numOnuPerOltPonPort := 256
khenaidoo820197c2020-02-13 16:35:33 -0500309 numUniPerOnu := 4
310 done := make(chan struct{})
311
312 fmt.Println(fmt.Sprintf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d",
313 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
314
315 start := time.Now()
316 // Create all the devices and logical device before computing the routes in one go
317 ld := &voltha.LogicalDevice{Id: logicalDeviceID}
318 ldMgrChnl := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
319 ldMgr := newLogicalDeviceManager(ld, ldMgrChnl, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
320 oltMgrChnl := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
321 oltMgr := newOltManager(oltDeviceID, ldMgr, numNNIPort, numPonPortOnOlt, oltMgrChnl)
322 onuMgr := newOnuManager(oltMgr, numOnuPerOltPonPort, numUniPerOnu, 2)
323 getDevice := onuMgr.GetDeviceHelper
Rohan Agrawal31f21802020-06-12 05:38:46 +0000324
325 ctx := context.Background()
khenaidoo820197c2020-02-13 16:35:33 -0500326 // Start the managers and trigger the routes to be built as the logical ports become available
Rohan Agrawal31f21802020-06-12 05:38:46 +0000327 go ldMgr.start(ctx, getDevice, true)
khenaidoo820197c2020-02-13 16:35:33 -0500328 go oltMgr.start()
329 go onuMgr.start(numNNIPort+1, numPonPortOnOlt)
330
331 // Wait for all the devices to be created and routes created
332 <-done
333 close(oltMgrChnl)
334 close(ldMgrChnl)
335
Rohan Agrawal31f21802020-06-12 05:38:46 +0000336 ldMgr.deviceRoutes.Print(ctx)
khenaidoo820197c2020-02-13 16:35:33 -0500337
338 // Validate the routes are up to date
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400339 assert.True(t, ldMgr.deviceRoutes.isUpToDate(ldMgr.ports))
khenaidoo820197c2020-02-13 16:35:33 -0500340
341 // Validate the expected number of routes
342 assert.EqualValues(t, 2*numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, len(ldMgr.deviceRoutes.Routes))
343
344 // Validate the root ports
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400345 for _, port := range ldMgr.ports {
khenaidoo820197c2020-02-13 16:35:33 -0500346 assert.Equal(t, port.RootPort, ldMgr.deviceRoutes.IsRootPort(port.OfpPort.PortNo))
347 }
348
349 fmt.Println(fmt.Sprintf("Total Time:%dms, Total Routes:%d NumGetDeviceInvoked:%d", time.Since(start)/time.Millisecond, len(ldMgr.deviceRoutes.Routes), onuMgr.numGetDeviceInvoked))
350}
351
352func TestDeviceRoutes_compareRoutesGeneration(t *testing.T) {
353 numNNIPort := 2
354 numPonPortOnOlt := 8
355 numOnuPerOltPonPort := 32
356 numUniPerOnu := 4
357 done := make(chan struct{})
358
359 fmt.Println(fmt.Sprintf("Test: Computing all routes. LogicalPorts:%d, NNI:%d, Pon/OLT:%d, ONU/Pon:%d, Uni/Onu:%d",
360 numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, numNNIPort, numPonPortOnOlt, numOnuPerOltPonPort, numUniPerOnu))
361
362 // Create all the devices and logical device before computing the routes in one go
363 ld1 := &voltha.LogicalDevice{Id: logicalDeviceID}
364 ldMgrChnl1 := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
365 ldMgr1 := newLogicalDeviceManager(ld1, ldMgrChnl1, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
366 oltMgrChnl1 := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
367 oltMgr1 := newOltManager(oltDeviceID, ldMgr1, numNNIPort, numPonPortOnOlt, oltMgrChnl1)
368 onuMgr1 := newOnuManager(oltMgr1, numOnuPerOltPonPort, numUniPerOnu, 2)
369 getDevice := onuMgr1.GetDeviceHelper
Rohan Agrawal31f21802020-06-12 05:38:46 +0000370 ctx := context.Background()
khenaidoo820197c2020-02-13 16:35:33 -0500371 // Start the managers. Only the devices are created. No routes will be built.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000372 go ldMgr1.start(ctx, getDevice, false)
khenaidoo820197c2020-02-13 16:35:33 -0500373 go oltMgr1.start()
374 go onuMgr1.start(numNNIPort+1, numPonPortOnOlt)
375
376 // Wait for all the devices to be created
377 <-done
378 close(oltMgrChnl1)
379 close(ldMgrChnl1)
380
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400381 err := ldMgr1.deviceRoutes.ComputeRoutes(context.TODO(), ldMgr1.ports)
khenaidoo820197c2020-02-13 16:35:33 -0500382 assert.Nil(t, err)
383
384 routesGeneratedAllAtOnce := ldMgr1.deviceRoutes.Routes
385
386 done = make(chan struct{})
387 // Create all the devices and logical device before computing the routes in one go
388 ld2 := &voltha.LogicalDevice{Id: logicalDeviceID}
389 ldMgrChnl2 := make(chan portRegistration, numNNIPort*numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu)
390 ldMgr2 := newLogicalDeviceManager(ld2, ldMgrChnl2, numNNIPort+numPonPortOnOlt*numOnuPerOltPonPort*numUniPerOnu, done)
391 oltMgrChnl2 := make(chan onuRegistration, numPonPortOnOlt*numOnuPerOltPonPort)
392 oltMgr2 := newOltManager(oltDeviceID, ldMgr2, numNNIPort, numPonPortOnOlt, oltMgrChnl2)
393 onuMgr2 := newOnuManager(oltMgr2, numOnuPerOltPonPort, numUniPerOnu, 2)
394 // Start the managers. Only the devices are created. No routes will be built.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000395 go ldMgr2.start(ctx, getDevice, true)
khenaidoo820197c2020-02-13 16:35:33 -0500396 go oltMgr2.start()
397 go onuMgr2.start(numNNIPort+1, numPonPortOnOlt)
398
399 // Wait for all the devices to be created
400 <-done
401 close(oltMgrChnl2)
402 close(ldMgrChnl2)
403
404 routesGeneratedPerPort := ldMgr1.deviceRoutes.Routes
405 assert.True(t, isEqual(routesGeneratedAllAtOnce, routesGeneratedPerPort))
406}
407
408func TestDeviceRoutes_reverseRoute(t *testing.T) {
409 // Test the typical use case - 2 hops in a route
410 route := make([]Hop, 2)
411 route[0].DeviceID = "d1"
412 route[0].Ingress = 1
413 route[0].Egress = 2
414 route[1].DeviceID = "d2"
415 route[1].Ingress = 10
416 route[1].Egress = 15
417
418 reverseRoute := getReverseRoute(route)
419 assert.Equal(t, 2, len(reverseRoute))
420 assert.Equal(t, "d2", reverseRoute[0].DeviceID)
421 assert.Equal(t, "d1", reverseRoute[1].DeviceID)
422 assert.Equal(t, uint32(15), reverseRoute[0].Ingress)
423 assert.Equal(t, uint32(10), reverseRoute[0].Egress)
424 assert.Equal(t, uint32(2), reverseRoute[1].Ingress)
425 assert.Equal(t, uint32(1), reverseRoute[1].Egress)
426
427 fmt.Println("Reverse of two hops successful.")
428
429 //Test 3 hops in a route
430 route = make([]Hop, 3)
431 route[0].DeviceID = "d1"
432 route[0].Ingress = 1
433 route[0].Egress = 2
434 route[1].DeviceID = "d2"
435 route[1].Ingress = 10
436 route[1].Egress = 15
437 route[2].DeviceID = "d3"
438 route[2].Ingress = 20
439 route[2].Egress = 25
440 reverseRoute = getReverseRoute(route)
441 assert.Equal(t, 3, len(reverseRoute))
442 assert.Equal(t, "d3", reverseRoute[0].DeviceID)
443 assert.Equal(t, "d2", reverseRoute[1].DeviceID)
444 assert.Equal(t, "d1", reverseRoute[2].DeviceID)
445 assert.Equal(t, uint32(25), reverseRoute[0].Ingress)
446 assert.Equal(t, uint32(20), reverseRoute[0].Egress)
447 assert.Equal(t, uint32(15), reverseRoute[1].Ingress)
448 assert.Equal(t, uint32(10), reverseRoute[1].Egress)
449 assert.Equal(t, uint32(2), reverseRoute[2].Ingress)
450 assert.Equal(t, uint32(1), reverseRoute[2].Egress)
451
452 fmt.Println("Reverse of three hops successful.")
453
454 // Test any number of hops in a route
455 numRoutes := rand.Intn(100)
456 route = make([]Hop, numRoutes)
457 deviceIds := make([]string, numRoutes)
458 ingressNos := make([]uint32, numRoutes)
459 egressNos := make([]uint32, numRoutes)
460 for i := 0; i < numRoutes; i++ {
461 deviceIds[i] = fmt.Sprintf("d-%d", i)
462 ingressNos[i] = rand.Uint32()
463 egressNos[i] = rand.Uint32()
464 }
465 for i := 0; i < numRoutes; i++ {
466 route[i].DeviceID = deviceIds[i]
467 route[i].Ingress = ingressNos[i]
468 route[i].Egress = egressNos[i]
469 }
470 reverseRoute = getReverseRoute(route)
471 assert.Equal(t, numRoutes, len(reverseRoute))
472 for i, j := 0, numRoutes-1; j >= 0; i, j = i+1, j-1 {
473 assert.Equal(t, deviceIds[j], reverseRoute[i].DeviceID)
474 assert.Equal(t, egressNos[j], reverseRoute[i].Ingress)
475 assert.Equal(t, ingressNos[j], reverseRoute[i].Egress)
476 }
477
478 fmt.Println(fmt.Sprintf("Reverse of %d hops successful.", numRoutes))
479
480 reverseOfReverse := getReverseRoute(reverseRoute)
481 assert.Equal(t, route, reverseOfReverse)
482 fmt.Println("Reverse of reverse successful.")
483}
484
485func isEqual(routes1 map[PathID][]Hop, routes2 map[PathID][]Hop) bool {
486 if routes1 == nil && routes2 == nil {
487 return true
488 }
489 if (routes1 == nil && routes2 != nil) || (routes2 == nil && routes1 != nil) {
490 return false
491 }
492 if len(routes1) != len(routes2) {
493 return false
494 }
495 for routeID1, routeHop1 := range routes1 {
496 found := false
497 for routeID2, routeHop2 := range routes2 {
498 if routeID1 == routeID2 {
499 if !reflect.DeepEqual(routeHop1, routeHop2) {
500 return false
501 }
502 found = true
503 break
504 }
505 }
506 if !found {
507 return false
508 }
509 }
510 return true
511}