blob: 6ee354ae728c4d8b14f1347622f2254ad1ff04bd [file] [log] [blame]
/*
* Copyright 2018-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {ForceSvgComponent} from './forcesvg.component';
import {
FnService, IconService,
LionService,
LogService, SvgUtilService,
UrlFnService,
WebSocketService
} from '../../../gui2-fw-lib/public_api';
import {DraggableDirective} from './draggable/draggable.directive';
import {ActivatedRoute, Params} from '@angular/router';
import {of} from 'rxjs';
import {DeviceNodeSvgComponent} from './visuals/devicenodesvg/devicenodesvg.component';
import {SubRegionNodeSvgComponent} from './visuals/subregionnodesvg/subregionnodesvg.component';
import {HostNodeSvgComponent} from './visuals/hostnodesvg/hostnodesvg.component';
import {LinkSvgComponent} from './visuals/linksvg/linksvg.component';
import {Device, Host, Link, LinkType, Region} from './models';
import {ChangeDetectorRef, SimpleChange} from '@angular/core';
import {TopologyService} from '../../topology.service';
import {BadgeSvgComponent} from './visuals/badgesvg/badgesvg.component';
class MockActivatedRoute extends ActivatedRoute {
constructor(params: Params) {
super();
this.queryParams = of(params);
}
}
class MockIconService {
loadIconDef() { }
}
class MockSvgUtilService {
cat7() {
const tcid = 'd3utilTestCard';
function getColor(id, muted, theme) {
// NOTE: since we are lazily assigning domain ids, we need to
// get the color from all 4 scales, to keep the domains
// in sync.
const ln = '#5b99d2';
const lm = '#9ebedf';
const dn = '#5b99d2';
const dm = '#9ebedf';
if (theme === 'dark') {
return muted ? dm : dn;
} else {
return muted ? lm : ln;
}
}
return {
// testCard: testCard,
getColor: getColor,
};
}
}
class MockUrlFnService { }
class MockWebSocketService {
createWebSocket() { }
isConnected() { return false; }
unbindHandlers() { }
bindHandlers() { }
}
class MockTopologyService {
public instancesIndex: Map<string, number>;
constructor() {
this.instancesIndex = new Map();
}
}
describe('ForceSvgComponent', () => {
let fs: FnService;
let ar: MockActivatedRoute;
let windowMock: Window;
let logServiceSpy: jasmine.SpyObj<LogService>;
let component: ForceSvgComponent;
let fixture: ComponentFixture<ForceSvgComponent>;
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(() => {
const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
ar = new MockActivatedRoute({ 'debug': 'txrx' });
windowMock = <any>{
location: <any>{
hostname: 'foo',
host: 'foo',
port: '80',
protocol: 'http',
search: { debug: 'true' },
href: 'ws://foo:123/onos/ui/websock/path',
absUrl: 'ws://foo:123/onos/ui/websock/path'
}
};
const bundleObj = {
'core.view.Topo': {
test: 'test1'
}
};
const mockLion = (key) => {
return bundleObj[key] || '%' + key + '%';
};
fs = new FnService(ar, logSpy, windowMock);
TestBed.configureTestingModule({
declarations: [
ForceSvgComponent,
DeviceNodeSvgComponent,
HostNodeSvgComponent,
SubRegionNodeSvgComponent,
LinkSvgComponent,
DraggableDirective,
BadgeSvgComponent
],
providers: [
{ provide: LogService, useValue: logSpy },
{ provide: ActivatedRoute, useValue: ar },
{ provide: FnService, useValue: fs },
{ provide: ChangeDetectorRef, useClass: ChangeDetectorRef },
{ provide: UrlFnService, useClass: MockUrlFnService },
{ provide: WebSocketService, useClass: MockWebSocketService },
{ provide: LionService, useFactory: (() => {
return {
bundle: ((bundleId) => mockLion),
ubercache: new Array(),
loadCbs: new Map<string, () => void>([])
};
})
},
{ provide: IconService, useClass: MockIconService },
{ provide: SvgUtilService, useClass: MockSvgUtilService },
{ provide: TopologyService, useClass: MockTopologyService },
{ provide: 'Window', useValue: windowMock },
]
})
.compileComponents();
logServiceSpy = TestBed.get(LogService);
fixture = TestBed.createComponent(ForceSvgComponent);
component = fixture.debugElement.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
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(openflowRegionData).toBeTruthy();
// console.log(regionData);
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 = openflowRegionData.devices[2][0];
expect(device246.id).toBe('of:0000000000000246');
expect(device246.nodeType).toBe('device');
expect(device246.type).toBe('switch');
expect(device246.online).toBe(true);
expect(device246.master).toBe('10.192.19.68');
expect(device246.layer).toBe('def');
expect(device246.props.managementAddress).toBe('10.192.19.69');
expect(device246.props.protocol).toBe('OF_13');
expect(device246.props.driver).toBe('ofdpa-ovs');
expect(device246.props.latitude).toBe('40.15');
expect(device246.props.name).toBe('s246');
expect(device246.props.locType).toBe('geo');
expect(device246.props.channelId).toBe('10.192.19.69:59980');
expect(device246.props.longitude).toBe('-121.679');
expect(device246.location.locType).toBe('geo');
expect(device246.location.latOrY).toBe(40.15);
expect(device246.location.longOrX).toBe(-121.679);
});
it('should read host 3 correctly', () => {
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');
expect(host3.configured).toBe(false);
expect(host3.ips.length).toBe(3);
expect(host3.ips[0]).toBe('fe80::288:ff:fe00:3');
expect(host3.ips[1]).toBe('2000::102');
expect(host3.ips[2]).toBe('10.0.1.2');
});
it('should read link 3-205 correctly', () => {
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');
expect(String(LinkType[link3_205.type])).toBe('2');
expect(link3_205.portA).toBe(undefined);
expect(link3_205.portB).toBe('6');
expect(link3_205.rollup).toBeTruthy();
expect(link3_205.rollup.length).toBe(1);
expect(link3_205.rollup[0].id).toBe('00:AA:00:00:00:03/None~of:0000000000000205/6');
expect(link3_205.rollup[0].epA).toBe('00:AA:00:00:00:03/None');
expect(link3_205.rollup[0].epB).toBe('of:0000000000000205');
expect(String(LinkType[link3_205.rollup[0].type])).toBe('2');
expect(link3_205.rollup[0].portA).toBe(undefined);
expect(link3_205.rollup[0].portB).toBe('6');
});
it('should handle regionData change - empty Region', () => {
component.ngOnChanges(
{'regionData' : new SimpleChange(<Region>{}, emptyRegion, true)});
expect(component.graph.nodes.length).toBe(0);
});
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', '161'))
.toEqual('00:AA:00:00:00:03');
// 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 openflow regionData change - sample Region', () => {
component.regionData = openflowRegionData;
component.ngOnChanges(
{'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);
});
});