blob: 4f1506f2ece49710f9b5ed58827b44dbb34a5726 [file] [log] [blame]
khenaidoo6e55d9e2019-12-12 18:26:26 -05001/*
2* Copyright 2019-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 core
17
18import (
19 "context"
20 "github.com/gogo/protobuf/proto"
21 "github.com/opencord/voltha-go/rw_core/config"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080022 com "github.com/opencord/voltha-lib-go/v3/pkg/adapters/common"
23 "github.com/opencord/voltha-lib-go/v3/pkg/kafka"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080024 lm "github.com/opencord/voltha-lib-go/v3/pkg/mocks"
25 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
26 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoo6e55d9e2019-12-12 18:26:26 -050027 "github.com/phayes/freeport"
28 "github.com/stretchr/testify/assert"
29 "math/rand"
khenaidoob2121e52019-12-16 17:17:22 -050030 "sort"
khenaidoo6e55d9e2019-12-12 18:26:26 -050031 "strings"
32 "sync"
33 "testing"
34 "time"
35)
36
37type DATest struct {
38 etcdServer *lm.EtcdServer
39 core *Core
40 kClient kafka.Client
41 kvClientPort int
42 oltAdapterName string
43 onuAdapterName string
44 coreInstanceID string
45 defaultTimeout time.Duration
46 maxTimeout time.Duration
47 device *voltha.Device
48 done chan int
49}
50
51func newDATest() *DATest {
52 test := &DATest{}
53 // Start the embedded etcd server
54 var err error
55 test.etcdServer, test.kvClientPort, err = startEmbeddedEtcdServer("voltha.rwcore.da.test", "voltha.rwcore.da.etcd", "error")
56 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +000057 logger.Fatal(err)
khenaidoo6e55d9e2019-12-12 18:26:26 -050058 }
59 // Create the kafka client
60 test.kClient = lm.NewKafkaClient()
61 test.oltAdapterName = "olt_adapter_mock"
62 test.onuAdapterName = "onu_adapter_mock"
63 test.coreInstanceID = "rw-da-test"
64 test.defaultTimeout = 5 * time.Second
65 test.maxTimeout = 20 * time.Second
66 test.done = make(chan int)
67 parentID := com.GetRandomString(10)
68 test.device = &voltha.Device{
69 Type: "onu_adapter_mock",
70 ParentId: parentID,
71 ParentPortNo: 1,
72 VendorId: "onu_adapter_mock",
73 Adapter: "onu_adapter_mock",
74 Vlan: 100,
75 Address: nil,
76 ProxyAddress: &voltha.Device_ProxyAddress{
77 DeviceId: parentID,
78 DeviceType: "olt_adapter_mock",
79 ChannelId: 100,
80 ChannelGroupId: 0,
81 ChannelTermination: "",
82 OnuId: 2,
83 },
84 AdminState: voltha.AdminState_PREPROVISIONED,
85 OperStatus: voltha.OperStatus_UNKNOWN,
86 Reason: "All good",
87 ConnectStatus: voltha.ConnectStatus_UNKNOWN,
88 Custom: nil,
89 Ports: []*voltha.Port{
90 {PortNo: 1, Label: "pon-1", Type: voltha.Port_PON_ONU, AdminState: voltha.AdminState_ENABLED,
91 OperStatus: voltha.OperStatus_ACTIVE, Peers: []*voltha.Port_PeerPort{{DeviceId: parentID, PortNo: 1}}},
92 {PortNo: 100, Label: "uni-100", Type: voltha.Port_ETHERNET_UNI, AdminState: voltha.AdminState_ENABLED,
93 OperStatus: voltha.OperStatus_ACTIVE},
94 },
95 }
96
97 return test
98}
99
100func (dat *DATest) startCore(inCompeteMode bool) {
101 cfg := config.NewRWCoreFlags()
102 cfg.CorePairTopic = "rw_core"
khenaidoo442e7c72020-03-10 16:13:48 -0400103 cfg.DefaultRequestTimeout = dat.defaultTimeout
khenaidoo6e55d9e2019-12-12 18:26:26 -0500104 cfg.KVStorePort = dat.kvClientPort
105 cfg.InCompetingMode = inCompeteMode
106 grpcPort, err := freeport.GetFreePort()
107 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000108 logger.Fatal("Cannot get a freeport for grpc")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500109 }
110 cfg.GrpcPort = grpcPort
111 cfg.GrpcHost = "127.0.0.1"
112 setCoreCompeteMode(inCompeteMode)
113 client := setupKVClient(cfg, dat.coreInstanceID)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530114 dat.core = NewCore(context.Background(), dat.coreInstanceID, cfg, client, dat.kClient)
115 err = dat.core.Start(context.Background())
116 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000117 logger.Fatal("Cannot start core")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530118 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500119}
120
121func (dat *DATest) stopAll() {
122 if dat.kClient != nil {
123 dat.kClient.Stop()
124 }
125 if dat.core != nil {
126 dat.core.Stop(context.Background())
127 }
128 if dat.etcdServer != nil {
129 stopEmbeddedEtcdServer(dat.etcdServer)
130 }
131}
132
133func (dat *DATest) createDeviceAgent(t *testing.T) *DeviceAgent {
134 deviceMgr := dat.core.deviceMgr
135 clonedDevice := proto.Clone(dat.device).(*voltha.Device)
136 deviceAgent := newDeviceAgent(deviceMgr.adapterProxy, clonedDevice, deviceMgr, deviceMgr.clusterDataProxy, deviceMgr.defaultTimeout)
137 d, err := deviceAgent.start(context.TODO(), clonedDevice)
138 assert.Nil(t, err)
139 assert.NotNil(t, d)
140 deviceMgr.addDeviceAgentToMap(deviceAgent)
141 return deviceAgent
142}
143
144func (dat *DATest) updateDeviceConcurrently(t *testing.T, da *DeviceAgent, globalWG *sync.WaitGroup) {
khenaidoo442e7c72020-03-10 16:13:48 -0400145 originalDevice, err := da.getDevice(context.Background())
146 assert.Nil(t, err)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500147 assert.NotNil(t, originalDevice)
148 var localWG sync.WaitGroup
149
150 // Update device routine
151 var (
152 root = false
153 vendor = "onu_adapter_mock"
154 model = "go-mock"
155 serialNumber = com.GetRandomSerialNumber()
156 macAddress = strings.ToUpper(com.GetRandomMacAddress())
157 vlan = rand.Uint32()
158 reason = "testing concurrent device update"
159 portToAdd = &voltha.Port{PortNo: 101, Label: "uni-101", Type: voltha.Port_ETHERNET_UNI, AdminState: voltha.AdminState_ENABLED,
160 OperStatus: voltha.OperStatus_ACTIVE}
161 )
162 localWG.Add(1)
163 go func() {
164 deviceToUpdate := proto.Clone(originalDevice).(*voltha.Device)
165 deviceToUpdate.Root = root
166 deviceToUpdate.Vendor = vendor
167 deviceToUpdate.Model = model
168 deviceToUpdate.SerialNumber = serialNumber
169 deviceToUpdate.MacAddress = macAddress
170 deviceToUpdate.Vlan = vlan
171 deviceToUpdate.Reason = reason
npujar467fe752020-01-16 20:17:45 +0530172 err := da.updateDeviceUsingAdapterData(context.Background(), deviceToUpdate)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500173 assert.Nil(t, err)
174 localWG.Done()
175 }()
176
177 // Update the device status routine
178 localWG.Add(1)
179 go func() {
npujar467fe752020-01-16 20:17:45 +0530180 err := da.updateDeviceStatus(context.Background(), voltha.OperStatus_ACTIVE, voltha.ConnectStatus_REACHABLE)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500181 assert.Nil(t, err)
182 localWG.Done()
183 }()
184
185 // Add a port routine
186 localWG.Add(1)
187 go func() {
npujar467fe752020-01-16 20:17:45 +0530188 err := da.addPort(context.Background(), portToAdd)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500189 assert.Nil(t, err)
190 localWG.Done()
191 }()
192
193 // wait for go routines to be done
194 localWG.Wait()
195
196 expectedChange := proto.Clone(originalDevice).(*voltha.Device)
197 expectedChange.OperStatus = voltha.OperStatus_ACTIVE
198 expectedChange.ConnectStatus = voltha.ConnectStatus_REACHABLE
199 expectedChange.Ports = append(expectedChange.Ports, portToAdd)
200 expectedChange.Root = root
201 expectedChange.Vendor = vendor
202 expectedChange.Model = model
203 expectedChange.SerialNumber = serialNumber
204 expectedChange.MacAddress = macAddress
205 expectedChange.Vlan = vlan
206 expectedChange.Reason = reason
207
khenaidoo442e7c72020-03-10 16:13:48 -0400208 updatedDevice, _ := da.getDevice(context.Background())
khenaidoo6e55d9e2019-12-12 18:26:26 -0500209 assert.NotNil(t, updatedDevice)
210 assert.True(t, proto.Equal(expectedChange, updatedDevice))
211
212 globalWG.Done()
213}
214
215func TestConcurrentDevices(t *testing.T) {
khenaidoo442e7c72020-03-10 16:13:48 -0400216 for i := 0; i < 2; i++ {
217 da := newDATest()
218 assert.NotNil(t, da)
219 defer da.stopAll()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500220
khenaidoo442e7c72020-03-10 16:13:48 -0400221 // Start the Core
222 da.startCore(false)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500223
khenaidoo442e7c72020-03-10 16:13:48 -0400224 var wg sync.WaitGroup
225 numConCurrentDeviceAgents := 20
226 for i := 0; i < numConCurrentDeviceAgents; i++ {
227 wg.Add(1)
228 a := da.createDeviceAgent(t)
229 go da.updateDeviceConcurrently(t, a, &wg)
230 }
231
232 wg.Wait()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500233 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500234}
khenaidoob2121e52019-12-16 17:17:22 -0500235
236func isFlowSliceEqual(a, b []*ofp.OfpFlowStats) bool {
237 if len(a) != len(b) {
238 return false
239 }
240 sort.Slice(a, func(i, j int) bool {
241 return a[i].Id < a[j].Id
242 })
243 sort.Slice(b, func(i, j int) bool {
244 return b[i].Id < b[j].Id
245 })
246 for idx := range a {
247 if !proto.Equal(a[idx], b[idx]) {
248 return false
249 }
250 }
251 return true
252}
253
254func isGroupSliceEqual(a, b []*ofp.OfpGroupEntry) bool {
255 if len(a) != len(b) {
256 return false
257 }
258 sort.Slice(a, func(i, j int) bool {
259 return a[i].Desc.GroupId < a[j].Desc.GroupId
260 })
261 sort.Slice(b, func(i, j int) bool {
262 return b[i].Desc.GroupId < b[j].Desc.GroupId
263 })
264 for idx := range a {
265 if !proto.Equal(a[idx], b[idx]) {
266 return false
267 }
268 }
269 return true
270}
271
272func TestFlowsToUpdateToDelete_EmptySlices(t *testing.T) {
273 newFlows := []*ofp.OfpFlowStats{}
274 existingFlows := []*ofp.OfpFlowStats{}
275 expectedNewFlows := []*ofp.OfpFlowStats{}
276 expectedFlowsToDelete := []*ofp.OfpFlowStats{}
277 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{}
278 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
279 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
280 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
281 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
282}
283
284func TestFlowsToUpdateToDelete_NoExistingFlows(t *testing.T) {
285 newFlows := []*ofp.OfpFlowStats{
286 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
287 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
288 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
289 }
290 existingFlows := []*ofp.OfpFlowStats{}
291 expectedNewFlows := []*ofp.OfpFlowStats{
292 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
293 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
294 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
295 }
296 expectedFlowsToDelete := []*ofp.OfpFlowStats{}
297 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{
298 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
299 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
300 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
301 }
302 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
303 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
304 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
305 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
306}
307
308func TestFlowsToUpdateToDelete_UpdateNoDelete(t *testing.T) {
309 newFlows := []*ofp.OfpFlowStats{
310 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
311 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
312 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
313 }
314 existingFlows := []*ofp.OfpFlowStats{
315 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
316 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
317 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
318 }
319 expectedNewFlows := []*ofp.OfpFlowStats{
320 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
321 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
322 }
323 expectedFlowsToDelete := []*ofp.OfpFlowStats{}
324 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{
325 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
326 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
327 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
328 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
329 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
330 }
331 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
332 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
333 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
334 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
335}
336
337func TestFlowsToUpdateToDelete_UpdateAndDelete(t *testing.T) {
338 newFlows := []*ofp.OfpFlowStats{
339 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 20},
340 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
341 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 10, Flags: 0, Cookie: 1250000, PacketCount: 0},
342 {Id: 126, TableId: 1260, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
343 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
344 }
345 existingFlows := []*ofp.OfpFlowStats{
346 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
347 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
348 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
349 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
350 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
351 }
352 expectedNewFlows := []*ofp.OfpFlowStats{
353 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 20},
354 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 10, Flags: 0, Cookie: 1250000, PacketCount: 0},
355 {Id: 126, TableId: 1260, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
356 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
357 }
358 expectedFlowsToDelete := []*ofp.OfpFlowStats{
359 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
360 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
361 }
362 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{
363 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
364 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
365 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 20},
366 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
367 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 10, Flags: 0, Cookie: 1250000, PacketCount: 0},
368 {Id: 126, TableId: 1260, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
369 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
370 }
371 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
372 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
373 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
374 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
375}
376
377func TestGroupsToUpdateToDelete_EmptySlices(t *testing.T) {
378 newGroups := []*ofp.OfpGroupEntry{}
379 existingGroups := []*ofp.OfpGroupEntry{}
380 expectedNewGroups := []*ofp.OfpGroupEntry{}
381 expectedGroupsToDelete := []*ofp.OfpGroupEntry{}
382 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{}
383 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
384 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
385 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
386 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
387}
388
389func TestGroupsToUpdateToDelete_NoExistingGroups(t *testing.T) {
390 newGroups := []*ofp.OfpGroupEntry{
391 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
392 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
393 }
394 existingGroups := []*ofp.OfpGroupEntry{}
395 expectedNewGroups := []*ofp.OfpGroupEntry{
396 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
397 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
398 }
399 expectedGroupsToDelete := []*ofp.OfpGroupEntry{}
400 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{
401 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
402 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
403 }
404 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
405 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
406 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
407 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
408}
409
410func TestGroupsToUpdateToDelete_UpdateNoDelete(t *testing.T) {
411 newGroups := []*ofp.OfpGroupEntry{
412 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
413 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
414 }
415 existingGroups := []*ofp.OfpGroupEntry{
416 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
417 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
418 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
419 }
420 expectedNewGroups := []*ofp.OfpGroupEntry{
421 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
422 }
423 expectedGroupsToDelete := []*ofp.OfpGroupEntry{}
424 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{
425 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
426 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
427 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
428 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
429 }
430 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
431 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
432 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
433 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
434}
435
436func TestGroupsToUpdateToDelete_UpdateWithDelete(t *testing.T) {
437 newGroups := []*ofp.OfpGroupEntry{
438 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
439 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: []*ofp.OfpBucket{{WatchPort: 10}}}},
440 }
441 existingGroups := []*ofp.OfpGroupEntry{
442 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
443 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
444 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
445 }
446 expectedNewGroups := []*ofp.OfpGroupEntry{
447 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
448 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: []*ofp.OfpBucket{{WatchPort: 10}}}},
449 }
450 expectedGroupsToDelete := []*ofp.OfpGroupEntry{
451 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
452 }
453 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{
454 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
455 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: []*ofp.OfpBucket{{WatchPort: 10}}}},
456 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
457 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
458 }
459 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
460 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
461 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
462 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
463}