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