1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, TestBed } from '@angular/core/testing';
3 import { By } from '@angular/platform-browser';
4 import { RouterTestingModule } from '@angular/router/testing';
6 import { AlertModule } from 'ngx-bootstrap/alert';
7 import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
8 import { ModalModule } from 'ngx-bootstrap/modal';
9 import { TabsModule } from 'ngx-bootstrap/tabs';
10 import { TooltipModule } from 'ngx-bootstrap/tooltip';
11 import { ToastrModule } from 'ngx-toastr';
12 import { BehaviorSubject, of } from 'rxjs';
18 } from '../../../../testing/unit-test-helper';
19 import { RbdService } from '../../../shared/api/rbd.service';
20 import { ActionLabels } from '../../../shared/constants/app.constants';
21 import { TableActionsComponent } from '../../../shared/datatable/table-actions/table-actions.component';
22 import { ViewCacheStatus } from '../../../shared/enum/view-cache-status.enum';
23 import { ExecutingTask } from '../../../shared/models/executing-task';
24 import { SummaryService } from '../../../shared/services/summary.service';
25 import { TaskListService } from '../../../shared/services/task-list.service';
26 import { SharedModule } from '../../../shared/shared.module';
27 import { RbdConfigurationListComponent } from '../rbd-configuration-list/rbd-configuration-list.component';
28 import { RbdDetailsComponent } from '../rbd-details/rbd-details.component';
29 import { RbdSnapshotListComponent } from '../rbd-snapshot-list/rbd-snapshot-list.component';
30 import { RbdListComponent } from './rbd-list.component';
31 import { RbdModel } from './rbd-model';
33 describe('RbdListComponent', () => {
34 let fixture: ComponentFixture<RbdListComponent>;
35 let component: RbdListComponent;
36 let summaryService: SummaryService;
37 let rbdService: RbdService;
39 const refresh = (data) => {
40 summaryService['summaryDataSource'].next(data);
46 BsDropdownModule.forRoot(),
48 ModalModule.forRoot(),
49 TooltipModule.forRoot(),
50 ToastrModule.forRoot(),
51 AlertModule.forRoot(),
53 HttpClientTestingModule
58 RbdSnapshotListComponent,
59 RbdConfigurationListComponent
61 providers: [TaskListService, i18nProviders]
65 fixture = TestBed.createComponent(RbdListComponent);
66 component = fixture.componentInstance;
67 summaryService = TestBed.get(SummaryService);
68 rbdService = TestBed.get(RbdService);
70 // this is needed because summaryService isn't being reset after each test.
71 summaryService['summaryDataSource'] = new BehaviorSubject(null);
72 summaryService['summaryData$'] = summaryService['summaryDataSource'].asObservable();
75 it('should create', () => {
76 expect(component).toBeTruthy();
79 describe('after ngOnInit', () => {
81 fixture.detectChanges();
82 spyOn(rbdService, 'list').and.callThrough();
85 it('should load images on init', () => {
87 expect(rbdService.list).toHaveBeenCalled();
90 it('should not load images on init because no data', () => {
92 expect(rbdService.list).not.toHaveBeenCalled();
95 it('should call error function on init when summary service fails', () => {
96 spyOn(component.table, 'reset');
97 summaryService['summaryDataSource'].error(undefined);
98 expect(component.table.reset).toHaveBeenCalled();
99 expect(component.viewCacheStatusList).toEqual([{ status: ViewCacheStatus.ValueException }]);
103 describe('handling of executing tasks', () => {
104 let images: RbdModel[];
106 const addImage = (name) => {
107 const model = new RbdModel();
110 model.pool_name = 'rbd';
114 const addTask = (name: string, image_name: string) => {
115 const task = new ExecutingTask();
120 dest_pool_name: 'rbd',
126 child_pool_name: 'rbd',
127 child_image_name: 'd'
133 image_name: image_name
137 summaryService.addRunningTask(task);
140 const expectImageTasks = (image: RbdModel, executing: string) => {
141 expect(image.cdExecuting).toEqual(executing);
149 component.images = images;
150 refresh({ executing_tasks: [], finished_tasks: [] });
151 spyOn(rbdService, 'list').and.callFake(() =>
152 of([{ poool_name: 'rbd', status: 1, value: images }])
154 fixture.detectChanges();
157 it('should gets all images without tasks', () => {
158 expect(component.images.length).toBe(3);
159 expect(component.images.every((image) => !image.cdExecuting)).toBeTruthy();
162 it('should add a new image from a task', () => {
163 addTask('rbd/create', 'd');
164 expect(component.images.length).toBe(4);
165 expectImageTasks(component.images[0], undefined);
166 expectImageTasks(component.images[1], undefined);
167 expectImageTasks(component.images[2], undefined);
168 expectImageTasks(component.images[3], 'Creating');
171 it('should show when a image is being cloned', () => {
172 addTask('rbd/clone', 'd');
173 expect(component.images.length).toBe(4);
174 expectImageTasks(component.images[0], undefined);
175 expectImageTasks(component.images[1], undefined);
176 expectImageTasks(component.images[2], undefined);
177 expectImageTasks(component.images[3], 'Cloning');
180 it('should show when a image is being copied', () => {
181 addTask('rbd/copy', 'd');
182 expect(component.images.length).toBe(4);
183 expectImageTasks(component.images[0], undefined);
184 expectImageTasks(component.images[1], undefined);
185 expectImageTasks(component.images[2], undefined);
186 expectImageTasks(component.images[3], 'Copying');
189 it('should show when an existing image is being modified', () => {
190 addTask('rbd/edit', 'a');
191 addTask('rbd/delete', 'b');
192 addTask('rbd/flatten', 'c');
193 expect(component.images.length).toBe(3);
194 expectImageTasks(component.images[0], 'Updating');
195 expectImageTasks(component.images[1], 'Deleting');
196 expectImageTasks(component.images[2], 'Flattening');
200 describe('show action buttons and drop down actions depending on permissions', () => {
201 let tableActions: TableActionsComponent;
202 let scenario: { fn; empty; single };
203 let permissionHelper: PermissionHelper;
205 const getTableActionComponent = (): TableActionsComponent => {
206 fixture.detectChanges();
207 return fixture.debugElement.query(By.directive(TableActionsComponent)).componentInstance;
211 permissionHelper = new PermissionHelper(component.permission, () =>
212 getTableActionComponent()
215 fn: () => tableActions.getCurrentButton().name,
216 single: ActionLabels.EDIT,
217 empty: ActionLabels.CREATE
221 describe('with all', () => {
223 tableActions = permissionHelper.setPermissionsAndGetActions(1, 1, 1);
226 it(`shows 'Edit' for single selection else 'Add' as main action`, () =>
227 permissionHelper.testScenarios(scenario));
229 it('shows all actions', () => {
230 expect(tableActions.tableActions.length).toBe(6);
231 expect(tableActions.tableActions).toEqual(component.tableActions);
235 describe('with read, create and update', () => {
237 tableActions = permissionHelper.setPermissionsAndGetActions(1, 1, 0);
240 it(`shows 'Edit' for single selection else 'Add' as main action`, () =>
241 permissionHelper.testScenarios(scenario));
243 it(`shows all actions except for 'Delete' and 'Move'`, () => {
244 expect(tableActions.tableActions.length).toBe(4);
245 component.tableActions.pop();
246 component.tableActions.pop();
247 expect(tableActions.tableActions).toEqual(component.tableActions);
251 describe('with read, create and delete', () => {
253 tableActions = permissionHelper.setPermissionsAndGetActions(1, 0, 1);
256 it(`shows 'Copy' for single selection else 'Add' as main action`, () => {
257 scenario.single = 'Copy';
258 permissionHelper.testScenarios(scenario);
261 it(`shows 'Add', 'Copy', 'Delete' and 'Move' action`, () => {
262 expect(tableActions.tableActions.length).toBe(4);
263 expect(tableActions.tableActions).toEqual([
264 component.tableActions[0],
265 component.tableActions[2],
266 component.tableActions[4],
267 component.tableActions[5]
272 describe('with read, edit and delete', () => {
274 tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 1);
277 it(`shows always 'Edit' as main action`, () => {
278 scenario.empty = 'Edit';
279 permissionHelper.testScenarios(scenario);
282 it(`shows 'Edit', 'Flatten', 'Delete' and 'Move' action`, () => {
283 expect(tableActions.tableActions.length).toBe(4);
284 expect(tableActions.tableActions).toEqual([
285 component.tableActions[1],
286 component.tableActions[3],
287 component.tableActions[4],
288 component.tableActions[5]
293 describe('with read and create', () => {
295 tableActions = permissionHelper.setPermissionsAndGetActions(1, 0, 0);
298 it(`shows 'Copy' for single selection else 'Add' as main action`, () => {
299 scenario.single = 'Copy';
300 permissionHelper.testScenarios(scenario);
303 it(`shows 'Copy' and 'Add' actions`, () => {
304 expect(tableActions.tableActions.length).toBe(2);
305 expect(tableActions.tableActions).toEqual([
306 component.tableActions[0],
307 component.tableActions[2]
312 describe('with read and edit', () => {
314 tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 0);
317 it(`shows always 'Edit' as main action`, () => {
318 scenario.empty = 'Edit';
319 permissionHelper.testScenarios(scenario);
322 it(`shows 'Edit' and 'Flatten' actions`, () => {
323 expect(tableActions.tableActions.length).toBe(2);
324 expect(tableActions.tableActions).toEqual([
325 component.tableActions[1],
326 component.tableActions[3]
331 describe('with read and delete', () => {
333 tableActions = permissionHelper.setPermissionsAndGetActions(0, 0, 1);
336 it(`shows always 'Delete' as main action`, () => {
337 scenario.single = 'Delete';
338 scenario.empty = 'Delete';
339 permissionHelper.testScenarios(scenario);
342 it(`shows 'Delete' and 'Move' actions`, () => {
343 expect(tableActions.tableActions.length).toBe(2);
344 expect(tableActions.tableActions).toEqual([
345 component.tableActions[4],
346 component.tableActions[5]
351 describe('with only read', () => {
353 tableActions = permissionHelper.setPermissionsAndGetActions(0, 0, 0);
356 it('shows no main action', () => {
357 permissionHelper.testScenarios({
358 fn: () => tableActions.getCurrentButton(),
364 it('shows no actions', () => {
365 expect(tableActions.tableActions.length).toBe(0);
366 expect(tableActions.tableActions).toEqual([]);