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