Added in panel support - details panels
Change-Id: I2803edd6fe12cb0d97a2d3c45a692ea701786dd2
diff --git a/web/gui2/src/main/webapp/app/fw/remote/urlfn.service.spec.ts b/web/gui2/src/main/webapp/app/fw/remote/urlfn.service.spec.ts
new file mode 100644
index 0000000..2b07f1c
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/remote/urlfn.service.spec.ts
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2015-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 { TestBed, inject } from '@angular/core/testing';
+
+import { LogService } from '../../log.service';
+import { ConsoleLoggerService } from '../../consolelogger.service';
+import { UrlFnService } from './urlfn.service';
+import { FnService } from '../util/fn.service';
+import { ActivatedRoute, Params } from '@angular/router';
+import { of } from 'rxjs';
+
+class MockActivatedRoute extends ActivatedRoute {
+ constructor(params: Params) {
+ super();
+ this.queryParams = of(params);
+ }
+}
+
+/**
+ * ONOS GUI -- Remote -- General Functions - Unit Tests
+ */
+describe('UrlFnService', () => {
+ let log: LogService;
+ let ufs: UrlFnService;
+ let fs: FnService;
+ let ar: MockActivatedRoute;
+ let windowMock: Window;
+
+ beforeEach(() => {
+ log = new ConsoleLoggerService();
+ ar = new MockActivatedRoute({'debug': 'TestService'});
+ windowMock = <any>{
+ location: <any> {
+ hostname: '',
+ host: '',
+ port: '',
+ protocol: '',
+ search: { debug: 'true'},
+ href: ''
+ }
+ };
+
+ fs = new FnService(ar, log, windowMock);
+
+ TestBed.configureTestingModule({
+ providers: [UrlFnService,
+ { provide: LogService, useValue: log },
+ { provide: 'Window', useFactory: (() => windowMock ) },
+ ]
+ });
+
+ ufs = TestBed.get(UrlFnService);
+ });
+
+ function setLoc(prot: string, h: string, p: string, ctx: string = '') {
+ windowMock.location.host = h;
+ windowMock.location.hostname = h;
+ windowMock.location.port = p;
+ windowMock.location.protocol = prot;
+ windowMock.location.href = prot + '://' + h + ':' + p +
+ ctx + '/onos/ui/';
+ }
+
+ it('should define UrlFnService', () => {
+ expect(ufs).toBeDefined();
+ });
+
+ it('should define api functions', () => {
+ expect(fs.areFunctions(ufs, [
+ 'rsUrl', 'wsUrl', 'urlBase', 'httpPrefix',
+ 'wsPrefix', 'matchSecure'
+ ])).toBeTruthy();
+ });
+
+ it('should return the correct (http) RS url', () => {
+ setLoc('http', 'foo', '123');
+ expect(ufs.rsUrl('path')).toEqual('http://foo:123/onos/ui/rs/path');
+ });
+
+ it('should return the correct (https) RS url', () => {
+ setLoc('https', 'foo', '123');
+ expect(ufs.rsUrl('path')).toEqual('https://foo:123/onos/ui/rs/path');
+ });
+
+ it('should return the correct (ws) WS url', () => {
+ setLoc('http', 'foo', '123');
+ expect(ufs.wsUrl('path')).toEqual('ws://foo:123/onos/ui/websock/path');
+ });
+
+ it('should return the correct (wss) WS url', () => {
+ setLoc('https', 'foo', '123');
+ expect(ufs.wsUrl('path')).toEqual('wss://foo:123/onos/ui/websock/path');
+ });
+
+ it('should allow us to define an alternate WS port', () => {
+ setLoc('http', 'foo', '123');
+ expect(ufs.wsUrl('xyyzy', '456')).toEqual('ws://foo:456/onos/ui/websock/xyyzy');
+ });
+
+ it('should allow us to define an alternate host', () => {
+ setLoc('http', 'foo', '123');
+ expect(ufs.wsUrl('core', '456', 'bar')).toEqual('ws://bar:456/onos/ui/websock/core');
+ });
+
+ it('should allow us to inject an app context', () => {
+ setLoc('http', 'foo', '123', '/my/app');
+ expect(ufs.wsUrl('path')).toEqual('ws://foo:123/my/app/onos/ui/websock/path');
+ });
+
+});
diff --git a/web/gui2/src/main/webapp/app/fw/remote/websocket.service.spec.ts b/web/gui2/src/main/webapp/app/fw/remote/websocket.service.spec.ts
new file mode 100644
index 0000000..57d8d34
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/fw/remote/websocket.service.spec.ts
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2015-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 { TestBed, inject } from '@angular/core/testing';
+
+import { LogService } from '../../log.service';
+import { WebSocketService, WsOptions, Callback, EventType } from './websocket.service';
+import { FnService } from '../util/fn.service';
+import { GlyphService } from '../svg/glyph.service';
+import { ActivatedRoute, Params } from '@angular/router';
+import { UrlFnService } from './urlfn.service';
+import { WSock } from './wsock.service';
+import { of } from 'rxjs';
+
+class MockActivatedRoute extends ActivatedRoute {
+ constructor(params: Params) {
+ super();
+ this.queryParams = of(params);
+ }
+}
+
+class MockGlyphService {}
+
+/**
+ * ONOS GUI -- Remote -- Web Socket Service - Unit Tests
+ */
+describe('WebSocketService', () => {
+ let wss: WebSocketService;
+ let fs: FnService;
+ let ar: MockActivatedRoute;
+ let windowMock: Window;
+ let logServiceSpy: jasmine.SpyObj<LogService>;
+
+ const noop = () => ({});
+ const send = jasmine.createSpy('send')
+ .and.callFake((ev) => ev);
+ const mockWebSocket = {
+ send: send,
+ onmessage: (msgEvent) => ({}),
+ onopen: () => ({}),
+ onclose: () => ({}),
+ };
+
+ 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'
+ }
+ };
+ fs = new FnService(ar, logSpy, windowMock);
+
+ TestBed.configureTestingModule({
+ providers: [WebSocketService,
+ { provide: FnService, useValue: fs },
+ { provide: LogService, useValue: logSpy },
+ { provide: GlyphService, useClass: MockGlyphService },
+ { provide: UrlFnService, useValue: new UrlFnService(logSpy, windowMock) },
+ { provide: 'Window', useFactory: (() => windowMock ) },
+ { provide: WSock, useFactory: (() => {
+ return {
+ newWebSocket: (() => mockWebSocket)
+ };
+ })
+ }
+ ]
+ });
+
+ wss = TestBed.get(WebSocketService);
+ logServiceSpy = TestBed.get(LogService);
+ });
+
+ it('should define WebSocketService', () => {
+ expect(wss).toBeDefined();
+ });
+
+ it('should define api functions', () => {
+ expect(fs.areFunctions(wss, ['bootstrap', 'error',
+ 'handleOpen', 'handleMessage', 'handleClose',
+ 'findGuiSuccessor', 'informListeners', 'send',
+ 'noHandlersWarn', 'resetState',
+ 'createWebSocket', 'bindHandlers', 'unbindHandlers',
+ 'addOpenListener', 'removeOpenListener', 'sendEvent',
+ 'setVeilDelegate', 'setLoadingDelegate', 'isConnected',
+ 'closeWebSocket', 'isHandling'
+ ])).toBeTruthy();
+ });
+
+ it('should use the appropriate URL, createWebsocket', () => {
+ const url = wss.createWebSocket();
+ expect(url).toEqual('ws://foo:80/onos/ui/websock/core');
+ });
+
+ it('should use the appropriate URL with modified port, createWebsocket',
+ () => {
+ const url = wss.createWebSocket(<WsOptions>{ wsport: 1243 });
+ expect(url).toEqual('ws://foo:1243/onos/ui/websock/core');
+ });
+
+ it('should verify websocket event handlers, createWebsocket', () => {
+ wss.createWebSocket({ wsport: 1234 });
+ expect(fs.isF(mockWebSocket.onopen)).toBeTruthy();
+ expect(fs.isF(mockWebSocket.onmessage)).toBeTruthy();
+ expect(fs.isF(mockWebSocket.onclose)).toBeTruthy();
+ });
+
+ it('should invoke listener callbacks when websocket is up, handleOpen',
+ () => {
+ let num = 0;
+ function incrementNum(host: string, url: string) {
+ expect(host).toEqual('foo');
+ num++;
+ }
+ wss.addOpenListener(incrementNum);
+ wss.createWebSocket({ wsport: 1234 });
+
+ mockWebSocket.onopen();
+ expect(num).toBe(1);
+ });
+
+ it('should send pending events, handleOpen', () => {
+ const fakeEvent = {
+ event: 'mockEv',
+ payload: { mock: 'thing' }
+ };
+ wss.sendEvent(fakeEvent.event, fakeEvent.payload);
+ // on opening the socket, a single authentication event should have
+ // been sent already...
+ expect(mockWebSocket.send.calls.count()).toEqual(1);
+
+ wss.createWebSocket({ wsport: 1234 });
+ mockWebSocket.onopen();
+ expect(mockWebSocket.send).toHaveBeenCalledWith(JSON.stringify(fakeEvent));
+ });
+
+ it('should handle an incoming bad JSON message, handleMessage', () => {
+ const badMsg = {
+ data: 'bad message'
+ };
+ wss.createWebSocket({ wsport: 1234 });
+ expect(mockWebSocket.onmessage(badMsg)).toBeNull();
+ expect(logServiceSpy.error).toHaveBeenCalled();
+ });
+
+ it('should verify message was handled, handleMessage', () => {
+ let num = 0;
+ function fakeHandler(data1: Object) { num++; }
+ const data = JSON.stringify(<EventType>{
+ event: 'mockEvResp',
+ payload: {}
+ });
+ const event = {
+ data: data
+ };
+
+ wss.createWebSocket({ wsport: 1234 });
+ wss.bindHandlers(new Map<string, (data) => void>([
+ ['mockEvResp', (data2) => fakeHandler(data2)]
+ ]));
+ expect(mockWebSocket.onmessage(event)).toBe(undefined);
+ expect(num).toBe(1);
+ });
+
+ it('should warn if there is an unhandled event, handleMessage', () => {
+ const data = { foo: 'bar', bar: 'baz'};
+ const dataString = JSON.stringify(data);
+ const badEv = {
+ data: dataString
+ };
+ wss.createWebSocket({ wsport: 1234 });
+ mockWebSocket.onmessage(badEv);
+ expect(logServiceSpy.warn).toHaveBeenCalledWith('Unhandled event:', data);
+ });
+
+ it('should not warn if valid input, bindHandlers', () => {
+ expect(wss.bindHandlers(new Map<string, (data) => void>([
+ ['test', noop ],
+ ['bar', noop ]
+ ]))).toBe(undefined);
+
+ expect(logServiceSpy.warn).not.toHaveBeenCalled();
+ });
+
+ it('should warn if no arguments, bindHandlers', () => {
+ expect(wss.bindHandlers(
+ new Map<string, (data) => void>([])
+ )).toBeNull();
+ expect(logServiceSpy.warn).toHaveBeenCalledWith(
+ 'WSS.bindHandlers(): no event handlers'
+ );
+ });
+
+ it('should warn if duplicate handlers were given, bindHandlers',
+ () => {
+ wss.bindHandlers(
+ new Map<string, (data) => void>([
+ ['noop', noop ]
+ ])
+ );
+ expect(wss.bindHandlers(
+ new Map<string, (data) => void>([
+ ['noop', noop ]
+ ])
+ )).toBe(undefined);
+ expect(logServiceSpy.warn).toHaveBeenCalledWith('duplicate bindings ignored:',
+ ['noop']);
+ });
+
+ it('should warn if no arguments, unbindHandlers', () => {
+ expect(wss.unbindHandlers([])).toBeNull();
+ expect(logServiceSpy.warn).toHaveBeenCalledWith(
+ 'WSS.unbindHandlers(): no event handlers'
+ );
+ });
+ // Note: cannot test unbindHandlers' forEach due to it using closure variable
+
+ it('should not warn if valid argument, addOpenListener', () => {
+ let o = wss.addOpenListener(noop);
+ expect(o.id === 1);
+ expect(o.cb === noop);
+ expect(logServiceSpy.warn).not.toHaveBeenCalled();
+ o = wss.addOpenListener(noop);
+ expect(o.id === 2);
+ expect(o.cb === noop);
+ expect(logServiceSpy.warn).not.toHaveBeenCalled();
+ });
+
+ it('should log error if callback not a function, addOpenListener',
+ () => {
+ const o = wss.addOpenListener(null);
+ expect(o.id === 1);
+ expect(o.cb === null);
+ expect(o.error === 'No callback defined');
+ expect(logServiceSpy.error).toHaveBeenCalledWith(
+ 'WSS.addOpenListener(): callback not a function'
+ );
+ });
+
+ it('should not warn if valid listener object, removeOpenListener', () => {
+ expect(wss.removeOpenListener(<Callback>{
+ id: 1,
+ error: 'error',
+ cb: noop
+ })).toBe(undefined);
+ expect(logServiceSpy.warn).not.toHaveBeenCalled();
+ });
+
+ it('should warn if listener is invalid, removeOpenListener', () => {
+ expect(wss.removeOpenListener(<Callback>{})).toBeNull();
+ expect(logServiceSpy.warn).toHaveBeenCalledWith(
+ 'WSS.removeOpenListener(): invalid listener', {}
+ );
+ });
+
+ // Note: handleClose is not currently tested due to all work it does relies
+ // on closure variables that cannot be mocked
+
+});
diff --git a/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts b/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts
index 18dd734..b5eeaa6 100644
--- a/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts
+++ b/web/gui2/src/main/webapp/app/fw/remote/websocket.service.ts
@@ -385,6 +385,10 @@
}
}
+ isHandling(handlerId: string): boolean {
+ return this.handlers.get(handlerId) !== undefined;
+ }
+
/**
* Add a listener function for listening for WebSocket opening.
* The function must give a host and url and return void