blob: 837acd9c4327f104e39feb3907be51d4c18c8377 [file] [log] [blame]
Elia Battistone1cecb22022-03-21 10:05:25 +01001/*
2* Copyright 2022-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 */
16
17package core
18
19import (
20 "fmt"
21 "testing"
Elia Battiston4750d3c2022-07-14 13:24:56 +000022 "time"
Elia Battistone1cecb22022-03-21 10:05:25 +010023
Elia Battistona1333642022-07-27 12:17:24 +000024 "github.com/opencord/voltha-northbound-bbf-adapter/internal/clients"
Elia Battiston4750d3c2022-07-14 13:24:56 +000025 "github.com/opencord/voltha-protos/v5/go/openflow_13"
Elia Battistone1cecb22022-03-21 10:05:25 +010026 "github.com/opencord/voltha-protos/v5/go/voltha"
27 "github.com/stretchr/testify/assert"
Elia Battiston4750d3c2022-07-14 13:24:56 +000028 "google.golang.org/protobuf/types/known/timestamppb"
Elia Battistone1cecb22022-03-21 10:05:25 +010029)
30
31const (
32 testDeviceId = "123145abcdef"
33)
34
35func getItemWithPath(items []YangItem, path string) (value string, ok bool) {
36 for _, item := range items {
37 if item.Path == path {
38 return item.Value, true
39 }
40 }
41
42 return "", false
43}
44
45func TestDevicePath(t *testing.T) {
46 path := getDevicePath(testDeviceId)
Elia Battistona1333642022-07-27 12:17:24 +000047 assert.Equal(t, "/bbf-device-aggregation:devices/device[name='123145abcdef']", path)
48}
49
50func TestDeviceHardwarePath(t *testing.T) {
51 path := getDeviceHardwarePath(testDeviceId)
52 assert.Equal(t, "/bbf-device-aggregation:devices/device[name='123145abcdef']/data/ietf-hardware:hardware/component[name='123145abcdef']", path)
53}
54
55func TestServicePortPath(t *testing.T) {
56 path := GetServicePortPath("testService", "testPort")
57 assert.Equal(t, "/bbf-nt-service-profile:service-profiles/service-profile[name='testService']/ports/port[name='testPort']", path)
58}
59
60func TestVlansPath(t *testing.T) {
61 path := GetVlansPath("testProfile")
62 assert.Equal(t, "/bbf-l2-access-attributes:vlan-translation-profiles/vlan-translation-profile[name='testProfile']", path)
Elia Battistone1cecb22022-03-21 10:05:25 +010063}
64
65func TestTranslateDevice(t *testing.T) {
Elia Battiston4750d3c2022-07-14 13:24:56 +000066 olt := &voltha.Device{
67 Id: testDeviceId,
68 Root: true,
69 Vendor: "BBSim",
70 Model: "asfvolt16",
71 SerialNumber: "BBSIM_OLT_10",
72 HardwareVersion: "v0.0.2",
73 FirmwareVersion: "v0.0.3",
74 AdminState: voltha.AdminState_ENABLED,
75 OperStatus: voltha.OperStatus_ACTIVE,
Elia Battistone1cecb22022-03-21 10:05:25 +010076 }
77 items := translateDevice(olt)
78
Elia Battiston4750d3c2022-07-14 13:24:56 +000079 oltPath := getDevicePath(testDeviceId)
80 oltHwPath := getDeviceHardwarePath(testDeviceId)
Elia Battistone1cecb22022-03-21 10:05:25 +010081
Elia Battiston4750d3c2022-07-14 13:24:56 +000082 expected := []YangItem{
83 {
84 Path: oltPath + "/type",
85 Value: DeviceTypeOlt,
86 },
87 {
88 Path: oltHwPath + "/mfg-name",
89 Value: "BBSim",
90 },
91 {
92 Path: oltHwPath + "/model-name",
93 Value: "asfvolt16",
94 },
95 {
96 Path: oltHwPath + "/hardware-rev",
97 Value: "v0.0.2",
98 },
99 {
100 Path: oltHwPath + "/firmware-rev",
101 Value: "v0.0.3",
102 },
103 {
104 Path: oltHwPath + "/serial-num",
105 Value: "BBSIM_OLT_10",
106 },
107 {
108 Path: oltHwPath + "/state/admin-state",
109 Value: ietfAdminStateUnlocked,
110 },
111 {
112 Path: oltHwPath + "/state/oper-state",
113 Value: ietfOperStateEnabled,
114 },
115 }
116
117 assert.NotEmpty(t, items, "No OLT items")
118 for _, e := range expected {
119 val, ok := getItemWithPath(items, e.Path)
120 assert.True(t, ok, e.Path+" missing for OLT")
121 assert.Equal(t, e.Value, val, "Wrong value for "+e.Path)
122 }
123
124 onu := &voltha.Device{
125 Id: testDeviceId,
126 Root: false,
127 Vendor: "BBSM",
128 Model: "v0.0.1",
129 SerialNumber: "BBSM000a0001",
130 HardwareVersion: "v0.0.2",
131 FirmwareVersion: "v0.0.3",
132 AdminState: voltha.AdminState_ENABLED,
133 OperStatus: voltha.OperStatus_ACTIVE,
Elia Battistona1333642022-07-27 12:17:24 +0000134 ParentId: "abcdef1234",
135 ParentPortNo: 1,
Elia Battistone1cecb22022-03-21 10:05:25 +0100136 }
137 items = translateDevice(onu)
138
Elia Battiston4750d3c2022-07-14 13:24:56 +0000139 onuPath := getDevicePath(testDeviceId)
140 onuHwPath := getDeviceHardwarePath(testDeviceId)
141
142 expected = []YangItem{
143 {
144 Path: onuPath + "/type",
145 Value: DeviceTypeOnu,
146 },
147 {
148 Path: onuHwPath + "/mfg-name",
149 Value: "BBSM",
150 },
151 {
152 Path: onuHwPath + "/model-name",
153 Value: "v0.0.1",
154 },
155 {
156 Path: onuHwPath + "/hardware-rev",
157 Value: "v0.0.2",
158 },
159 {
160 Path: onuHwPath + "/firmware-rev",
161 Value: "v0.0.3",
162 },
163 {
164 Path: onuHwPath + "/serial-num",
165 Value: "BBSM000a0001",
166 },
167 {
168 Path: onuHwPath + "/state/admin-state",
169 Value: ietfAdminStateUnlocked,
170 },
171 {
172 Path: onuHwPath + "/state/oper-state",
173 Value: ietfOperStateEnabled,
174 },
Elia Battistona1333642022-07-27 12:17:24 +0000175 {
176 Path: onuHwPath + "/parent",
177 Value: "abcdef1234",
178 },
179 {
180 Path: onuHwPath + "/parent-rel-pos",
181 Value: "1",
182 },
Elia Battiston4750d3c2022-07-14 13:24:56 +0000183 }
184
185 assert.NotEmpty(t, items, "No ONU items")
186 for _, e := range expected {
187 val, ok := getItemWithPath(items, e.Path)
188 assert.True(t, ok, e.Path+" missing for ONU")
189 assert.Equal(t, e.Value, val, "Wrong value for "+e.Path)
190 }
Elia Battistone1cecb22022-03-21 10:05:25 +0100191}
192
Elia Battiston4750d3c2022-07-14 13:24:56 +0000193func TestTranslateOnuPorts(t *testing.T) {
194 ports := &voltha.Ports{
195 Items: []*voltha.Port{
196 {
197 PortNo: 0,
198 Type: voltha.Port_ETHERNET_UNI,
199 OperStatus: voltha.OperStatus_ACTIVE,
200 },
201 },
Elia Battistone1cecb22022-03-21 10:05:25 +0100202 }
203
Elia Battiston4750d3c2022-07-14 13:24:56 +0000204 _, err := translateOnuPorts(testDeviceId, ports)
205 assert.Error(t, err, "No error for missing Ofp port")
206
207 ports = &voltha.Ports{
208 Items: []*voltha.Port{
209 {
210 PortNo: 0,
211 Type: voltha.Port_ETHERNET_UNI,
212 OfpPort: &openflow_13.OfpPort{
213 Name: "BBSM000a0001-1",
214 },
215 OperStatus: voltha.OperStatus_ACTIVE,
216 },
217 {
218 PortNo: 1,
219 Type: voltha.Port_ETHERNET_UNI,
220 OfpPort: &openflow_13.OfpPort{
221 Name: "BBSM000a0001-2",
222 },
223 OperStatus: voltha.OperStatus_UNKNOWN,
224 },
225 {
226 PortNo: 0,
227 Type: voltha.Port_PON_ONU,
228 OperStatus: voltha.OperStatus_UNKNOWN,
229 },
230 },
Elia Battistone1cecb22022-03-21 10:05:25 +0100231 }
232
Elia Battiston4750d3c2022-07-14 13:24:56 +0000233 portsItems, err := translateOnuPorts(testDeviceId, ports)
234 assert.Nil(t, err, "Translation error")
Elia Battistone1cecb22022-03-21 10:05:25 +0100235
Elia Battiston4750d3c2022-07-14 13:24:56 +0000236 /*2 items for 2 UNIs, PON is ignored*/
237 assert.Equal(t, 4, len(portsItems), "No ports items")
Elia Battistone1cecb22022-03-21 10:05:25 +0100238
Elia Battiston4750d3c2022-07-14 13:24:56 +0000239 interfacesPath := getDevicePath(testDeviceId) + "/data/ietf-interfaces:interfaces"
Elia Battistone1cecb22022-03-21 10:05:25 +0100240
Elia Battiston4750d3c2022-07-14 13:24:56 +0000241 expected := []YangItem{
242 {
243 Path: fmt.Sprintf("%s/interface[name='%s']/oper-status", interfacesPath, "BBSM000a0001-1"),
244 Value: ietfOperStateUp,
245 },
246 {
247 Path: fmt.Sprintf("%s/interface[name='%s']/type", interfacesPath, "BBSM000a0001-1"),
248 Value: "bbf-xpon-if-type:onu-v-vrefpoint",
249 },
250 {
251 Path: fmt.Sprintf("%s/interface[name='%s']/oper-status", interfacesPath, "BBSM000a0001-2"),
252 Value: ietfOperStateUnknown,
253 },
254 {
255 Path: fmt.Sprintf("%s/interface[name='%s']/type", interfacesPath, "BBSM000a0001-2"),
256 Value: "bbf-xpon-if-type:onu-v-vrefpoint",
257 },
258 }
259
260 for _, e := range expected {
261 val, ok := getItemWithPath(portsItems, e.Path)
262 assert.True(t, ok, e.Path+" missing for ports")
263 assert.Equal(t, e.Value, val, "Wrong value for "+e.Path)
264 }
265}
266
267func TestTranslateOnuActive(t *testing.T) {
268 timestamp := time.Now()
269 eventHeader := &voltha.EventHeader{
270 Id: "Voltha.openolt.ONU_ACTIVATED.1657705515351182767",
271 RaisedTs: timestamppb.New(timestamp),
272 Category: voltha.EventCategory_EQUIPMENT,
273 Type: voltha.EventType_DEVICE_EVENT,
274 }
275
276 deviceEvent := &voltha.DeviceEvent{
277 ResourceId: testDeviceId,
278 DeviceEventName: "ONU_ACTIVATED_RAISE_EVENT",
279 Description: "ONU Event - ONU_ACTIVATED - Raised",
280 Context: map[string]string{},
281 }
282
283 _, _, err := TranslateOnuActivatedEvent(eventHeader, deviceEvent)
284 assert.Error(t, err, "Empty context produces no error")
285
286 deviceEvent.Context[eventContextKeyPonId] = "0"
287 deviceEvent.Context[eventContextKeyOnuSn] = "BBSM000a0001"
288 deviceEvent.Context[eventContextKeyOltSn] = "BBSIM_OLT_10"
289
290 notificationPath := "/bbf-xpon-onu-states:onu-state-change"
291 expected := []YangItem{
292 {
293 Path: notificationPath + "/detected-serial-number",
294 Value: "BBSM000a0001",
295 },
296 {
297 Path: notificationPath + "/onu-state-last-change",
298 Value: timestamp.Format(time.RFC3339),
299 },
300 {
301 Path: notificationPath + "/onu-state",
302 Value: "bbf-xpon-onu-types:onu-present",
303 },
304 {
305 Path: notificationPath + "/detected-registration-id",
306 Value: testDeviceId,
307 },
308 }
309
310 notificationItems, channelTerminationItems, err := TranslateOnuActivatedEvent(eventHeader, deviceEvent)
311 assert.Nil(t, err, "Translation error")
312
313 assert.NotEmpty(t, channelTerminationItems, "No channel termination items")
314
315 assert.NotEmpty(t, notificationItems, "No notification items")
316
317 _, ok := getItemWithPath(notificationItems, notificationPath+"/channel-termination-ref")
318 assert.True(t, ok, "No channel termination reference in notification")
319
320 for _, e := range expected {
321 val, ok := getItemWithPath(notificationItems, e.Path)
322 assert.True(t, ok, e.Path+" missing for notification")
323 assert.Equal(t, e.Value, val, "Wrong value for "+e.Path)
Elia Battistone1cecb22022-03-21 10:05:25 +0100324 }
325}
Elia Battistona1333642022-07-27 12:17:24 +0000326
327func TestTranslateServices(t *testing.T) {
328 subscribers := []clients.ProgrammedSubscriber{
329 {
330 Location: "of:00001/256",
331 TagInfo: clients.SadisUniTag{
332 UniTagMatch: 100,
333 PonCTag: 4096,
334 PonSTag: 102,
335 TechnologyProfileID: 64,
336 UpstreamBandwidthProfile: "BW1",
337 DownstreamBandwidthProfile: "BW2",
338 UpstreamOltBandwidthProfile: "OLTBW",
339 IsDhcpRequired: true,
340 IsIgmpRequired: false,
341 IsPPPoERequired: false,
342 ConfiguredMacAddress: "00:11:22:33:44:55",
343 EnableMacLearning: true,
344 UsPonCTagPriority: 1,
345 UsPonSTagPriority: 2,
346 DsPonCTagPriority: 3,
347 DsPonSTagPriority: -1,
348 ServiceName: "testService",
349 },
350 },
351 }
352
353 ports := []clients.OnosPort{
354 {
355 Element: "of:00001",
356 Port: "256",
357 Annotations: map[string]string{
358 "portName": "TESTPORT-1",
359 },
360 },
361 {
362 Element: "of:00001",
363 Port: "257",
364 Annotations: map[string]string{
365 "portName": "TESTPORT-2",
366 },
367 },
368 }
369
370 servicesItesm, err := translateServices(subscribers, ports)
371 assert.Nil(t, err, "Translation error")
372
373 assert.NotEmpty(t, servicesItesm, "No services items")
374
375 servicePortPath := ServiceProfilesPath + "/service-profile[name='TESTPORT-1-testService']/ports/port[name='TESTPORT-1']"
376
377 expected := []YangItem{
378 {
379 Path: servicePortPath + "/bbf-nt-service-profile-voltha:configured-mac-address",
380 Value: "00:11:22:33:44:55",
381 },
382 {
383 Path: servicePortPath + "/bbf-nt-service-profile-voltha:upstream-subscriber-bp-name",
384 Value: "BW1",
385 },
386 {
387 Path: servicePortPath + "/bbf-nt-service-profile-voltha:downstream-subscriber-bp-name",
388 Value: "BW2",
389 },
390 {
391 Path: servicePortPath + "/bbf-nt-service-profile-voltha:upstream-olt-bp-name",
392 Value: "OLTBW",
393 },
394 {
395 Path: servicePortPath + "/bbf-nt-service-profile-voltha:mac-learning-enabled",
396 Value: "true",
397 },
398 {
399 Path: servicePortPath + "/bbf-nt-service-profile-voltha:dhcp-required",
400 Value: "true",
401 },
402 {
403 Path: servicePortPath + "/bbf-nt-service-profile-voltha:igmp-required",
404 Value: "false",
405 },
406 {
407 Path: servicePortPath + "/bbf-nt-service-profile-voltha:pppoe-required",
408 Value: "false",
409 },
410 }
411
412 _, ok := getItemWithPath(servicesItesm, servicePortPath+"/port-vlans/port-vlan[name='TESTPORT-1-testService']")
413 assert.True(t, ok, "No vlans leafref in services")
414
415 _, ok = getItemWithPath(servicesItesm, servicePortPath+"/bbf-nt-service-profile-voltha:downstream-olt-bp-name")
416 assert.False(t, ok, "Downstream OLT bandwidth profile should not be present")
417
418 for _, e := range expected {
419 val, ok := getItemWithPath(servicesItesm, e.Path)
420 assert.True(t, ok, e.Path+" missing for services")
421 assert.Equal(t, e.Value, val, "Wrong value for "+e.Path)
422 }
423}
424
425func TestTranslateVlans(t *testing.T) {
426 subscribers := []clients.ProgrammedSubscriber{
427 {
428 Location: "of:00001/256",
429 TagInfo: clients.SadisUniTag{
430 UniTagMatch: 100,
431 PonCTag: 4096,
432 PonSTag: 102,
433 TechnologyProfileID: 64,
434 UpstreamBandwidthProfile: "BW1",
435 DownstreamBandwidthProfile: "BW2",
436 UpstreamOltBandwidthProfile: "OLTBW",
437 IsDhcpRequired: true,
438 IsIgmpRequired: false,
439 IsPPPoERequired: false,
440 ConfiguredMacAddress: "00:11:22:33:44:55",
441 EnableMacLearning: true,
442 UsPonCTagPriority: 1,
443 UsPonSTagPriority: 2,
444 DsPonCTagPriority: 3,
445 DsPonSTagPriority: -1,
446 ServiceName: "testService",
447 },
448 },
449 }
450
451 ports := []clients.OnosPort{
452 {
453 Element: "of:00001",
454 Port: "256",
455 Annotations: map[string]string{
456 "portName": "TESTPORT-1",
457 },
458 },
459 {
460 Element: "of:00001",
461 Port: "257",
462 Annotations: map[string]string{
463 "portName": "TESTPORT-2",
464 },
465 },
466 }
467
468 vlanItems, err := translateVlans(subscribers, ports)
469 assert.Nil(t, err, "Translation error")
470
471 assert.NotEmpty(t, vlanItems, "No vlans items")
472
473 vlanPath := VlansPath + "/vlan-translation-profile[name='TESTPORT-1-testService']"
474
475 expected := []YangItem{
476 {
477 Path: vlanPath + "/match-criteria/outer-tag/vlan-id",
478 Value: "100",
479 },
480 {
481 Path: vlanPath + "/ingress-rewrite/push-second-tag/vlan-id",
482 Value: "any",
483 },
484 {
485 Path: vlanPath + "/ingress-rewrite/push-outer-tag/vlan-id",
486 Value: "102",
487 },
488 {
489 Path: vlanPath + "/match-criteria/second-tag/vlan-id",
490 Value: "any",
491 },
492 {
493 Path: vlanPath + "/ingress-rewrite/push-second-tag/pbit",
494 Value: "1",
495 },
496 {
497 Path: vlanPath + "/ingress-rewrite/push-outer-tag/pbit",
498 Value: "2",
499 },
500 {
501 Path: vlanPath + "/ingress-rewrite/push-second-tag/bbf-voltha-vlan-translation:dpbit",
502 Value: "3",
503 },
504 }
505
506 _, ok := getItemWithPath(vlanItems, vlanPath+"/ingress-rewrite/push-outer-tag/bbf-voltha-vlan-translation:dpbit")
507 assert.False(t, ok, "Pbit value should not be present")
508
509 for _, e := range expected {
510 val, ok := getItemWithPath(vlanItems, e.Path)
511 assert.True(t, ok, e.Path+" missing for vlans")
512 assert.Equal(t, e.Value, val, "Wrong value for "+e.Path)
513 }
514}