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