blob: 6ee354ae728c4d8b14f1347622f2254ad1ff04bd [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 Condon98b6ddb2019-12-24 08:07:40 +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 Condonc13d9562019-04-18 13:24:42 +010033import {Device, Host, Link, LinkType, 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 Condonc13d9562019-04-18 13:24:42 +0100105 const emptyRegion: Region = <Region>{devices: [ [], [], [] ], hosts: [ [], [], [] ], links: []};
Sean Condonf4f54a12018-10-10 23:25:46 +0100106
Sean Condon64060ff2019-05-30 15:48:11 +0100107 beforeEach(() => {
Sean Condon0c577f62018-11-18 22:40:05 +0000108 const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
109 ar = new MockActivatedRoute({ 'debug': 'txrx' });
110
111 windowMock = <any>{
112 location: <any>{
113 hostname: 'foo',
114 host: 'foo',
115 port: '80',
116 protocol: 'http',
117 search: { debug: 'true' },
118 href: 'ws://foo:123/onos/ui/websock/path',
119 absUrl: 'ws://foo:123/onos/ui/websock/path'
120 }
121 };
122
Sean Condon64060ff2019-05-30 15:48:11 +0100123 const bundleObj = {
124 'core.view.Topo': {
125 test: 'test1'
126 }
127 };
128 const mockLion = (key) => {
129 return bundleObj[key] || '%' + key + '%';
130 };
131
Sean Condon71910542019-02-16 18:16:42 +0000132 fs = new FnService(ar, logSpy, windowMock);
133
Sean Condonf4f54a12018-10-10 23:25:46 +0100134 TestBed.configureTestingModule({
Sean Condon0c577f62018-11-18 22:40:05 +0000135 declarations: [
136 ForceSvgComponent,
137 DeviceNodeSvgComponent,
138 HostNodeSvgComponent,
139 SubRegionNodeSvgComponent,
Sean Condon50855cf2018-12-23 15:37:42 +0000140 LinkSvgComponent,
Sean Condon590b34b2019-12-04 18:44:37 +0000141 DraggableDirective,
142 BadgeSvgComponent
Sean Condon0c577f62018-11-18 22:40:05 +0000143 ],
144 providers: [
145 { provide: LogService, useValue: logSpy },
Sean Condon64060ff2019-05-30 15:48:11 +0100146 { provide: ActivatedRoute, useValue: ar },
147 { provide: FnService, useValue: fs },
148 { provide: ChangeDetectorRef, useClass: ChangeDetectorRef },
149 { provide: UrlFnService, useClass: MockUrlFnService },
150 { provide: WebSocketService, useClass: MockWebSocketService },
151 { provide: LionService, useFactory: (() => {
152 return {
153 bundle: ((bundleId) => mockLion),
154 ubercache: new Array(),
155 loadCbs: new Map<string, () => void>([])
156 };
157 })
158 },
159 { provide: IconService, useClass: MockIconService },
160 { provide: SvgUtilService, useClass: MockSvgUtilService },
161 { provide: TopologyService, useClass: MockTopologyService },
Sean Condon71910542019-02-16 18:16:42 +0000162 { provide: 'Window', useValue: windowMock },
Sean Condon0c577f62018-11-18 22:40:05 +0000163 ]
Sean Condonf4f54a12018-10-10 23:25:46 +0100164 })
165 .compileComponents();
Sean Condon0c577f62018-11-18 22:40:05 +0000166 logServiceSpy = TestBed.get(LogService);
Sean Condonf4f54a12018-10-10 23:25:46 +0100167
Sean Condonf4f54a12018-10-10 23:25:46 +0100168 fixture = TestBed.createComponent(ForceSvgComponent);
Sean Condon0c577f62018-11-18 22:40:05 +0000169 component = fixture.debugElement.componentInstance;
Sean Condonf4f54a12018-10-10 23:25:46 +0100170 fixture.detectChanges();
171 });
172
173 it('should create', () => {
174 expect(component).toBeTruthy();
175 });
Sean Condonc13d9562019-04-18 13:24:42 +0100176
Sean Condonb77768e2019-05-04 20:23:42 +0100177 it('load sample files', () => {
178 expect(openflowSampleData).toBeTruthy();
179 expect(openflowSampleData.payload).toBeTruthy();
180 expect(openflowSampleData.payload.id).toBe('(root)');
181
182 expect(odtnSampleData).toBeTruthy();
183 expect(odtnSampleData.payload).toBeTruthy();
184 expect(odtnSampleData.payload.id).toBe('(root)');
Sean Condonc13d9562019-04-18 13:24:42 +0100185 });
186
187 it('should read sample data payload as Region', () => {
Sean Condonb77768e2019-05-04 20:23:42 +0100188 expect(openflowRegionData).toBeTruthy();
Sean Condonc13d9562019-04-18 13:24:42 +0100189 // console.log(regionData);
Sean Condonb77768e2019-05-04 20:23:42 +0100190 expect(openflowRegionData.id).toBe('(root)');
191 expect(openflowRegionData.devices).toBeTruthy();
192 expect(openflowRegionData.devices.length).toBe(3);
193 expect(openflowRegionData.devices[2].length).toBe(10);
194 expect(openflowRegionData.hosts.length).toBe(3);
195 expect(openflowRegionData.hosts[2].length).toBe(20);
196 expect(openflowRegionData.links.length).toBe(44);
Sean Condonc13d9562019-04-18 13:24:42 +0100197 });
198
199 it('should read device246 correctly', () => {
Sean Condonb77768e2019-05-04 20:23:42 +0100200 const device246: Device = openflowRegionData.devices[2][0];
Sean Condonc13d9562019-04-18 13:24:42 +0100201 expect(device246.id).toBe('of:0000000000000246');
202 expect(device246.nodeType).toBe('device');
203 expect(device246.type).toBe('switch');
204 expect(device246.online).toBe(true);
205 expect(device246.master).toBe('10.192.19.68');
206 expect(device246.layer).toBe('def');
207
208 expect(device246.props.managementAddress).toBe('10.192.19.69');
209 expect(device246.props.protocol).toBe('OF_13');
210 expect(device246.props.driver).toBe('ofdpa-ovs');
211 expect(device246.props.latitude).toBe('40.15');
212 expect(device246.props.name).toBe('s246');
213 expect(device246.props.locType).toBe('geo');
214 expect(device246.props.channelId).toBe('10.192.19.69:59980');
215 expect(device246.props.longitude).toBe('-121.679');
216
217 expect(device246.location.locType).toBe('geo');
218 expect(device246.location.latOrY).toBe(40.15);
219 expect(device246.location.longOrX).toBe(-121.679);
220 });
221
222 it('should read host 3 correctly', () => {
Sean Condonb77768e2019-05-04 20:23:42 +0100223 const host3: Host = openflowRegionData.hosts[2][0];
Sean Condonc13d9562019-04-18 13:24:42 +0100224 expect(host3.id).toBe('00:88:00:00:00:03/110');
225 expect(host3.nodeType).toBe('host');
226 expect(host3.layer).toBe('def');
227 expect(host3.configured).toBe(false);
228 expect(host3.ips.length).toBe(3);
229 expect(host3.ips[0]).toBe('fe80::288:ff:fe00:3');
230 expect(host3.ips[1]).toBe('2000::102');
231 expect(host3.ips[2]).toBe('10.0.1.2');
232 });
233
234 it('should read link 3-205 correctly', () => {
Sean Condonb77768e2019-05-04 20:23:42 +0100235 const link3_205: Link = openflowRegionData.links[0];
Sean Condonc13d9562019-04-18 13:24:42 +0100236 expect(link3_205.id).toBe('00:AA:00:00:00:03/None~of:0000000000000205/6');
237 expect(link3_205.epA).toBe('00:AA:00:00:00:03/None');
238 expect(link3_205.epB).toBe('of:0000000000000205');
239 expect(String(LinkType[link3_205.type])).toBe('2');
240 expect(link3_205.portA).toBe(undefined);
241 expect(link3_205.portB).toBe('6');
242
243 expect(link3_205.rollup).toBeTruthy();
244 expect(link3_205.rollup.length).toBe(1);
245 expect(link3_205.rollup[0].id).toBe('00:AA:00:00:00:03/None~of:0000000000000205/6');
246 expect(link3_205.rollup[0].epA).toBe('00:AA:00:00:00:03/None');
247 expect(link3_205.rollup[0].epB).toBe('of:0000000000000205');
248 expect(String(LinkType[link3_205.rollup[0].type])).toBe('2');
249 expect(link3_205.rollup[0].portA).toBe(undefined);
250 expect(link3_205.rollup[0].portB).toBe('6');
251
252 });
253
254 it('should handle regionData change - empty Region', () => {
255 component.ngOnChanges(
256 {'regionData' : new SimpleChange(<Region>{}, emptyRegion, true)});
257
258 expect(component.graph.nodes.length).toBe(0);
259 });
260
Sean Condonb77768e2019-05-04 20:23:42 +0100261 it('should know how to format names', () => {
262 expect(ForceSvgComponent.extractNodeName('00:AA:00:00:00:03/None', undefined))
Sean Condonc13d9562019-04-18 13:24:42 +0100263 .toEqual('00:AA:00:00:00:03/None');
264
Sean Condonb77768e2019-05-04 20:23:42 +0100265 expect(ForceSvgComponent.extractNodeName('00:AA:00:00:00:03/161', '161'))
266 .toEqual('00:AA:00:00:00:03');
Sean Condonc13d9562019-04-18 13:24:42 +0100267
Sean Condonb77768e2019-05-04 20:23:42 +0100268 // Like epB of first example in sampleData file - endPtStr contains port number
269 expect(ForceSvgComponent.extractNodeName('of:0000000000000206/6', '6'))
270 .toEqual('of:0000000000000206');
271
272 // Like epB of second example in sampleData file - endPtStr does not contain port number
273 expect(ForceSvgComponent.extractNodeName('of:0000000000000206', '6'))
Sean Condonc13d9562019-04-18 13:24:42 +0100274 .toEqual('of:0000000000000206');
275 });
276
Sean Condonb77768e2019-05-04 20:23:42 +0100277 it('should handle openflow regionData change - sample Region', () => {
278 component.regionData = openflowRegionData;
Sean Condonc13d9562019-04-18 13:24:42 +0100279 component.ngOnChanges(
Sean Condonb77768e2019-05-04 20:23:42 +0100280 {'regionData' : new SimpleChange(<Region>{}, openflowRegionData, true)});
Sean Condonc13d9562019-04-18 13:24:42 +0100281
282 expect(component.graph.nodes.length).toBe(30);
283
284 expect(component.graph.links.length).toBe(44);
285
286 });
Sean Condonb77768e2019-05-04 20:23:42 +0100287
288 it('should handle odtn regionData change - sample odtn Region', () => {
289 component.regionData = odtnRegionData;
290 component.ngOnChanges(
291 {'regionData' : new SimpleChange(<Region>{}, odtnRegionData, true)});
292
293 expect(component.graph.nodes.length).toBe(2);
294
295 expect(component.graph.links.length).toBe(6);
296
297 });
Sean Condonf4f54a12018-10-10 23:25:46 +0100298});