blob: a41809c264419e1f18e4a89ab36ccb519cc0b123 [file] [log] [blame]
Matteo Scandolo8cf33a32017-11-14 15:52:29 -08001
2/*
3 * Copyright 2017-present Open Networking Foundation
4
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8
9 * http://www.apache.org/licenses/LICENSE-2.0
10
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18import * as _ from 'lodash';
19import * as angular from 'angular';
20import 'angular-mocks';
21import {IXosGraphStore, XosGraphStore} from './graph.store';
22import {Subject} from 'rxjs/Subject';
23import {Graph} from 'graphlib';
24import {XosDebouncer} from '../../core/services/helpers/debounce.helper';
25
26interface ITestXosGraphStore extends IXosGraphStore {
27
28 // state
29 serviceGraph: Graph;
30 serviceInstanceShown: boolean;
31
32 // private methods
33 getNodeId: any;
34 getModelType: any;
35 addNode: any;
36 addEdge: any;
37 nodesFromGraph: any;
38 toggleServiceInstances: any;
39
40 // observables
41 ServiceInstanceSubscription: any;
42 ServiceInstanceLinkSubscription: any;
43}
44
45let service: ITestXosGraphStore;
46
47let scope: ng.IRootScopeService;
48
49const services = [
50 {
51 id: 1,
52 class_names: 'Service,XOSBase',
53 name: 'Service 1'
54 },
55 {
56 id: 2,
57 class_names: 'Service,XOSBase',
58 name: 'Service 2'
59 }
60];
61
62const servicedependencies = [
63 {
64 id: 1,
65 class_names: 'ServiceDependency,XOSBase',
66 provider_service_id: 2,
67 subscriber_service_id: 1
68 }
69];
70
71const serviceInstances = [
72 {
73 id: 1,
74 class_names: 'ServiceInstance,XOSBase',
75 name: 'ServiceInstance 1',
76 owner_id: 1
77 },
78 {
79 id: 2,
80 class_names: 'ServiceInstance,XOSBase',
81 name: 'ServiceInstance 2',
82 owner_id: 2
83 }
84];
85
86const serviceInstanceLinks = [
87 {
88 id: 1,
89 class_names: 'ServiceInstanceLink,XOSBase',
90 provider_service_instance_id: 1,
91 subscriber_service_instance_id: 2,
92 }
93];
94
95const subject_services = new Subject();
96const subject_servicedependency = new Subject();
97const subject_serviceinstances = new Subject();
98const subject_serviceinstancelinks = new Subject();
99
100let MockModelStore = {
101 query: jasmine.createSpy('XosModelStore.query')
102 .and.callFake((model) => {
103 if (model === 'Service') {
104 return subject_services.asObservable();
105 }
106 else if (model === 'ServiceDependency') {
107 return subject_servicedependency.asObservable();
108 }
109 else if (model === 'ServiceInstance') {
110 return subject_serviceinstances.asObservable();
111 }
112 else if (model === 'ServiceInstanceLink') {
113 return subject_serviceinstancelinks.asObservable();
114 }
115 })
116};
117
118
119describe('The XosGraphStore service', () => {
120
121 beforeEach(() => {
122 angular.module('XosGraphStore', [])
123 .service('XosGraphStore', XosGraphStore)
124 .value('XosModelStore', MockModelStore)
125 .service('XosDebouncer', XosDebouncer);
126
127 angular.mock.module('XosGraphStore');
128 });
129
130 beforeEach(angular.mock.inject((XosGraphStore: ITestXosGraphStore,
131 $rootScope: ng.IRootScopeService,
132 _$q_: ng.IQService) => {
133
134 service = XosGraphStore;
135 scope = $rootScope;
136
137 }));
138
139 it('should load services and service-dependency and add nodes to the graph', (done) => {
140 let event = 0;
141 service.get().subscribe(
142 (graph: Graph) => {
143 if (event === 1) {
144 expect(graph.nodes().length).toBe(services.length);
145 expect(graph.nodes()).toEqual(['service~1', 'service~2']);
146 expect(graph.edges().length).toBe(servicedependencies.length);
147 expect(graph.edges()).toEqual([{v: 'service~1', w: 'service~2'}]);
148 done();
149 }
150 else {
151 event = event + 1;
152 }
153 }
154 );
155 subject_services.next(services);
156 subject_servicedependency.next(servicedependencies);
157 scope.$apply();
158 });
159
160 describe(`the getModelType`, () => {
161 it('should return the node type', () => {
162 const res = service.getModelType(services[0]);
163 expect(res).toBe('service');
164 });
165
166 it('should return the node type', () => {
167 const res = service.getModelType(serviceInstances[0]);
168 expect(res).toBe('serviceinstance');
169 });
170 });
171
172 describe('the getNodeId method', () => {
173 it('should return the id for a Service', () => {
174 const res = service.getNodeId(services[0]);
175 expect(res).toBe(`service~1`);
176 });
177
178 it('should return the id for a ServiceInstance', () => {
179 const res = service.getNodeId(serviceInstances[0]);
180 expect(res).toBe(`serviceinstance~1`);
181 });
182 });
183
184 describe('the addNode method', () => {
185
186 beforeEach(() => {
187 spyOn(service.serviceGraph, 'setNode');
188 spyOn(service.serviceGraph, 'setEdge');
189 });
190
191 it(`should a service to the graph`, () => {
192 service.addNode(services[0]);
193 expect(service.serviceGraph.setNode).toHaveBeenCalledWith('service~1', services[0]);
194 });
195
196 it('should add a service instance to the graph', () => {
197 service.addNode(serviceInstances[0]);
198 expect(service.serviceGraph.setNode).toHaveBeenCalledWith('serviceinstance~1', serviceInstances[0]);
199 });
200
201 it('should add an "ownership" edge to the graph', () => {
202 service.addNode(serviceInstances[0]);
203 expect(service.serviceGraph.setEdge).toHaveBeenCalledWith('serviceinstance~1', 'service~1', {service: 1, service_instance: 1, type: 'ownership'});
204 });
205 });
206
207 describe('the addEdge method', () => {
208
209 beforeEach(() => {
210 spyOn(service.serviceGraph, 'setEdge');
211 });
212
213 it('should add a ServiceDependency to the graph', () => {
214 service.addEdge(servicedependencies[0]);
215 expect(service.serviceGraph.setEdge).toHaveBeenCalledWith('service~1', 'service~2', servicedependencies[0]);
216 });
217
218 it('should add a ServiceInstanceLink to the graph', () => {
219 service.addEdge(serviceInstanceLinks[0]);
220 expect(service.serviceGraph.setEdge).toHaveBeenCalledWith('serviceinstance~1', 'serviceinstance~2', serviceInstanceLinks[0]);
221 });
222 });
223
224 describe('the nodesFromGraph and linksFromGraph methods', () => {
225 let graph: Graph;
226
227 beforeEach(() => {
228 graph = new Graph();
229 services.forEach(s => {
230 graph.setNode(`service~${s.id}`, s);
231 });
232
233 servicedependencies.forEach(sd => {
234 graph.setEdge('service~1', 'service~2', sd);
235 });
236 });
237
238 it('should add id and type to the nodes', () => {
239 const nodes = service.nodesFromGraph(graph);
240 expect(nodes[0].id).toBe('service~1');
241 expect(nodes[0].type).toBe('service');
242 expect(nodes[0].data).toBeDefined();
243 });
244
245 it('should add id and type to the links', () => {
246 const links = service.linksFromGraph(graph);
247 expect(links[0].id).toBe('service~1-service~2');
248 expect(links[0].type).toBe('servicedependency');
249 expect(links[0].data).toBeDefined();
250 });
251
252 it('should handle ownership links', () => {
253 graph.setNode(`serviceinstance~1`, serviceInstances[0]);
254 graph.setEdge('service~1', 'serviceinstance~1', {type: 'ownership', service: 1, service_instance: 1});
255 const links = service.linksFromGraph(graph);
256 expect(links[1].source).toBe(0);
257 expect(links[1].target).toBe(2);
258 });
259
260 it('should handle serviceinstancelink links', () => {
261 graph.setNode(`serviceinstance~1`, serviceInstances[0]);
262 graph.setNode(`serviceinstance~2`, serviceInstances[1]);
263 graph.setEdge('serviceinstance~1', 'serviceinstance~2', serviceInstanceLinks[0]);
264 const links = service.linksFromGraph(graph);
265 const targetLink = _.find(links, {id: `serviceinstance~1-serviceinstance~2`});
266 expect(targetLink).toBeDefined();
267 expect(targetLink.source).toBe(3);
268 expect(targetLink.target).toBe(2);
269 });
270 });
271
272 describe(`the toggleServiceInstances method`, () => {
273 describe('when they are disabled', () => {
274
275 beforeEach(() => {
276 MockModelStore.query.calls.reset();
277 });
278
279 it('should fetch them', () => {
280 service.toggleServiceInstances();
281 expect(service.serviceInstanceShown).toBeTruthy();
282 expect(MockModelStore.query).toHaveBeenCalledWith(`ServiceInstance`, '/core/serviceinstances');
283 expect(MockModelStore.query).toHaveBeenCalledWith(`ServiceInstanceLink`, '/core/serviceinstancelinks');
284 expect(service.ServiceInstanceSubscription).toBeDefined();
285 expect(service.ServiceInstanceLinkSubscription).toBeDefined();
286 });
287 });
288
289 describe('when they are enabled', () => {
290 beforeEach(() => {
291 service.ServiceInstanceSubscription = {
292 unsubscribe: jasmine.createSpy('ServiceInstanceSubscription')
293 };
294 service.ServiceInstanceLinkSubscription = {
295 unsubscribe: jasmine.createSpy('ServiceInstanceLinkSubscription')
296 };
297 service.serviceInstanceShown = true;
298 });
299
300 it('should cancel subscriptions', () => {
301 service.toggleServiceInstances();
302 expect(service.serviceInstanceShown).toBeFalsy();
303 expect(service.ServiceInstanceSubscription.unsubscribe).toHaveBeenCalled();
304 expect(service.ServiceInstanceLinkSubscription.unsubscribe).toHaveBeenCalled();
305 });
306
307 describe('and loaded in the graph', () => {
308 beforeEach(() => {
309 service.serviceGraph = new Graph();
310
311 services.forEach(s => {
312 service.addNode(s);
313 });
314
315 serviceInstances.forEach(si => {
316 service.addNode(si);
317 });
318
319 serviceInstanceLinks.forEach(sil => {
320 service.addEdge(sil);
321 });
322 });
323 it('should remove ServiceInstance and related nodes/edges from the graph', () => {
324 let filteredGraph = service.toggleServiceInstances();
325 expect(service.serviceInstanceShown).toBeFalsy();
326 expect(filteredGraph.nodes().length).toBe(2);
327 expect(filteredGraph.edges().length).toBe(0);
328 expect(service.serviceGraph.nodes().length).toBe(2);
329 expect(service.serviceGraph.edges().length).toBe(0);
330 });
331 });
332 });
333 });
334});