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