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