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