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