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