[ONOS-7981] GUI2 Topo View Link handling fails WIP
on device name with multiple ':'
Change-Id: I698ff2e9a38d3ee45ce1ffa163137c84c12439f3
(cherry picked from commit b77768e06e72dda3c84f917ca39b7d114f6d84bf)
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.spec.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.spec.ts
index fb8f42c..d10df1c9 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.spec.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.spec.ts
@@ -26,7 +26,6 @@
import {DraggableDirective} from './draggable/draggable.directive';
import {ActivatedRoute, Params} from '@angular/router';
import {of} from 'rxjs';
-import {MapSvgComponent} from '../mapsvg/mapsvg.component';
import {DeviceNodeSvgComponent} from './visuals/devicenodesvg/devicenodesvg.component';
import {SubRegionNodeSvgComponent} from './visuals/subregionnodesvg/subregionnodesvg.component';
import {HostNodeSvgComponent} from './visuals/hostnodesvg/hostnodesvg.component';
@@ -96,8 +95,12 @@
let logServiceSpy: jasmine.SpyObj<LogService>;
let component: ForceSvgComponent;
let fixture: ComponentFixture<ForceSvgComponent>;
- const sampledata = require('./tests/test-module-topo2CurrentRegion.json');
- const regionData: Region = <Region><unknown>(sampledata.payload);
+ const openflowSampleData = require('./tests/test-module-topo2CurrentRegion.json');
+ const openflowRegionData: Region = <Region><unknown>(openflowSampleData.payload);
+
+ const odtnSampleData = require('./tests/test-OdtnConfig-topo2CurrentRegion.json');
+ const odtnRegionData: Region = <Region><unknown>(odtnSampleData.payload);
+
const emptyRegion: Region = <Region>{devices: [ [], [], [] ], hosts: [ [], [], [] ], links: []};
beforeEach(() => {
@@ -169,26 +172,30 @@
expect(component).toBeTruthy();
});
- it('load sample file', () => {
- expect(sampledata).toBeTruthy();
- expect(sampledata.payload).toBeTruthy();
- expect(sampledata.payload.id).toBe('(root)');
+ it('load sample files', () => {
+ expect(openflowSampleData).toBeTruthy();
+ expect(openflowSampleData.payload).toBeTruthy();
+ expect(openflowSampleData.payload.id).toBe('(root)');
+
+ expect(odtnSampleData).toBeTruthy();
+ expect(odtnSampleData.payload).toBeTruthy();
+ expect(odtnSampleData.payload.id).toBe('(root)');
});
it('should read sample data payload as Region', () => {
- expect(regionData).toBeTruthy();
+ expect(openflowRegionData).toBeTruthy();
// console.log(regionData);
- expect(regionData.id).toBe('(root)');
- expect(regionData.devices).toBeTruthy();
- expect(regionData.devices.length).toBe(3);
- expect(regionData.devices[2].length).toBe(10);
- expect(regionData.hosts.length).toBe(3);
- expect(regionData.hosts[2].length).toBe(20);
- expect(regionData.links.length).toBe(44);
+ expect(openflowRegionData.id).toBe('(root)');
+ expect(openflowRegionData.devices).toBeTruthy();
+ expect(openflowRegionData.devices.length).toBe(3);
+ expect(openflowRegionData.devices[2].length).toBe(10);
+ expect(openflowRegionData.hosts.length).toBe(3);
+ expect(openflowRegionData.hosts[2].length).toBe(20);
+ expect(openflowRegionData.links.length).toBe(44);
});
it('should read device246 correctly', () => {
- const device246: Device = regionData.devices[2][0];
+ const device246: Device = openflowRegionData.devices[2][0];
expect(device246.id).toBe('of:0000000000000246');
expect(device246.nodeType).toBe('device');
expect(device246.type).toBe('switch');
@@ -211,7 +218,7 @@
});
it('should read host 3 correctly', () => {
- const host3: Host = regionData.hosts[2][0];
+ const host3: Host = openflowRegionData.hosts[2][0];
expect(host3.id).toBe('00:88:00:00:00:03/110');
expect(host3.nodeType).toBe('host');
expect(host3.layer).toBe('def');
@@ -223,7 +230,7 @@
});
it('should read link 3-205 correctly', () => {
- const link3_205: Link = regionData.links[0];
+ const link3_205: Link = openflowRegionData.links[0];
expect(link3_205.id).toBe('00:AA:00:00:00:03/None~of:0000000000000205/6');
expect(link3_205.epA).toBe('00:AA:00:00:00:03/None');
expect(link3_205.epB).toBe('of:0000000000000205');
@@ -249,25 +256,41 @@
expect(component.graph.nodes.length).toBe(0);
});
- it('should know hwo to format names', () => {
- expect(ForceSvgComponent.extractNodeName('00:AA:00:00:00:03/None'))
+ it('should know how to format names', () => {
+ expect(ForceSvgComponent.extractNodeName('00:AA:00:00:00:03/None', undefined))
.toEqual('00:AA:00:00:00:03/None');
- expect(ForceSvgComponent.extractNodeName('00:AA:00:00:00:03/161'))
- .toEqual('00:AA:00:00:00:03/161');
+ expect(ForceSvgComponent.extractNodeName('00:AA:00:00:00:03/161', '161'))
+ .toEqual('00:AA:00:00:00:03');
- expect(ForceSvgComponent.extractNodeName('of:0000000000000206/6'))
+ // Like epB of first example in sampleData file - endPtStr contains port number
+ expect(ForceSvgComponent.extractNodeName('of:0000000000000206/6', '6'))
+ .toEqual('of:0000000000000206');
+
+ // Like epB of second example in sampleData file - endPtStr does not contain port number
+ expect(ForceSvgComponent.extractNodeName('of:0000000000000206', '6'))
.toEqual('of:0000000000000206');
});
- it('should handle regionData change - sample Region', () => {
- component.regionData = regionData;
+ it('should handle openflow regionData change - sample Region', () => {
+ component.regionData = openflowRegionData;
component.ngOnChanges(
- {'regionData' : new SimpleChange(<Region>{}, regionData, true)});
+ {'regionData' : new SimpleChange(<Region>{}, openflowRegionData, true)});
expect(component.graph.nodes.length).toBe(30);
expect(component.graph.links.length).toBe(44);
});
+
+ it('should handle odtn regionData change - sample odtn Region', () => {
+ component.regionData = odtnRegionData;
+ component.ngOnChanges(
+ {'regionData' : new SimpleChange(<Region>{}, odtnRegionData, true)});
+
+ expect(component.graph.nodes.length).toBe(2);
+
+ expect(component.graph.links.length).toBe(6);
+
+ });
});
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.ts
index d6a9148..adc814e 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.ts
@@ -119,21 +119,13 @@
* name
* @param endPtStr The end point name
*/
- static extractNodeName(endPtStr: string): string {
- const slash: number = endPtStr.indexOf('/');
- if (slash === -1) {
+ static extractNodeName(endPtStr: string, portStr: string): string {
+ if (portStr === undefined || endPtStr === undefined) {
return endPtStr;
- } else {
- const afterSlash = endPtStr.substr(slash + 1);
- const beforeSlash = endPtStr.substr(0, slash);
- if (afterSlash === 'None') {
- return endPtStr;
- } else if (beforeSlash.split(':').length > 2) {
- return endPtStr; // Host name with mac address
- } else {
- return endPtStr.substr(0, slash);
- }
+ } else if (endPtStr.includes('/')) {
+ return endPtStr.substr(0, endPtStr.length - portStr.length - 1);
}
+ return endPtStr;
}
/**
@@ -236,13 +228,21 @@
// Associate the endpoints of each link with a real node
this.graph.links = [];
for (const linkIdx of Object.keys(this.regionData.links)) {
- const epA = ForceSvgComponent.extractNodeName(
- this.regionData.links[linkIdx].epA);
+ const link = this.regionData.links[linkIdx];
+ const epA = ForceSvgComponent.extractNodeName(link.epA, link.portA);
+ if (!this.graph.nodes.find((node) => node.id === epA)) {
+ this.log.error('ngOnChange Could not find endpoint A', epA, 'for', link);
+ continue;
+ }
+ const epB = ForceSvgComponent.extractNodeName(
+ link.epB, link.portB);
+ if (!this.graph.nodes.find((node) => node.id === epB)) {
+ this.log.error('ngOnChange Could not find endpoint B', epB, 'for', link);
+ continue;
+ }
this.regionData.links[linkIdx].source =
this.graph.nodes.find((node) =>
node.id === epA);
- const epB = ForceSvgComponent.extractNodeName(
- this.regionData.links[linkIdx].epB);
this.regionData.links[linkIdx].target =
this.graph.nodes.find((node) =>
node.id === epB);
@@ -472,17 +472,27 @@
case ModelEventType.LINK_ADDED_OR_UPDATED:
if (memo === ModelEventMemo.ADDED &&
this.regionData.links.findIndex((l) => l.id === subject) === -1) {
- const listLen = this.regionData.links.push(<RegionLink>data);
+ const newLink = <RegionLink>data;
+
+
const epA = ForceSvgComponent.extractNodeName(
- this.regionData.links[listLen - 1].epA);
- this.regionData.links[listLen - 1].source =
- this.graph.nodes.find((node) =>
- node.id === epA);
+ newLink.epA, newLink.portA);
+ if (!this.graph.nodes.find((node) => node.id === epA)) {
+ this.log.error('Could not find endpoint A', epA, 'of', newLink);
+ break;
+ }
const epB = ForceSvgComponent.extractNodeName(
- this.regionData.links[listLen - 1].epB);
+ newLink.epB, newLink.portB);
+ if (!this.graph.nodes.find((node) => node.id === epB)) {
+ this.log.error('Could not find endpoint B', epB, 'of link', newLink);
+ break;
+ }
+
+ const listLen = this.regionData.links.push(<RegionLink>data);
+ this.regionData.links[listLen - 1].source =
+ this.graph.nodes.find((node) => node.id === epA);
this.regionData.links[listLen - 1].target =
- this.graph.nodes.find((node) =>
- node.id === epB);
+ this.graph.nodes.find((node) => node.id === epB);
this.log.debug('Link added', subject);
} else if (memo === ModelEventMemo.UPDATED) {
const oldLink = this.regionData.links.find((l) => l.id === subject);
@@ -510,8 +520,8 @@
const len = this.regionData.links.length;
for (let i = 0; i < len; i++) {
const linkIdx = this.regionData.links.findIndex((l) =>
- (ForceSvgComponent.extractNodeName(l.epA) === subject ||
- ForceSvgComponent.extractNodeName(l.epB) === subject));
+ (ForceSvgComponent.extractNodeName(l.epA, l.portA) === subject ||
+ ForceSvgComponent.extractNodeName(l.epB, l.portB) === subject));
if (linkIdx >= 0) {
this.regionData.links.splice(linkIdx, 1);
this.log.debug('Link ', linkIdx, 'removed on attempt', i);
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/tests/test-OdtnConfig-topo2CurrentRegion.json b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/tests/test-OdtnConfig-topo2CurrentRegion.json
new file mode 100644
index 0000000..2087940
--- /dev/null
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/tests/test-OdtnConfig-topo2CurrentRegion.json
@@ -0,0 +1,165 @@
+{
+ "event": "topo2CurrentRegion",
+ "payload": {
+ "id": "(root)",
+ "subregions": [],
+ "links": [
+ {
+ "id": "netconf:127.0.0.1:11002/201~netconf:127.0.0.1:11003/201",
+ "epA": "netconf:127.0.0.1:11002/201",
+ "epB": "netconf:127.0.0.1:11003/201",
+ "type": "UiDeviceLink",
+ "portA": "201",
+ "portB": "201",
+ "rollup": [
+ {
+ "id": "netconf:127.0.0.1:11002/201~netconf:127.0.0.1:11003/201",
+ "epA": "netconf:127.0.0.1:11002/201",
+ "epB": "netconf:127.0.0.1:11003/201",
+ "type": "UiDeviceLink",
+ "portA": "201",
+ "portB": "201"
+ }
+ ]
+ },
+ {
+ "id": "netconf:127.0.0.1:11002/202~netconf:127.0.0.1:11003/202",
+ "epA": "netconf:127.0.0.1:11002/202",
+ "epB": "netconf:127.0.0.1:11003/202",
+ "type": "UiDeviceLink",
+ "portA": "202",
+ "portB": "202",
+ "rollup": [
+ {
+ "id": "netconf:127.0.0.1:11002/202~netconf:127.0.0.1:11003/202",
+ "epA": "netconf:127.0.0.1:11002/202",
+ "epB": "netconf:127.0.0.1:11003/202",
+ "type": "UiDeviceLink",
+ "portA": "202",
+ "portB": "202"
+ }
+ ]
+ },
+ {
+ "id": "netconf:127.0.0.1:11002/203~netconf:127.0.0.1:11003/203",
+ "epA": "netconf:127.0.0.1:11002/203",
+ "epB": "netconf:127.0.0.1:11003/203",
+ "type": "UiDeviceLink",
+ "portA": "203",
+ "portB": "203",
+ "rollup": [
+ {
+ "id": "netconf:127.0.0.1:11002/203~netconf:127.0.0.1:11003/203",
+ "epA": "netconf:127.0.0.1:11002/203",
+ "epB": "netconf:127.0.0.1:11003/203",
+ "type": "UiDeviceLink",
+ "portA": "203",
+ "portB": "203"
+ }
+ ]
+ },
+ {
+ "id": "netconf:127.0.0.1:11002/204~netconf:127.0.0.1:11003/204",
+ "epA": "netconf:127.0.0.1:11002/204",
+ "epB": "netconf:127.0.0.1:11003/204",
+ "type": "UiDeviceLink",
+ "portA": "204",
+ "portB": "204",
+ "rollup": [
+ {
+ "id": "netconf:127.0.0.1:11002/204~netconf:127.0.0.1:11003/204",
+ "epA": "netconf:127.0.0.1:11002/204",
+ "epB": "netconf:127.0.0.1:11003/204",
+ "type": "UiDeviceLink",
+ "portA": "204",
+ "portB": "204"
+ }
+ ]
+ },
+ {
+ "id": "netconf:127.0.0.1:11002/205~netconf:127.0.0.1:11003/205",
+ "epA": "netconf:127.0.0.1:11002/205",
+ "epB": "netconf:127.0.0.1:11003/205",
+ "type": "UiDeviceLink",
+ "portA": "205",
+ "portB": "205",
+ "rollup": [
+ {
+ "id": "netconf:127.0.0.1:11002/205~netconf:127.0.0.1:11003/205",
+ "epA": "netconf:127.0.0.1:11002/205",
+ "epB": "netconf:127.0.0.1:11003/205",
+ "type": "UiDeviceLink",
+ "portA": "205",
+ "portB": "205"
+ }
+ ]
+ },
+ {
+ "id": "netconf:127.0.0.1:11002/206~netconf:127.0.0.1:11003/206",
+ "epA": "netconf:127.0.0.1:11002/206",
+ "epB": "netconf:127.0.0.1:11003/206",
+ "type": "UiDeviceLink",
+ "portA": "206",
+ "portB": "206",
+ "rollup": [
+ {
+ "id": "netconf:127.0.0.1:11002/206~netconf:127.0.0.1:11003/206",
+ "epA": "netconf:127.0.0.1:11002/206",
+ "epB": "netconf:127.0.0.1:11003/206",
+ "type": "UiDeviceLink",
+ "portA": "206",
+ "portB": "206"
+ }
+ ]
+ }
+ ],
+ "devices": [
+ [],
+ [],
+ [
+ {
+ "id": "netconf:127.0.0.1:11002",
+ "nodeType": "device",
+ "type": "terminal_device",
+ "online": true,
+ "master": "127.0.0.1",
+ "layer": "def",
+ "props": {
+ "ipaddress": "127.0.0.1",
+ "protocol": "NETCONF",
+ "driver": "cassini-ocnos",
+ "port": "11002",
+ "name": "cassini2",
+ "locType": "none"
+ }
+ },
+ {
+ "id": "netconf:127.0.0.1:11003",
+ "nodeType": "device",
+ "type": "terminal_device",
+ "online": true,
+ "master": "127.0.0.1",
+ "layer": "def",
+ "props": {
+ "ipaddress": "127.0.0.1",
+ "protocol": "NETCONF",
+ "driver": "cassini-ocnos",
+ "port": "11003",
+ "name": "cassini1",
+ "locType": "none"
+ }
+ }
+ ]
+ ],
+ "hosts": [
+ [],
+ [],
+ []
+ ],
+ "layerOrder": [
+ "opt",
+ "pkt",
+ "def"
+ ]
+ }
+}