blob: e3716a74870f93a017516bcd5ee0179651cb7434 [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"
Kent Hagermanf6db9f12020-07-22 17:16:19 -040021 "fmt"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070022 "math/rand"
23 "sort"
Neha Sharmad1387da2020-05-07 20:07:28 +000024 "strconv"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070025 "strings"
26 "sync"
27 "testing"
28 "time"
29
khenaidoo6e55d9e2019-12-12 18:26:26 -050030 "github.com/gogo/protobuf/proto"
Kent Hagerman2b216042020-04-03 18:28:56 -040031 "github.com/opencord/voltha-go/db/model"
khenaidoo6e55d9e2019-12-12 18:26:26 -050032 "github.com/opencord/voltha-go/rw_core/config"
Kent Hagerman2b216042020-04-03 18:28:56 -040033 "github.com/opencord/voltha-go/rw_core/core/adapter"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070034 cm "github.com/opencord/voltha-go/rw_core/mocks"
35 tst "github.com/opencord/voltha-go/rw_core/test"
yasin sapli5458a1c2021-06-14 22:24:38 +000036 com "github.com/opencord/voltha-lib-go/v5/pkg/adapters/common"
37 "github.com/opencord/voltha-lib-go/v5/pkg/db"
38 "github.com/opencord/voltha-lib-go/v5/pkg/events"
39 "github.com/opencord/voltha-lib-go/v5/pkg/kafka"
40 "github.com/opencord/voltha-lib-go/v5/pkg/log"
41 mock_etcd "github.com/opencord/voltha-lib-go/v5/pkg/mocks/etcd"
42 mock_kafka "github.com/opencord/voltha-lib-go/v5/pkg/mocks/kafka"
Maninderdfadc982020-10-28 14:04:33 +053043 ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
44 "github.com/opencord/voltha-protos/v4/go/voltha"
khenaidoo6e55d9e2019-12-12 18:26:26 -050045 "github.com/phayes/freeport"
46 "github.com/stretchr/testify/assert"
khenaidoo6e55d9e2019-12-12 18:26:26 -050047)
48
49type DATest struct {
Kent Hagerman2b216042020-04-03 18:28:56 -040050 etcdServer *mock_etcd.EtcdServer
51 deviceMgr *Manager
52 logicalDeviceMgr *LogicalManager
Mahir Gunyel03de0d32020-06-03 01:36:59 -070053 adapterMgr *adapter.Manager
Kent Hagerman2b216042020-04-03 18:28:56 -040054 kmp kafka.InterContainerProxy
55 kClient kafka.Client
Himani Chawlab4c25912020-11-12 17:16:38 +053056 kEventClient kafka.Client
Kent Hagerman2b216042020-04-03 18:28:56 -040057 kvClientPort int
Mahir Gunyel03de0d32020-06-03 01:36:59 -070058 oltAdapter *cm.OLTAdapter
59 onuAdapter *cm.ONUAdapter
Kent Hagerman2b216042020-04-03 18:28:56 -040060 oltAdapterName string
61 onuAdapterName string
62 coreInstanceID string
63 defaultTimeout time.Duration
64 maxTimeout time.Duration
65 device *voltha.Device
Kent Hagerman2a07b862020-06-19 15:23:07 -040066 devicePorts map[uint32]*voltha.Port
Kent Hagerman2b216042020-04-03 18:28:56 -040067 done chan int
khenaidoo6e55d9e2019-12-12 18:26:26 -050068}
69
Rohan Agrawal31f21802020-06-12 05:38:46 +000070func newDATest(ctx context.Context) *DATest {
khenaidoo6e55d9e2019-12-12 18:26:26 -050071 test := &DATest{}
72 // Start the embedded etcd server
73 var err error
Rohan Agrawal31f21802020-06-12 05:38:46 +000074 test.etcdServer, test.kvClientPort, err = tst.StartEmbeddedEtcdServer(ctx, "voltha.rwcore.da.test", "voltha.rwcore.da.etcd", "error")
khenaidoo6e55d9e2019-12-12 18:26:26 -050075 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +000076 logger.Fatal(ctx, err)
khenaidoo6e55d9e2019-12-12 18:26:26 -050077 }
78 // Create the kafka client
Matteo Scandolod525ae32020-04-02 17:27:29 -070079 test.kClient = mock_kafka.NewKafkaClient()
Himani Chawlab4c25912020-11-12 17:16:38 +053080 test.kEventClient = mock_kafka.NewKafkaClient()
khenaidoo6e55d9e2019-12-12 18:26:26 -050081 test.oltAdapterName = "olt_adapter_mock"
82 test.onuAdapterName = "onu_adapter_mock"
83 test.coreInstanceID = "rw-da-test"
84 test.defaultTimeout = 5 * time.Second
85 test.maxTimeout = 20 * time.Second
86 test.done = make(chan int)
87 parentID := com.GetRandomString(10)
88 test.device = &voltha.Device{
89 Type: "onu_adapter_mock",
90 ParentId: parentID,
91 ParentPortNo: 1,
92 VendorId: "onu_adapter_mock",
93 Adapter: "onu_adapter_mock",
94 Vlan: 100,
95 Address: nil,
96 ProxyAddress: &voltha.Device_ProxyAddress{
97 DeviceId: parentID,
98 DeviceType: "olt_adapter_mock",
99 ChannelId: 100,
100 ChannelGroupId: 0,
101 ChannelTermination: "",
102 OnuId: 2,
103 },
104 AdminState: voltha.AdminState_PREPROVISIONED,
105 OperStatus: voltha.OperStatus_UNKNOWN,
106 Reason: "All good",
107 ConnectStatus: voltha.ConnectStatus_UNKNOWN,
108 Custom: nil,
Kent Hagerman2a07b862020-06-19 15:23:07 -0400109 }
110 test.devicePorts = map[uint32]*voltha.Port{
111 1: {PortNo: 1, Label: "pon-1", Type: voltha.Port_PON_ONU, AdminState: voltha.AdminState_ENABLED,
112 OperStatus: voltha.OperStatus_ACTIVE, Peers: []*voltha.Port_PeerPort{{DeviceId: parentID, PortNo: 1}}},
113 100: {PortNo: 100, Label: "uni-100", Type: voltha.Port_ETHERNET_UNI, AdminState: voltha.AdminState_ENABLED,
114 OperStatus: voltha.OperStatus_ACTIVE},
khenaidoo6e55d9e2019-12-12 18:26:26 -0500115 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500116 return test
117}
118
Rohan Agrawal31f21802020-06-12 05:38:46 +0000119func (dat *DATest) startCore(ctx context.Context) {
David K. Bainbridge6080c172021-07-24 00:22:28 +0000120 cfg := &config.RWCoreFlags{}
121 cfg.ParseCommandArguments([]string{})
serkant.uluderya8ff291d2020-05-20 00:58:00 -0700122 cfg.CoreTopic = "rw_core"
Himani Chawlab4c25912020-11-12 17:16:38 +0530123 cfg.EventTopic = "voltha.events"
khenaidoo442e7c72020-03-10 16:13:48 -0400124 cfg.DefaultRequestTimeout = dat.defaultTimeout
Neha Sharmad1387da2020-05-07 20:07:28 +0000125 cfg.KVStoreAddress = "127.0.0.1" + ":" + strconv.Itoa(dat.kvClientPort)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500126 grpcPort, err := freeport.GetFreePort()
127 if err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000128 logger.Fatal(ctx, "Cannot get a freeport for grpc")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500129 }
Neha Sharmad1387da2020-05-07 20:07:28 +0000130 cfg.GrpcAddress = "127.0.0.1" + ":" + strconv.Itoa(grpcPort)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000131 client := tst.SetupKVClient(ctx, cfg, dat.coreInstanceID)
Kent Hagerman2b216042020-04-03 18:28:56 -0400132 backend := &db.Backend{
133 Client: client,
134 StoreType: cfg.KVStoreType,
Neha Sharmad1387da2020-05-07 20:07:28 +0000135 Address: cfg.KVStoreAddress,
Kent Hagerman2b216042020-04-03 18:28:56 -0400136 Timeout: cfg.KVStoreTimeout,
serkant.uluderya8ff291d2020-05-20 00:58:00 -0700137 LivenessChannelInterval: cfg.LiveProbeInterval / 2}
Kent Hagerman2b216042020-04-03 18:28:56 -0400138 dat.kmp = kafka.NewInterContainerProxy(
Neha Sharmad1387da2020-05-07 20:07:28 +0000139 kafka.InterContainerAddress(cfg.KafkaAdapterAddress),
Kent Hagerman2b216042020-04-03 18:28:56 -0400140 kafka.MsgClient(dat.kClient),
David Bainbridge9ae13132020-06-22 17:28:01 -0700141 kafka.DefaultTopic(&kafka.Topic{Name: cfg.CoreTopic}))
Kent Hagerman2b216042020-04-03 18:28:56 -0400142
143 endpointMgr := kafka.NewEndpointManager(backend)
Kent Hagermanf5a67352020-04-30 15:15:26 -0400144 proxy := model.NewDBPath(backend)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000145 dat.adapterMgr = adapter.NewAdapterManager(ctx, proxy, dat.coreInstanceID, dat.kClient)
Himani Chawlab4c25912020-11-12 17:16:38 +0530146 eventProxy := events.NewEventProxy(events.MsgClient(dat.kEventClient), events.MsgTopic(kafka.Topic{Name: cfg.EventTopic}))
Maninder0aabf0c2021-03-17 14:55:14 +0530147 dat.deviceMgr, dat.logicalDeviceMgr = NewManagers(proxy, dat.adapterMgr, dat.kmp, endpointMgr, cfg, dat.coreInstanceID, eventProxy)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700148 dat.adapterMgr.Start(context.Background())
Rohan Agrawal31f21802020-06-12 05:38:46 +0000149 if err = dat.kmp.Start(ctx); err != nil {
150 logger.Fatal(ctx, "Cannot start InterContainerProxy")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530151 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700152
Rohan Agrawal31f21802020-06-12 05:38:46 +0000153 if err := dat.kmp.SubscribeWithDefaultRequestHandler(ctx, kafka.Topic{Name: cfg.CoreTopic}, kafka.OffsetNewest); err != nil {
154 logger.Fatalf(ctx, "Cannot add default request handler: %s", err)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700155 }
156
khenaidoo6e55d9e2019-12-12 18:26:26 -0500157}
158
Rohan Agrawal31f21802020-06-12 05:38:46 +0000159func (dat *DATest) stopAll(ctx context.Context) {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500160 if dat.kClient != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000161 dat.kClient.Stop(ctx)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500162 }
Kent Hagerman2b216042020-04-03 18:28:56 -0400163 if dat.kmp != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000164 dat.kmp.Stop(ctx)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500165 }
166 if dat.etcdServer != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000167 tst.StopEmbeddedEtcdServer(ctx, dat.etcdServer)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500168 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530169 if dat.kEventClient != nil {
170 dat.kEventClient.Stop(ctx)
171 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500172}
173
Kent Hagerman2b216042020-04-03 18:28:56 -0400174func (dat *DATest) createDeviceAgent(t *testing.T) *Agent {
175 deviceMgr := dat.deviceMgr
khenaidoo6e55d9e2019-12-12 18:26:26 -0500176 clonedDevice := proto.Clone(dat.device).(*voltha.Device)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700177 deviceAgent := newAgent(deviceMgr.adapterProxy, clonedDevice, deviceMgr, deviceMgr.dbPath, deviceMgr.dProxy, deviceMgr.defaultTimeout)
khenaidoo7585a962021-06-10 16:15:38 -0400178 d, err := deviceAgent.start(context.TODO(), false, clonedDevice)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500179 assert.Nil(t, err)
180 assert.NotNil(t, d)
Kent Hagerman2a07b862020-06-19 15:23:07 -0400181 for _, port := range dat.devicePorts {
182 err := deviceAgent.addPort(context.TODO(), port)
183 assert.Nil(t, err)
184 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500185 deviceMgr.addDeviceAgentToMap(deviceAgent)
186 return deviceAgent
187}
188
Kent Hagerman2b216042020-04-03 18:28:56 -0400189func (dat *DATest) updateDeviceConcurrently(t *testing.T, da *Agent, globalWG *sync.WaitGroup) {
Kent Hagermancba2f302020-07-28 13:37:36 -0400190 originalDevice, err := da.getDeviceReadOnly(context.Background())
Kent Hagerman2a07b862020-06-19 15:23:07 -0400191 originalDevicePorts := da.listDevicePorts()
khenaidoo442e7c72020-03-10 16:13:48 -0400192 assert.Nil(t, err)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500193 assert.NotNil(t, originalDevice)
194 var localWG sync.WaitGroup
195
196 // Update device routine
197 var (
198 root = false
199 vendor = "onu_adapter_mock"
200 model = "go-mock"
201 serialNumber = com.GetRandomSerialNumber()
202 macAddress = strings.ToUpper(com.GetRandomMacAddress())
203 vlan = rand.Uint32()
204 reason = "testing concurrent device update"
205 portToAdd = &voltha.Port{PortNo: 101, Label: "uni-101", Type: voltha.Port_ETHERNET_UNI, AdminState: voltha.AdminState_ENABLED,
206 OperStatus: voltha.OperStatus_ACTIVE}
207 )
208 localWG.Add(1)
209 go func() {
210 deviceToUpdate := proto.Clone(originalDevice).(*voltha.Device)
211 deviceToUpdate.Root = root
212 deviceToUpdate.Vendor = vendor
213 deviceToUpdate.Model = model
214 deviceToUpdate.SerialNumber = serialNumber
215 deviceToUpdate.MacAddress = macAddress
216 deviceToUpdate.Vlan = vlan
217 deviceToUpdate.Reason = reason
npujar467fe752020-01-16 20:17:45 +0530218 err := da.updateDeviceUsingAdapterData(context.Background(), deviceToUpdate)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500219 assert.Nil(t, err)
220 localWG.Done()
221 }()
222
223 // Update the device status routine
224 localWG.Add(1)
225 go func() {
npujar467fe752020-01-16 20:17:45 +0530226 err := da.updateDeviceStatus(context.Background(), voltha.OperStatus_ACTIVE, voltha.ConnectStatus_REACHABLE)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500227 assert.Nil(t, err)
228 localWG.Done()
229 }()
230
231 // Add a port routine
232 localWG.Add(1)
233 go func() {
npujar467fe752020-01-16 20:17:45 +0530234 err := da.addPort(context.Background(), portToAdd)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500235 assert.Nil(t, err)
236 localWG.Done()
237 }()
238
239 // wait for go routines to be done
240 localWG.Wait()
241
242 expectedChange := proto.Clone(originalDevice).(*voltha.Device)
243 expectedChange.OperStatus = voltha.OperStatus_ACTIVE
244 expectedChange.ConnectStatus = voltha.ConnectStatus_REACHABLE
khenaidoo6e55d9e2019-12-12 18:26:26 -0500245 expectedChange.Root = root
246 expectedChange.Vendor = vendor
247 expectedChange.Model = model
248 expectedChange.SerialNumber = serialNumber
249 expectedChange.MacAddress = macAddress
250 expectedChange.Vlan = vlan
251 expectedChange.Reason = reason
252
Kent Hagermancba2f302020-07-28 13:37:36 -0400253 updatedDevice, _ := da.getDeviceReadOnly(context.Background())
Kent Hagerman2a07b862020-06-19 15:23:07 -0400254 updatedDevicePorts := da.listDevicePorts()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500255 assert.NotNil(t, updatedDevice)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400256 fmt.Printf("1 %+v\n", expectedChange)
257 fmt.Printf("2 %+v\n", updatedDevice)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500258 assert.True(t, proto.Equal(expectedChange, updatedDevice))
Kent Hagerman2a07b862020-06-19 15:23:07 -0400259 assert.Equal(t, len(originalDevicePorts)+1, len(updatedDevicePorts))
260 assert.True(t, proto.Equal(updatedDevicePorts[portToAdd.PortNo], portToAdd))
khenaidoo6e55d9e2019-12-12 18:26:26 -0500261
262 globalWG.Done()
263}
264
265func TestConcurrentDevices(t *testing.T) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000266 ctx := context.Background()
khenaidoo442e7c72020-03-10 16:13:48 -0400267 for i := 0; i < 2; i++ {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000268 da := newDATest(ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400269 assert.NotNil(t, da)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000270 defer da.stopAll(ctx)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700271 log.SetPackageLogLevel("github.com/opencord/voltha-go/rw_core/core", log.DebugLevel)
khenaidoo442e7c72020-03-10 16:13:48 -0400272 // Start the Core
Rohan Agrawal31f21802020-06-12 05:38:46 +0000273 da.startCore(ctx)
khenaidoo6e55d9e2019-12-12 18:26:26 -0500274
khenaidoo442e7c72020-03-10 16:13:48 -0400275 var wg sync.WaitGroup
276 numConCurrentDeviceAgents := 20
277 for i := 0; i < numConCurrentDeviceAgents; i++ {
278 wg.Add(1)
279 a := da.createDeviceAgent(t)
280 go da.updateDeviceConcurrently(t, a, &wg)
281 }
282
283 wg.Wait()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500284 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500285}
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700286func TestFlowUpdates(t *testing.T) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000287 ctx := context.Background()
288 da := newDATest(ctx)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700289 assert.NotNil(t, da)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000290 defer da.stopAll(ctx)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700291
292 log.SetPackageLogLevel("github.com/opencord/voltha-go/rw_core/core", log.DebugLevel)
293 // Start the Core
Rohan Agrawal31f21802020-06-12 05:38:46 +0000294 da.startCore(ctx)
295 da.oltAdapter, da.onuAdapter = tst.CreateAndregisterAdapters(ctx, t, da.kClient, da.coreInstanceID, da.oltAdapterName, da.onuAdapterName, da.adapterMgr)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700296
297 a := da.createDeviceAgent(t)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400298 err1 := a.requestQueue.WaitForGreenLight(ctx)
299 assert.Nil(t, err1)
300 cloned := a.cloneDeviceWithoutLock()
301 cloned.AdminState, cloned.ConnectStatus, cloned.OperStatus = voltha.AdminState_ENABLED, voltha.ConnectStatus_REACHABLE, voltha.OperStatus_ACTIVE
302 err2 := a.updateDeviceAndReleaseLock(ctx, cloned)
303 assert.Nil(t, err2)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700304 da.testFlowAddDeletes(t, a)
305}
306
307func TestGroupUpdates(t *testing.T) {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000308 ctx := context.Background()
309 da := newDATest(ctx)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700310 assert.NotNil(t, da)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000311 defer da.stopAll(ctx)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700312
313 // Start the Core
Rohan Agrawal31f21802020-06-12 05:38:46 +0000314 da.startCore(ctx)
315 da.oltAdapter, da.onuAdapter = tst.CreateAndregisterAdapters(ctx, t, da.kClient, da.coreInstanceID, da.oltAdapterName, da.onuAdapterName, da.adapterMgr)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700316 a := da.createDeviceAgent(t)
Kent Hagermanf6db9f12020-07-22 17:16:19 -0400317 err1 := a.requestQueue.WaitForGreenLight(ctx)
318 assert.Nil(t, err1)
319 cloned := a.cloneDeviceWithoutLock()
320 cloned.AdminState, cloned.ConnectStatus, cloned.OperStatus = voltha.AdminState_ENABLED, voltha.ConnectStatus_REACHABLE, voltha.OperStatus_ACTIVE
321 err2 := a.updateDeviceAndReleaseLock(ctx, cloned)
322 assert.Nil(t, err2)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700323 da.testGroupAddDeletes(t, a)
324}
khenaidoob2121e52019-12-16 17:17:22 -0500325
326func isFlowSliceEqual(a, b []*ofp.OfpFlowStats) bool {
327 if len(a) != len(b) {
328 return false
329 }
330 sort.Slice(a, func(i, j int) bool {
331 return a[i].Id < a[j].Id
332 })
333 sort.Slice(b, func(i, j int) bool {
334 return b[i].Id < b[j].Id
335 })
336 for idx := range a {
337 if !proto.Equal(a[idx], b[idx]) {
338 return false
339 }
340 }
341 return true
342}
343
344func isGroupSliceEqual(a, b []*ofp.OfpGroupEntry) bool {
345 if len(a) != len(b) {
346 return false
347 }
348 sort.Slice(a, func(i, j int) bool {
349 return a[i].Desc.GroupId < a[j].Desc.GroupId
350 })
351 sort.Slice(b, func(i, j int) bool {
352 return b[i].Desc.GroupId < b[j].Desc.GroupId
353 })
354 for idx := range a {
355 if !proto.Equal(a[idx], b[idx]) {
356 return false
357 }
358 }
359 return true
360}
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700361func changeToFlowList(flowList map[uint64]*ofp.OfpFlowStats) []*ofp.OfpFlowStats {
362 flows := make([]*ofp.OfpFlowStats, 0)
363 for _, flow := range flowList {
364 flows = append(flows, flow)
365 }
366 return flows
khenaidoob2121e52019-12-16 17:17:22 -0500367}
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700368func changeToGroupList(groupList map[uint32]*ofp.OfpGroupEntry) []*ofp.OfpGroupEntry {
369 groups := make([]*ofp.OfpGroupEntry, 0)
370 for _, group := range groupList {
371 groups = append(groups, group)
372 }
373 return groups
374}
375func (dat *DATest) testFlowAddDeletes(t *testing.T, da *Agent) {
376 //Add new Flows on empty list
khenaidoob2121e52019-12-16 17:17:22 -0500377 newFlows := []*ofp.OfpFlowStats{
378 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
379 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
380 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
381 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700382 err := da.addFlowsAndGroups(context.Background(), newFlows, []*ofp.OfpGroupEntry{}, &voltha.FlowMetadata{})
383 assert.Nil(t, err)
384 daFlows := changeToFlowList(da.listDeviceFlows())
385 assert.True(t, isFlowSliceEqual(newFlows, daFlows))
khenaidoob2121e52019-12-16 17:17:22 -0500386
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700387 //Add new Flows on existing ones
388 newFlows = []*ofp.OfpFlowStats{
389 {Id: 126, TableId: 1260, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
khenaidoob2121e52019-12-16 17:17:22 -0500390 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
391 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700392
393 expectedFlows := []*ofp.OfpFlowStats{
394 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
395 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
396 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
397 {Id: 126, TableId: 1260, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
398 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270000, PacketCount: 0},
399 }
400
401 err = da.addFlowsAndGroups(context.Background(), newFlows, []*ofp.OfpGroupEntry{}, &voltha.FlowMetadata{})
402 assert.Nil(t, err)
403 daFlows = changeToFlowList(da.listDeviceFlows())
404 assert.True(t, isFlowSliceEqual(expectedFlows, daFlows))
405
406 //Add existing Flows again with a new flow
407 newFlows = []*ofp.OfpFlowStats{
408 {Id: 126, TableId: 1260, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
409 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270001, PacketCount: 0},
410 {Id: 128, TableId: 1280, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1280000, PacketCount: 0},
411 }
412
413 expectedFlows = []*ofp.OfpFlowStats{
414 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
415 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
416 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
417 {Id: 126, TableId: 1260, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
418 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270001, PacketCount: 0},
419 {Id: 128, TableId: 1280, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1280000, PacketCount: 0},
420 }
421
422 err = da.addFlowsAndGroups(context.Background(), newFlows, []*ofp.OfpGroupEntry{}, &voltha.FlowMetadata{})
423 assert.Nil(t, err)
424 daFlows = changeToFlowList(da.listDeviceFlows())
425 assert.True(t, isFlowSliceEqual(expectedFlows, daFlows))
426
427 //Add already existing flows again
428 newFlows = []*ofp.OfpFlowStats{
429 {Id: 126, TableId: 1260, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
430 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270001, PacketCount: 0},
431 {Id: 128, TableId: 1280, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1280000, PacketCount: 0},
432 }
433
434 expectedFlows = []*ofp.OfpFlowStats{
435 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
436 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
437 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
438 {Id: 126, TableId: 1260, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
439 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270001, PacketCount: 0},
440 {Id: 128, TableId: 1280, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1280000, PacketCount: 0},
441 }
442
443 err = da.addFlowsAndGroups(context.Background(), newFlows, []*ofp.OfpGroupEntry{}, &voltha.FlowMetadata{})
444 assert.Nil(t, err)
445 daFlows = changeToFlowList(da.listDeviceFlows())
446 assert.True(t, isFlowSliceEqual(expectedFlows, daFlows))
447
448 //Delete flows
449 flowsToDelete := []*ofp.OfpFlowStats{
450 {Id: 126, TableId: 1260, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1260000, PacketCount: 0},
451 {Id: 127, TableId: 1270, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1270001, PacketCount: 0},
452 {Id: 128, TableId: 1280, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1280000, PacketCount: 0},
453 }
454
455 expectedFlows = []*ofp.OfpFlowStats{
khenaidoob2121e52019-12-16 17:17:22 -0500456 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
457 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
458 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
459 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700460
461 err = da.deleteFlowsAndGroups(context.Background(), flowsToDelete, []*ofp.OfpGroupEntry{}, &voltha.FlowMetadata{})
462 assert.Nil(t, err)
463 daFlows = changeToFlowList(da.listDeviceFlows())
464 assert.True(t, isFlowSliceEqual(expectedFlows, daFlows))
465 //Delete flows with an unexisting one
466 flowsToDelete = []*ofp.OfpFlowStats{
khenaidoob2121e52019-12-16 17:17:22 -0500467 {Id: 125, TableId: 1250, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1250000, PacketCount: 0},
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700468 {Id: 129, TableId: 1290, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1290000, PacketCount: 0},
khenaidoob2121e52019-12-16 17:17:22 -0500469 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700470
471 expectedFlows = []*ofp.OfpFlowStats{
472 {Id: 123, TableId: 1230, Priority: 100, IdleTimeout: 0, Flags: 0, Cookie: 1230000, PacketCount: 0},
khenaidoob2121e52019-12-16 17:17:22 -0500473 {Id: 124, TableId: 1240, Priority: 1000, IdleTimeout: 0, Flags: 0, Cookie: 1240000, PacketCount: 0},
khenaidoob2121e52019-12-16 17:17:22 -0500474 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700475
476 err = da.deleteFlowsAndGroups(context.Background(), flowsToDelete, []*ofp.OfpGroupEntry{}, &voltha.FlowMetadata{})
477 assert.Nil(t, err)
478 daFlows = changeToFlowList(da.listDeviceFlows())
479 assert.True(t, isFlowSliceEqual(expectedFlows, daFlows))
khenaidoob2121e52019-12-16 17:17:22 -0500480}
481
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700482func (dat *DATest) testGroupAddDeletes(t *testing.T, da *Agent) {
483 //Add new Groups on empty list
khenaidoob2121e52019-12-16 17:17:22 -0500484 newGroups := []*ofp.OfpGroupEntry{
485 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
486 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
487 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700488 err := da.addFlowsAndGroups(context.Background(), []*ofp.OfpFlowStats{}, newGroups, &voltha.FlowMetadata{})
489 assert.Nil(t, err)
490 daGroups := changeToGroupList(da.listDeviceGroups())
491 assert.True(t, isGroupSliceEqual(newGroups, daGroups))
khenaidoob2121e52019-12-16 17:17:22 -0500492
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700493 //Add new Groups on existing ones
494 newGroups = []*ofp.OfpGroupEntry{
khenaidoob2121e52019-12-16 17:17:22 -0500495 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
496 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
497 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700498 expectedGroups := []*ofp.OfpGroupEntry{
khenaidoob2121e52019-12-16 17:17:22 -0500499 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
500 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
501 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
502 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
503 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700504 err = da.addFlowsAndGroups(context.Background(), []*ofp.OfpFlowStats{}, newGroups, &voltha.FlowMetadata{})
505 assert.Nil(t, err)
506 daGroups = changeToGroupList(da.listDeviceGroups())
507 assert.True(t, isGroupSliceEqual(expectedGroups, daGroups))
khenaidoob2121e52019-12-16 17:17:22 -0500508
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700509 //Add new Groups on existing ones
510 newGroups = []*ofp.OfpGroupEntry{
511 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
512 {Desc: &ofp.OfpGroupDesc{Type: 44, GroupId: 40, Buckets: nil}},
513 {Desc: &ofp.OfpGroupDesc{Type: 5, GroupId: 50, Buckets: nil}},
khenaidoob2121e52019-12-16 17:17:22 -0500514 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700515 expectedGroups = []*ofp.OfpGroupEntry{
516 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
khenaidoob2121e52019-12-16 17:17:22 -0500517 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
518 {Desc: &ofp.OfpGroupDesc{Type: 3, GroupId: 30, Buckets: nil}},
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700519 {Desc: &ofp.OfpGroupDesc{Type: 44, GroupId: 40, Buckets: nil}},
520 {Desc: &ofp.OfpGroupDesc{Type: 5, GroupId: 50, Buckets: nil}},
khenaidoob2121e52019-12-16 17:17:22 -0500521 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700522 err = da.addFlowsAndGroups(context.Background(), []*ofp.OfpFlowStats{}, newGroups, &voltha.FlowMetadata{})
523 assert.Nil(t, err)
524 daGroups = changeToGroupList(da.listDeviceGroups())
525 assert.True(t, isGroupSliceEqual(expectedGroups, daGroups))
526
527 //Modify Group
528 updtGroups := []*ofp.OfpGroupEntry{
529 {Desc: &ofp.OfpGroupDesc{Type: 33, GroupId: 30, Buckets: nil}},
530 }
531 expectedGroups = []*ofp.OfpGroupEntry{
khenaidoob2121e52019-12-16 17:17:22 -0500532 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
khenaidoob2121e52019-12-16 17:17:22 -0500533 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700534 {Desc: &ofp.OfpGroupDesc{Type: 33, GroupId: 30, Buckets: nil}},
535 {Desc: &ofp.OfpGroupDesc{Type: 44, GroupId: 40, Buckets: nil}},
536 {Desc: &ofp.OfpGroupDesc{Type: 5, GroupId: 50, Buckets: nil}},
khenaidoob2121e52019-12-16 17:17:22 -0500537 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700538 err = da.updateFlowsAndGroups(context.Background(), []*ofp.OfpFlowStats{}, updtGroups, &voltha.FlowMetadata{})
539 assert.Nil(t, err)
540 daGroups = changeToGroupList(da.listDeviceGroups())
541 assert.True(t, isGroupSliceEqual(expectedGroups, daGroups))
542
543 //Delete Group
544 delGroups := []*ofp.OfpGroupEntry{
545 {Desc: &ofp.OfpGroupDesc{Type: 33, GroupId: 30, Buckets: nil}},
546 }
547 expectedGroups = []*ofp.OfpGroupEntry{
khenaidoob2121e52019-12-16 17:17:22 -0500548 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700549 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
550 {Desc: &ofp.OfpGroupDesc{Type: 44, GroupId: 40, Buckets: nil}},
551 {Desc: &ofp.OfpGroupDesc{Type: 5, GroupId: 50, Buckets: nil}},
552 }
553 err = da.deleteFlowsAndGroups(context.Background(), []*ofp.OfpFlowStats{}, delGroups, &voltha.FlowMetadata{})
554 assert.Nil(t, err)
555 daGroups = changeToGroupList(da.listDeviceGroups())
556 assert.True(t, isGroupSliceEqual(expectedGroups, daGroups))
557
558 //Delete Group
559 delGroups = []*ofp.OfpGroupEntry{
khenaidoob2121e52019-12-16 17:17:22 -0500560 {Desc: &ofp.OfpGroupDesc{Type: 4, GroupId: 40, Buckets: nil}},
561 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700562 expectedGroups = []*ofp.OfpGroupEntry{
563 {Desc: &ofp.OfpGroupDesc{Type: 1, GroupId: 10, Buckets: nil}},
564 {Desc: &ofp.OfpGroupDesc{Type: 2, GroupId: 20, Buckets: nil}},
565 {Desc: &ofp.OfpGroupDesc{Type: 5, GroupId: 50, Buckets: nil}},
566 }
567 err = da.deleteFlowsAndGroups(context.Background(), []*ofp.OfpFlowStats{}, delGroups, &voltha.FlowMetadata{})
568 assert.Nil(t, err)
569 daGroups = changeToGroupList(da.listDeviceGroups())
570 assert.True(t, isGroupSliceEqual(expectedGroups, daGroups))
khenaidoob2121e52019-12-16 17:17:22 -0500571}