blob: ce69599a97492bb89ccba08697e4395174d78079 [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 */
Kent Hagerman2b216042020-04-03 18:28:56 -040016package device
khenaidoo6e55d9e2019-12-12 18:26:26 -050017
18import (
19 "context"
20 "github.com/gogo/protobuf/proto"
Kent Hagerman2b216042020-04-03 18:28:56 -040021 "github.com/opencord/voltha-go/db/model"
khenaidoo6e55d9e2019-12-12 18:26:26 -050022 "github.com/opencord/voltha-go/rw_core/config"
Kent Hagerman2b216042020-04-03 18:28:56 -040023 "github.com/opencord/voltha-go/rw_core/core/adapter"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080024 com "github.com/opencord/voltha-lib-go/v3/pkg/adapters/common"
Kent Hagerman2b216042020-04-03 18:28:56 -040025 "github.com/opencord/voltha-lib-go/v3/pkg/db"
26 "github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080027 "github.com/opencord/voltha-lib-go/v3/pkg/kafka"
Matteo Scandolod525ae32020-04-02 17:27:29 -070028 mock_etcd "github.com/opencord/voltha-lib-go/v3/pkg/mocks/etcd"
29 mock_kafka "github.com/opencord/voltha-lib-go/v3/pkg/mocks/kafka"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080030 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
31 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoo6e55d9e2019-12-12 18:26:26 -050032 "github.com/phayes/freeport"
33 "github.com/stretchr/testify/assert"
Kent Hagerman2b216042020-04-03 18:28:56 -040034 "google.golang.org/grpc/codes"
35 "google.golang.org/grpc/status"
khenaidoo6e55d9e2019-12-12 18:26:26 -050036 "math/rand"
khenaidoob2121e52019-12-16 17:17:22 -050037 "sort"
Kent Hagerman2b216042020-04-03 18:28:56 -040038 "strconv"
khenaidoo6e55d9e2019-12-12 18:26:26 -050039 "strings"
40 "sync"
41 "testing"
42 "time"
43)
44
45type DATest struct {
Kent Hagerman2b216042020-04-03 18:28:56 -040046 etcdServer *mock_etcd.EtcdServer
47 deviceMgr *Manager
48 logicalDeviceMgr *LogicalManager
49 kmp kafka.InterContainerProxy
50 kClient kafka.Client
51 kvClientPort int
52 oltAdapterName string
53 onuAdapterName string
54 coreInstanceID string
55 defaultTimeout time.Duration
56 maxTimeout time.Duration
57 device *voltha.Device
58 done chan int
khenaidoo6e55d9e2019-12-12 18:26:26 -050059}
60
61func newDATest() *DATest {
62 test := &DATest{}
63 // Start the embedded etcd server
64 var err error
65 test.etcdServer, test.kvClientPort, err = startEmbeddedEtcdServer("voltha.rwcore.da.test", "voltha.rwcore.da.etcd", "error")
66 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +000067 logger.Fatal(err)
khenaidoo6e55d9e2019-12-12 18:26:26 -050068 }
69 // Create the kafka client
Matteo Scandolod525ae32020-04-02 17:27:29 -070070 test.kClient = mock_kafka.NewKafkaClient()
khenaidoo6e55d9e2019-12-12 18:26:26 -050071 test.oltAdapterName = "olt_adapter_mock"
72 test.onuAdapterName = "onu_adapter_mock"
73 test.coreInstanceID = "rw-da-test"
74 test.defaultTimeout = 5 * time.Second
75 test.maxTimeout = 20 * time.Second
76 test.done = make(chan int)
77 parentID := com.GetRandomString(10)
78 test.device = &voltha.Device{
79 Type: "onu_adapter_mock",
80 ParentId: parentID,
81 ParentPortNo: 1,
82 VendorId: "onu_adapter_mock",
83 Adapter: "onu_adapter_mock",
84 Vlan: 100,
85 Address: nil,
86 ProxyAddress: &voltha.Device_ProxyAddress{
87 DeviceId: parentID,
88 DeviceType: "olt_adapter_mock",
89 ChannelId: 100,
90 ChannelGroupId: 0,
91 ChannelTermination: "",
92 OnuId: 2,
93 },
94 AdminState: voltha.AdminState_PREPROVISIONED,
95 OperStatus: voltha.OperStatus_UNKNOWN,
96 Reason: "All good",
97 ConnectStatus: voltha.ConnectStatus_UNKNOWN,
98 Custom: nil,
99 Ports: []*voltha.Port{
100 {PortNo: 1, Label: "pon-1", Type: voltha.Port_PON_ONU, AdminState: voltha.AdminState_ENABLED,
101 OperStatus: voltha.OperStatus_ACTIVE, Peers: []*voltha.Port_PeerPort{{DeviceId: parentID, PortNo: 1}}},
102 {PortNo: 100, Label: "uni-100", Type: voltha.Port_ETHERNET_UNI, AdminState: voltha.AdminState_ENABLED,
103 OperStatus: voltha.OperStatus_ACTIVE},
104 },
105 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500106 return test
107}
108
Kent Hagerman2b216042020-04-03 18:28:56 -0400109type fakeEventCallbacks struct{}
110
111func (fakeEventCallbacks) SendChangeEvent(_ string, _ *ofp.OfpPortStatus) {}
112func (fakeEventCallbacks) SendPacketIn(_ string, _ string, _ *ofp.OfpPacketIn) {}
113
khenaidoo6e55d9e2019-12-12 18:26:26 -0500114func (dat *DATest) startCore(inCompeteMode bool) {
115 cfg := config.NewRWCoreFlags()
116 cfg.CorePairTopic = "rw_core"
khenaidoo442e7c72020-03-10 16:13:48 -0400117 cfg.DefaultRequestTimeout = dat.defaultTimeout
khenaidoo6e55d9e2019-12-12 18:26:26 -0500118 cfg.KVStorePort = dat.kvClientPort
119 cfg.InCompetingMode = inCompeteMode
120 grpcPort, err := freeport.GetFreePort()
121 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000122 logger.Fatal("Cannot get a freeport for grpc")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500123 }
124 cfg.GrpcPort = grpcPort
125 cfg.GrpcHost = "127.0.0.1"
khenaidoo6e55d9e2019-12-12 18:26:26 -0500126 client := setupKVClient(cfg, dat.coreInstanceID)
Kent Hagerman2b216042020-04-03 18:28:56 -0400127 backend := &db.Backend{
128 Client: client,
129 StoreType: cfg.KVStoreType,
130 Host: cfg.KVStoreHost,
131 Port: cfg.KVStorePort,
132 Timeout: cfg.KVStoreTimeout,
133 LivenessChannelInterval: cfg.LiveProbeInterval / 2,
134 PathPrefix: cfg.KVStoreDataPrefix}
135 dat.kmp = kafka.NewInterContainerProxy(
136 kafka.InterContainerHost(cfg.KafkaAdapterHost),
137 kafka.InterContainerPort(cfg.KafkaAdapterPort),
138 kafka.MsgClient(dat.kClient),
139 kafka.DefaultTopic(&kafka.Topic{Name: cfg.CoreTopic}),
140 kafka.DeviceDiscoveryTopic(&kafka.Topic{Name: cfg.AffinityRouterTopic}))
141
142 endpointMgr := kafka.NewEndpointManager(backend)
143 proxy := model.NewProxy(backend, "/")
144 adapterMgr := adapter.NewAdapterManager(proxy, dat.coreInstanceID, dat.kClient)
145
146 dat.deviceMgr, dat.logicalDeviceMgr = NewDeviceManagers(proxy, adapterMgr, dat.kmp, endpointMgr, cfg.CorePairTopic, dat.coreInstanceID, cfg.DefaultCoreTimeout)
147 dat.logicalDeviceMgr.SetEventCallbacks(fakeEventCallbacks{})
148 if err = dat.kmp.Start(); err != nil {
149 logger.Fatal("Cannot start InterContainerProxy")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530150 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400151 if err = adapterMgr.Start(context.Background()); err != nil {
152 logger.Fatal("Cannot start adapterMgr")
153 }
154 dat.deviceMgr.Start(context.Background())
155 dat.logicalDeviceMgr.Start(context.Background())
khenaidoo6e55d9e2019-12-12 18:26:26 -0500156}
157
158func (dat *DATest) stopAll() {
159 if dat.kClient != nil {
160 dat.kClient.Stop()
161 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400162 if dat.logicalDeviceMgr != nil {
163 dat.logicalDeviceMgr.Stop(context.Background())
164 }
165 if dat.deviceMgr != nil {
166 dat.deviceMgr.Stop(context.Background())
167 }
168 if dat.kmp != nil {
169 dat.kmp.Stop()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500170 }
171 if dat.etcdServer != nil {
172 stopEmbeddedEtcdServer(dat.etcdServer)
173 }
174}
175
Kent Hagerman2b216042020-04-03 18:28:56 -0400176//startEmbeddedEtcdServer creates and starts an Embedded etcd server locally.
177func startEmbeddedEtcdServer(configName, storageDir, logLevel string) (*mock_etcd.EtcdServer, int, error) {
178 kvClientPort, err := freeport.GetFreePort()
179 if err != nil {
180 return nil, 0, err
181 }
182 peerPort, err := freeport.GetFreePort()
183 if err != nil {
184 return nil, 0, err
185 }
186 etcdServer := mock_etcd.StartEtcdServer(mock_etcd.MKConfig(configName, kvClientPort, peerPort, storageDir, logLevel))
187 if etcdServer == nil {
188 return nil, 0, status.Error(codes.Internal, "Embedded server failed to start")
189 }
190 return etcdServer, kvClientPort, nil
191}
192
193func stopEmbeddedEtcdServer(server *mock_etcd.EtcdServer) {
194 if server != nil {
195 server.Stop()
196 }
197}
198
199func setupKVClient(cf *config.RWCoreFlags, coreInstanceID string) kvstore.Client {
200 addr := cf.KVStoreHost + ":" + strconv.Itoa(cf.KVStorePort)
201 client, err := kvstore.NewEtcdClient(addr, cf.KVStoreTimeout)
202 if err != nil {
203 panic("no kv client")
204 }
205 return client
206}
207
208func (dat *DATest) createDeviceAgent(t *testing.T) *Agent {
209 deviceMgr := dat.deviceMgr
khenaidoo6e55d9e2019-12-12 18:26:26 -0500210 clonedDevice := proto.Clone(dat.device).(*voltha.Device)
Kent Hagerman2b216042020-04-03 18:28:56 -0400211 deviceAgent := newAgent(deviceMgr.adapterProxy, clonedDevice, deviceMgr, deviceMgr.clusterDataProxy, deviceMgr.defaultTimeout)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500212 d, err := deviceAgent.start(context.TODO(), clonedDevice)
213 assert.Nil(t, err)
214 assert.NotNil(t, d)
215 deviceMgr.addDeviceAgentToMap(deviceAgent)
216 return deviceAgent
217}
218
Kent Hagerman2b216042020-04-03 18:28:56 -0400219func (dat *DATest) updateDeviceConcurrently(t *testing.T, da *Agent, globalWG *sync.WaitGroup) {
khenaidoo442e7c72020-03-10 16:13:48 -0400220 originalDevice, err := da.getDevice(context.Background())
221 assert.Nil(t, err)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500222 assert.NotNil(t, originalDevice)
223 var localWG sync.WaitGroup
224
225 // Update device routine
226 var (
227 root = false
228 vendor = "onu_adapter_mock"
229 model = "go-mock"
230 serialNumber = com.GetRandomSerialNumber()
231 macAddress = strings.ToUpper(com.GetRandomMacAddress())
232 vlan = rand.Uint32()
233 reason = "testing concurrent device update"
234 portToAdd = &voltha.Port{PortNo: 101, Label: "uni-101", Type: voltha.Port_ETHERNET_UNI, AdminState: voltha.AdminState_ENABLED,
235 OperStatus: voltha.OperStatus_ACTIVE}
236 )
237 localWG.Add(1)
238 go func() {
239 deviceToUpdate := proto.Clone(originalDevice).(*voltha.Device)
240 deviceToUpdate.Root = root
241 deviceToUpdate.Vendor = vendor
242 deviceToUpdate.Model = model
243 deviceToUpdate.SerialNumber = serialNumber
244 deviceToUpdate.MacAddress = macAddress
245 deviceToUpdate.Vlan = vlan
246 deviceToUpdate.Reason = reason
npujar467fe752020-01-16 20:17:45 +0530247 err := da.updateDeviceUsingAdapterData(context.Background(), deviceToUpdate)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500248 assert.Nil(t, err)
249 localWG.Done()
250 }()
251
252 // Update the device status routine
253 localWG.Add(1)
254 go func() {
npujar467fe752020-01-16 20:17:45 +0530255 err := da.updateDeviceStatus(context.Background(), voltha.OperStatus_ACTIVE, voltha.ConnectStatus_REACHABLE)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500256 assert.Nil(t, err)
257 localWG.Done()
258 }()
259
260 // Add a port routine
261 localWG.Add(1)
262 go func() {
npujar467fe752020-01-16 20:17:45 +0530263 err := da.addPort(context.Background(), portToAdd)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500264 assert.Nil(t, err)
265 localWG.Done()
266 }()
267
268 // wait for go routines to be done
269 localWG.Wait()
270
271 expectedChange := proto.Clone(originalDevice).(*voltha.Device)
272 expectedChange.OperStatus = voltha.OperStatus_ACTIVE
273 expectedChange.ConnectStatus = voltha.ConnectStatus_REACHABLE
274 expectedChange.Ports = append(expectedChange.Ports, portToAdd)
275 expectedChange.Root = root
276 expectedChange.Vendor = vendor
277 expectedChange.Model = model
278 expectedChange.SerialNumber = serialNumber
279 expectedChange.MacAddress = macAddress
280 expectedChange.Vlan = vlan
281 expectedChange.Reason = reason
282
khenaidoo442e7c72020-03-10 16:13:48 -0400283 updatedDevice, _ := da.getDevice(context.Background())
khenaidoo6e55d9e2019-12-12 18:26:26 -0500284 assert.NotNil(t, updatedDevice)
285 assert.True(t, proto.Equal(expectedChange, updatedDevice))
286
287 globalWG.Done()
288}
289
290func TestConcurrentDevices(t *testing.T) {
khenaidoo442e7c72020-03-10 16:13:48 -0400291 for i := 0; i < 2; i++ {
292 da := newDATest()
293 assert.NotNil(t, da)
294 defer da.stopAll()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500295
khenaidoo442e7c72020-03-10 16:13:48 -0400296 // Start the Core
297 da.startCore(false)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500298
khenaidoo442e7c72020-03-10 16:13:48 -0400299 var wg sync.WaitGroup
300 numConCurrentDeviceAgents := 20
301 for i := 0; i < numConCurrentDeviceAgents; i++ {
302 wg.Add(1)
303 a := da.createDeviceAgent(t)
304 go da.updateDeviceConcurrently(t, a, &wg)
305 }
306
307 wg.Wait()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500308 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500309}
khenaidoob2121e52019-12-16 17:17:22 -0500310
311func isFlowSliceEqual(a, b []*ofp.OfpFlowStats) bool {
312 if len(a) != len(b) {
313 return false
314 }
315 sort.Slice(a, func(i, j int) bool {
316 return a[i].Id < a[j].Id
317 })
318 sort.Slice(b, func(i, j int) bool {
319 return b[i].Id < b[j].Id
320 })
321 for idx := range a {
322 if !proto.Equal(a[idx], b[idx]) {
323 return false
324 }
325 }
326 return true
327}
328
329func isGroupSliceEqual(a, b []*ofp.OfpGroupEntry) bool {
330 if len(a) != len(b) {
331 return false
332 }
333 sort.Slice(a, func(i, j int) bool {
334 return a[i].Desc.GroupId < a[j].Desc.GroupId
335 })
336 sort.Slice(b, func(i, j int) bool {
337 return b[i].Desc.GroupId < b[j].Desc.GroupId
338 })
339 for idx := range a {
340 if !proto.Equal(a[idx], b[idx]) {
341 return false
342 }
343 }
344 return true
345}
346
347func TestFlowsToUpdateToDelete_EmptySlices(t *testing.T) {
348 newFlows := []*ofp.OfpFlowStats{}
349 existingFlows := []*ofp.OfpFlowStats{}
350 expectedNewFlows := []*ofp.OfpFlowStats{}
351 expectedFlowsToDelete := []*ofp.OfpFlowStats{}
352 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{}
353 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
354 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
355 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
356 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
357}
358
359func TestFlowsToUpdateToDelete_NoExistingFlows(t *testing.T) {
360 newFlows := []*ofp.OfpFlowStats{
361 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
362 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
363 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
364 }
365 existingFlows := []*ofp.OfpFlowStats{}
366 expectedNewFlows := []*ofp.OfpFlowStats{
367 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
368 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
369 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
370 }
371 expectedFlowsToDelete := []*ofp.OfpFlowStats{}
372 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{
373 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
374 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
375 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
376 }
377 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
378 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
379 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
380 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
381}
382
383func TestFlowsToUpdateToDelete_UpdateNoDelete(t *testing.T) {
384 newFlows := []*ofp.OfpFlowStats{
385 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
386 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
387 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
388 }
389 existingFlows := []*ofp.OfpFlowStats{
390 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
391 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
392 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
393 }
394 expectedNewFlows := []*ofp.OfpFlowStats{
395 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
396 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
397 }
398 expectedFlowsToDelete := []*ofp.OfpFlowStats{}
399 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{
400 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
401 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
402 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
403 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
404 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
405 }
406 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
407 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
408 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
409 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
410}
411
412func TestFlowsToUpdateToDelete_UpdateAndDelete(t *testing.T) {
413 newFlows := []*ofp.OfpFlowStats{
414 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 20},
415 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
416 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 10, Flags: 0, Cookie: 1250000, PacketCount: 0},
417 {Id: 126, TableId: 1260, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
418 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
419 }
420 existingFlows := []*ofp.OfpFlowStats{
421 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
422 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
423 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
424 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
425 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
426 }
427 expectedNewFlows := []*ofp.OfpFlowStats{
428 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 20},
429 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 10, Flags: 0, Cookie: 1250000, PacketCount: 0},
430 {Id: 126, TableId: 1260, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
431 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
432 }
433 expectedFlowsToDelete := []*ofp.OfpFlowStats{
434 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
435 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
436 }
437 expectedUpdatedAllFlows := []*ofp.OfpFlowStats{
438 {Id: 121, TableId: 1210, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1210000, PacketCount: 0},
439 {Id: 122, TableId: 1220, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1220000, PacketCount: 0},
440 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 20},
441 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
442 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 10, Flags: 0, Cookie: 1250000, PacketCount: 0},
443 {Id: 126, TableId: 1260, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
444 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
445 }
446 uNF, fD, uAF := flowsToUpdateToDelete(newFlows, existingFlows)
447 assert.True(t, isFlowSliceEqual(uNF, expectedNewFlows))
448 assert.True(t, isFlowSliceEqual(fD, expectedFlowsToDelete))
449 assert.True(t, isFlowSliceEqual(uAF, expectedUpdatedAllFlows))
450}
451
452func TestGroupsToUpdateToDelete_EmptySlices(t *testing.T) {
453 newGroups := []*ofp.OfpGroupEntry{}
454 existingGroups := []*ofp.OfpGroupEntry{}
455 expectedNewGroups := []*ofp.OfpGroupEntry{}
456 expectedGroupsToDelete := []*ofp.OfpGroupEntry{}
457 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{}
458 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
459 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
460 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
461 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
462}
463
464func TestGroupsToUpdateToDelete_NoExistingGroups(t *testing.T) {
465 newGroups := []*ofp.OfpGroupEntry{
466 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
467 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
468 }
469 existingGroups := []*ofp.OfpGroupEntry{}
470 expectedNewGroups := []*ofp.OfpGroupEntry{
471 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
472 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
473 }
474 expectedGroupsToDelete := []*ofp.OfpGroupEntry{}
475 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{
476 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
477 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
478 }
479 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
480 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
481 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
482 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
483}
484
485func TestGroupsToUpdateToDelete_UpdateNoDelete(t *testing.T) {
486 newGroups := []*ofp.OfpGroupEntry{
487 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
488 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
489 }
490 existingGroups := []*ofp.OfpGroupEntry{
491 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
492 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
493 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
494 }
495 expectedNewGroups := []*ofp.OfpGroupEntry{
496 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
497 }
498 expectedGroupsToDelete := []*ofp.OfpGroupEntry{}
499 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{
500 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
501 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
502 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
503 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
504 }
505 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
506 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
507 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
508 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
509}
510
511func TestGroupsToUpdateToDelete_UpdateWithDelete(t *testing.T) {
512 newGroups := []*ofp.OfpGroupEntry{
513 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
514 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: []*ofp.OfpBucket{{WatchPort: 10}}}},
515 }
516 existingGroups := []*ofp.OfpGroupEntry{
517 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
518 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
519 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
520 }
521 expectedNewGroups := []*ofp.OfpGroupEntry{
522 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
523 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: []*ofp.OfpBucket{{WatchPort: 10}}}},
524 }
525 expectedGroupsToDelete := []*ofp.OfpGroupEntry{
526 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
527 }
528 expectedUpdatedAllGroups := []*ofp.OfpGroupEntry{
529 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
530 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: []*ofp.OfpBucket{{WatchPort: 10}}}},
531 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
532 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
533 }
534 uNG, gD, uAG := groupsToUpdateToDelete(newGroups, existingGroups)
535 assert.True(t, isGroupSliceEqual(uNG, expectedNewGroups))
536 assert.True(t, isGroupSliceEqual(gD, expectedGroupsToDelete))
537 assert.True(t, isGroupSliceEqual(uAG, expectedUpdatedAllGroups))
538}