blob: 8b003b4cac6600b2cba8a8068db061dc32a98a40 [file] [log] [blame]
khenaidoo6e55d9e2019-12-12 18:26:26 -05001/*
Kent Hagerman45a13e42020-04-13 12:23:50 -04002 * 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.
khenaidoo6e55d9e2019-12-12 18:26:26 -050015 */
Kent Hagerman45a13e42020-04-13 12:23:50 -040016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoo6e55d9e2019-12-12 18:26:26 -050018
19import (
20 "context"
21 "github.com/gogo/protobuf/proto"
Kent Hagerman2b216042020-04-03 18:28:56 -040022 "github.com/opencord/voltha-go/db/model"
khenaidoo6e55d9e2019-12-12 18:26:26 -050023 "github.com/opencord/voltha-go/rw_core/config"
Kent Hagerman2b216042020-04-03 18:28:56 -040024 "github.com/opencord/voltha-go/rw_core/core/adapter"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080025 com "github.com/opencord/voltha-lib-go/v3/pkg/adapters/common"
Kent Hagerman2b216042020-04-03 18:28:56 -040026 "github.com/opencord/voltha-lib-go/v3/pkg/db"
27 "github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080028 "github.com/opencord/voltha-lib-go/v3/pkg/kafka"
Scott Baker504b4802020-04-17 10:12:20 -070029 "github.com/opencord/voltha-lib-go/v3/pkg/log"
Matteo Scandolod525ae32020-04-02 17:27:29 -070030 mock_etcd "github.com/opencord/voltha-lib-go/v3/pkg/mocks/etcd"
31 mock_kafka "github.com/opencord/voltha-lib-go/v3/pkg/mocks/kafka"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080032 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
33 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoo6e55d9e2019-12-12 18:26:26 -050034 "github.com/phayes/freeport"
35 "github.com/stretchr/testify/assert"
Kent Hagerman2b216042020-04-03 18:28:56 -040036 "google.golang.org/grpc/codes"
37 "google.golang.org/grpc/status"
khenaidoo6e55d9e2019-12-12 18:26:26 -050038 "math/rand"
khenaidoob2121e52019-12-16 17:17:22 -050039 "sort"
Kent Hagerman2b216042020-04-03 18:28:56 -040040 "strconv"
khenaidoo6e55d9e2019-12-12 18:26:26 -050041 "strings"
42 "sync"
43 "testing"
44 "time"
45)
46
47type DATest struct {
Kent Hagerman2b216042020-04-03 18:28:56 -040048 etcdServer *mock_etcd.EtcdServer
49 deviceMgr *Manager
50 logicalDeviceMgr *LogicalManager
51 kmp kafka.InterContainerProxy
52 kClient kafka.Client
53 kvClientPort int
54 oltAdapterName string
55 onuAdapterName string
56 coreInstanceID string
57 defaultTimeout time.Duration
58 maxTimeout time.Duration
59 device *voltha.Device
60 done chan int
khenaidoo6e55d9e2019-12-12 18:26:26 -050061}
62
63func newDATest() *DATest {
64 test := &DATest{}
65 // Start the embedded etcd server
66 var err error
67 test.etcdServer, test.kvClientPort, err = startEmbeddedEtcdServer("voltha.rwcore.da.test", "voltha.rwcore.da.etcd", "error")
68 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +000069 logger.Fatal(err)
khenaidoo6e55d9e2019-12-12 18:26:26 -050070 }
71 // Create the kafka client
Matteo Scandolod525ae32020-04-02 17:27:29 -070072 test.kClient = mock_kafka.NewKafkaClient()
khenaidoo6e55d9e2019-12-12 18:26:26 -050073 test.oltAdapterName = "olt_adapter_mock"
74 test.onuAdapterName = "onu_adapter_mock"
75 test.coreInstanceID = "rw-da-test"
76 test.defaultTimeout = 5 * time.Second
77 test.maxTimeout = 20 * time.Second
78 test.done = make(chan int)
79 parentID := com.GetRandomString(10)
80 test.device = &voltha.Device{
81 Type: "onu_adapter_mock",
82 ParentId: parentID,
83 ParentPortNo: 1,
84 VendorId: "onu_adapter_mock",
85 Adapter: "onu_adapter_mock",
86 Vlan: 100,
87 Address: nil,
88 ProxyAddress: &voltha.Device_ProxyAddress{
89 DeviceId: parentID,
90 DeviceType: "olt_adapter_mock",
91 ChannelId: 100,
92 ChannelGroupId: 0,
93 ChannelTermination: "",
94 OnuId: 2,
95 },
96 AdminState: voltha.AdminState_PREPROVISIONED,
97 OperStatus: voltha.OperStatus_UNKNOWN,
98 Reason: "All good",
99 ConnectStatus: voltha.ConnectStatus_UNKNOWN,
100 Custom: nil,
101 Ports: []*voltha.Port{
102 {PortNo: 1, Label: "pon-1", Type: voltha.Port_PON_ONU, AdminState: voltha.AdminState_ENABLED,
103 OperStatus: voltha.OperStatus_ACTIVE, Peers: []*voltha.Port_PeerPort{{DeviceId: parentID, PortNo: 1}}},
104 {PortNo: 100, Label: "uni-100", Type: voltha.Port_ETHERNET_UNI, AdminState: voltha.AdminState_ENABLED,
105 OperStatus: voltha.OperStatus_ACTIVE},
106 },
107 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500108 return test
109}
110
111func (dat *DATest) startCore(inCompeteMode bool) {
112 cfg := config.NewRWCoreFlags()
113 cfg.CorePairTopic = "rw_core"
khenaidoo442e7c72020-03-10 16:13:48 -0400114 cfg.DefaultRequestTimeout = dat.defaultTimeout
khenaidoo6e55d9e2019-12-12 18:26:26 -0500115 cfg.KVStorePort = dat.kvClientPort
116 cfg.InCompetingMode = inCompeteMode
117 grpcPort, err := freeport.GetFreePort()
118 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000119 logger.Fatal("Cannot get a freeport for grpc")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500120 }
121 cfg.GrpcPort = grpcPort
122 cfg.GrpcHost = "127.0.0.1"
khenaidoo6e55d9e2019-12-12 18:26:26 -0500123 client := setupKVClient(cfg, dat.coreInstanceID)
Kent Hagerman2b216042020-04-03 18:28:56 -0400124 backend := &db.Backend{
125 Client: client,
126 StoreType: cfg.KVStoreType,
127 Host: cfg.KVStoreHost,
128 Port: cfg.KVStorePort,
129 Timeout: cfg.KVStoreTimeout,
130 LivenessChannelInterval: cfg.LiveProbeInterval / 2,
131 PathPrefix: cfg.KVStoreDataPrefix}
132 dat.kmp = kafka.NewInterContainerProxy(
133 kafka.InterContainerHost(cfg.KafkaAdapterHost),
134 kafka.InterContainerPort(cfg.KafkaAdapterPort),
135 kafka.MsgClient(dat.kClient),
136 kafka.DefaultTopic(&kafka.Topic{Name: cfg.CoreTopic}),
137 kafka.DeviceDiscoveryTopic(&kafka.Topic{Name: cfg.AffinityRouterTopic}))
138
139 endpointMgr := kafka.NewEndpointManager(backend)
140 proxy := model.NewProxy(backend, "/")
141 adapterMgr := adapter.NewAdapterManager(proxy, dat.coreInstanceID, dat.kClient)
142
Kent Hagerman45a13e42020-04-13 12:23:50 -0400143 dat.deviceMgr, dat.logicalDeviceMgr = NewManagers(proxy, adapterMgr, dat.kmp, endpointMgr, cfg.CorePairTopic, dat.coreInstanceID, cfg.DefaultCoreTimeout)
Kent Hagerman2b216042020-04-03 18:28:56 -0400144 if err = dat.kmp.Start(); err != nil {
145 logger.Fatal("Cannot start InterContainerProxy")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530146 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400147 if err = adapterMgr.Start(context.Background()); err != nil {
148 logger.Fatal("Cannot start adapterMgr")
149 }
150 dat.deviceMgr.Start(context.Background())
151 dat.logicalDeviceMgr.Start(context.Background())
khenaidoo6e55d9e2019-12-12 18:26:26 -0500152}
153
154func (dat *DATest) stopAll() {
155 if dat.kClient != nil {
156 dat.kClient.Stop()
157 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400158 if dat.logicalDeviceMgr != nil {
159 dat.logicalDeviceMgr.Stop(context.Background())
160 }
161 if dat.deviceMgr != nil {
162 dat.deviceMgr.Stop(context.Background())
163 }
164 if dat.kmp != nil {
165 dat.kmp.Stop()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500166 }
167 if dat.etcdServer != nil {
168 stopEmbeddedEtcdServer(dat.etcdServer)
169 }
170}
171
Kent Hagerman2b216042020-04-03 18:28:56 -0400172//startEmbeddedEtcdServer creates and starts an Embedded etcd server locally.
173func startEmbeddedEtcdServer(configName, storageDir, logLevel string) (*mock_etcd.EtcdServer, int, error) {
174 kvClientPort, err := freeport.GetFreePort()
175 if err != nil {
176 return nil, 0, err
177 }
178 peerPort, err := freeport.GetFreePort()
179 if err != nil {
180 return nil, 0, err
181 }
182 etcdServer := mock_etcd.StartEtcdServer(mock_etcd.MKConfig(configName, kvClientPort, peerPort, storageDir, logLevel))
183 if etcdServer == nil {
184 return nil, 0, status.Error(codes.Internal, "Embedded server failed to start")
185 }
186 return etcdServer, kvClientPort, nil
187}
188
189func stopEmbeddedEtcdServer(server *mock_etcd.EtcdServer) {
190 if server != nil {
191 server.Stop()
192 }
193}
194
195func setupKVClient(cf *config.RWCoreFlags, coreInstanceID string) kvstore.Client {
196 addr := cf.KVStoreHost + ":" + strconv.Itoa(cf.KVStorePort)
Scott Baker504b4802020-04-17 10:12:20 -0700197 client, err := kvstore.NewEtcdClient(addr, cf.KVStoreTimeout, log.FatalLevel)
Kent Hagerman2b216042020-04-03 18:28:56 -0400198 if err != nil {
199 panic("no kv client")
200 }
201 return client
202}
203
204func (dat *DATest) createDeviceAgent(t *testing.T) *Agent {
205 deviceMgr := dat.deviceMgr
khenaidoo6e55d9e2019-12-12 18:26:26 -0500206 clonedDevice := proto.Clone(dat.device).(*voltha.Device)
Kent Hagerman2b216042020-04-03 18:28:56 -0400207 deviceAgent := newAgent(deviceMgr.adapterProxy, clonedDevice, deviceMgr, deviceMgr.clusterDataProxy, deviceMgr.defaultTimeout)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500208 d, err := deviceAgent.start(context.TODO(), clonedDevice)
209 assert.Nil(t, err)
210 assert.NotNil(t, d)
211 deviceMgr.addDeviceAgentToMap(deviceAgent)
212 return deviceAgent
213}
214
Kent Hagerman2b216042020-04-03 18:28:56 -0400215func (dat *DATest) updateDeviceConcurrently(t *testing.T, da *Agent, globalWG *sync.WaitGroup) {
khenaidoo442e7c72020-03-10 16:13:48 -0400216 originalDevice, err := da.getDevice(context.Background())
217 assert.Nil(t, err)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500218 assert.NotNil(t, originalDevice)
219 var localWG sync.WaitGroup
220
221 // Update device routine
222 var (
223 root = false
224 vendor = "onu_adapter_mock"
225 model = "go-mock"
226 serialNumber = com.GetRandomSerialNumber()
227 macAddress = strings.ToUpper(com.GetRandomMacAddress())
228 vlan = rand.Uint32()
229 reason = "testing concurrent device update"
230 portToAdd = &voltha.Port{PortNo: 101, Label: "uni-101", Type: voltha.Port_ETHERNET_UNI, AdminState: voltha.AdminState_ENABLED,
231 OperStatus: voltha.OperStatus_ACTIVE}
232 )
233 localWG.Add(1)
234 go func() {
235 deviceToUpdate := proto.Clone(originalDevice).(*voltha.Device)
236 deviceToUpdate.Root = root
237 deviceToUpdate.Vendor = vendor
238 deviceToUpdate.Model = model
239 deviceToUpdate.SerialNumber = serialNumber
240 deviceToUpdate.MacAddress = macAddress
241 deviceToUpdate.Vlan = vlan
242 deviceToUpdate.Reason = reason
npujar467fe752020-01-16 20:17:45 +0530243 err := da.updateDeviceUsingAdapterData(context.Background(), deviceToUpdate)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500244 assert.Nil(t, err)
245 localWG.Done()
246 }()
247
248 // Update the device status routine
249 localWG.Add(1)
250 go func() {
npujar467fe752020-01-16 20:17:45 +0530251 err := da.updateDeviceStatus(context.Background(), voltha.OperStatus_ACTIVE, voltha.ConnectStatus_REACHABLE)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500252 assert.Nil(t, err)
253 localWG.Done()
254 }()
255
256 // Add a port routine
257 localWG.Add(1)
258 go func() {
npujar467fe752020-01-16 20:17:45 +0530259 err := da.addPort(context.Background(), portToAdd)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500260 assert.Nil(t, err)
261 localWG.Done()
262 }()
263
264 // wait for go routines to be done
265 localWG.Wait()
266
267 expectedChange := proto.Clone(originalDevice).(*voltha.Device)
268 expectedChange.OperStatus = voltha.OperStatus_ACTIVE
269 expectedChange.ConnectStatus = voltha.ConnectStatus_REACHABLE
270 expectedChange.Ports = append(expectedChange.Ports, portToAdd)
271 expectedChange.Root = root
272 expectedChange.Vendor = vendor
273 expectedChange.Model = model
274 expectedChange.SerialNumber = serialNumber
275 expectedChange.MacAddress = macAddress
276 expectedChange.Vlan = vlan
277 expectedChange.Reason = reason
278
khenaidoo442e7c72020-03-10 16:13:48 -0400279 updatedDevice, _ := da.getDevice(context.Background())
khenaidoo6e55d9e2019-12-12 18:26:26 -0500280 assert.NotNil(t, updatedDevice)
281 assert.True(t, proto.Equal(expectedChange, updatedDevice))
282
283 globalWG.Done()
284}
285
286func TestConcurrentDevices(t *testing.T) {
khenaidoo442e7c72020-03-10 16:13:48 -0400287 for i := 0; i < 2; i++ {
288 da := newDATest()
289 assert.NotNil(t, da)
290 defer da.stopAll()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500291
khenaidoo442e7c72020-03-10 16:13:48 -0400292 // Start the Core
293 da.startCore(false)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500294
khenaidoo442e7c72020-03-10 16:13:48 -0400295 var wg sync.WaitGroup
296 numConCurrentDeviceAgents := 20
297 for i := 0; i < numConCurrentDeviceAgents; i++ {
298 wg.Add(1)
299 a := da.createDeviceAgent(t)
300 go da.updateDeviceConcurrently(t, a, &wg)
301 }
302
303 wg.Wait()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500304 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500305}
khenaidoob2121e52019-12-16 17:17:22 -0500306
307func isFlowSliceEqual(a, b []*ofp.OfpFlowStats) bool {
308 if len(a) != len(b) {
309 return false
310 }
311 sort.Slice(a, func(i, j int) bool {
312 return a[i].Id < a[j].Id
313 })
314 sort.Slice(b, func(i, j int) bool {
315 return b[i].Id < b[j].Id
316 })
317 for idx := range a {
318 if !proto.Equal(a[idx], b[idx]) {
319 return false
320 }
321 }
322 return true
323}
324
325func isGroupSliceEqual(a, b []*ofp.OfpGroupEntry) bool {
326 if len(a) != len(b) {
327 return false
328 }
329 sort.Slice(a, func(i, j int) bool {
330 return a[i].Desc.GroupId < a[j].Desc.GroupId
331 })
332 sort.Slice(b, func(i, j int) bool {
333 return b[i].Desc.GroupId < b[j].Desc.GroupId
334 })
335 for idx := range a {
336 if !proto.Equal(a[idx], b[idx]) {
337 return false
338 }
339 }
340 return true
341}
342
343func TestFlowsToUpdateToDelete_EmptySlices(t *testing.T) {
344 newFlows := []*ofp.OfpFlowStats{}
345 existingFlows := []*ofp.OfpFlowStats{}
346 expectedNewFlows := []*ofp.OfpFlowStats{}
347 expectedFlowsToDelete := []*ofp.OfpFlowStats{}
348 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{}
349 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
350 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
351 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
352 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
353}
354
355func TestFlowsToUpdateToDelete_NoExistingFlows(t *testing.T) {
356 newFlows := []*ofp.OfpFlowStats{
357 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
358 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
359 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
360 }
361 existingFlows := []*ofp.OfpFlowStats{}
362 expectedNewFlows := []*ofp.OfpFlowStats{
363 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
364 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
365 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
366 }
367 expectedFlowsToDelete := []*ofp.OfpFlowStats{}
368 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{
369 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
370 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
371 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
372 }
373 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
374 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
375 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
376 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
377}
378
379func TestFlowsToUpdateToDelete_UpdateNoDelete(t *testing.T) {
380 newFlows := []*ofp.OfpFlowStats{
381 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
382 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
383 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
384 }
385 existingFlows := []*ofp.OfpFlowStats{
386 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
387 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
388 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
389 }
390 expectedNewFlows := []*ofp.OfpFlowStats{
391 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
392 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
393 }
394 expectedFlowsToDelete := []*ofp.OfpFlowStats{}
395 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{
396 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
397 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
398 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
399 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
400 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
401 }
402 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
403 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
404 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
405 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
406}
407
408func TestFlowsToUpdateToDelete_UpdateAndDelete(t *testing.T) {
409 newFlows := []*ofp.OfpFlowStats{
410 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 20},
411 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
412 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 10, Flags: 0, Cookie: 1250000, PacketCount: 0},
413 {Id: 126, TableId: 1260, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
414 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
415 }
416 existingFlows := []*ofp.OfpFlowStats{
417 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
418 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
419 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
420 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
421 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
422 }
423 expectedNewFlows := []*ofp.OfpFlowStats{
424 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 20},
425 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 10, Flags: 0, Cookie: 1250000, PacketCount: 0},
426 {Id: 126, TableId: 1260, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
427 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
428 }
429 expectedFlowsToDelete := []*ofp.OfpFlowStats{
430 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
431 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
432 }
433 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{
434 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
435 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
436 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 20},
437 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
438 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 10, Flags: 0, Cookie: 1250000, PacketCount: 0},
439 {Id: 126, TableId: 1260, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
440 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
441 }
442 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
443 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
444 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
445 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
446}
447
448func TestGroupsToUpdateToDelete_EmptySlices(t *testing.T) {
449 newGroups := []*ofp.OfpGroupEntry{}
450 existingGroups := []*ofp.OfpGroupEntry{}
451 expectedNewGroups := []*ofp.OfpGroupEntry{}
452 expectedGroupsToDelete := []*ofp.OfpGroupEntry{}
453 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{}
454 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
455 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
456 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
457 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
458}
459
460func TestGroupsToUpdateToDelete_NoExistingGroups(t *testing.T) {
461 newGroups := []*ofp.OfpGroupEntry{
462 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
463 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
464 }
465 existingGroups := []*ofp.OfpGroupEntry{}
466 expectedNewGroups := []*ofp.OfpGroupEntry{
467 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
468 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
469 }
470 expectedGroupsToDelete := []*ofp.OfpGroupEntry{}
471 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{
472 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
473 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
474 }
475 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
476 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
477 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
478 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
479}
480
481func TestGroupsToUpdateToDelete_UpdateNoDelete(t *testing.T) {
482 newGroups := []*ofp.OfpGroupEntry{
483 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
484 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
485 }
486 existingGroups := []*ofp.OfpGroupEntry{
487 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
488 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
489 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
490 }
491 expectedNewGroups := []*ofp.OfpGroupEntry{
492 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
493 }
494 expectedGroupsToDelete := []*ofp.OfpGroupEntry{}
495 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{
496 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
497 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
498 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
499 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
500 }
501 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
502 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
503 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
504 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
505}
506
507func TestGroupsToUpdateToDelete_UpdateWithDelete(t *testing.T) {
508 newGroups := []*ofp.OfpGroupEntry{
509 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
510 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: []*ofp.OfpBucket{{WatchPort: 10}}}},
511 }
512 existingGroups := []*ofp.OfpGroupEntry{
513 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
514 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
515 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
516 }
517 expectedNewGroups := []*ofp.OfpGroupEntry{
518 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
519 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: []*ofp.OfpBucket{{WatchPort: 10}}}},
520 }
521 expectedGroupsToDelete := []*ofp.OfpGroupEntry{
522 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
523 }
524 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{
525 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
526 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: []*ofp.OfpBucket{{WatchPort: 10}}}},
527 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
528 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
529 }
530 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
531 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
532 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
533 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
534}