]> 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
update source to Ceph Pacific 16.2.2
[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 }));
11fdf7f2
TL
59 });
60
61 it('should create', () => {
62 expect(component).toBeTruthy();
63 });
64
65 describe('after ngOnInit', () => {
66 beforeEach(() => {
67 spyOn(iscsiService, 'listTargets').and.callThrough();
68 fixture.detectChanges();
69 });
70
71 it('should load targets on init', () => {
72 refresh({});
73 expect(iscsiService.status).toHaveBeenCalled();
74 expect(iscsiService.listTargets).toHaveBeenCalled();
75 });
76
77 it('should not load targets on init because no data', () => {
78 refresh(undefined);
79 expect(iscsiService.listTargets).not.toHaveBeenCalled();
80 });
81
82 it('should call error function on init when summary service fails', () => {
83 spyOn(component.table, 'reset');
84 summaryService['summaryDataSource'].error(undefined);
85 expect(component.table.reset).toHaveBeenCalled();
86 });
87 });
88
89 describe('handling of executing tasks', () => {
90 let targets: any[];
91
9f95a23c 92 const addTarget = (name: string) => {
11fdf7f2
TL
93 const model: any = {
94 target_iqn: name,
95 portals: [{ host: 'node1', ip: '192.168.100.201' }],
96 disks: [{ pool: 'rbd', image: 'disk_1', controls: {} }],
97 clients: [
98 {
99 client_iqn: 'iqn.1994-05.com.redhat:rh7-client',
100 luns: [{ pool: 'rbd', image: 'disk_1' }],
101 auth: {
102 user: 'myiscsiusername',
103 password: 'myiscsipassword',
104 mutual_user: null,
105 mutual_password: null
106 }
107 }
108 ],
109 groups: [],
110 target_controls: {}
111 };
112 targets.push(model);
113 };
114
115 const addTask = (name: string, target_iqn: string) => {
116 const task = new ExecutingTask();
117 task.name = name;
118 switch (task.name) {
119 case 'iscsi/target/create':
120 task.metadata = {
121 target_iqn: target_iqn
122 };
123 break;
124 case 'iscsi/target/delete':
125 task.metadata = {
126 target_iqn: target_iqn
127 };
128 break;
129 default:
130 task.metadata = {
131 target_iqn: target_iqn
132 };
133 break;
134 }
135 summaryService.addRunningTask(task);
136 };
137
11fdf7f2
TL
138 beforeEach(() => {
139 targets = [];
140 addTarget('iqn.a');
141 addTarget('iqn.b');
142 addTarget('iqn.c');
143
144 component.targets = targets;
145 refresh({ executing_tasks: [], finished_tasks: [] });
146 spyOn(iscsiService, 'listTargets').and.callFake(() => of(targets));
147 fixture.detectChanges();
148 });
149
150 it('should gets all targets without tasks', () => {
151 expect(component.targets.length).toBe(3);
152 expect(component.targets.every((target) => !target.cdExecuting)).toBeTruthy();
153 });
154
155 it('should add a new target from a task', () => {
156 addTask('iscsi/target/create', 'iqn.d');
157 expect(component.targets.length).toBe(4);
eafe8130
TL
158 expectItemTasks(component.targets[0], undefined);
159 expectItemTasks(component.targets[1], undefined);
160 expectItemTasks(component.targets[2], undefined);
161 expectItemTasks(component.targets[3], 'Creating');
11fdf7f2
TL
162 });
163
164 it('should show when an existing target is being modified', () => {
165 addTask('iscsi/target/delete', 'iqn.b');
166 expect(component.targets.length).toBe(3);
eafe8130 167 expectItemTasks(component.targets[1], 'Deleting');
11fdf7f2
TL
168 });
169 });
170
f6b5b4d7
TL
171 describe('handling of actions', () => {
172 beforeEach(() => {
173 fixture.detectChanges();
174 });
175
176 let action: CdTableAction;
177
178 const getAction = (name: string): CdTableAction => {
179 return component.tableActions.find((tableAction) => tableAction.name === name);
180 };
181
182 describe('edit', () => {
183 beforeEach(() => {
184 action = getAction('Edit');
185 });
186
187 it('should be disabled if no gateways', () => {
188 component.selection.selected = [
189 {
190 id: '-1'
191 }
192 ];
f91f0fd5 193 expect(action.disable(undefined)).toBe('Unavailable gateway(s)');
f6b5b4d7
TL
194 });
195
196 it('should be enabled if active sessions', () => {
197 component.selection.selected = [
198 {
199 id: '-1',
200 info: {
201 num_sessions: 1
202 }
203 }
204 ];
205 expect(action.disable(undefined)).toBeFalsy();
f6b5b4d7
TL
206 });
207
208 it('should be enabled if no active sessions', () => {
209 component.selection.selected = [
210 {
211 id: '-1',
212 info: {
213 num_sessions: 0
214 }
215 }
216 ];
217 expect(action.disable(undefined)).toBeFalsy();
f6b5b4d7
TL
218 });
219 });
220
221 describe('delete', () => {
222 beforeEach(() => {
223 action = getAction('Delete');
224 });
225
226 it('should be disabled if no gateways', () => {
227 component.selection.selected = [
228 {
229 id: '-1'
230 }
231 ];
f91f0fd5 232 expect(action.disable(undefined)).toBe('Unavailable gateway(s)');
f6b5b4d7
TL
233 });
234
235 it('should be disabled if active sessions', () => {
236 component.selection.selected = [
237 {
238 id: '-1',
239 info: {
240 num_sessions: 1
241 }
242 }
243 ];
f91f0fd5 244 expect(action.disable(undefined)).toBe('Target has active sessions');
f6b5b4d7
TL
245 });
246
247 it('should be enabled if no active sessions', () => {
248 component.selection.selected = [
249 {
250 id: '-1',
251 info: {
252 num_sessions: 0
253 }
254 }
255 ];
256 expect(action.disable(undefined)).toBeFalsy();
f6b5b4d7
TL
257 });
258 });
259 });
260
9f95a23c
TL
261 it('should test all TableActions combinations', () => {
262 const permissionHelper: PermissionHelper = new PermissionHelper(component.permission);
263 const tableActions: TableActionsComponent = permissionHelper.setPermissionsAndGetActions(
264 component.tableActions
265 );
266
267 expect(tableActions).toEqual({
268 'create,update,delete': {
269 actions: ['Create', 'Edit', 'Delete'],
270 primary: { multiple: 'Create', executing: 'Edit', single: 'Edit', no: 'Create' }
271 },
272 'create,update': {
273 actions: ['Create', 'Edit'],
274 primary: { multiple: 'Create', executing: 'Edit', single: 'Edit', no: 'Create' }
275 },
276 'create,delete': {
277 actions: ['Create', 'Delete'],
278 primary: { multiple: 'Create', executing: 'Delete', single: 'Delete', no: 'Create' }
279 },
280 create: {
281 actions: ['Create'],
282 primary: { multiple: 'Create', executing: 'Create', single: 'Create', no: 'Create' }
283 },
284 'update,delete': {
285 actions: ['Edit', 'Delete'],
286 primary: { multiple: 'Edit', executing: 'Edit', single: 'Edit', no: 'Edit' }
287 },
288 update: {
289 actions: ['Edit'],
290 primary: { multiple: 'Edit', executing: 'Edit', single: 'Edit', no: 'Edit' }
291 },
292 delete: {
293 actions: ['Delete'],
294 primary: { multiple: 'Delete', executing: 'Delete', single: 'Delete', no: 'Delete' }
295 },
296 'no-permissions': {
297 actions: [],
298 primary: { multiple: '', executing: '', single: '', no: '' }
299 }
11fdf7f2
TL
300 });
301 });
302});