blob: 53f24fc30b8570d9b8101feca1420444f2819e5b [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;
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080030
31 // private methods
32 getNodeId: any;
33 getModelType: any;
34 addNode: any;
35 addEdge: any;
36 nodesFromGraph: any;
Matteo Scandolo8cf33a32017-11-14 15:52:29 -080037
38 // observables
39 ServiceInstanceSubscription: any;
40 ServiceInstanceLinkSubscription: any;
41}
42
43let service: ITestXosGraphStore;
44
45let scope: ng.IRootScopeService;
46
47const services = [
48 {
49 id: 1,
50 class_names: 'Service,XOSBase',
51 name: 'Service 1'
52 },
53 {
54 id: 2,
55 class_names: 'Service,XOSBase',
56 name: 'Service 2'
57 }
58];
59
60const servicedependencies = [
61 {
62 id: 1,
63 class_names: 'ServiceDependency,XOSBase',
64 provider_service_id: 2,
65 subscriber_service_id: 1
66 }
67];
68
69const serviceInstances = [
70 {
71 id: 1,
72 class_names: 'ServiceInstance,XOSBase',
73 name: 'ServiceInstance 1',
74 owner_id: 1
75 },
76 {
77 id: 2,
78 class_names: 'ServiceInstance,XOSBase',
79 name: 'ServiceInstance 2',
80 owner_id: 2
81 }
82];
83
84const serviceInstanceLinks = [
85 {
86 id: 1,
87 class_names: 'ServiceInstanceLink,XOSBase',
88 provider_service_instance_id: 1,
89 subscriber_service_instance_id: 2,
90 }
91];
92
93const subject_services = new Subject();
94const subject_servicedependency = new Subject();
95const subject_serviceinstances = new Subject();
96const subject_serviceinstancelinks = new Subject();
97
98let MockModelStore = {
99 query: jasmine.createSpy('XosModelStore.query')
100 .and.callFake((model) => {
101 if (model === 'Service') {
102 return subject_services.asObservable();
103 }
104 else if (model === 'ServiceDependency') {
105 return subject_servicedependency.asObservable();
106 }
107 else if (model === 'ServiceInstance') {
108 return subject_serviceinstances.asObservable();
109 }
110 else if (model === 'ServiceInstanceLink') {
111 return subject_serviceinstancelinks.asObservable();
112 }
113 })
114};
115
116
117describe('The XosGraphStore service', () => {
118
119 beforeEach(() => {
120 angular.module('XosGraphStore', [])
121 .service('XosGraphStore', XosGraphStore)
122 .value('XosModelStore', MockModelStore)
123 .service('XosDebouncer', XosDebouncer);
124
125 angular.mock.module('XosGraphStore');
126 });
127
128 beforeEach(angular.mock.inject((XosGraphStore: ITestXosGraphStore,
129 $rootScope: ng.IRootScopeService,
130 _$q_: ng.IQService) => {
131
132 service = XosGraphStore;
133 scope = $rootScope;
134
135 }));
136
137 it('should load services and service-dependency and add nodes to the graph', (done) => {
138 let event = 0;
139 service.get().subscribe(
140 (graph: Graph) => {
141 if (event === 1) {
142 expect(graph.nodes().length).toBe(services.length);
143 expect(graph.nodes()).toEqual(['service~1', 'service~2']);
144 expect(graph.edges().length).toBe(servicedependencies.length);
145 expect(graph.edges()).toEqual([{v: 'service~1', w: 'service~2'}]);
146 done();
147 }
148 else {
149 event = event + 1;
150 }
151 }
152 );
153 subject_services.next(services);
154 subject_servicedependency.next(servicedependencies);
155 scope.$apply();
156 });
157
158 describe(`the getModelType`, () => {
159 it('should return the node type', () => {
160 const res = service.getModelType(services[0]);
161 expect(res).toBe('service');
162 });
163
164 it('should return the node type', () => {
165 const res = service.getModelType(serviceInstances[0]);
166 expect(res).toBe('serviceinstance');
167 });
168 });
169
170 describe('the getNodeId method', () => {
171 it('should return the id for a Service', () => {
172 const res = service.getNodeId(services[0]);
173 expect(res).toBe(`service~1`);
174 });
175
176 it('should return the id for a ServiceInstance', () => {
177 const res = service.getNodeId(serviceInstances[0]);
178 expect(res).toBe(`serviceinstance~1`);
179 });
180 });
181
182 describe('the addNode method', () => {
183
184 beforeEach(() => {
185 spyOn(service.serviceGraph, 'setNode');
186 spyOn(service.serviceGraph, 'setEdge');
187 });
188
189 it(`should a service to the graph`, () => {
190 service.addNode(services[0]);
191 expect(service.serviceGraph.setNode).toHaveBeenCalledWith('service~1', services[0]);
192 });
193
194 it('should add a service instance to the graph', () => {
195 service.addNode(serviceInstances[0]);
196 expect(service.serviceGraph.setNode).toHaveBeenCalledWith('serviceinstance~1', serviceInstances[0]);
197 });
198
199 it('should add an "ownership" edge to the graph', () => {
200 service.addNode(serviceInstances[0]);
201 expect(service.serviceGraph.setEdge).toHaveBeenCalledWith('serviceinstance~1', 'service~1', {service: 1, service_instance: 1, type: 'ownership'});
202 });
203 });
204
205 describe('the addEdge method', () => {
206
207 beforeEach(() => {
208 spyOn(service.serviceGraph, 'setEdge');
209 });
210
211 it('should add a ServiceDependency to the graph', () => {
212 service.addEdge(servicedependencies[0]);
213 expect(service.serviceGraph.setEdge).toHaveBeenCalledWith('service~1', 'service~2', servicedependencies[0]);
214 });
215
216 it('should add a ServiceInstanceLink to the graph', () => {
217 service.addEdge(serviceInstanceLinks[0]);
218 expect(service.serviceGraph.setEdge).toHaveBeenCalledWith('serviceinstance~1', 'serviceinstance~2', serviceInstanceLinks[0]);
219 });
220 });
221
222 describe('the nodesFromGraph and linksFromGraph methods', () => {
223 let graph: Graph;
224
225 beforeEach(() => {
226 graph = new Graph();
227 services.forEach(s => {
228 graph.setNode(`service~${s.id}`, s);
229 });
230
231 servicedependencies.forEach(sd => {
232 graph.setEdge('service~1', 'service~2', sd);
233 });
234 });
235
236 it('should add id and type to the nodes', () => {
237 const nodes = service.nodesFromGraph(graph);
238 expect(nodes[0].id).toBe('service~1');
239 expect(nodes[0].type).toBe('service');
240 expect(nodes[0].data).toBeDefined();
241 });
242
243 it('should add id and type to the links', () => {
244 const links = service.linksFromGraph(graph);
245 expect(links[0].id).toBe('service~1-service~2');
246 expect(links[0].type).toBe('servicedependency');
247 expect(links[0].data).toBeDefined();
248 });
249
250 it('should handle ownership links', () => {
251 graph.setNode(`serviceinstance~1`, serviceInstances[0]);
252 graph.setEdge('service~1', 'serviceinstance~1', {type: 'ownership', service: 1, service_instance: 1});
253 const links = service.linksFromGraph(graph);
254 expect(links[1].source).toBe(0);
255 expect(links[1].target).toBe(2);
256 });
257
258 it('should handle serviceinstancelink links', () => {
259 graph.setNode(`serviceinstance~1`, serviceInstances[0]);
260 graph.setNode(`serviceinstance~2`, serviceInstances[1]);
261 graph.setEdge('serviceinstance~1', 'serviceinstance~2', serviceInstanceLinks[0]);
262 const links = service.linksFromGraph(graph);
263 const targetLink = _.find(links, {id: `serviceinstance~1-serviceinstance~2`});
264 expect(targetLink).toBeDefined();
265 expect(targetLink.source).toBe(3);
266 expect(targetLink.target).toBe(2);
267 });
268 });
269
Matteo Scandolob8cdf552018-02-12 17:56:26 -0800270 describe('the addServiceInstance method', () => {
271 beforeEach(() => {
272 MockModelStore.query.calls.reset();
273 });
Matteo Scandolo8cf33a32017-11-14 15:52:29 -0800274
Matteo Scandolob8cdf552018-02-12 17:56:26 -0800275 it('should add them to the graph', () => {
276 service.addServiceInstances();
277 expect(MockModelStore.query).toHaveBeenCalledWith(`ServiceInstance`, '/core/serviceinstances');
278 expect(MockModelStore.query).toHaveBeenCalledWith(`ServiceInstanceLink`, '/core/serviceinstancelinks');
279 expect(service.ServiceInstanceSubscription).toBeDefined();
280 expect(service.ServiceInstanceLinkSubscription).toBeDefined();
281 // TODO wait for the Observable to return and check the graph
282 });
283 });
284
285 describe('the removeServiceInstance method', () => {
286 beforeEach(() => {
287 service.ServiceInstanceSubscription = {
288 unsubscribe: jasmine.createSpy('ServiceInstanceSubscription')
289 };
290 service.ServiceInstanceLinkSubscription = {
291 unsubscribe: jasmine.createSpy('ServiceInstanceLinkSubscription')
292 };
293
294 service.serviceGraph = new Graph();
295
296 services.forEach(s => {
297 service.addNode(s);
Matteo Scandolo8cf33a32017-11-14 15:52:29 -0800298 });
299
Matteo Scandolob8cdf552018-02-12 17:56:26 -0800300 serviceInstances.forEach(si => {
301 service.addNode(si);
302 });
303
304 serviceInstanceLinks.forEach(sil => {
305 service.addEdge(sil);
Matteo Scandolo8cf33a32017-11-14 15:52:29 -0800306 });
307 });
308
Matteo Scandolob8cdf552018-02-12 17:56:26 -0800309 it('should cancel subscriptions', () => {
310 service.removeServiceInstances();
311 expect(service.ServiceInstanceSubscription.unsubscribe).toHaveBeenCalled();
312 expect(service.ServiceInstanceLinkSubscription.unsubscribe).toHaveBeenCalled();
313 });
Matteo Scandolo8cf33a32017-11-14 15:52:29 -0800314
Matteo Scandolob8cdf552018-02-12 17:56:26 -0800315 it('should remove ServiceInstance and related nodes/edges from the graph', () => {
316 let filteredGraph = service.removeServiceInstances();
317 expect(filteredGraph.nodes().length).toBe(2);
318 expect(filteredGraph.edges().length).toBe(0);
319 expect(service.serviceGraph.nodes().length).toBe(2);
320 expect(service.serviceGraph.edges().length).toBe(0);
Matteo Scandolo8cf33a32017-11-14 15:52:29 -0800321 });
322 });
323});