]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.spec.ts
import 15.2.0 Octopus source
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / block / iscsi-target-form / iscsi-target-form.component.spec.ts
1 import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
2 import { ComponentFixture, TestBed } from '@angular/core/testing';
3 import { ReactiveFormsModule } from '@angular/forms';
4 import { ActivatedRoute } from '@angular/router';
5 import { RouterTestingModule } from '@angular/router/testing';
6
7 import { ToastrModule } from 'ngx-toastr';
8
9 import { ActivatedRouteStub } from '../../../../testing/activated-route-stub';
10 import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
11 import { SharedModule } from '../../../shared/shared.module';
12 import { IscsiTargetFormComponent } from './iscsi-target-form.component';
13
14 describe('IscsiTargetFormComponent', () => {
15 let component: IscsiTargetFormComponent;
16 let fixture: ComponentFixture<IscsiTargetFormComponent>;
17 let httpTesting: HttpTestingController;
18 let activatedRoute: ActivatedRouteStub;
19
20 const SETTINGS = {
21 config: { minimum_gateways: 2 },
22 disk_default_controls: {
23 'backstore:1': {
24 hw_max_sectors: 1024,
25 osd_op_timeout: 30
26 },
27 'backstore:2': {
28 qfull_timeout: 5
29 }
30 },
31 target_default_controls: {
32 cmdsn_depth: 128,
33 dataout_timeout: 20,
34 immediate_data: true
35 },
36 required_rbd_features: {
37 'backstore:1': 0,
38 'backstore:2': 0
39 },
40 unsupported_rbd_features: {
41 'backstore:1': 0,
42 'backstore:2': 0
43 },
44 backstores: ['backstore:1', 'backstore:2'],
45 default_backstore: 'backstore:1',
46 api_version: 1
47 };
48
49 const LIST_TARGET: any[] = [
50 {
51 target_iqn: 'iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw',
52 portals: [{ host: 'node1', ip: '192.168.100.201' }],
53 disks: [
54 {
55 pool: 'rbd',
56 image: 'disk_1',
57 controls: {},
58 backstore: 'backstore:1',
59 wwn: '64af6678-9694-4367-bacc-f8eb0baa'
60 }
61 ],
62 clients: [
63 {
64 client_iqn: 'iqn.1994-05.com.redhat:rh7-client',
65 luns: [{ pool: 'rbd', image: 'disk_1', lun: 0 }],
66 auth: {
67 user: 'myiscsiusername',
68 password: 'myiscsipassword',
69 mutual_user: null,
70 mutual_password: null
71 }
72 }
73 ],
74 groups: [],
75 target_controls: {}
76 }
77 ];
78
79 const PORTALS = [
80 { name: 'node1', ip_addresses: ['192.168.100.201', '10.0.2.15'] },
81 { name: 'node2', ip_addresses: ['192.168.100.202'] }
82 ];
83
84 const VERSION = {
85 ceph_iscsi_config_version: 11
86 };
87
88 const RBD_LIST: any[] = [
89 { status: 0, value: [], pool_name: 'ganesha' },
90 {
91 status: 0,
92 value: [
93 {
94 size: 96636764160,
95 obj_size: 4194304,
96 num_objs: 23040,
97 order: 22,
98 block_name_prefix: 'rbd_data.148162fb31a8',
99 name: 'disk_1',
100 id: '148162fb31a8',
101 pool_name: 'rbd',
102 features: 61,
103 features_name: ['deep-flatten', 'exclusive-lock', 'fast-diff', 'layering', 'object-map'],
104 timestamp: '2019-01-18T10:44:26Z',
105 stripe_count: 1,
106 stripe_unit: 4194304,
107 data_pool: null,
108 parent: null,
109 snapshots: [],
110 total_disk_usage: 0,
111 disk_usage: 0
112 },
113 {
114 size: 119185342464,
115 obj_size: 4194304,
116 num_objs: 28416,
117 order: 22,
118 block_name_prefix: 'rbd_data.14b292cee6cb',
119 name: 'disk_2',
120 id: '14b292cee6cb',
121 pool_name: 'rbd',
122 features: 61,
123 features_name: ['deep-flatten', 'exclusive-lock', 'fast-diff', 'layering', 'object-map'],
124 timestamp: '2019-01-18T10:45:56Z',
125 stripe_count: 1,
126 stripe_unit: 4194304,
127 data_pool: null,
128 parent: null,
129 snapshots: [],
130 total_disk_usage: 0,
131 disk_usage: 0
132 }
133 ],
134 pool_name: 'rbd'
135 }
136 ];
137
138 configureTestBed(
139 {
140 declarations: [IscsiTargetFormComponent],
141 imports: [
142 SharedModule,
143 ReactiveFormsModule,
144 HttpClientTestingModule,
145 RouterTestingModule,
146 ToastrModule.forRoot()
147 ],
148 providers: [
149 i18nProviders,
150 {
151 provide: ActivatedRoute,
152 useValue: new ActivatedRouteStub({ target_iqn: undefined })
153 }
154 ]
155 },
156 true
157 );
158
159 beforeEach(() => {
160 fixture = TestBed.createComponent(IscsiTargetFormComponent);
161 component = fixture.componentInstance;
162 httpTesting = TestBed.get(HttpTestingController);
163 activatedRoute = TestBed.get(ActivatedRoute);
164 fixture.detectChanges();
165
166 httpTesting.expectOne('ui-api/iscsi/settings').flush(SETTINGS);
167 httpTesting.expectOne('ui-api/iscsi/portals').flush(PORTALS);
168 httpTesting.expectOne('ui-api/iscsi/version').flush(VERSION);
169 httpTesting.expectOne('api/summary').flush({});
170 httpTesting.expectOne('api/block/image').flush(RBD_LIST);
171 httpTesting.expectOne('api/iscsi/target').flush(LIST_TARGET);
172 httpTesting.verify();
173 });
174
175 it('should create', () => {
176 expect(component).toBeTruthy();
177 });
178
179 it('should only show images not used in other targets', () => {
180 expect(component.imagesAll).toEqual([RBD_LIST[1]['value'][1]]);
181 expect(component.imagesSelections).toEqual([
182 { description: '', name: 'rbd/disk_2', selected: false, enabled: true }
183 ]);
184 });
185
186 it('should generate portals selectOptions', () => {
187 expect(component.portalsSelections).toEqual([
188 { description: '', name: 'node1:192.168.100.201', selected: false, enabled: true },
189 { description: '', name: 'node1:10.0.2.15', selected: false, enabled: true },
190 { description: '', name: 'node2:192.168.100.202', selected: false, enabled: true }
191 ]);
192 });
193
194 it('should create the form', () => {
195 expect(component.targetForm.value).toEqual({
196 disks: [],
197 groups: [],
198 initiators: [],
199 acl_enabled: false,
200 auth: {
201 password: '',
202 user: '',
203 mutual_password: '',
204 mutual_user: ''
205 },
206 portals: [],
207 target_controls: {},
208 target_iqn: component.targetForm.value.target_iqn
209 });
210 });
211
212 it('should prepare data when selecting an image', () => {
213 expect(component.imagesSettings).toEqual({});
214 component.onImageSelection({ option: { name: 'rbd/disk_2', selected: true } });
215 expect(component.imagesSettings).toEqual({
216 'rbd/disk_2': {
217 lun: 0,
218 backstore: 'backstore:1',
219 'backstore:1': {}
220 }
221 });
222 });
223
224 it('should clean data when removing an image', () => {
225 component.onImageSelection({ option: { name: 'rbd/disk_2', selected: true } });
226 component.addGroup();
227 component.groups.controls[0].patchValue({
228 group_id: 'foo',
229 disks: ['rbd/disk_2']
230 });
231
232 expect(component.groups.controls[0].value).toEqual({
233 disks: ['rbd/disk_2'],
234 group_id: 'foo',
235 members: []
236 });
237
238 component.onImageSelection({ option: { name: 'rbd/disk_2', selected: false } });
239
240 expect(component.groups.controls[0].value).toEqual({ disks: [], group_id: 'foo', members: [] });
241 expect(component.imagesSettings).toEqual({
242 'rbd/disk_2': {
243 lun: 0,
244 backstore: 'backstore:1',
245 'backstore:1': {}
246 }
247 });
248 });
249
250 describe('should test initiators', () => {
251 beforeEach(() => {
252 component.onImageSelection({ option: { name: 'rbd/disk_2', selected: true } });
253 component.targetForm.patchValue({ disks: ['rbd/disk_2'], acl_enabled: true });
254 component.addGroup().patchValue({ name: 'group_1' });
255 component.addGroup().patchValue({ name: 'group_2' });
256
257 component.addInitiator();
258 component.initiators.controls[0].patchValue({
259 client_iqn: 'iqn.initiator'
260 });
261 component.updatedInitiatorSelector();
262 });
263
264 it('should prepare data when creating an initiator', () => {
265 expect(component.initiators.controls.length).toBe(1);
266 expect(component.initiators.controls[0].value).toEqual({
267 auth: { mutual_password: '', mutual_user: '', password: '', user: '' },
268 cdIsInGroup: false,
269 client_iqn: 'iqn.initiator',
270 luns: []
271 });
272 expect(component.imagesInitiatorSelections).toEqual([
273 [{ description: '', name: 'rbd/disk_2', selected: false, enabled: true }]
274 ]);
275 expect(component.groupMembersSelections).toEqual([
276 [{ description: '', name: 'iqn.initiator', selected: false, enabled: true }],
277 [{ description: '', name: 'iqn.initiator', selected: false, enabled: true }]
278 ]);
279 });
280
281 it('should update data when changing an initiator name', () => {
282 expect(component.groupMembersSelections).toEqual([
283 [{ description: '', name: 'iqn.initiator', selected: false, enabled: true }],
284 [{ description: '', name: 'iqn.initiator', selected: false, enabled: true }]
285 ]);
286
287 component.initiators.controls[0].patchValue({
288 client_iqn: 'iqn.initiator_new'
289 });
290 component.updatedInitiatorSelector();
291
292 expect(component.groupMembersSelections).toEqual([
293 [{ description: '', name: 'iqn.initiator_new', selected: false, enabled: true }],
294 [{ description: '', name: 'iqn.initiator_new', selected: false, enabled: true }]
295 ]);
296 });
297
298 it('should clean data when removing an initiator', () => {
299 component.groups.controls[0].patchValue({
300 group_id: 'foo',
301 members: ['iqn.initiator']
302 });
303
304 expect(component.groups.controls[0].value).toEqual({
305 disks: [],
306 group_id: 'foo',
307 members: ['iqn.initiator']
308 });
309
310 component.removeInitiator(0);
311
312 expect(component.groups.controls[0].value).toEqual({
313 disks: [],
314 group_id: 'foo',
315 members: []
316 });
317 expect(component.groupMembersSelections).toEqual([[], []]);
318 expect(component.imagesInitiatorSelections).toEqual([]);
319 });
320
321 it('should remove images in the initiator when added in a group', () => {
322 component.initiators.controls[0].patchValue({
323 luns: ['rbd/disk_2']
324 });
325 expect(component.initiators.controls[0].value).toEqual({
326 auth: { mutual_password: '', mutual_user: '', password: '', user: '' },
327 cdIsInGroup: false,
328 client_iqn: 'iqn.initiator',
329 luns: ['rbd/disk_2']
330 });
331
332 component.addGroup();
333 component.groups.controls[0].patchValue({
334 group_id: 'foo',
335 members: ['iqn.initiator']
336 });
337 component.onGroupMemberSelection({
338 option: {
339 name: 'iqn.initiator',
340 selected: true
341 }
342 });
343
344 expect(component.initiators.controls[0].value).toEqual({
345 auth: { mutual_password: '', mutual_user: '', password: '', user: '' },
346 cdIsInGroup: true,
347 client_iqn: 'iqn.initiator',
348 luns: []
349 });
350 });
351
352 it('should disabled the initiator when selected', () => {
353 expect(component.groupMembersSelections).toEqual([
354 [{ description: '', enabled: true, name: 'iqn.initiator', selected: false }],
355 [{ description: '', enabled: true, name: 'iqn.initiator', selected: false }]
356 ]);
357
358 component.groupMembersSelections[0][0].selected = true;
359 component.onGroupMemberSelection({ option: { name: 'iqn.initiator', selected: true } });
360
361 expect(component.groupMembersSelections).toEqual([
362 [{ description: '', enabled: false, name: 'iqn.initiator', selected: true }],
363 [{ description: '', enabled: false, name: 'iqn.initiator', selected: false }]
364 ]);
365 });
366 });
367
368 describe('should submit request', () => {
369 beforeEach(() => {
370 component.onImageSelection({ option: { name: 'rbd/disk_2', selected: true } });
371 component.targetForm.patchValue({ disks: ['rbd/disk_2'], acl_enabled: true });
372 component.portals.setValue(['node1:192.168.100.201', 'node2:192.168.100.202']);
373 component.addInitiator().patchValue({
374 client_iqn: 'iqn.initiator'
375 });
376 component.addGroup().patchValue({
377 group_id: 'foo',
378 members: ['iqn.initiator'],
379 disks: ['rbd/disk_2']
380 });
381 });
382
383 it('should call update', () => {
384 activatedRoute.setParams({ target_iqn: 'iqn.iscsi' });
385 component.isEdit = true;
386 component.target_iqn = 'iqn.iscsi';
387
388 component.submit();
389
390 const req = httpTesting.expectOne('api/iscsi/target/iqn.iscsi');
391 expect(req.request.method).toBe('PUT');
392 expect(req.request.body).toEqual({
393 clients: [
394 {
395 auth: { mutual_password: '', mutual_user: '', password: '', user: '' },
396 client_iqn: 'iqn.initiator',
397 luns: []
398 }
399 ],
400 disks: [
401 {
402 backstore: 'backstore:1',
403 controls: {},
404 image: 'disk_2',
405 pool: 'rbd',
406 lun: 0,
407 wwn: undefined
408 }
409 ],
410 groups: [
411 { disks: [{ image: 'disk_2', pool: 'rbd' }], group_id: 'foo', members: ['iqn.initiator'] }
412 ],
413 new_target_iqn: component.targetForm.value.target_iqn,
414 portals: [
415 { host: 'node1', ip: '192.168.100.201' },
416 { host: 'node2', ip: '192.168.100.202' }
417 ],
418 target_controls: {},
419 target_iqn: component.target_iqn,
420 acl_enabled: true,
421 auth: {
422 password: '',
423 user: '',
424 mutual_password: '',
425 mutual_user: ''
426 }
427 });
428 });
429
430 it('should call create', () => {
431 component.submit();
432
433 const req = httpTesting.expectOne('api/iscsi/target');
434 expect(req.request.method).toBe('POST');
435 expect(req.request.body).toEqual({
436 clients: [
437 {
438 auth: { mutual_password: '', mutual_user: '', password: '', user: '' },
439 client_iqn: 'iqn.initiator',
440 luns: []
441 }
442 ],
443 disks: [
444 {
445 backstore: 'backstore:1',
446 controls: {},
447 image: 'disk_2',
448 pool: 'rbd',
449 lun: 0,
450 wwn: undefined
451 }
452 ],
453 groups: [
454 {
455 disks: [{ image: 'disk_2', pool: 'rbd' }],
456 group_id: 'foo',
457 members: ['iqn.initiator']
458 }
459 ],
460 portals: [
461 { host: 'node1', ip: '192.168.100.201' },
462 { host: 'node2', ip: '192.168.100.202' }
463 ],
464 target_controls: {},
465 target_iqn: component.targetForm.value.target_iqn,
466 acl_enabled: true,
467 auth: {
468 password: '',
469 user: '',
470 mutual_password: '',
471 mutual_user: ''
472 }
473 });
474 });
475
476 it('should call create with acl_enabled disabled', () => {
477 component.targetForm.patchValue({ acl_enabled: false });
478 component.submit();
479
480 const req = httpTesting.expectOne('api/iscsi/target');
481 expect(req.request.method).toBe('POST');
482 expect(req.request.body).toEqual({
483 clients: [],
484 disks: [
485 {
486 backstore: 'backstore:1',
487 controls: {},
488 image: 'disk_2',
489 pool: 'rbd',
490 lun: 0,
491 wwn: undefined
492 }
493 ],
494 groups: [],
495 acl_enabled: false,
496 auth: {
497 password: '',
498 user: '',
499 mutual_password: '',
500 mutual_user: ''
501 },
502 portals: [
503 { host: 'node1', ip: '192.168.100.201' },
504 { host: 'node2', ip: '192.168.100.202' }
505 ],
506 target_controls: {},
507 target_iqn: component.targetForm.value.target_iqn
508 });
509 });
510 });
511 });