]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts
import ceph 16.2.6
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / block / iscsi-target-list / iscsi-target-list.component.spec.ts
CommitLineData
11fdf7f2
TL
1import { HttpClientTestingModule } from '@angular/common/http/testing';
2import { ComponentFixture, TestBed } from '@angular/core/testing';
e306af50 3import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
11fdf7f2
TL
4import { RouterTestingModule } from '@angular/router/testing';
5
f67539c2
TL
6import { TreeModule } from '@circlon/angular-tree-component';
7import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
494da23a 8import { ToastrModule } from 'ngx-toastr';
11fdf7f2
TL
9import { BehaviorSubject, of } from 'rxjs';
10
f67539c2
TL
11import { IscsiService } from '~/app/shared/api/iscsi.service';
12import { TableActionsComponent } from '~/app/shared/datatable/table-actions/table-actions.component';
13import { CdTableAction } from '~/app/shared/models/cd-table-action';
14import { ExecutingTask } from '~/app/shared/models/executing-task';
15import { SummaryService } from '~/app/shared/services/summary.service';
16import { TaskListService } from '~/app/shared/services/task-list.service';
17import { SharedModule } from '~/app/shared/shared.module';
18import { configureTestBed, expectItemTasks, PermissionHelper } from '~/testing/unit-test-helper';
11fdf7f2
TL
19import { IscsiTabsComponent } from '../iscsi-tabs/iscsi-tabs.component';
20import { IscsiTargetDetailsComponent } from '../iscsi-target-details/iscsi-target-details.component';
21import { IscsiTargetListComponent } from './iscsi-target-list.component';
22
23describe('IscsiTargetListComponent', () => {
24 let component: IscsiTargetListComponent;
25 let fixture: ComponentFixture<IscsiTargetListComponent>;
26 let summaryService: SummaryService;
27 let iscsiService: IscsiService;
28
9f95a23c 29 const refresh = (data: any) => {
11fdf7f2
TL
30 summaryService['summaryDataSource'].next(data);
31 };
32
33 configureTestBed({
34 imports: [
e306af50 35 BrowserAnimationsModule,
11fdf7f2
TL
36 HttpClientTestingModule,
37 RouterTestingModule,
38 SharedModule,
11fdf7f2 39 TreeModule,
f67539c2
TL
40 ToastrModule.forRoot(),
41 NgbNavModule
11fdf7f2
TL
42 ],
43 declarations: [IscsiTargetListComponent, IscsiTabsComponent, IscsiTargetDetailsComponent],
f67539c2 44 providers: [TaskListService]
11fdf7f2
TL
45 });
46
47 beforeEach(() => {
48 fixture = TestBed.createComponent(IscsiTargetListComponent);
49 component = fixture.componentInstance;
f67539c2
TL
50 summaryService = TestBed.inject(SummaryService);
51 iscsiService = TestBed.inject(IscsiService);
11fdf7f2
TL
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 }));
eafe8130 58 spyOn(iscsiService, 'version').and.returnValue(of({ ceph_iscsi_config_version: 11 }));
522d829b 59 spyOn(component, 'setTableRefreshTimeout').and.stub();
11fdf7f2
TL
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 });
522d829b
TL
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 });
11fdf7f2
TL
94 });
95
96 describe('handling of executing tasks', () => {
97 let targets: any[];
98
9f95a23c 99 const addTarget = (name: string) => {
11fdf7f2
TL
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
11fdf7f2
TL
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);
eafe8130
TL
165 expectItemTasks(component.targets[0], undefined);
166 expectItemTasks(component.targets[1], undefined);
167 expectItemTasks(component.targets[2], undefined);
168 expectItemTasks(component.targets[3], 'Creating');
11fdf7f2
TL
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);
eafe8130 174 expectItemTasks(component.targets[1], 'Deleting');
11fdf7f2
TL
175 });
176 });
177
f6b5b4d7
TL
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 ];
f91f0fd5 200 expect(action.disable(undefined)).toBe('Unavailable gateway(s)');
f6b5b4d7
TL
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();
f6b5b4d7
TL
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();
f6b5b4d7
TL
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 ];
f91f0fd5 239 expect(action.disable(undefined)).toBe('Unavailable gateway(s)');
f6b5b4d7
TL
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 ];
f91f0fd5 251 expect(action.disable(undefined)).toBe('Target has active sessions');
f6b5b4d7
TL
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();
f6b5b4d7
TL
264 });
265 });
266 });
267
9f95a23c
TL
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 }
11fdf7f2
TL
307 });
308 });
309});