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