]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-form/iscsi-target-form.component.spec.ts
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / block / iscsi-target-form / iscsi-target-form.component.spec.ts
CommitLineData
11fdf7f2
TL
1import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
2import { ComponentFixture, TestBed } from '@angular/core/testing';
3import { ReactiveFormsModule } from '@angular/forms';
4import { ActivatedRoute } from '@angular/router';
5import { RouterTestingModule } from '@angular/router/testing';
6
494da23a 7import { ToastrModule } from 'ngx-toastr';
11fdf7f2
TL
8
9import { ActivatedRouteStub } from '../../../../testing/activated-route-stub';
10import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
11import { SharedModule } from '../../../shared/shared.module';
12import { IscsiTargetFormComponent } from './iscsi-target-form.component';
13
14describe('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 },
81eedcae
TL
40 unsupported_rbd_features: {
41 'backstore:1': 0,
42 'backstore:2': 0
11fdf7f2
TL
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,
494da23a 133 ToastrModule.forRoot()
11fdf7f2
TL
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([
81eedcae 168 { description: '', name: 'rbd/disk_2', selected: false, enabled: true }
11fdf7f2
TL
169 ]);
170 });
171
172 it('should generate portals selectOptions', () => {
173 expect(component.portalsSelections).toEqual([
81eedcae
TL
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 }
11fdf7f2
TL
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' });
81eedcae 232 component.addGroup().patchValue({ name: 'group_2' });
11fdf7f2
TL
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([
81eedcae 251 [{ description: '', name: 'rbd/disk_2', selected: false, enabled: true }]
11fdf7f2
TL
252 ]);
253 expect(component.groupMembersSelections).toEqual([
81eedcae
TL
254 [{ description: '', name: 'iqn.initiator', selected: false, enabled: true }],
255 [{ description: '', name: 'iqn.initiator', selected: false, enabled: true }]
11fdf7f2
TL
256 ]);
257 });
258
259 it('should update data when changing an initiator name', () => {
260 expect(component.groupMembersSelections).toEqual([
81eedcae
TL
261 [{ description: '', name: 'iqn.initiator', selected: false, enabled: true }],
262 [{ description: '', name: 'iqn.initiator', selected: false, enabled: true }]
11fdf7f2
TL
263 ]);
264
265 component.initiators.controls[0].patchValue({
266 client_iqn: 'iqn.initiator_new'
267 });
268 component.updatedInitiatorSelector();
269
270 expect(component.groupMembersSelections).toEqual([
81eedcae
TL
271 [{ description: '', name: 'iqn.initiator_new', selected: false, enabled: true }],
272 [{ description: '', name: 'iqn.initiator_new', selected: false, enabled: true }]
11fdf7f2
TL
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 });
81eedcae 295 expect(component.groupMembersSelections).toEqual([[], []]);
11fdf7f2
TL
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 });
81eedcae
TL
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 });
11fdf7f2
TL
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});