]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
2f93c86a63ea2bb5f3ca8220939a1eec3ae958e3
[ceph.git] /
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';
5
6 import { TreeModule } from 'ng2-tree';
7 import { TabsModule } from 'ngx-bootstrap/tabs';
8 import { ToastrModule } from 'ngx-toastr';
9 import { BehaviorSubject, of } from 'rxjs';
10
11 import {
12   configureTestBed,
13   i18nProviders,
14   PermissionHelper
15 } from '../../../../testing/unit-test-helper';
16 import { IscsiService } from '../../../shared/api/iscsi.service';
17 import { TableActionsComponent } from '../../../shared/datatable/table-actions/table-actions.component';
18 import { ExecutingTask } from '../../../shared/models/executing-task';
19 import { SummaryService } from '../../../shared/services/summary.service';
20 import { TaskListService } from '../../../shared/services/task-list.service';
21 import { SharedModule } from '../../../shared/shared.module';
22 import { IscsiTabsComponent } from '../iscsi-tabs/iscsi-tabs.component';
23 import { IscsiTargetDetailsComponent } from '../iscsi-target-details/iscsi-target-details.component';
24 import { IscsiTargetListComponent } from './iscsi-target-list.component';
25
26 describe('IscsiTargetListComponent', () => {
27   let component: IscsiTargetListComponent;
28   let fixture: ComponentFixture<IscsiTargetListComponent>;
29   let summaryService: SummaryService;
30   let iscsiService: IscsiService;
31
32   const refresh = (data) => {
33     summaryService['summaryDataSource'].next(data);
34   };
35
36   configureTestBed({
37     imports: [
38       HttpClientTestingModule,
39       RouterTestingModule,
40       SharedModule,
41       TabsModule.forRoot(),
42       TreeModule,
43       ToastrModule.forRoot()
44     ],
45     declarations: [IscsiTargetListComponent, IscsiTabsComponent, IscsiTargetDetailsComponent],
46     providers: [TaskListService, i18nProviders]
47   });
48
49   beforeEach(() => {
50     fixture = TestBed.createComponent(IscsiTargetListComponent);
51     component = fixture.componentInstance;
52     summaryService = TestBed.get(SummaryService);
53     iscsiService = TestBed.get(IscsiService);
54
55     // this is needed because summaryService isn't being reset after each test.
56     summaryService['summaryDataSource'] = new BehaviorSubject(null);
57     summaryService['summaryData$'] = summaryService['summaryDataSource'].asObservable();
58
59     spyOn(iscsiService, 'status').and.returnValue(of({ available: true }));
60   });
61
62   it('should create', () => {
63     expect(component).toBeTruthy();
64   });
65
66   describe('after ngOnInit', () => {
67     beforeEach(() => {
68       spyOn(iscsiService, 'listTargets').and.callThrough();
69       fixture.detectChanges();
70     });
71
72     it('should load targets on init', () => {
73       refresh({});
74       expect(iscsiService.status).toHaveBeenCalled();
75       expect(iscsiService.listTargets).toHaveBeenCalled();
76     });
77
78     it('should not load targets on init because no data', () => {
79       refresh(undefined);
80       expect(iscsiService.listTargets).not.toHaveBeenCalled();
81     });
82
83     it('should call error function on init when summary service fails', () => {
84       spyOn(component.table, 'reset');
85       summaryService['summaryDataSource'].error(undefined);
86       expect(component.table.reset).toHaveBeenCalled();
87     });
88   });
89
90   describe('handling of executing tasks', () => {
91     let targets: any[];
92
93     const addTarget = (name) => {
94       const model: any = {
95         target_iqn: name,
96         portals: [{ host: 'node1', ip: '192.168.100.201' }],
97         disks: [{ pool: 'rbd', image: 'disk_1', controls: {} }],
98         clients: [
99           {
100             client_iqn: 'iqn.1994-05.com.redhat:rh7-client',
101             luns: [{ pool: 'rbd', image: 'disk_1' }],
102             auth: {
103               user: 'myiscsiusername',
104               password: 'myiscsipassword',
105               mutual_user: null,
106               mutual_password: null
107             }
108           }
109         ],
110         groups: [],
111         target_controls: {}
112       };
113       targets.push(model);
114     };
115
116     const addTask = (name: string, target_iqn: string) => {
117       const task = new ExecutingTask();
118       task.name = name;
119       switch (task.name) {
120         case 'iscsi/target/create':
121           task.metadata = {
122             target_iqn: target_iqn
123           };
124           break;
125         case 'iscsi/target/delete':
126           task.metadata = {
127             target_iqn: target_iqn
128           };
129           break;
130         default:
131           task.metadata = {
132             target_iqn: target_iqn
133           };
134           break;
135       }
136       summaryService.addRunningTask(task);
137     };
138
139     const expectTargetTasks = (target: any, executing: string) => {
140       expect(target.cdExecuting).toEqual(executing);
141     };
142
143     beforeEach(() => {
144       targets = [];
145       addTarget('iqn.a');
146       addTarget('iqn.b');
147       addTarget('iqn.c');
148
149       component.targets = targets;
150       refresh({ executing_tasks: [], finished_tasks: [] });
151       spyOn(iscsiService, 'listTargets').and.callFake(() => of(targets));
152       fixture.detectChanges();
153     });
154
155     it('should gets all targets without tasks', () => {
156       expect(component.targets.length).toBe(3);
157       expect(component.targets.every((target) => !target.cdExecuting)).toBeTruthy();
158     });
159
160     it('should add a new target from a task', () => {
161       addTask('iscsi/target/create', 'iqn.d');
162       expect(component.targets.length).toBe(4);
163       expectTargetTasks(component.targets[0], undefined);
164       expectTargetTasks(component.targets[1], undefined);
165       expectTargetTasks(component.targets[2], undefined);
166       expectTargetTasks(component.targets[3], 'Creating');
167     });
168
169     it('should show when an existing target is being modified', () => {
170       addTask('iscsi/target/delete', 'iqn.b');
171       expect(component.targets.length).toBe(3);
172       expectTargetTasks(component.targets[1], 'Deleting');
173     });
174   });
175
176   describe('show action buttons and drop down actions depending on permissions', () => {
177     let tableActions: TableActionsComponent;
178     let scenario: { fn; empty; single };
179     let permissionHelper: PermissionHelper;
180
181     const getTableActionComponent = (): TableActionsComponent => {
182       fixture.detectChanges();
183       return fixture.debugElement.query(By.directive(TableActionsComponent)).componentInstance;
184     };
185
186     beforeEach(() => {
187       permissionHelper = new PermissionHelper(component.permissions.iscsi, () =>
188         getTableActionComponent()
189       );
190       scenario = {
191         fn: () => tableActions.getCurrentButton().name,
192         single: 'Edit',
193         empty: 'Add'
194       };
195     });
196
197     describe('with all', () => {
198       beforeEach(() => {
199         tableActions = permissionHelper.setPermissionsAndGetActions(1, 1, 1);
200       });
201
202       it(`shows 'Edit' for single selection else 'Add' as main action`, () => {
203         permissionHelper.testScenarios(scenario);
204       });
205
206       it('shows all actions', () => {
207         expect(tableActions.tableActions.length).toBe(3);
208         expect(tableActions.tableActions).toEqual(component.tableActions);
209       });
210     });
211
212     describe('with read, create and update', () => {
213       beforeEach(() => {
214         tableActions = permissionHelper.setPermissionsAndGetActions(1, 1, 0);
215         scenario.single = 'Edit';
216       });
217
218       it(`should always show 'Edit'`, () => {
219         permissionHelper.testScenarios(scenario);
220       });
221
222       it(`shows all actions except for 'Delete'`, () => {
223         expect(tableActions.tableActions.length).toBe(2);
224         component.tableActions.pop();
225         expect(tableActions.tableActions).toEqual(component.tableActions);
226       });
227     });
228
229     describe('with read, create and delete', () => {
230       beforeEach(() => {
231         tableActions = permissionHelper.setPermissionsAndGetActions(1, 0, 1);
232       });
233
234       it(`shows 'Delete' for single selection else 'Add' as main action`, () => {
235         scenario.single = 'Delete';
236         permissionHelper.testScenarios(scenario);
237       });
238
239       it(`shows 'Add' and 'Delete' actions`, () => {
240         expect(tableActions.tableActions.length).toBe(2);
241         expect(tableActions.tableActions).toEqual([
242           component.tableActions[0],
243           component.tableActions[2]
244         ]);
245       });
246     });
247
248     describe('with read, edit and delete', () => {
249       beforeEach(() => {
250         tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 1);
251       });
252
253       it(`shows always 'Edit' as main action`, () => {
254         scenario.empty = 'Edit';
255         permissionHelper.testScenarios(scenario);
256       });
257
258       it(`shows 'Edit' and 'Delete' actions`, () => {
259         expect(tableActions.tableActions.length).toBe(2);
260         expect(tableActions.tableActions).toEqual([
261           component.tableActions[1],
262           component.tableActions[2]
263         ]);
264       });
265     });
266
267     describe('with read and create', () => {
268       beforeEach(() => {
269         tableActions = permissionHelper.setPermissionsAndGetActions(1, 0, 0);
270       });
271
272       it(`shows 'Add' for single selection and 'Add' as main action`, () => {
273         scenario.single = 'Add';
274         permissionHelper.testScenarios(scenario);
275       });
276
277       it(`shows 'Add' actions`, () => {
278         expect(tableActions.tableActions.length).toBe(1);
279         expect(tableActions.tableActions).toEqual([component.tableActions[0]]);
280       });
281     });
282
283     describe('with read and edit', () => {
284       beforeEach(() => {
285         tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 0);
286       });
287
288       it(`shows no actions`, () => {
289         expect(tableActions.tableActions.length).toBe(1);
290         expect(tableActions.tableActions).toEqual([component.tableActions[1]]);
291       });
292     });
293
294     describe('with read and delete', () => {
295       beforeEach(() => {
296         tableActions = permissionHelper.setPermissionsAndGetActions(0, 0, 1);
297       });
298
299       it(`shows always 'Delete' as main action`, () => {
300         scenario.single = 'Delete';
301         scenario.empty = 'Delete';
302         permissionHelper.testScenarios(scenario);
303       });
304
305       it(`shows 'Delete' actions`, () => {
306         expect(tableActions.tableActions.length).toBe(1);
307         expect(tableActions.tableActions).toEqual([component.tableActions[2]]);
308       });
309     });
310
311     describe('with only read', () => {
312       beforeEach(() => {
313         tableActions = permissionHelper.setPermissionsAndGetActions(0, 0, 0);
314       });
315
316       it('shows no main action', () => {
317         permissionHelper.testScenarios({
318           fn: () => tableActions.getCurrentButton(),
319           single: undefined,
320           empty: undefined
321         });
322       });
323
324       it('shows no actions', () => {
325         expect(tableActions.tableActions.length).toBe(0);
326         expect(tableActions.tableActions).toEqual([]);
327       });
328     });
329   });
330 });