blob: 81fe7cee17105d2def791514cab577671de67932 [file] [log] [blame]
Sean Condonf4f54a12018-10-10 23:25:46 +01001/*
2 * Copyright 2018-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 */
Sean Condonc13d9562019-04-18 13:24:42 +010016import {async, ComponentFixture, TestBed} from '@angular/core/testing';
Sean Condonf4f54a12018-10-10 23:25:46 +010017
Sean Condonc13d9562019-04-18 13:24:42 +010018import {ForceSvgComponent} from './forcesvg.component';
Sean Condon64060ff2019-05-30 15:48:11 +010019import {
20 FnService, IconService,
21 LionService,
22 LogService, SvgUtilService,
23 UrlFnService,
24 WebSocketService
Sean Condona3ad7792020-01-04 19:26:34 +000025} from 'gui2-fw-lib/public_api';
Sean Condon0c577f62018-11-18 22:40:05 +000026import {DraggableDirective} from './draggable/draggable.directive';
27import {ActivatedRoute, Params} from '@angular/router';
28import {of} from 'rxjs';
Sean Condonff85fbe2019-03-16 14:28:46 +000029import {DeviceNodeSvgComponent} from './visuals/devicenodesvg/devicenodesvg.component';
30import {SubRegionNodeSvgComponent} from './visuals/subregionnodesvg/subregionnodesvg.component';
31import {HostNodeSvgComponent} from './visuals/hostnodesvg/hostnodesvg.component';
32import {LinkSvgComponent} from './visuals/linksvg/linksvg.component';
Sean Condond92b0bd2020-03-23 08:40:55 +000033import {Device, Host, Link, LinkType, LinkHighlight, Region} from './models';
Sean Condon64060ff2019-05-30 15:48:11 +010034import {ChangeDetectorRef, SimpleChange} from '@angular/core';
35import {TopologyService} from '../../topology.service';
Sean Condon590b34b2019-12-04 18:44:37 +000036import {BadgeSvgComponent} from './visuals/badgesvg/badgesvg.component';
Sean Condon0c577f62018-11-18 22:40:05 +000037
38class MockActivatedRoute extends ActivatedRoute {
39 constructor(params: Params) {
40 super();
41 this.queryParams = of(params);
42 }
43}
44
Sean Condon64060ff2019-05-30 15:48:11 +010045class MockIconService {
46 loadIconDef() { }
47}
48
49class MockSvgUtilService {
50
51 cat7() {
52 const tcid = 'd3utilTestCard';
53
54 function getColor(id, muted, theme) {
55 // NOTE: since we are lazily assigning domain ids, we need to
56 // get the color from all 4 scales, to keep the domains
57 // in sync.
58 const ln = '#5b99d2';
59 const lm = '#9ebedf';
60 const dn = '#5b99d2';
61 const dm = '#9ebedf';
62 if (theme === 'dark') {
63 return muted ? dm : dn;
64 } else {
65 return muted ? lm : ln;
66 }
67 }
68
69 return {
70 // testCard: testCard,
71 getColor: getColor,
72 };
73 }
74}
75
76class MockUrlFnService { }
77
78class MockWebSocketService {
79 createWebSocket() { }
80 isConnected() { return false; }
81 unbindHandlers() { }
82 bindHandlers() { }
83}
84
85class MockTopologyService {
86 public instancesIndex: Map<string, number>;
87 constructor() {
88 this.instancesIndex = new Map();
89 }
90}
91
Sean Condonf4f54a12018-10-10 23:25:46 +010092describe('ForceSvgComponent', () => {
Sean Condon71910542019-02-16 18:16:42 +000093 let fs: FnService;
Sean Condon0c577f62018-11-18 22:40:05 +000094 let ar: MockActivatedRoute;
95 let windowMock: Window;
96 let logServiceSpy: jasmine.SpyObj<LogService>;
Sean Condonf4f54a12018-10-10 23:25:46 +010097 let component: ForceSvgComponent;
98 let fixture: ComponentFixture<ForceSvgComponent>;
Sean Condonb77768e2019-05-04 20:23:42 +010099 const openflowSampleData = require('./tests/test-module-topo2CurrentRegion.json');
100 const openflowRegionData: Region = <Region><unknown>(openflowSampleData.payload);
101
102 const odtnSampleData = require('./tests/test-OdtnConfig-topo2CurrentRegion.json');
103 const odtnRegionData: Region = <Region><unknown>(odtnSampleData.payload);
104
Sean Condond92b0bd2020-03-23 08:40:55 +0000105 const topo2BaseData = require('./tests/topo2Highlights-base-data.json');
106 const topo2BaseRegionData: Region = <Region><unknown>(topo2BaseData.payload);
107
108 const highlightSampleData = require('./tests/topo2Highlights-sample.json');
109 const linkHightlights: LinkHighlight[] = <LinkHighlight[]><unknown>(highlightSampleData.payload.links);
110
Sean Condonc13d9562019-04-18 13:24:42 +0100111 const emptyRegion: Region = <Region>{devices: [ [], [], [] ], hosts: [ [], [], [] ], links: []};
Sean Condonf4f54a12018-10-10 23:25:46 +0100112
Sean Condon64060ff2019-05-30 15:48:11 +0100113 beforeEach(() => {
Sean Condon0c577f62018-11-18 22:40:05 +0000114 const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
115 ar = new MockActivatedRoute({ 'debug': 'txrx' });
116
117 windowMock = <any>{
118 location: <any>{
119 hostname: 'foo',
120 host: 'foo',
121 port: '80',
122 protocol: 'http',
123 search: { debug: 'true' },
124 href: 'ws://foo:123/onos/ui/websock/path',
125 absUrl: 'ws://foo:123/onos/ui/websock/path'
126 }
127 };
128
Sean Condon64060ff2019-05-30 15:48:11 +0100129 const bundleObj = {
130 'core.view.Topo': {
131 test: 'test1'
132 }
133 };
134 const mockLion = (key) => {
135 return bundleObj[key] || '%' + key + '%';
136 };
137
Sean Condon71910542019-02-16 18:16:42 +0000138 fs = new FnService(ar, logSpy, windowMock);
139
Sean Condonf4f54a12018-10-10 23:25:46 +0100140 TestBed.configureTestingModule({
Sean Condon0c577f62018-11-18 22:40:05 +0000141 declarations: [
142 ForceSvgComponent,
143 DeviceNodeSvgComponent,
144 HostNodeSvgComponent,
145 SubRegionNodeSvgComponent,
Sean Condon50855cf2018-12-23 15:37:42 +0000146 LinkSvgComponent,
Sean Condon590b34b2019-12-04 18:44:37 +0000147 DraggableDirective,
148 BadgeSvgComponent
Sean Condon0c577f62018-11-18 22:40:05 +0000149 ],
150 providers: [
151 { provide: LogService, useValue: logSpy },
Sean Condon64060ff2019-05-30 15:48:11 +0100152 { provide: ActivatedRoute, useValue: ar },
153 { provide: FnService, useValue: fs },
154 { provide: ChangeDetectorRef, useClass: ChangeDetectorRef },
155 { provide: UrlFnService, useClass: MockUrlFnService },
156 { provide: WebSocketService, useClass: MockWebSocketService },
157 { provide: LionService, useFactory: (() => {
158 return {
159 bundle: ((bundleId) => mockLion),
160 ubercache: new Array(),
161 loadCbs: new Map<string, () => void>([])
162 };
163 })
164 },
165 { provide: IconService, useClass: MockIconService },
166 { provide: SvgUtilService, useClass: MockSvgUtilService },
167 { provide: TopologyService, useClass: MockTopologyService },
Sean Condon71910542019-02-16 18:16:42 +0000168 { provide: 'Window', useValue: windowMock },
Sean Condon0c577f62018-11-18 22:40:05 +0000169 ]
Sean Condonf4f54a12018-10-10 23:25:46 +0100170 })
171 .compileComponents();
Sean Condon0c577f62018-11-18 22:40:05 +0000172 logServiceSpy = TestBed.get(LogService);
Sean Condonf4f54a12018-10-10 23:25:46 +0100173
Sean Condonf4f54a12018-10-10 23:25:46 +0100174 fixture = TestBed.createComponent(ForceSvgComponent);
Sean Condon0c577f62018-11-18 22:40:05 +0000175 component = fixture.debugElement.componentInstance;
Sean Condonf4f54a12018-10-10 23:25:46 +0100176 fixture.detectChanges();
177 });
178
179 it('should create', () => {
180 expect(component).toBeTruthy();
181 });
Sean Condonc13d9562019-04-18 13:24:42 +0100182
Sean Condonb77768e2019-05-04 20:23:42 +0100183 it('load sample files', () => {
184 expect(openflowSampleData).toBeTruthy();
185 expect(openflowSampleData.payload).toBeTruthy();
186 expect(openflowSampleData.payload.id).toBe('(root)');
187
188 expect(odtnSampleData).toBeTruthy();
189 expect(odtnSampleData.payload).toBeTruthy();
190 expect(odtnSampleData.payload.id).toBe('(root)');
Sean Condonc13d9562019-04-18 13:24:42 +0100191 });
192
193 it('should read sample data payload as Region', () => {
Sean Condonb77768e2019-05-04 20:23:42 +0100194 expect(openflowRegionData).toBeTruthy();
Sean Condonc13d9562019-04-18 13:24:42 +0100195 // console.log(regionData);
Sean Condonb77768e2019-05-04 20:23:42 +0100196 expect(openflowRegionData.id).toBe('(root)');
197 expect(openflowRegionData.devices).toBeTruthy();
198 expect(openflowRegionData.devices.length).toBe(3);
199 expect(openflowRegionData.devices[2].length).toBe(10);
200 expect(openflowRegionData.hosts.length).toBe(3);
201 expect(openflowRegionData.hosts[2].length).toBe(20);
202 expect(openflowRegionData.links.length).toBe(44);
Sean Condonc13d9562019-04-18 13:24:42 +0100203 });
204
205 it('should read device246 correctly', () => {
Sean Condonb77768e2019-05-04 20:23:42 +0100206 const device246: Device = openflowRegionData.devices[2][0];
Sean Condonc13d9562019-04-18 13:24:42 +0100207 expect(device246.id).toBe('of:0000000000000246');
208 expect(device246.nodeType).toBe('device');
209 expect(device246.type).toBe('switch');
210 expect(device246.online).toBe(true);
211 expect(device246.master).toBe('10.192.19.68');
212 expect(device246.layer).toBe('def');
213
214 expect(device246.props.managementAddress).toBe('10.192.19.69');
215 expect(device246.props.protocol).toBe('OF_13');
216 expect(device246.props.driver).toBe('ofdpa-ovs');
217 expect(device246.props.latitude).toBe('40.15');
218 expect(device246.props.name).toBe('s246');
219 expect(device246.props.locType).toBe('geo');
220 expect(device246.props.channelId).toBe('10.192.19.69:59980');
221 expect(device246.props.longitude).toBe('-121.679');
222
223 expect(device246.location.locType).toBe('geo');
224 expect(device246.location.latOrY).toBe(40.15);
225 expect(device246.location.longOrX).toBe(-121.679);
226 });
227
228 it('should read host 3 correctly', () => {
Sean Condonb77768e2019-05-04 20:23:42 +0100229 const host3: Host = openflowRegionData.hosts[2][0];
Sean Condonc13d9562019-04-18 13:24:42 +0100230 expect(host3.id).toBe('00:88:00:00:00:03/110');
231 expect(host3.nodeType).toBe('host');
232 expect(host3.layer).toBe('def');
233 expect(host3.configured).toBe(false);
234 expect(host3.ips.length).toBe(3);
235 expect(host3.ips[0]).toBe('fe80::288:ff:fe00:3');
236 expect(host3.ips[1]).toBe('2000::102');
237 expect(host3.ips[2]).toBe('10.0.1.2');
238 });
239
240 it('should read link 3-205 correctly', () => {
Sean Condonb77768e2019-05-04 20:23:42 +0100241 const link3_205: Link = openflowRegionData.links[0];
Sean Condonc13d9562019-04-18 13:24:42 +0100242 expect(link3_205.id).toBe('00:AA:00:00:00:03/None~of:0000000000000205/6');
243 expect(link3_205.epA).toBe('00:AA:00:00:00:03/None');
244 expect(link3_205.epB).toBe('of:0000000000000205');
245 expect(String(LinkType[link3_205.type])).toBe('2');
246 expect(link3_205.portA).toBe(undefined);
247 expect(link3_205.portB).toBe('6');
248
249 expect(link3_205.rollup).toBeTruthy();
250 expect(link3_205.rollup.length).toBe(1);
251 expect(link3_205.rollup[0].id).toBe('00:AA:00:00:00:03/None~of:0000000000000205/6');
252 expect(link3_205.rollup[0].epA).toBe('00:AA:00:00:00:03/None');
253 expect(link3_205.rollup[0].epB).toBe('of:0000000000000205');
254 expect(String(LinkType[link3_205.rollup[0].type])).toBe('2');
255 expect(link3_205.rollup[0].portA).toBe(undefined);
256 expect(link3_205.rollup[0].portB).toBe('6');
257
258 });
259
260 it('should handle regionData change - empty Region', () => {
261 component.ngOnChanges(
262 {'regionData' : new SimpleChange(<Region>{}, emptyRegion, true)});
263
264 expect(component.graph.nodes.length).toBe(0);
265 });
266
Sean Condonb77768e2019-05-04 20:23:42 +0100267 it('should know how to format names', () => {
268 expect(ForceSvgComponent.extractNodeName('00:AA:00:00:00:03/None', undefined))
Sean Condonc13d9562019-04-18 13:24:42 +0100269 .toEqual('00:AA:00:00:00:03/None');
270
Sean Condonb77768e2019-05-04 20:23:42 +0100271 expect(ForceSvgComponent.extractNodeName('00:AA:00:00:00:03/161', '161'))
272 .toEqual('00:AA:00:00:00:03');
Sean Condonc13d9562019-04-18 13:24:42 +0100273
Sean Condonb77768e2019-05-04 20:23:42 +0100274 // Like epB of first example in sampleData file - endPtStr contains port number
275 expect(ForceSvgComponent.extractNodeName('of:0000000000000206/6', '6'))
276 .toEqual('of:0000000000000206');
277
278 // Like epB of second example in sampleData file - endPtStr does not contain port number
279 expect(ForceSvgComponent.extractNodeName('of:0000000000000206', '6'))
Sean Condonc13d9562019-04-18 13:24:42 +0100280 .toEqual('of:0000000000000206');
281 });
282
Sean Condonb77768e2019-05-04 20:23:42 +0100283 it('should handle openflow regionData change - sample Region', () => {
284 component.regionData = openflowRegionData;
Sean Condonc13d9562019-04-18 13:24:42 +0100285 component.ngOnChanges(
Sean Condonb77768e2019-05-04 20:23:42 +0100286 {'regionData' : new SimpleChange(<Region>{}, openflowRegionData, true)});
Sean Condonc13d9562019-04-18 13:24:42 +0100287
288 expect(component.graph.nodes.length).toBe(30);
289
290 expect(component.graph.links.length).toBe(44);
291
292 });
Sean Condonb77768e2019-05-04 20:23:42 +0100293
294 it('should handle odtn regionData change - sample odtn Region', () => {
295 component.regionData = odtnRegionData;
296 component.ngOnChanges(
297 {'regionData' : new SimpleChange(<Region>{}, odtnRegionData, true)});
298
299 expect(component.graph.nodes.length).toBe(2);
300
301 expect(component.graph.links.length).toBe(6);
302
303 });
Sean Condond92b0bd2020-03-23 08:40:55 +0000304
305 it('should handle highlights and match them to existing links', () => {
306 component.regionData = topo2BaseRegionData;
307 component.ngOnChanges(
308 {'regionData' : new SimpleChange(<Region>{}, topo2BaseRegionData, true)});
309
310 expect(component.graph.links.length).toBe(9);
311
312 expect(linkHightlights.length).toBe(6);
313
314 // should be able to find all of the highlighted links in the original data set
315 linkHightlights.forEach((lh: LinkHighlight) => {
316 const foundLink = component.graph.links.find((l: Link) => l.id === Link.linkIdFromShowHighlights(lh.id));
317 expect(foundLink).toBeDefined();
318 });
319 });
Sean Condonf4f54a12018-10-10 23:25:46 +0100320});