]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
25f4ba3b83e51ac560f5b20657c04a6a54f7a28d
[ceph.git] /
1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
3 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
4 import { RouterTestingModule } from '@angular/router/testing';
5
6 import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
7 import { I18n } from '@ngx-translate/i18n-polyfill';
8 import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
9 import { ToastrModule } from 'ngx-toastr';
10 import { Subject, throwError as observableThrowError } from 'rxjs';
11
12 import {
13   configureTestBed,
14   expectItemTasks,
15   i18nProviders,
16   PermissionHelper
17 } from '../../../../testing/unit-test-helper';
18 import { ApiModule } from '../../../shared/api/api.module';
19 import { RbdService } from '../../../shared/api/rbd.service';
20 import { ComponentsModule } from '../../../shared/components/components.module';
21 import { ActionLabelsI18n } from '../../../shared/constants/app.constants';
22 import { DataTableModule } from '../../../shared/datatable/datatable.module';
23 import { TableActionsComponent } from '../../../shared/datatable/table-actions/table-actions.component';
24 import { ExecutingTask } from '../../../shared/models/executing-task';
25 import { Permissions } from '../../../shared/models/permissions';
26 import { PipesModule } from '../../../shared/pipes/pipes.module';
27 import { AuthStorageService } from '../../../shared/services/auth-storage.service';
28 import { NotificationService } from '../../../shared/services/notification.service';
29 import { SummaryService } from '../../../shared/services/summary.service';
30 import { TaskListService } from '../../../shared/services/task-list.service';
31 import { RbdSnapshotFormModalComponent } from '../rbd-snapshot-form/rbd-snapshot-form-modal.component';
32 import { RbdTabsComponent } from '../rbd-tabs/rbd-tabs.component';
33 import { RbdSnapshotListComponent } from './rbd-snapshot-list.component';
34 import { RbdSnapshotModel } from './rbd-snapshot.model';
35
36 describe('RbdSnapshotListComponent', () => {
37   let component: RbdSnapshotListComponent;
38   let fixture: ComponentFixture<RbdSnapshotListComponent>;
39   let summaryService: SummaryService;
40
41   const fakeAuthStorageService = {
42     isLoggedIn: () => {
43       return true;
44     },
45     getPermissions: () => {
46       return new Permissions({ 'rbd-image': ['read', 'update', 'create', 'delete'] });
47     }
48   };
49
50   configureTestBed({
51     declarations: [RbdSnapshotListComponent, RbdTabsComponent],
52     imports: [
53       ApiModule,
54       BrowserAnimationsModule,
55       ComponentsModule,
56       DataTableModule,
57       HttpClientTestingModule,
58       PipesModule,
59       RouterTestingModule,
60       NgbNavModule,
61       ToastrModule.forRoot()
62     ],
63     providers: [
64       { provide: AuthStorageService, useValue: fakeAuthStorageService },
65       TaskListService,
66       i18nProviders
67     ]
68   });
69
70   beforeEach(() => {
71     fixture = TestBed.createComponent(RbdSnapshotListComponent);
72     component = fixture.componentInstance;
73     component.ngOnChanges();
74     summaryService = TestBed.inject(SummaryService);
75   });
76
77   it('should create', () => {
78     fixture.detectChanges();
79     expect(component).toBeTruthy();
80   });
81
82   describe('api delete request', () => {
83     let called: boolean;
84     let rbdService: RbdService;
85     let notificationService: NotificationService;
86     let authStorageService: AuthStorageService;
87
88     beforeEach(() => {
89       fixture.detectChanges();
90       const i18n = TestBed.inject(I18n);
91       const actionLabelsI18n = TestBed.inject(ActionLabelsI18n);
92       called = false;
93       rbdService = new RbdService(null, null);
94       notificationService = new NotificationService(null, null, null);
95       authStorageService = new AuthStorageService();
96       authStorageService.set('user', '', { 'rbd-image': ['create', 'read', 'update', 'delete'] });
97       component = new RbdSnapshotListComponent(
98         authStorageService,
99         null,
100         null,
101         null,
102         rbdService,
103         null,
104         notificationService,
105         null,
106         null,
107         i18n,
108         actionLabelsI18n
109       );
110       spyOn(rbdService, 'deleteSnapshot').and.returnValue(observableThrowError({ status: 500 }));
111       spyOn(notificationService, 'notifyTask').and.stub();
112       component.modalRef = new BsModalRef();
113       component.modalRef.content = {
114         stopLoadingSpinner: () => (called = true)
115       };
116     });
117
118     it('should call stopLoadingSpinner if the request fails', fakeAsync(() => {
119       expect(called).toBe(false);
120       component._asyncTask('deleteSnapshot', 'rbd/snap/delete', 'someName');
121       tick(500);
122       expect(called).toBe(true);
123     }));
124   });
125
126   describe('handling of executing tasks', () => {
127     let snapshots: RbdSnapshotModel[];
128
129     const addSnapshot = (name: string) => {
130       const model = new RbdSnapshotModel();
131       model.id = 1;
132       model.name = name;
133       snapshots.push(model);
134     };
135
136     const addTask = (task_name: string, snapshot_name: string) => {
137       const task = new ExecutingTask();
138       task.name = task_name;
139       task.metadata = {
140         image_spec: 'rbd/foo',
141         snapshot_name: snapshot_name
142       };
143       summaryService.addRunningTask(task);
144     };
145
146     const refresh = (data: any) => {
147       summaryService['summaryDataSource'].next(data);
148     };
149
150     beforeEach(() => {
151       fixture.detectChanges();
152       snapshots = [];
153       addSnapshot('a');
154       addSnapshot('b');
155       addSnapshot('c');
156       component.snapshots = snapshots;
157       component.poolName = 'rbd';
158       component.rbdName = 'foo';
159       refresh({ executing_tasks: [], finished_tasks: [] });
160       component.ngOnChanges();
161       fixture.detectChanges();
162     });
163
164     it('should gets all snapshots without tasks', () => {
165       expect(component.snapshots.length).toBe(3);
166       expect(component.snapshots.every((image) => !image.cdExecuting)).toBeTruthy();
167     });
168
169     it('should add a new image from a task', () => {
170       addTask('rbd/snap/create', 'd');
171       expect(component.snapshots.length).toBe(4);
172       expectItemTasks(component.snapshots[0], undefined);
173       expectItemTasks(component.snapshots[1], undefined);
174       expectItemTasks(component.snapshots[2], undefined);
175       expectItemTasks(component.snapshots[3], 'Creating');
176     });
177
178     it('should show when an existing image is being modified', () => {
179       addTask('rbd/snap/edit', 'a');
180       addTask('rbd/snap/delete', 'b');
181       addTask('rbd/snap/rollback', 'c');
182       expect(component.snapshots.length).toBe(3);
183       expectItemTasks(component.snapshots[0], 'Updating');
184       expectItemTasks(component.snapshots[1], 'Deleting');
185       expectItemTasks(component.snapshots[2], 'Rolling back');
186     });
187   });
188
189   describe('snapshot modal dialog', () => {
190     beforeEach(() => {
191       component.poolName = 'pool01';
192       component.rbdName = 'image01';
193       spyOn(TestBed.inject(BsModalService), 'show').and.callFake(() => {
194         const ref = new BsModalRef();
195         ref.content = new RbdSnapshotFormModalComponent(
196           null,
197           null,
198           null,
199           null,
200           TestBed.inject(I18n),
201           TestBed.inject(ActionLabelsI18n)
202         );
203         ref.content.onSubmit = new Subject();
204         return ref;
205       });
206     });
207
208     it('should display old snapshot name', () => {
209       component.selection.selected = [{ name: 'oldname' }];
210       component.openEditSnapshotModal();
211       expect(component.modalRef.content.snapName).toBe('oldname');
212       expect(component.modalRef.content.editing).toBeTruthy();
213     });
214
215     it('should display suggested snapshot name', () => {
216       component.openCreateSnapshotModal();
217       expect(component.modalRef.content.snapName).toMatch(
218         RegExp(`^${component.rbdName}_[\\d-]+T[\\d.:]+[\\+-][\\d:]+$`)
219       );
220     });
221   });
222
223   it('should test all TableActions combinations', () => {
224     const permissionHelper: PermissionHelper = new PermissionHelper(component.permission);
225     const tableActions: TableActionsComponent = permissionHelper.setPermissionsAndGetActions(
226       component.tableActions
227     );
228
229     expect(tableActions).toEqual({
230       'create,update,delete': {
231         actions: [
232           'Create',
233           'Rename',
234           'Protect',
235           'Unprotect',
236           'Clone',
237           'Copy',
238           'Rollback',
239           'Delete'
240         ],
241         primary: { multiple: 'Create', executing: 'Rename', single: 'Rename', no: 'Create' }
242       },
243       'create,update': {
244         actions: ['Create', 'Rename', 'Protect', 'Unprotect', 'Clone', 'Copy', 'Rollback'],
245         primary: { multiple: 'Create', executing: 'Rename', single: 'Rename', no: 'Create' }
246       },
247       'create,delete': {
248         actions: ['Create', 'Clone', 'Copy', 'Delete'],
249         primary: { multiple: 'Create', executing: 'Clone', single: 'Clone', no: 'Create' }
250       },
251       create: {
252         actions: ['Create', 'Clone', 'Copy'],
253         primary: { multiple: 'Create', executing: 'Clone', single: 'Clone', no: 'Create' }
254       },
255       'update,delete': {
256         actions: ['Rename', 'Protect', 'Unprotect', 'Rollback', 'Delete'],
257         primary: { multiple: 'Rename', executing: 'Rename', single: 'Rename', no: 'Rename' }
258       },
259       update: {
260         actions: ['Rename', 'Protect', 'Unprotect', 'Rollback'],
261         primary: { multiple: 'Rename', executing: 'Rename', single: 'Rename', no: 'Rename' }
262       },
263       delete: {
264         actions: ['Delete'],
265         primary: { multiple: 'Delete', executing: 'Delete', single: 'Delete', no: 'Delete' }
266       },
267       'no-permissions': {
268         actions: [],
269         primary: { multiple: '', executing: '', single: '', no: '' }
270       }
271     });
272   });
273 });