]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
47c61ad120ba11f77e278e3f04e0d5fd2b02ab68
[ceph.git] /
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 });