]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
39a8d10d09f625d91b3cf5f3a866deb3720068c6
[ceph.git] /
1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
3 import { By } from '@angular/platform-browser';
4 import { RouterTestingModule } from '@angular/router/testing';
5
6 import { ToastModule } from 'ng2-toastr';
7 import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
8 import { Subject, throwError as observableThrowError } from 'rxjs';
9
10 import { configureTestBed, PermissionHelper } from '../../../../testing/unit-test-helper';
11 import { ApiModule } from '../../../shared/api/api.module';
12 import { RbdService } from '../../../shared/api/rbd.service';
13 import { ComponentsModule } from '../../../shared/components/components.module';
14 import { DataTableModule } from '../../../shared/datatable/datatable.module';
15 import { TableActionsComponent } from '../../../shared/datatable/table-actions/table-actions.component';
16 import { ExecutingTask } from '../../../shared/models/executing-task';
17 import { Permissions } from '../../../shared/models/permissions';
18 import { PipesModule } from '../../../shared/pipes/pipes.module';
19 import { AuthStorageService } from '../../../shared/services/auth-storage.service';
20 import { NotificationService } from '../../../shared/services/notification.service';
21 import { ServicesModule } from '../../../shared/services/services.module';
22 import { SummaryService } from '../../../shared/services/summary.service';
23 import { TaskListService } from '../../../shared/services/task-list.service';
24 import { RbdSnapshotListComponent } from './rbd-snapshot-list.component';
25 import { RbdSnapshotModel } from './rbd-snapshot.model';
26
27 describe('RbdSnapshotListComponent', () => {
28   let component: RbdSnapshotListComponent;
29   let fixture: ComponentFixture<RbdSnapshotListComponent>;
30   let summaryService: SummaryService;
31
32   const fakeAuthStorageService = {
33     isLoggedIn: () => {
34       return true;
35     },
36     getPermissions: () => {
37       return new Permissions({ 'rbd-image': ['read', 'update', 'create', 'delete'] });
38     }
39   };
40
41   configureTestBed({
42     declarations: [RbdSnapshotListComponent],
43     imports: [
44       DataTableModule,
45       ComponentsModule,
46       ToastModule.forRoot(),
47       ServicesModule,
48       ApiModule,
49       HttpClientTestingModule,
50       RouterTestingModule,
51       PipesModule
52     ],
53     providers: [{ provide: AuthStorageService, useValue: fakeAuthStorageService }, TaskListService]
54   });
55
56   beforeEach(() => {
57     fixture = TestBed.createComponent(RbdSnapshotListComponent);
58     component = fixture.componentInstance;
59     summaryService = TestBed.get(SummaryService);
60   });
61
62   it('should create', () => {
63     fixture.detectChanges();
64     expect(component).toBeTruthy();
65   });
66
67   describe('api delete request', () => {
68     let called;
69     let rbdService: RbdService;
70     let notificationService: NotificationService;
71     let authStorageService: AuthStorageService;
72
73     beforeEach(() => {
74       fixture.detectChanges();
75       called = false;
76       rbdService = new RbdService(null);
77       notificationService = new NotificationService(null, null);
78       authStorageService = new AuthStorageService();
79       authStorageService.set('user', { 'rbd-image': ['create', 'read', 'update', 'delete'] });
80       component = new RbdSnapshotListComponent(
81         authStorageService,
82         null,
83         null,
84         null,
85         rbdService,
86         null,
87         notificationService,
88         null,
89         null
90       );
91       spyOn(rbdService, 'deleteSnapshot').and.returnValue(observableThrowError({ status: 500 }));
92       spyOn(notificationService, 'notifyTask').and.stub();
93       component.modalRef = new BsModalRef();
94       component.modalRef.content = {
95         stopLoadingSpinner: () => (called = true)
96       };
97     });
98
99     it('should call stopLoadingSpinner if the request fails', <any>fakeAsync(() => {
100       expect(called).toBe(false);
101       component._asyncTask('deleteSnapshot', 'rbd/snap/delete', 'someName');
102       tick(500);
103       expect(called).toBe(true);
104     }));
105   });
106
107   describe('handling of executing tasks', () => {
108     let snapshots: RbdSnapshotModel[];
109
110     const addSnapshot = (name) => {
111       const model = new RbdSnapshotModel();
112       model.id = 1;
113       model.name = name;
114       snapshots.push(model);
115     };
116
117     const addTask = (task_name: string, snapshot_name: string) => {
118       const task = new ExecutingTask();
119       task.name = task_name;
120       task.metadata = {
121         pool_name: 'rbd',
122         image_name: 'foo',
123         snapshot_name: snapshot_name
124       };
125       summaryService.addRunningTask(task);
126     };
127
128     const expectImageTasks = (snapshot: RbdSnapshotModel, executing: string) => {
129       expect(snapshot.cdExecuting).toEqual(executing);
130     };
131
132     const refresh = (data) => {
133       summaryService['summaryDataSource'].next(data);
134     };
135
136     beforeEach(() => {
137       fixture.detectChanges();
138       snapshots = [];
139       addSnapshot('a');
140       addSnapshot('b');
141       addSnapshot('c');
142       component.snapshots = snapshots;
143       component.poolName = 'rbd';
144       component.rbdName = 'foo';
145       refresh({ executing_tasks: [], finished_tasks: [] });
146       component.ngOnChanges();
147       fixture.detectChanges();
148     });
149
150     it('should gets all snapshots without tasks', () => {
151       expect(component.snapshots.length).toBe(3);
152       expect(component.snapshots.every((image) => !image.cdExecuting)).toBeTruthy();
153     });
154
155     it('should add a new image from a task', () => {
156       addTask('rbd/snap/create', 'd');
157       expect(component.snapshots.length).toBe(4);
158       expectImageTasks(component.snapshots[0], undefined);
159       expectImageTasks(component.snapshots[1], undefined);
160       expectImageTasks(component.snapshots[2], undefined);
161       expectImageTasks(component.snapshots[3], 'Creating');
162     });
163
164     it('should show when an existing image is being modified', () => {
165       addTask('rbd/snap/edit', 'a');
166       addTask('rbd/snap/delete', 'b');
167       addTask('rbd/snap/rollback', 'c');
168       expect(component.snapshots.length).toBe(3);
169       expectImageTasks(component.snapshots[0], 'Updating');
170       expectImageTasks(component.snapshots[1], 'Deleting');
171       expectImageTasks(component.snapshots[2], 'Rolling back');
172     });
173   });
174
175   describe('snapshot modal dialog', () => {
176     beforeEach(() => {
177       component.poolName = 'pool01';
178       component.rbdName = 'image01';
179       spyOn(TestBed.get(BsModalService), 'show').and.callFake((content) => {
180         const ref = new BsModalRef();
181         ref.content = new content();
182         ref.content.onSubmit = new Subject();
183         return ref;
184       });
185     });
186
187     it('should display old snapshot name', () => {
188       component.selection.selected = [{ name: 'oldname' }];
189       component.selection.update();
190       component.openEditSnapshotModal();
191       expect(component.modalRef.content.snapName).toBe('oldname');
192       expect(component.modalRef.content.editing).toBeTruthy();
193     });
194
195     it('should display suggested snapshot name', () => {
196       component.openCreateSnapshotModal();
197       expect(component.modalRef.content.snapName).toMatch(
198         RegExp(`^${component.rbdName}-\\d+T\\d+Z\$`)
199       );
200     });
201   });
202
203   describe('show action buttons and drop down actions depending on permissions', () => {
204     let tableActions: TableActionsComponent;
205     let scenario: { fn; empty; single };
206     let permissionHelper: PermissionHelper;
207
208     const getTableActionComponent = (): TableActionsComponent => {
209       fixture.detectChanges();
210       return fixture.debugElement.query(By.directive(TableActionsComponent)).componentInstance;
211     };
212
213     beforeEach(() => {
214       permissionHelper = new PermissionHelper(component.permission, () =>
215         getTableActionComponent()
216       );
217       scenario = {
218         fn: () => tableActions.getCurrentButton().name,
219         single: 'Rename',
220         empty: 'Create'
221       };
222     });
223
224     describe('with all', () => {
225       beforeEach(() => {
226         tableActions = permissionHelper.setPermissionsAndGetActions(1, 1, 1);
227       });
228
229       it(`shows 'Rename' for single selection else 'Create' as main action`, () =>
230         permissionHelper.testScenarios(scenario));
231
232       it('shows all actions', () => {
233         expect(tableActions.tableActions.length).toBe(8);
234         expect(tableActions.tableActions).toEqual(component.tableActions);
235       });
236     });
237
238     describe('with read, create and update', () => {
239       beforeEach(() => {
240         tableActions = permissionHelper.setPermissionsAndGetActions(1, 1, 0);
241       });
242
243       it(`shows 'Rename' for single selection else 'Create' as main action`, () =>
244         permissionHelper.testScenarios(scenario));
245
246       it(`shows all actions except for 'Delete'`, () => {
247         expect(tableActions.tableActions.length).toBe(7);
248         component.tableActions.pop();
249         expect(tableActions.tableActions).toEqual(component.tableActions);
250       });
251     });
252
253     describe('with read, create and delete', () => {
254       beforeEach(() => {
255         tableActions = permissionHelper.setPermissionsAndGetActions(1, 0, 1);
256       });
257
258       it(`shows 'Clone' for single selection else 'Create' as main action`, () => {
259         scenario.single = 'Clone';
260         permissionHelper.testScenarios(scenario);
261       });
262
263       it(`shows 'Create', 'Clone', 'Copy' and 'Delete' action`, () => {
264         expect(tableActions.tableActions.length).toBe(4);
265         expect(tableActions.tableActions).toEqual([
266           component.tableActions[0],
267           component.tableActions[4],
268           component.tableActions[5],
269           component.tableActions[7]
270         ]);
271       });
272     });
273
274     describe('with read, edit and delete', () => {
275       beforeEach(() => {
276         tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 1);
277       });
278
279       it(`shows always 'Rename' as main action`, () => {
280         scenario.empty = 'Rename';
281         permissionHelper.testScenarios(scenario);
282       });
283
284       it(`shows 'Rename', 'Protect', 'Unprotect', 'Rollback' and 'Delete' action`, () => {
285         expect(tableActions.tableActions.length).toBe(5);
286         expect(tableActions.tableActions).toEqual([
287           component.tableActions[1],
288           component.tableActions[2],
289           component.tableActions[3],
290           component.tableActions[6],
291           component.tableActions[7]
292         ]);
293       });
294     });
295
296     describe('with read and create', () => {
297       beforeEach(() => {
298         tableActions = permissionHelper.setPermissionsAndGetActions(1, 0, 0);
299       });
300
301       it(`shows 'Clone' for single selection else 'Create' as main action`, () => {
302         scenario.single = 'Clone';
303         permissionHelper.testScenarios(scenario);
304       });
305
306       it(`shows 'Create', 'Clone' and 'Copy' actions`, () => {
307         expect(tableActions.tableActions.length).toBe(3);
308         expect(tableActions.tableActions).toEqual([
309           component.tableActions[0],
310           component.tableActions[4],
311           component.tableActions[5]
312         ]);
313       });
314     });
315
316     describe('with read and edit', () => {
317       beforeEach(() => {
318         tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 0);
319       });
320
321       it(`shows always 'Rename' as main action`, () => {
322         scenario.empty = 'Rename';
323         permissionHelper.testScenarios(scenario);
324       });
325
326       it(`shows 'Rename', 'Protect', 'Unprotect' and 'Rollback' actions`, () => {
327         expect(tableActions.tableActions.length).toBe(4);
328         expect(tableActions.tableActions).toEqual([
329           component.tableActions[1],
330           component.tableActions[2],
331           component.tableActions[3],
332           component.tableActions[6]
333         ]);
334       });
335     });
336
337     describe('with read and delete', () => {
338       beforeEach(() => {
339         tableActions = permissionHelper.setPermissionsAndGetActions(0, 0, 1);
340       });
341
342       it(`shows always 'Delete' as main action`, () => {
343         scenario.single = 'Delete';
344         scenario.empty = 'Delete';
345         permissionHelper.testScenarios(scenario);
346       });
347
348       it(`shows only 'Delete' action`, () => {
349         expect(tableActions.tableActions.length).toBe(1);
350         expect(tableActions.tableActions).toEqual([component.tableActions[7]]);
351       });
352     });
353
354     describe('with only read', () => {
355       beforeEach(() => {
356         tableActions = permissionHelper.setPermissionsAndGetActions(0, 0, 0);
357       });
358
359       it('shows no main action', () => {
360         permissionHelper.testScenarios({
361           fn: () => tableActions.getCurrentButton(),
362           single: undefined,
363           empty: undefined
364         });
365       });
366
367       it('shows no actions', () => {
368         expect(tableActions.tableActions.length).toBe(0);
369         expect(tableActions.tableActions).toEqual([]);
370       });
371     });
372
373     describe('test unprotected and protected action cases', () => {
374       beforeEach(() => {
375         tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 0);
376       });
377
378       it(`shows none of them if nothing is selected`, () => {
379         permissionHelper.setSelection([]);
380         fixture.detectChanges();
381         expect(tableActions.dropDownActions).toEqual([
382           component.tableActions[1],
383           component.tableActions[6]
384         ]);
385       });
386
387       it(`shows 'Protect' of them if nothing is selected`, () => {
388         permissionHelper.setSelection([{ is_protected: false }]);
389         fixture.detectChanges();
390         expect(tableActions.dropDownActions).toEqual([
391           component.tableActions[1],
392           component.tableActions[2],
393           component.tableActions[6]
394         ]);
395       });
396
397       it(`shows 'Unprotect' of them if nothing is selected`, () => {
398         permissionHelper.setSelection([{ is_protected: true }]);
399         fixture.detectChanges();
400         expect(tableActions.dropDownActions).toEqual([
401           component.tableActions[1],
402           component.tableActions[3],
403           component.tableActions[6]
404         ]);
405       });
406     });
407   });
408 });