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';
6 import { ToastModule } from 'ng2-toastr';
7 import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
8 import { Subject, throwError as observableThrowError } from 'rxjs';
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';
27 describe('RbdSnapshotListComponent', () => {
28 let component: RbdSnapshotListComponent;
29 let fixture: ComponentFixture<RbdSnapshotListComponent>;
30 let summaryService: SummaryService;
32 const fakeAuthStorageService = {
36 getPermissions: () => {
37 return new Permissions({ 'rbd-image': ['read', 'update', 'create', 'delete'] });
42 declarations: [RbdSnapshotListComponent],
46 ToastModule.forRoot(),
49 HttpClientTestingModule,
53 providers: [{ provide: AuthStorageService, useValue: fakeAuthStorageService }, TaskListService]
57 fixture = TestBed.createComponent(RbdSnapshotListComponent);
58 component = fixture.componentInstance;
59 summaryService = TestBed.get(SummaryService);
62 it('should create', () => {
63 fixture.detectChanges();
64 expect(component).toBeTruthy();
67 describe('api delete request', () => {
69 let rbdService: RbdService;
70 let notificationService: NotificationService;
71 let authStorageService: AuthStorageService;
74 fixture.detectChanges();
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(
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)
99 it('should call stopLoadingSpinner if the request fails', <any>fakeAsync(() => {
100 expect(called).toBe(false);
101 component._asyncTask('deleteSnapshot', 'rbd/snap/delete', 'someName');
103 expect(called).toBe(true);
107 describe('handling of executing tasks', () => {
108 let snapshots: RbdSnapshotModel[];
110 const addSnapshot = (name) => {
111 const model = new RbdSnapshotModel();
114 snapshots.push(model);
117 const addTask = (task_name: string, snapshot_name: string) => {
118 const task = new ExecutingTask();
119 task.name = task_name;
123 snapshot_name: snapshot_name
125 summaryService.addRunningTask(task);
128 const expectImageTasks = (snapshot: RbdSnapshotModel, executing: string) => {
129 expect(snapshot.cdExecuting).toEqual(executing);
132 const refresh = (data) => {
133 summaryService['summaryDataSource'].next(data);
137 fixture.detectChanges();
142 component.snapshots = snapshots;
143 component.poolName = 'rbd';
144 component.rbdName = 'foo';
145 refresh({ executing_tasks: [], finished_tasks: [] });
146 component.ngOnChanges();
147 fixture.detectChanges();
150 it('should gets all snapshots without tasks', () => {
151 expect(component.snapshots.length).toBe(3);
152 expect(component.snapshots.every((image) => !image.cdExecuting)).toBeTruthy();
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');
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');
175 describe('snapshot modal dialog', () => {
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();
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();
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\$`)
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;
208 const getTableActionComponent = (): TableActionsComponent => {
209 fixture.detectChanges();
210 return fixture.debugElement.query(By.directive(TableActionsComponent)).componentInstance;
214 permissionHelper = new PermissionHelper(component.permission, () =>
215 getTableActionComponent()
218 fn: () => tableActions.getCurrentButton().name,
224 describe('with all', () => {
226 tableActions = permissionHelper.setPermissionsAndGetActions(1, 1, 1);
229 it(`shows 'Rename' for single selection else 'Create' as main action`, () =>
230 permissionHelper.testScenarios(scenario));
232 it('shows all actions', () => {
233 expect(tableActions.tableActions.length).toBe(8);
234 expect(tableActions.tableActions).toEqual(component.tableActions);
238 describe('with read, create and update', () => {
240 tableActions = permissionHelper.setPermissionsAndGetActions(1, 1, 0);
243 it(`shows 'Rename' for single selection else 'Create' as main action`, () =>
244 permissionHelper.testScenarios(scenario));
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);
253 describe('with read, create and delete', () => {
255 tableActions = permissionHelper.setPermissionsAndGetActions(1, 0, 1);
258 it(`shows 'Clone' for single selection else 'Create' as main action`, () => {
259 scenario.single = 'Clone';
260 permissionHelper.testScenarios(scenario);
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]
274 describe('with read, edit and delete', () => {
276 tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 1);
279 it(`shows always 'Rename' as main action`, () => {
280 scenario.empty = 'Rename';
281 permissionHelper.testScenarios(scenario);
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]
296 describe('with read and create', () => {
298 tableActions = permissionHelper.setPermissionsAndGetActions(1, 0, 0);
301 it(`shows 'Clone' for single selection else 'Create' as main action`, () => {
302 scenario.single = 'Clone';
303 permissionHelper.testScenarios(scenario);
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]
316 describe('with read and edit', () => {
318 tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 0);
321 it(`shows always 'Rename' as main action`, () => {
322 scenario.empty = 'Rename';
323 permissionHelper.testScenarios(scenario);
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]
337 describe('with read and delete', () => {
339 tableActions = permissionHelper.setPermissionsAndGetActions(0, 0, 1);
342 it(`shows always 'Delete' as main action`, () => {
343 scenario.single = 'Delete';
344 scenario.empty = 'Delete';
345 permissionHelper.testScenarios(scenario);
348 it(`shows only 'Delete' action`, () => {
349 expect(tableActions.tableActions.length).toBe(1);
350 expect(tableActions.tableActions).toEqual([component.tableActions[7]]);
354 describe('with only read', () => {
356 tableActions = permissionHelper.setPermissionsAndGetActions(0, 0, 0);
359 it('shows no main action', () => {
360 permissionHelper.testScenarios({
361 fn: () => tableActions.getCurrentButton(),
367 it('shows no actions', () => {
368 expect(tableActions.tableActions.length).toBe(0);
369 expect(tableActions.tableActions).toEqual([]);
373 describe('test unprotected and protected action cases', () => {
375 tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 0);
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]
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]
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]