blob: dd3249170f483881d82aeba8805bff504fafe4a0 [file] [log] [blame]
Simon Hunt3a6eec02015-02-09 21:16:43 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Simon Hunt3a6eec02015-02-09 21:16:43 -08003 *
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 */
16
17/*
18 ONOS GUI -- Topo View -- Topo Model Service - Unit Tests
19 */
20describe('factory: view/topo/topoModel.js', function() {
21 var $log, fs, rnd, tms;
22
23 // stop random numbers from being quite so random
24 var mockRandom = {
25 // mock spread returns s + 1
26 spread: function (s) {
27 return s + 1;
28 },
29 // mock random dimension returns d / 2 - 1
30 randDim: function (d) {
31 return d/2 - 1;
32 },
33 mock: 'yup'
34 };
35
Simon Huntffbad3b2017-05-16 15:37:51 -070036 // to mock out the [longOrX,latOrY] <=> [x,y] transformations, we will
Simon Hunt3a6eec02015-02-09 21:16:43 -080037 // add/subtract 2000, 3000 respectively:
Simon Huntffbad3b2017-05-16 15:37:51 -070038 // longOrX:2005 === x:5, latOrY:3004 === y:4
Simon Hunt3a6eec02015-02-09 21:16:43 -080039
40 var mockProjection = function (lnglat) {
41 return [lnglat[0] - 2000, lnglat[1] - 3000];
42 };
43
44 mockProjection.invert = function (xy) {
45 return [xy[0] + 2000, xy[1] + 3000];
46 };
47
Simon Huntdc6adea2015-02-09 22:29:36 -080048 // our test devices and hosts:
49 var dev1 = {
Simon Hunt3a6eec02015-02-09 21:16:43 -080050 'class': 'device',
51 id: 'dev1',
52 x: 17,
53 y: 27,
54 online: true
55 },
Simon Huntdc6adea2015-02-09 22:29:36 -080056 dev2 = {
Simon Hunt3a6eec02015-02-09 21:16:43 -080057 'class': 'device',
58 id: 'dev2',
59 x: 18,
60 y: 28,
61 online: true
62 },
Simon Huntdc6adea2015-02-09 22:29:36 -080063 host1 = {
Simon Hunt3a6eec02015-02-09 21:16:43 -080064 'class': 'host',
65 id: 'host1',
66 x: 23,
67 y: 33,
68 cp: {
69 device: 'dev1',
70 port: 7
71 },
72 ingress: 'dev1/7-host1'
73 },
Simon Huntdc6adea2015-02-09 22:29:36 -080074 host2 = {
Simon Hunt3a6eec02015-02-09 21:16:43 -080075 'class': 'host',
76 id: 'host2',
77 x: 24,
78 y: 34,
79 cp: {
80 device: 'dev0',
81 port: 0
82 },
83 ingress: 'dev0/0-host2'
Simon Huntdc6adea2015-02-09 22:29:36 -080084 };
85
Simon Hunt3a6eec02015-02-09 21:16:43 -080086
87 // our test api
88 var api = {
89 projection: function () { return mockProjection; },
Simon Huntdc6adea2015-02-09 22:29:36 -080090 network: {
91 nodes: [dev1, dev2, host1, host2],
92 links: [],
93 lookup: {dev1: dev1, dev2: dev2, host1: host1, host2: host2},
94 revLinkToKey: {}
95 },
96 restyleLinkElement: function () {},
97 removeLinkElement: function () {}
Simon Hunt3a6eec02015-02-09 21:16:43 -080098 };
99
100 // our test dimensions and well known locations..
101 var dim = [20, 40],
102 randLoc = [9, 19], // random location using randDim(): d/2-1
103 randHostLoc = [40, 50], // host "near" random location
104 // given that 'nearDist' = 15
105 // and spread(15) = 16
106 // 9 + 15 + 16 = 40; 19 + 15 + 16 = 50
107 nearDev1 = [48,58], // [17+15+16, 27+15+16]
108 dev1Loc = [17,27],
109 dev2Loc = [18,28],
110 host1Loc = [23,33],
111 host2Loc = [24,34];
112
113 // implement some custom matchers...
114 beforeEach(function () {
115 jasmine.addMatchers({
116 toBePositionedAt: function () {
117 return {
118 compare: function (actual, xy) {
119 var result = {},
120 actCoord = [actual.x, actual.y];
121
122 result.pass = (actual.x === xy[0]) && (actual.y === xy[1]);
123
124 if (result.pass) {
125 // for negation with ".not"
126 result.message = 'Expected [' + actCoord +
127 '] NOT to be positioned at [' + xy + ']';
128 } else {
129 result.message = 'Expected [' + actCoord +
130 '] to be positioned at [' + xy + ']';
131 }
132 return result;
133 }
134 }
135 },
136 toHaveEndPoints: function () {
137 return {
138 compare: function (actual, xy1, xy2) {
139 var result = {};
140
Simon Hunt14caf7c2015-03-02 15:51:18 -0800141 result.pass = (actual.source.x === xy1[0]) &&
142 (actual.source.y === xy1[1]) &&
143 (actual.target.x === xy2[0]) &&
144 (actual.target.y === xy2[1]);
Simon Hunt3a6eec02015-02-09 21:16:43 -0800145
146 if (result.pass) {
147 // for negation with ".not"
148 result.message = 'Expected ' + actual +
149 ' NOT to have endpoints [' + xy1 + ']-[' + xy2 + ']';
150 } else {
151 result.message = 'Expected ' + actual +
152 ' to have endpoints [' + xy1 + ']-[' + xy2 + ']';
153 }
154 return result;
155 }
156 }
157 },
158 toBeFixed: function () {
159 return {
160 compare: function (actual) {
161 var result = {
162 pass: actual.fixed
163 };
164 if (result.pass) {
165 result.message = 'Expected ' + actual +
166 ' NOT to be fixed!';
167 } else {
168 result.message = 'Expected ' + actual +
169 ' to be fixed!';
170 }
171 return result;
172 }
173 }
174 }
175 });
176 });
177
Matteo Scandolo812aa5a2016-04-19 18:12:45 -0700178 beforeEach(module('ovTopo', 'onosUtil', 'onosNav', 'onosLayer', 'onosWidget', 'onosMast'));
Simon Hunt3a6eec02015-02-09 21:16:43 -0800179
180 beforeEach(function () {
181 module(function ($provide) {
182 $provide.value('RandomService', mockRandom);
183 });
184 });
185
186 beforeEach(inject(function (_$log_, FnService, RandomService, TopoModelService) {
187 $log = _$log_;
188 fs = FnService;
189 rnd = RandomService;
190 tms = TopoModelService;
191 tms.initModel(api, dim);
192 }));
193
194
195 it('should install the mock random service', function () {
196 expect(rnd.mock).toBe('yup');
197 expect(rnd.spread(4)).toBe(5);
198 expect(rnd.randDim(8)).toBe(3);
199 });
200
201 it('should install the mock projection', function () {
Simon Huntffbad3b2017-05-16 15:37:51 -0700202 expect(tms.coordFromLngLat({longOrX: 2005, latOrY: 3004})).toEqual([5,4]);
Simon Hunt3a6eec02015-02-09 21:16:43 -0800203 expect(tms.lngLatFromCoord([5,4])).toEqual([2005,3004]);
204 });
205
206 it('should define TopoModelService', function () {
207 expect(tms).toBeDefined();
208 });
209
Matteo Scandolo209c6c62016-05-21 10:08:57 -0700210 it('should define api functions', function () {
Simon Hunt3a6eec02015-02-09 21:16:43 -0800211 expect(fs.areFunctions(tms, [
Simon Huntf542d842015-02-11 16:20:33 -0800212 'initModel', 'newDim', 'destroyModel',
Simon Hunt10618f62017-06-15 19:30:52 -0700213 'positionNode', 'resetAllLocations',
214 'createDeviceNode', 'createHostNode',
Simon Hunt3a6eec02015-02-09 21:16:43 -0800215 'createHostLink', 'createLink',
Simon Huntdc6adea2015-02-09 22:29:36 -0800216 'coordFromLngLat', 'lngLatFromCoord',
Simon Hunt10618f62017-06-15 19:30:52 -0700217 'findLink', 'findLinkById', 'findDevices', 'findHosts',
Simon Huntaabee152015-04-02 23:14:11 -0700218 'findAttachedHosts', 'findAttachedLinks', 'findBadLinks'
Simon Hunt3a6eec02015-02-09 21:16:43 -0800219 ])).toBeTruthy();
220 });
221
222 // === unit tests for positionNode()
223
224 it('should position a node using meta x/y', function () {
225 var node = {
226 metaUi: { x:37, y:48 }
227 };
228 tms.positionNode(node);
229 expect(node).toBePositionedAt([37,48]);
230 expect(node).toBeFixed();
231 });
232
233 it('should position a node by translating lng/lat', function () {
234 var node = {
235 location: {
Simon Huntffbad3b2017-05-16 15:37:51 -0700236 locType: 'geo',
237 longOrX: 2008,
238 latOrY: 3009
Simon Hunt3a6eec02015-02-09 21:16:43 -0800239 }
240 };
241 tms.positionNode(node);
242 expect(node).toBePositionedAt([8,9]);
243 expect(node).toBeFixed();
244 });
245
246 it('should position a device with no location randomly', function () {
247 var node = { 'class': 'device' };
248 tms.positionNode(node);
249 expect(node).toBePositionedAt(randLoc);
250 expect(node).not.toBeFixed();
251 });
252
253 it('should position a device randomly even if x/y set', function () {
254 var node = { 'class': 'device', x: 1, y: 2 };
255 tms.positionNode(node);
256 expect(node).toBePositionedAt(randLoc);
257 expect(node).not.toBeFixed();
258 });
259
260 it('should NOT reposition a device randomly on update', function () {
261 var node = { 'class': 'device', x: 1, y: 2 };
262 tms.positionNode(node, true);
263 expect(node).toBePositionedAt([1,2]);
264 expect(node).not.toBeFixed();
265 });
266
267 it('should position a host close to its device', function () {
268 var node = { 'class': 'host', cp: { device: 'dev1' } };
269 tms.positionNode(node);
270
271 // note: nearDist is 15; spread(15) adds 16; dev1 at [17,27]
272
273 expect(node).toBePositionedAt(nearDev1);
274 expect(node).not.toBeFixed();
275 });
276
277 it('should randomize host with no assoc device', function () {
278 var node = { 'class': 'host', cp: { device: 'dev0' } };
279 tms.positionNode(node);
280
281 // note: no device gives 'rand loc' [9,19]
282 // nearDist is 15; spread(15) adds 16
283
284 expect(node).toBePositionedAt(randHostLoc);
285 expect(node).not.toBeFixed();
286 });
287
288 // === unit tests for createDeviceNode()
289
290 it('should create a basic device node', function () {
291 var node = tms.createDeviceNode({ id: 'foo' });
292 expect(node).toBePositionedAt(randLoc);
293 expect(node).not.toBeFixed();
294 expect(node.class).toEqual('device');
295 expect(node.svgClass).toEqual('node device');
296 expect(node.id).toEqual('foo');
297 });
298
299 it('should create device node with type', function () {
300 var node = tms.createDeviceNode({ id: 'foo', type: 'cool' });
301 expect(node).toBePositionedAt(randLoc);
302 expect(node).not.toBeFixed();
303 expect(node.class).toEqual('device');
304 expect(node.svgClass).toEqual('node device cool');
305 expect(node.id).toEqual('foo');
306 });
307
308 it('should create online device node with type', function () {
309 var node = tms.createDeviceNode({ id: 'foo', type: 'cool', online: true });
310 expect(node).toBePositionedAt(randLoc);
311 expect(node).not.toBeFixed();
312 expect(node.class).toEqual('device');
313 expect(node.svgClass).toEqual('node device cool online');
314 expect(node.id).toEqual('foo');
315 });
316
317 it('should create online device node with type and lng/lat', function () {
318 var node = tms.createDeviceNode({
319 id: 'foo',
320 type: 'yowser',
321 online: true,
322 location: {
Simon Huntffbad3b2017-05-16 15:37:51 -0700323 locType: 'geo',
324 longOrX: 2048,
325 latOrY: 3096
Simon Hunt3a6eec02015-02-09 21:16:43 -0800326 }
327 });
328 expect(node).toBePositionedAt([48,96]);
329 expect(node).toBeFixed();
330 expect(node.class).toEqual('device');
331 expect(node.svgClass).toEqual('node device yowser online');
332 expect(node.id).toEqual('foo');
333 });
334
335 // === unit tests for createHostNode()
336
337 it('should create a basic host node', function () {
338 var node = tms.createHostNode({ id: 'bar', cp: { device: 'dev0' } });
339 expect(node).toBePositionedAt(randHostLoc);
340 expect(node).not.toBeFixed();
341 expect(node.class).toEqual('host');
342 expect(node.svgClass).toEqual('node host endstation');
343 expect(node.id).toEqual('bar');
344 });
345
346 it('should create a host with type', function () {
347 var node = tms.createHostNode({
348 id: 'bar',
349 type: 'classic',
350 cp: { device: 'dev1' }
351 });
352 expect(node).toBePositionedAt(nearDev1);
353 expect(node).not.toBeFixed();
354 expect(node.class).toEqual('host');
355 expect(node.svgClass).toEqual('node host classic');
356 expect(node.id).toEqual('bar');
357 });
358
359 // === unit tests for createHostLink()
360
361 it('should create a basic host link', function () {
Simon Huntdc6adea2015-02-09 22:29:36 -0800362 var link = tms.createHostLink(host1);
363 expect(link.source).toEqual(host1);
364 expect(link.target).toEqual(dev1);
Simon Hunt3a6eec02015-02-09 21:16:43 -0800365 expect(link).toHaveEndPoints(host1Loc, dev1Loc);
366 expect(link.key).toEqual('dev1/7-host1');
367 expect(link.class).toEqual('link');
368 expect(link.type()).toEqual('hostLink');
369 expect(link.linkWidth()).toEqual(1);
370 expect(link.online()).toEqual(true);
371 });
372
373 it('should return null for failed endpoint lookup', function () {
374 spyOn($log, 'error');
Simon Huntdc6adea2015-02-09 22:29:36 -0800375 var link = tms.createHostLink(host2);
Simon Hunt3a6eec02015-02-09 21:16:43 -0800376 expect(link).toBeNull();
377 expect($log.error).toHaveBeenCalledWith(
378 'Node(s) not on map for link:\n[dst] "dev0" missing'
379 );
380 });
381
382 // === unit tests for createLink()
383
384 it('should return null for missing endpoints', function () {
385 spyOn($log, 'error');
386 var link = tms.createLink({src: 'dev0', dst: 'dev00'});
387 expect(link).toBeNull();
388 expect($log.error).toHaveBeenCalledWith(
389 'Node(s) not on map for link:\n[src] "dev0" missing\n[dst] "dev00" missing'
390 );
391 });
392
Matteo Scandolo812aa5a2016-04-19 18:12:45 -0700393 xit('should create a basic link', function () {
Simon Hunt3a6eec02015-02-09 21:16:43 -0800394 var linkData = {
395 src: 'dev1',
396 dst: 'dev2',
397 id: 'baz',
398 type: 'zoo',
399 online: true,
400 linkWidth: 1.5
401 },
402 link = tms.createLink(linkData);
Simon Huntdc6adea2015-02-09 22:29:36 -0800403 expect(link.source).toEqual(dev1);
404 expect(link.target).toEqual(dev2);
Simon Hunt3a6eec02015-02-09 21:16:43 -0800405 expect(link).toHaveEndPoints(dev1Loc, dev2Loc);
406 expect(link.key).toEqual('baz');
407 expect(link.class).toEqual('link');
408 expect(link.fromSource).toBe(linkData);
409 expect(link.type()).toEqual('zoo');
Matteo Scandolo209c6c62016-05-21 10:08:57 -0700410 expect(link.online()).toEqual(true); // this is the condition failing
Simon Hunt3a6eec02015-02-09 21:16:43 -0800411 expect(link.linkWidth()).toEqual(1.5);
412 });
413
Simon Huntdc6adea2015-02-09 22:29:36 -0800414 // TODO: more unit tests for additional functions....
Simon Hunt3a6eec02015-02-09 21:16:43 -0800415});