blob: e9499e3cf1ee2a47015c471fc96133bc631016b3 [file] [log] [blame]
khenaidoob64fc8a2019-11-27 15:08:19 -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 "errors"
21 "fmt"
22 "github.com/golang/protobuf/ptypes/empty"
23 "github.com/opencord/voltha-go/rw_core/config"
24 cm "github.com/opencord/voltha-go/rw_core/mocks"
25 "github.com/opencord/voltha-lib-go/v2/pkg/kafka"
26 "github.com/opencord/voltha-lib-go/v2/pkg/log"
27 lm "github.com/opencord/voltha-lib-go/v2/pkg/mocks"
28 "github.com/opencord/voltha-lib-go/v2/pkg/version"
29 ofp "github.com/opencord/voltha-protos/v2/go/openflow_13"
30 "github.com/opencord/voltha-protos/v2/go/voltha"
31 "github.com/phayes/freeport"
32 "github.com/stretchr/testify/assert"
33 "google.golang.org/grpc/codes"
34 "google.golang.org/grpc/status"
35 "strings"
36 "testing"
37 "time"
38)
39
40type NBTest struct {
41 etcdServer *lm.EtcdServer
42 core *Core
43 kClient kafka.Client
44 kvClientPort int
45 numONUPerOLT int
46 oltAdapterName string
47 onuAdapterName string
48 coreInstanceID string
49 defaultTimeout time.Duration
50 maxTimeout time.Duration
51}
52
53func newNBTest() *NBTest {
54 test := &NBTest{}
55 // Start the embedded etcd server
56 var err error
57 test.etcdServer, test.kvClientPort, err = startEmbeddedEtcdServer("voltha.rwcore.nb.test", "voltha.rwcore.nb.etcd", "error")
58 if err != nil {
59 log.Fatal(err)
60 }
61 // Create the kafka client
62 test.kClient = lm.NewKafkaClient()
63 test.oltAdapterName = "olt_adapter_mock"
64 test.onuAdapterName = "onu_adapter_mock"
65 test.coreInstanceID = "rw-nbi-test"
66 test.defaultTimeout = 5 * time.Second
67 test.maxTimeout = 20 * time.Second
68 return test
69}
70
71func (nb *NBTest) startCore(inCompeteMode bool) {
72 cfg := config.NewRWCoreFlags()
73 cfg.CorePairTopic = "rw_core"
74 cfg.DefaultRequestTimeout = nb.defaultTimeout.Nanoseconds() / 1000000 //TODO: change when Core changes to Duration
75 cfg.KVStorePort = nb.kvClientPort
76 cfg.InCompetingMode = inCompeteMode
77 grpcPort, err := freeport.GetFreePort()
78 if err != nil {
79 log.Fatal("Cannot get a freeport for grpc")
80 }
81 cfg.GrpcPort = grpcPort
82 cfg.GrpcHost = "127.0.0.1"
83 setCoreCompeteMode(inCompeteMode)
84 client := setupKVClient(cfg, nb.coreInstanceID)
85 nb.core = NewCore(nb.coreInstanceID, cfg, client, nb.kClient)
86 nb.core.Start(context.Background())
87}
88
89func (nb *NBTest) createAndregisterAdapters() {
90 // Setup the mock OLT adapter
91 oltAdapter, err := createMockAdapter(OltAdapter, nb.kClient, nb.coreInstanceID, coreName, nb.oltAdapterName)
92 if err != nil {
93 log.Fatalw("setting-mock-olt-adapter-failed", log.Fields{"error": err})
94 }
95 if adapter, ok := (oltAdapter).(*cm.OLTAdapter); ok {
96 nb.numONUPerOLT = adapter.GetNumONUPerOLT()
97 }
98 // Register the adapter
99 registrationData := &voltha.Adapter{
100 Id: nb.oltAdapterName,
101 Vendor: "Voltha-olt",
102 Version: version.VersionInfo.Version,
103 }
104 types := []*voltha.DeviceType{{Id: nb.oltAdapterName, Adapter: nb.oltAdapterName, AcceptsAddRemoveFlowUpdates: true}}
105 deviceTypes := &voltha.DeviceTypes{Items: types}
106 nb.core.adapterMgr.registerAdapter(registrationData, deviceTypes)
107
108 // Setup the mock ONU adapter
109 if _, err := createMockAdapter(OnuAdapter, nb.kClient, nb.coreInstanceID, coreName, nb.onuAdapterName); err != nil {
110 log.Fatalw("setting-mock-onu-adapter-failed", log.Fields{"error": err})
111 }
112 // Register the adapter
113 registrationData = &voltha.Adapter{
114 Id: nb.onuAdapterName,
115 Vendor: "Voltha-onu",
116 Version: version.VersionInfo.Version,
117 }
118 types = []*voltha.DeviceType{{Id: nb.onuAdapterName, Adapter: nb.onuAdapterName, AcceptsAddRemoveFlowUpdates: true}}
119 deviceTypes = &voltha.DeviceTypes{Items: types}
120 nb.core.adapterMgr.registerAdapter(registrationData, deviceTypes)
121}
122
123func (nb *NBTest) stopAll() {
124 if nb.kClient != nil {
125 nb.kClient.Stop()
126 }
127 if nb.core != nil {
128 nb.core.Stop(context.Background())
129 }
130 if nb.etcdServer != nil {
131 stopEmbeddedEtcdServer(nb.etcdServer)
132 }
133}
134
135func (nb *NBTest) verifyLogicalDevices(t *testing.T, oltDevice *voltha.Device, nbi *APIHandler) {
136 // Get the latest set of logical devices
137 logicalDevices, err := nbi.ListLogicalDevices(getContext(), &empty.Empty{})
138 assert.Nil(t, err)
139 assert.NotNil(t, logicalDevices)
140 assert.Equal(t, 1, len(logicalDevices.Items))
141
142 ld := logicalDevices.Items[0]
143 assert.NotEqual(t, "", ld.Id)
144 assert.NotEqual(t, uint64(0), ld.DatapathId)
145 assert.Equal(t, "olt_adapter_mock", ld.Desc.HwDesc)
146 assert.Equal(t, "olt_adapter_mock", ld.Desc.SwDesc)
147 assert.NotEqual(t, "", ld.RootDeviceId)
148 assert.NotEqual(t, "", ld.Desc.SerialNum)
149 assert.Equal(t, uint32(256), ld.SwitchFeatures.NBuffers)
150 assert.Equal(t, uint32(2), ld.SwitchFeatures.NTables)
151 assert.Equal(t, uint32(15), ld.SwitchFeatures.Capabilities)
152 assert.Equal(t, 1+nb.numONUPerOLT, len(ld.Ports))
153 assert.Equal(t, oltDevice.ParentId, ld.Id)
154 //Expected port no
155 expectedPortNo := make(map[uint32]bool)
156 expectedPortNo[uint32(2)] = false
157 for i := 0; i < nb.numONUPerOLT; i++ {
158 expectedPortNo[uint32(i+100)] = false
159 }
160 for _, p := range ld.Ports {
161 assert.Equal(t, p.OfpPort.PortNo, p.DevicePortNo)
162 assert.Equal(t, uint32(4), p.OfpPort.State)
163 expectedPortNo[p.OfpPort.PortNo] = true
164 if strings.HasPrefix(p.Id, "nni") {
165 assert.Equal(t, true, p.RootPort)
166 //assert.Equal(t, uint32(2), p.OfpPort.PortNo)
167 assert.Equal(t, p.Id, fmt.Sprintf("nni-%d", p.DevicePortNo))
168 } else {
169 assert.Equal(t, p.Id, fmt.Sprintf("uni-%d", p.DevicePortNo))
170 assert.Equal(t, false, p.RootPort)
171 }
172 }
173}
174
175func (nb *NBTest) verifyDevices(t *testing.T, nbi *APIHandler) {
176 // Get the latest set of devices
177 devices, err := nbi.ListDevices(getContext(), &empty.Empty{})
178 assert.Nil(t, err)
179 assert.NotNil(t, devices)
180
181 // Wait until devices are in the correct states
182 var vFunction isDeviceConditionSatisfied = func(device *voltha.Device) bool {
183 return device.AdminState == voltha.AdminState_ENABLED && device.OperStatus == voltha.OperStatus_ACTIVE
184 }
185 for _, d := range devices.Items {
186 err = waitUntilDeviceReadiness(d.Id, nb.maxTimeout, vFunction, nbi)
187 assert.Nil(t, err)
188 assert.NotNil(t, d)
189 }
190 // Get the latest device updates as they may have changed since last list devices
191 updatedDevices, err := nbi.ListDevices(getContext(), &empty.Empty{})
192 assert.Nil(t, err)
193 assert.NotNil(t, devices)
194 for _, d := range updatedDevices.Items {
195 assert.Equal(t, voltha.AdminState_ENABLED, d.AdminState)
196 assert.Equal(t, voltha.ConnectStatus_REACHABLE, d.ConnectStatus)
197 assert.Equal(t, voltha.OperStatus_ACTIVE, d.OperStatus)
198 assert.Equal(t, d.Type, d.Adapter)
199 assert.NotEqual(t, "", d.MacAddress)
200 assert.NotEqual(t, "", d.SerialNumber)
201
202 if d.Type == "olt_adapter_mock" {
203 assert.Equal(t, true, d.Root)
204 assert.NotEqual(t, "", d.Id)
205 assert.NotEqual(t, "", d.ParentId)
206 assert.Nil(t, d.ProxyAddress)
207 } else if d.Type == "onu_adapter_mock" {
208 assert.Equal(t, false, d.Root)
209 assert.NotEqual(t, uint32(0), d.Vlan)
210 assert.NotEqual(t, "", d.Id)
211 assert.NotEqual(t, "", d.ParentId)
212 assert.NotEqual(t, "", d.ProxyAddress.DeviceId)
213 assert.Equal(t, "olt_adapter_mock", d.ProxyAddress.DeviceType)
214 } else {
215 assert.Error(t, errors.New("invalid-device-type"))
216 }
217 assert.Equal(t, 2, len(d.Ports))
218 for _, p := range d.Ports {
219 assert.Equal(t, voltha.AdminState_ENABLED, p.AdminState)
220 assert.Equal(t, voltha.OperStatus_ACTIVE, p.OperStatus)
221 if p.Type == voltha.Port_ETHERNET_NNI || p.Type == voltha.Port_ETHERNET_UNI {
222 assert.Equal(t, 0, len(p.Peers))
223 } else if p.Type == voltha.Port_PON_OLT {
224 assert.Equal(t, nb.numONUPerOLT, len(p.Peers))
225 assert.Equal(t, uint32(1), p.PortNo)
226 } else if p.Type == voltha.Port_PON_ONU {
227 assert.Equal(t, 1, len(p.Peers))
228 assert.Equal(t, uint32(1), p.PortNo)
229 } else {
230 assert.Error(t, errors.New("invalid-port"))
231 }
232 }
233 }
234}
235
236func (nb *NBTest) getADevice(rootDevice bool, nbi *APIHandler) (*voltha.Device, error) {
237 devices, err := nbi.ListDevices(getContext(), &empty.Empty{})
238 if err != nil {
239 return nil, err
240 }
241 for _, d := range devices.Items {
242 if d.Root == rootDevice {
243 return d, nil
244 }
245 }
246 return nil, status.Errorf(codes.NotFound, "%v device not found", rootDevice)
247}
248
249func (nb *NBTest) testCoreWithoutData(t *testing.T, nbi *APIHandler) {
250 lds, err := nbi.ListLogicalDevices(getContext(), &empty.Empty{})
251 assert.Nil(t, err)
252 assert.NotNil(t, lds)
253 assert.Equal(t, 0, len(lds.Items))
254 devices, err := nbi.ListDevices(getContext(), &empty.Empty{})
255 assert.Nil(t, err)
256 assert.NotNil(t, devices)
257 assert.Equal(t, 0, len(devices.Items))
258 adapters, err := nbi.ListAdapters(getContext(), &empty.Empty{})
259 assert.Nil(t, err)
260 assert.NotNil(t, adapters)
261 assert.Equal(t, 0, len(adapters.Items))
262}
263
264func (nb *NBTest) testAdapterRegistration(t *testing.T, nbi *APIHandler) {
265 adapters, err := nbi.ListAdapters(getContext(), &empty.Empty{})
266 assert.Nil(t, err)
267 assert.NotNil(t, adapters)
268 assert.Equal(t, 2, len(adapters.Items))
269 for _, a := range adapters.Items {
270 switch a.Id {
271 case nb.oltAdapterName:
272 assert.Equal(t, "Voltha-olt", a.Vendor)
273 case nb.onuAdapterName:
274 assert.Equal(t, "Voltha-onu", a.Vendor)
275 default:
276 log.Fatal("unregistered-adapter", a.Id)
277 }
278 }
279 deviceTypes, err := nbi.ListDeviceTypes(getContext(), &empty.Empty{})
280 assert.Nil(t, err)
281 assert.NotNil(t, deviceTypes)
282 assert.Equal(t, 2, len(deviceTypes.Items))
283 for _, dt := range deviceTypes.Items {
284 switch dt.Id {
285 case nb.oltAdapterName:
286 assert.Equal(t, nb.oltAdapterName, dt.Adapter)
287 assert.Equal(t, false, dt.AcceptsBulkFlowUpdate)
288 assert.Equal(t, true, dt.AcceptsAddRemoveFlowUpdates)
289 case nb.onuAdapterName:
290 assert.Equal(t, nb.onuAdapterName, dt.Adapter)
291 assert.Equal(t, false, dt.AcceptsBulkFlowUpdate)
292 assert.Equal(t, true, dt.AcceptsAddRemoveFlowUpdates)
293 default:
294 log.Fatal("invalid-device-type", dt.Id)
295 }
296 }
297}
298
299func (nb *NBTest) testCreateDevice(t *testing.T, nbi *APIHandler) {
300 // Create a valid device
301 oltDevice, err := nbi.CreateDevice(getContext(), &voltha.Device{Type: nb.oltAdapterName, MacAddress: "aa:bb:cc:cc:ee:ee"})
302 assert.Nil(t, err)
303 assert.NotNil(t, oltDevice)
304 device, err := nbi.GetDevice(getContext(), &voltha.ID{Id: oltDevice.Id})
305 assert.Nil(t, err)
306 assert.NotNil(t, device)
307 assert.Equal(t, oltDevice.String(), device.String())
308
309 // Try to create the same device
310 _, err = nbi.CreateDevice(getContext(), &voltha.Device{Type: nb.oltAdapterName, MacAddress: "aa:bb:cc:cc:ee:ee"})
311 assert.NotNil(t, err)
312 assert.Equal(t, "Device is already pre-provisioned", err.Error())
313
314 // Try to create a device with invalid data
315 _, err = nbi.CreateDevice(getContext(), &voltha.Device{Type: nb.oltAdapterName})
316 assert.NotNil(t, err)
317 assert.Equal(t, "No Device Info Present; MAC or HOSTIP&PORT", err.Error())
318
319 // Ensure we only have 1 device in the Core
320 devices, err := nbi.ListDevices(getContext(), &empty.Empty{})
321 assert.Nil(t, err)
322 assert.NotNil(t, devices)
323 assert.Equal(t, 1, len(devices.Items))
324 assert.Equal(t, oltDevice.String(), devices.Items[0].String())
325
326 //Remove the device
327 _, err = nbi.DeleteDevice(getContext(), &voltha.ID{Id: oltDevice.Id})
328 assert.Nil(t, err)
329
330 //Ensure there are no devices in the Core now - wait until condition satisfied or timeout
331 var vFunction isDevicesConditionSatisfied = func(devices *voltha.Devices) bool {
332 return devices != nil && len(devices.Items) == 0
333 }
334 err = waitUntilConditionForDevices(5*time.Second, nbi, vFunction)
335 assert.Nil(t, err)
336}
337
338func (nb *NBTest) testEnableDevice(t *testing.T, nbi *APIHandler) {
339 // Create a device that has no adapter registered
340 oltDeviceNoAdapter, err := nbi.CreateDevice(getContext(), &voltha.Device{Type: "noAdapterRegistered", MacAddress: "aa:bb:cc:cc:ee:ff"})
341 assert.Nil(t, err)
342 assert.NotNil(t, oltDeviceNoAdapter)
343
344 // Try to enable the oltDevice and check the error message
345 _, err = nbi.EnableDevice(getContext(), &voltha.ID{Id: oltDeviceNoAdapter.Id})
346 assert.NotNil(t, err)
347 assert.Equal(t, "Adapter-not-registered-for-device-type noAdapterRegistered", err.Error())
348
349 //Remove the device
350 _, err = nbi.DeleteDevice(getContext(), &voltha.ID{Id: oltDeviceNoAdapter.Id})
351 assert.Nil(t, err)
352
353 //Ensure there are no devices in the Core now - wait until condition satisfied or timeout
354 var vdFunction isDevicesConditionSatisfied = func(devices *voltha.Devices) bool {
355 return devices != nil && len(devices.Items) == 0
356 }
357 err = waitUntilConditionForDevices(5*time.Second, nbi, vdFunction)
358 assert.Nil(t, err)
359
360 // Create the device with valid data
361 oltDevice, err := nbi.CreateDevice(getContext(), &voltha.Device{Type: nb.oltAdapterName, MacAddress: "aa:bb:cc:cc:ee:ee"})
362 assert.Nil(t, err)
363 assert.NotNil(t, oltDevice)
364
365 // Verify oltDevice exist in the core
366 devices, err := nbi.ListDevices(getContext(), &empty.Empty{})
367 assert.Nil(t, err)
368 assert.Equal(t, 1, len(devices.Items))
369 assert.Equal(t, oltDevice.Id, devices.Items[0].Id)
370
371 // Enable the oltDevice
372 _, err = nbi.EnableDevice(getContext(), &voltha.ID{Id: oltDevice.Id})
373 assert.Nil(t, err)
374
375 // Wait for the logical device to be in the ready state
376 var vldFunction isLogicalDeviceConditionSatisfied = func(ld *voltha.LogicalDevice) bool {
377 return ld != nil && len(ld.Ports) == nb.numONUPerOLT+1
378 }
379 err = waitUntilLogicalDeviceReadiness(oltDevice.Id, nb.maxTimeout, nbi, vldFunction)
380 assert.Nil(t, err)
381
382 // Verify that the devices have been setup correctly
383 nb.verifyDevices(t, nbi)
384
385 // Get latest oltDevice data
386 oltDevice, err = nbi.GetDevice(getContext(), &voltha.ID{Id: oltDevice.Id})
387 assert.Nil(t, err)
388
389 // Verify that the logical device has been setup correctly
390 nb.verifyLogicalDevices(t, oltDevice, nbi)
391}
392
393func (nb *NBTest) testDisableAndReEnableRootDevice(t *testing.T, nbi *APIHandler) {
394 //Get an OLT device
395 oltDevice, err := nb.getADevice(true, nbi)
396 assert.Nil(t, err)
397 assert.NotNil(t, oltDevice)
398
399 // Disable the oltDevice
400 _, err = nbi.DisableDevice(getContext(), &voltha.ID{Id: oltDevice.Id})
401 assert.Nil(t, err)
402
403 // Wait for the old device to be disabled
404 var vdFunction isDeviceConditionSatisfied = func(device *voltha.Device) bool {
405 return device.AdminState == voltha.AdminState_DISABLED && device.OperStatus == voltha.OperStatus_UNKNOWN
406 }
407 err = waitUntilDeviceReadiness(oltDevice.Id, nb.maxTimeout, vdFunction, nbi)
408 assert.Nil(t, err)
409
410 // Verify that all onu devices are disabled as well
411 onuDevices, err := nb.core.deviceMgr.getAllChildDevices(oltDevice.Id)
412 assert.Nil(t, err)
413 for _, onu := range onuDevices.Items {
414 err = waitUntilDeviceReadiness(onu.Id, nb.maxTimeout, vdFunction, nbi)
415 assert.Nil(t, err)
416 }
417
418 // Wait for the logical device to satisfy the expected condition
419 var vlFunction isLogicalDeviceConditionSatisfied = func(ld *voltha.LogicalDevice) bool {
420 for _, lp := range ld.Ports {
421 if (lp.OfpPort.Config&uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN) != lp.OfpPort.Config) ||
422 lp.OfpPort.State != uint32(ofp.OfpPortState_OFPPS_LINK_DOWN) {
423 return false
424 }
425 }
426 return true
427 }
428 err = waitUntilLogicalDeviceReadiness(oltDevice.Id, nb.maxTimeout, nbi, vlFunction)
429 assert.Nil(t, err)
430
431 // Reenable the oltDevice
432 _, err = nbi.EnableDevice(getContext(), &voltha.ID{Id: oltDevice.Id})
433 assert.Nil(t, err)
434
435 // Wait for the old device to be enabled
436 vdFunction = func(device *voltha.Device) bool {
437 return device.AdminState == voltha.AdminState_ENABLED && device.OperStatus == voltha.OperStatus_ACTIVE
438 }
439 err = waitUntilDeviceReadiness(oltDevice.Id, nb.maxTimeout, vdFunction, nbi)
440 assert.Nil(t, err)
441
442 // Verify that all onu devices are enabled as well
443 onuDevices, err = nb.core.deviceMgr.getAllChildDevices(oltDevice.Id)
444 assert.Nil(t, err)
445 for _, onu := range onuDevices.Items {
446 err = waitUntilDeviceReadiness(onu.Id, nb.maxTimeout, vdFunction, nbi)
447 assert.Nil(t, err)
448 }
449
450 // Wait for the logical device to satisfy the expected condition
451 vlFunction = func(ld *voltha.LogicalDevice) bool {
452 for _, lp := range ld.Ports {
453 if (lp.OfpPort.Config&^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN) != lp.OfpPort.Config) ||
454 lp.OfpPort.State != uint32(ofp.OfpPortState_OFPPS_LIVE) {
455 return false
456 }
457 }
458 return true
459 }
460 err = waitUntilLogicalDeviceReadiness(oltDevice.Id, nb.maxTimeout, nbi, vlFunction)
461 assert.Nil(t, err)
462}
463
464func TestSuite1(t *testing.T) {
465 nb := newNBTest()
466 assert.NotNil(t, nb)
467
468 defer nb.stopAll()
469
470 // Start the Core
471 nb.startCore(false)
472
473 // Set the grpc API interface - no grpc server is running in unit test
474 nbi := NewAPIHandler(nb.core)
475
476 // 1. Basic test with no data in Core
477 nb.testCoreWithoutData(t, nbi)
478
479 // Create/register the adapters
480 nb.createAndregisterAdapters()
481
482 // 2. Test adapter registration
483 nb.testAdapterRegistration(t, nbi)
484
485 // 3. Test create device
486 nb.testCreateDevice(t, nbi)
487
488 // 4. Test Enable a device
489 nb.testEnableDevice(t, nbi)
490
491 // 5. Test disable and ReEnable a root device
492 nb.testDisableAndReEnableRootDevice(t, nbi)
493
494 //x. TODO - More tests to come
495}