]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
7d3a57fad2337502509bb054f9be54113fc4fb71
[ceph-ci.git] /
1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, TestBed } from '@angular/core/testing';
3 import { ReactiveFormsModule } from '@angular/forms';
4 import { By } from '@angular/platform-browser';
5 import { RouterTestingModule } from '@angular/router/testing';
6
7 import { NgbActiveModal, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
8 import _ from 'lodash';
9 import { ToastrModule } from 'ngx-toastr';
10 import { of } from 'rxjs';
11
12 import { CephServiceService } from '~/app/shared/api/ceph-service.service';
13 import { PaginateObservable } from '~/app/shared/api/paginate.model';
14 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
15 import { SharedModule } from '~/app/shared/shared.module';
16 import { configureTestBed, FormHelper } from '~/testing/unit-test-helper';
17 import { ServiceFormComponent } from './service-form.component';
18
19 describe('ServiceFormComponent', () => {
20   let component: ServiceFormComponent;
21   let fixture: ComponentFixture<ServiceFormComponent>;
22   let cephServiceService: CephServiceService;
23   let form: CdFormGroup;
24   let formHelper: FormHelper;
25
26   configureTestBed({
27     declarations: [ServiceFormComponent],
28     providers: [NgbActiveModal],
29     imports: [
30       HttpClientTestingModule,
31       NgbTypeaheadModule,
32       ReactiveFormsModule,
33       RouterTestingModule,
34       SharedModule,
35       ToastrModule.forRoot()
36     ]
37   });
38
39   beforeEach(() => {
40     fixture = TestBed.createComponent(ServiceFormComponent);
41     component = fixture.componentInstance;
42     component.ngOnInit();
43     form = component.serviceForm;
44     formHelper = new FormHelper(form);
45     fixture.detectChanges();
46   });
47
48   it('should create', () => {
49     expect(component).toBeTruthy();
50   });
51
52   describe('should test form', () => {
53     beforeEach(() => {
54       cephServiceService = TestBed.inject(CephServiceService);
55       spyOn(cephServiceService, 'create').and.stub();
56     });
57
58     it('should test placement (host)', () => {
59       formHelper.setValue('service_type', 'crash');
60       formHelper.setValue('placement', 'hosts');
61       formHelper.setValue('hosts', ['mgr0', 'mon0', 'osd0']);
62       formHelper.setValue('count', 2);
63       component.onSubmit();
64       expect(cephServiceService.create).toHaveBeenCalledWith({
65         service_type: 'crash',
66         placement: {
67           hosts: ['mgr0', 'mon0', 'osd0'],
68           count: 2
69         },
70         unmanaged: false
71       });
72     });
73
74     it('should test placement (label)', () => {
75       formHelper.setValue('service_type', 'mgr');
76       formHelper.setValue('placement', 'label');
77       formHelper.setValue('label', 'foo');
78       component.onSubmit();
79       expect(cephServiceService.create).toHaveBeenCalledWith({
80         service_type: 'mgr',
81         placement: {
82           label: 'foo'
83         },
84         unmanaged: false
85       });
86     });
87
88     it('should submit valid count', () => {
89       formHelper.setValue('count', 1);
90       component.onSubmit();
91       formHelper.expectValid('count');
92     });
93
94     it('should submit invalid count (1)', () => {
95       formHelper.setValue('count', 0);
96       component.onSubmit();
97       formHelper.expectError('count', 'min');
98     });
99
100     it('should submit invalid count (2)', () => {
101       formHelper.setValue('count', 'abc');
102       component.onSubmit();
103       formHelper.expectError('count', 'pattern');
104     });
105
106     it('should test unmanaged', () => {
107       formHelper.setValue('service_type', 'mgr');
108       formHelper.setValue('service_id', 'svc');
109       formHelper.setValue('placement', 'label');
110       formHelper.setValue('label', 'bar');
111       formHelper.setValue('unmanaged', true);
112       component.onSubmit();
113       expect(cephServiceService.create).toHaveBeenCalledWith({
114         service_type: 'mgr',
115         service_id: 'svc',
116         placement: {},
117         unmanaged: true
118       });
119     });
120
121     it('should test various services', () => {
122       _.forEach(
123         ['alertmanager', 'crash', 'mds', 'mgr', 'mon', 'node-exporter', 'prometheus', 'rbd-mirror'],
124         (serviceType) => {
125           formHelper.setValue('service_type', serviceType);
126           component.onSubmit();
127           expect(cephServiceService.create).toHaveBeenCalledWith({
128             service_type: serviceType,
129             placement: {},
130             unmanaged: false
131           });
132         }
133       );
134     });
135
136     describe('should test service grafana', () => {
137       beforeEach(() => {
138         formHelper.setValue('service_type', 'grafana');
139       });
140
141       it('should sumbit grafana', () => {
142         component.onSubmit();
143         expect(cephServiceService.create).toHaveBeenCalledWith({
144           service_type: 'grafana',
145           placement: {},
146           unmanaged: false,
147           initial_admin_password: null,
148           port: null
149         });
150       });
151
152       it('should sumbit grafana with custom port and initial password', () => {
153         formHelper.setValue('grafana_port', 1234);
154         formHelper.setValue('grafana_admin_password', 'foo');
155         component.onSubmit();
156         expect(cephServiceService.create).toHaveBeenCalledWith({
157           service_type: 'grafana',
158           placement: {},
159           unmanaged: false,
160           initial_admin_password: 'foo',
161           port: 1234
162         });
163       });
164     });
165
166     describe('should test service nfs', () => {
167       beforeEach(() => {
168         formHelper.setValue('service_type', 'nfs');
169       });
170
171       it('should submit nfs', () => {
172         component.onSubmit();
173         expect(cephServiceService.create).toHaveBeenCalledWith({
174           service_type: 'nfs',
175           placement: {},
176           unmanaged: false
177         });
178       });
179     });
180
181     describe('should test service rgw', () => {
182       beforeEach(() => {
183         formHelper.setValue('service_type', 'rgw');
184         formHelper.setValue('service_id', 'svc');
185       });
186
187       it('should test rgw valid service id', () => {
188         formHelper.setValue('service_id', 'svc.realm.zone');
189         formHelper.expectValid('service_id');
190         formHelper.setValue('service_id', 'svc');
191         formHelper.expectValid('service_id');
192       });
193
194       it('should submit rgw with realm, zonegroup and zone', () => {
195         formHelper.setValue('service_id', 'svc');
196         formHelper.setValue('realm_name', 'my-realm');
197         formHelper.setValue('zone_name', 'my-zone');
198         formHelper.setValue('zonegroup_name', 'my-zonegroup');
199         component.onSubmit();
200         expect(cephServiceService.create).toHaveBeenCalledWith({
201           service_type: 'rgw',
202           service_id: 'svc',
203           rgw_realm: 'my-realm',
204           rgw_zone: 'my-zone',
205           rgw_zonegroup: 'my-zonegroup',
206           placement: {},
207           unmanaged: false,
208           ssl: false
209         });
210       });
211
212       it('should submit rgw with port and ssl enabled', () => {
213         formHelper.setValue('rgw_frontend_port', 1234);
214         formHelper.setValue('ssl', true);
215         component.onSubmit();
216         expect(cephServiceService.create).toHaveBeenCalledWith({
217           service_type: 'rgw',
218           service_id: 'svc',
219           rgw_realm: null,
220           rgw_zone: null,
221           rgw_zonegroup: null,
222           placement: {},
223           unmanaged: false,
224           rgw_frontend_port: 1234,
225           rgw_frontend_ssl_certificate: '',
226           ssl: true
227         });
228       });
229
230       it('should submit valid rgw port (1)', () => {
231         formHelper.setValue('rgw_frontend_port', 1);
232         component.onSubmit();
233         formHelper.expectValid('rgw_frontend_port');
234       });
235
236       it('should submit valid rgw port (2)', () => {
237         formHelper.setValue('rgw_frontend_port', 65535);
238         component.onSubmit();
239         formHelper.expectValid('rgw_frontend_port');
240       });
241
242       it('should submit invalid rgw port (1)', () => {
243         formHelper.setValue('rgw_frontend_port', 0);
244         fixture.detectChanges();
245         formHelper.expectError('rgw_frontend_port', 'min');
246       });
247
248       it('should submit invalid rgw port (2)', () => {
249         formHelper.setValue('rgw_frontend_port', 65536);
250         fixture.detectChanges();
251         formHelper.expectError('rgw_frontend_port', 'max');
252       });
253
254       it('should submit invalid rgw port (3)', () => {
255         formHelper.setValue('rgw_frontend_port', 'abc');
256         component.onSubmit();
257         formHelper.expectError('rgw_frontend_port', 'pattern');
258       });
259
260       it('should submit rgw w/o port', () => {
261         formHelper.setValue('ssl', false);
262         component.onSubmit();
263         expect(cephServiceService.create).toHaveBeenCalledWith({
264           service_type: 'rgw',
265           service_id: 'svc',
266           rgw_realm: null,
267           rgw_zone: null,
268           rgw_zonegroup: null,
269           placement: {},
270           unmanaged: false,
271           ssl: false
272         });
273       });
274
275       it('should not show private key field', () => {
276         formHelper.setValue('ssl', true);
277         fixture.detectChanges();
278         const ssl_key = fixture.debugElement.query(By.css('#ssl_key'));
279         expect(ssl_key).toBeNull();
280       });
281
282       it('should test .pem file', () => {
283         const pemCert = `
284 -----BEGIN CERTIFICATE-----
285 iJ5IbgzlKPssdYwuAEI3yPZxX/g5vKBrgcyD3LttLL/DlElq/1xCnwVrv7WROSNu
286 -----END CERTIFICATE-----
287 -----BEGIN CERTIFICATE-----
288 mn/S7BNBEC7AGe5ajmN+8hBTGdACUXe8rwMNrtTy/MwBZ0VpJsAAjJh+aptZh5yB
289 -----END CERTIFICATE-----
290 -----BEGIN RSA PRIVATE KEY-----
291 x4Ea7kGVgx9kWh5XjWz9wjZvY49UKIT5ppIAWPMbLl3UpfckiuNhTA==
292 -----END RSA PRIVATE KEY-----`;
293         formHelper.setValue('ssl', true);
294         formHelper.setValue('ssl_cert', pemCert);
295         fixture.detectChanges();
296         formHelper.expectValid('ssl_cert');
297       });
298     });
299
300     describe('should test service iscsi', () => {
301       beforeEach(() => {
302         formHelper.setValue('service_type', 'iscsi');
303         formHelper.setValue('pool', 'xyz');
304         formHelper.setValue('api_user', 'user');
305         formHelper.setValue('api_password', 'password');
306         formHelper.setValue('ssl', false);
307       });
308
309       it('should submit iscsi', () => {
310         component.onSubmit();
311         expect(cephServiceService.create).toHaveBeenCalledWith({
312           service_type: 'iscsi',
313           placement: {},
314           unmanaged: false,
315           pool: 'xyz',
316           api_user: 'user',
317           api_password: 'password',
318           api_secure: false
319         });
320       });
321
322       it('should submit iscsi with trusted ips', () => {
323         formHelper.setValue('ssl', true);
324         formHelper.setValue('trusted_ip_list', ' 172.16.0.5, 192.1.1.10  ');
325         component.onSubmit();
326         expect(cephServiceService.create).toHaveBeenCalledWith({
327           service_type: 'iscsi',
328           placement: {},
329           unmanaged: false,
330           pool: 'xyz',
331           api_user: 'user',
332           api_password: 'password',
333           api_secure: true,
334           ssl_cert: '',
335           ssl_key: '',
336           trusted_ip_list: '172.16.0.5, 192.1.1.10'
337         });
338       });
339
340       it('should submit iscsi with port', () => {
341         formHelper.setValue('api_port', 456);
342         component.onSubmit();
343         expect(cephServiceService.create).toHaveBeenCalledWith({
344           service_type: 'iscsi',
345           placement: {},
346           unmanaged: false,
347           pool: 'xyz',
348           api_user: 'user',
349           api_password: 'password',
350           api_secure: false,
351           api_port: 456
352         });
353       });
354
355       it('should submit valid iscsi port (1)', () => {
356         formHelper.setValue('api_port', 1);
357         component.onSubmit();
358         formHelper.expectValid('api_port');
359       });
360
361       it('should submit valid iscsi port (2)', () => {
362         formHelper.setValue('api_port', 65535);
363         component.onSubmit();
364         formHelper.expectValid('api_port');
365       });
366
367       it('should submit invalid iscsi port (1)', () => {
368         formHelper.setValue('api_port', 0);
369         fixture.detectChanges();
370         formHelper.expectError('api_port', 'min');
371       });
372
373       it('should submit invalid iscsi port (2)', () => {
374         formHelper.setValue('api_port', 65536);
375         fixture.detectChanges();
376         formHelper.expectError('api_port', 'max');
377       });
378
379       it('should submit invalid iscsi port (3)', () => {
380         formHelper.setValue('api_port', 'abc');
381         component.onSubmit();
382         formHelper.expectError('api_port', 'pattern');
383       });
384
385       it('should throw error when there is no pool', () => {
386         formHelper.expectErrorChange('pool', '', 'required');
387       });
388     });
389
390     describe('should test service nvmeof', () => {
391       beforeEach(() => {
392         formHelper.setValue('service_type', 'nvmeof');
393         formHelper.setValue('service_id', 'svc');
394         formHelper.setValue('pool', 'xyz');
395         formHelper.setValue('group', 'abc');
396       });
397
398       it('should submit nvmeof', () => {
399         component.onSubmit();
400         expect(cephServiceService.create).toHaveBeenCalledWith({
401           service_type: 'nvmeof',
402           service_id: 'svc',
403           placement: {},
404           unmanaged: false,
405           pool: 'xyz',
406           group: 'abc'
407         });
408       });
409
410       it('should throw error when there is no service id', () => {
411         formHelper.expectErrorChange('service_id', '', 'required');
412       });
413
414       it('should throw error when there is no pool', () => {
415         formHelper.expectErrorChange('pool', '', 'required');
416       });
417
418       it('should throw error when there is no group', () => {
419         formHelper.expectErrorChange('group', '', 'required');
420       });
421     });
422
423     describe('should test service smb', () => {
424       beforeEach(() => {
425         formHelper.setValue('service_type', 'smb');
426         formHelper.setValue('service_id', 'foo');
427         formHelper.setValue('cluster_id', 'cluster_foo');
428         formHelper.setValue('config_uri', 'rados://.smb/foo/scc.toml');
429       });
430
431       it('should submit smb', () => {
432         component.onSubmit();
433         expect(cephServiceService.create).toHaveBeenCalledWith({
434           service_type: 'smb',
435           placement: {},
436           unmanaged: false,
437           service_id: 'foo',
438           cluster_id: 'cluster_foo',
439           config_uri: 'rados://.smb/foo/scc.toml'
440         });
441       });
442     });
443
444     describe('should test service ingress', () => {
445       beforeEach(() => {
446         formHelper.setValue('service_type', 'ingress');
447         formHelper.setValue('backend_service', 'rgw.foo');
448         formHelper.setValue('virtual_ip', '192.168.20.1/24');
449         formHelper.setValue('ssl', false);
450       });
451
452       it('should submit ingress', () => {
453         component.onSubmit();
454         expect(cephServiceService.create).toHaveBeenCalledWith({
455           service_type: 'ingress',
456           placement: {},
457           unmanaged: false,
458           backend_service: 'rgw.foo',
459           service_id: 'rgw.foo',
460           virtual_ip: '192.168.20.1/24',
461           virtual_interface_networks: null,
462           ssl: false
463         });
464       });
465
466       it('should pre-populate the service id', () => {
467         component.prePopulateId();
468         const prePopulatedID = component.serviceForm.getValue('service_id');
469         expect(prePopulatedID).toBe('rgw.foo');
470       });
471
472       it('should submit valid frontend and monitor port', () => {
473         // min value
474         formHelper.setValue('frontend_port', 1);
475         formHelper.setValue('monitor_port', 1);
476         fixture.detectChanges();
477         formHelper.expectValid('frontend_port');
478         formHelper.expectValid('monitor_port');
479
480         // max value
481         formHelper.setValue('frontend_port', 65535);
482         formHelper.setValue('monitor_port', 65535);
483         fixture.detectChanges();
484         formHelper.expectValid('frontend_port');
485         formHelper.expectValid('monitor_port');
486       });
487
488       it('should submit invalid frontend and monitor port', () => {
489         // min
490         formHelper.setValue('frontend_port', 0);
491         formHelper.setValue('monitor_port', 0);
492         fixture.detectChanges();
493         formHelper.expectError('frontend_port', 'min');
494         formHelper.expectError('monitor_port', 'min');
495
496         // max
497         formHelper.setValue('frontend_port', 65536);
498         formHelper.setValue('monitor_port', 65536);
499         fixture.detectChanges();
500         formHelper.expectError('frontend_port', 'max');
501         formHelper.expectError('monitor_port', 'max');
502
503         // pattern
504         formHelper.setValue('frontend_port', 'abc');
505         formHelper.setValue('monitor_port', 'abc');
506         component.onSubmit();
507         formHelper.expectError('frontend_port', 'pattern');
508         formHelper.expectError('monitor_port', 'pattern');
509       });
510
511       it('should not show private key field with ssl enabled', () => {
512         formHelper.setValue('ssl', true);
513         fixture.detectChanges();
514         const ssl_key = fixture.debugElement.query(By.css('#ssl_key'));
515         expect(ssl_key).toBeNull();
516       });
517
518       it('should test .pem file with ssl enabled', () => {
519         const pemCert = `
520 -----BEGIN CERTIFICATE-----
521 iJ5IbgzlKPssdYwuAEI3yPZxX/g5vKBrgcyD3LttLL/DlElq/1xCnwVrv7WROSNu
522 -----END CERTIFICATE-----
523 -----BEGIN CERTIFICATE-----
524 mn/S7BNBEC7AGe5ajmN+8hBTGdACUXe8rwMNrtTy/MwBZ0VpJsAAjJh+aptZh5yB
525 -----END CERTIFICATE-----
526 -----BEGIN RSA PRIVATE KEY-----
527 x4Ea7kGVgx9kWh5XjWz9wjZvY49UKIT5ppIAWPMbLl3UpfckiuNhTA==
528 -----END RSA PRIVATE KEY-----`;
529         formHelper.setValue('ssl', true);
530         formHelper.setValue('ssl_cert', pemCert);
531         fixture.detectChanges();
532         formHelper.expectValid('ssl_cert');
533       });
534     });
535
536     describe('should test service snmp-gateway', () => {
537       beforeEach(() => {
538         formHelper.setValue('service_type', 'snmp-gateway');
539         formHelper.setValue('snmp_destination', '192.168.20.1:8443');
540       });
541
542       it('should test snmp-gateway service with V2c', () => {
543         formHelper.setValue('snmp_version', 'V2c');
544         formHelper.setValue('snmp_community', 'public');
545         component.onSubmit();
546         expect(cephServiceService.create).toHaveBeenCalledWith({
547           service_type: 'snmp-gateway',
548           placement: {},
549           unmanaged: false,
550           snmp_version: 'V2c',
551           snmp_destination: '192.168.20.1:8443',
552           credentials: {
553             snmp_community: 'public'
554           }
555         });
556       });
557
558       it('should test snmp-gateway service with V3', () => {
559         formHelper.setValue('snmp_version', 'V3');
560         formHelper.setValue('engine_id', '800C53F00000');
561         formHelper.setValue('auth_protocol', 'SHA');
562         formHelper.setValue('privacy_protocol', 'DES');
563         formHelper.setValue('snmp_v3_auth_username', 'testuser');
564         formHelper.setValue('snmp_v3_auth_password', 'testpass');
565         formHelper.setValue('snmp_v3_priv_password', 'testencrypt');
566         component.onSubmit();
567         expect(cephServiceService.create).toHaveBeenCalledWith({
568           service_type: 'snmp-gateway',
569           placement: {},
570           unmanaged: false,
571           snmp_version: 'V3',
572           snmp_destination: '192.168.20.1:8443',
573           engine_id: '800C53F00000',
574           auth_protocol: 'SHA',
575           privacy_protocol: 'DES',
576           credentials: {
577             snmp_v3_auth_username: 'testuser',
578             snmp_v3_auth_password: 'testpass',
579             snmp_v3_priv_password: 'testencrypt'
580           }
581         });
582       });
583
584       it('should submit invalid snmp destination', () => {
585         formHelper.setValue('snmp_version', 'V2c');
586         formHelper.setValue('snmp_destination', '192.168.20.1');
587         formHelper.setValue('snmp_community', 'public');
588         formHelper.expectError('snmp_destination', 'snmpDestinationPattern');
589       });
590
591       it('should submit invalid snmp engine id', () => {
592         formHelper.setValue('snmp_version', 'V3');
593         formHelper.setValue('snmp_destination', '192.168.20.1');
594         formHelper.setValue('engine_id', 'AABBCCDDE');
595         formHelper.setValue('auth_protocol', 'SHA');
596         formHelper.setValue('privacy_protocol', 'DES');
597         formHelper.setValue('snmp_v3_auth_username', 'testuser');
598         formHelper.setValue('snmp_v3_auth_password', 'testpass');
599
600         formHelper.expectError('engine_id', 'snmpEngineIdPattern');
601       });
602     });
603
604     describe('should test service mds', () => {
605       beforeEach(() => {
606         formHelper.setValue('service_type', 'mds');
607         const paginate_obs = new PaginateObservable<any>(of({}));
608         spyOn(cephServiceService, 'list').and.returnValue(paginate_obs);
609       });
610
611       it('should test mds valid service id', () => {
612         formHelper.setValue('service_id', 'svc123');
613         formHelper.expectValid('service_id');
614         formHelper.setValue('service_id', 'svc_id-1');
615         formHelper.expectValid('service_id');
616       });
617
618       it('should test mds invalid service id', () => {
619         formHelper.setValue('service_id', '123');
620         formHelper.expectError('service_id', 'mdsPattern');
621         formHelper.setValue('service_id', '123svc');
622         formHelper.expectError('service_id', 'mdsPattern');
623         formHelper.setValue('service_id', 'svc#1');
624         formHelper.expectError('service_id', 'mdsPattern');
625       });
626     });
627
628     describe('check edit fields', () => {
629       beforeEach(() => {
630         component.editing = true;
631       });
632
633       it('should check whether edit field is correctly loaded', () => {
634         const paginate_obs = new PaginateObservable<any>(of({}));
635         const cephServiceSpy = spyOn(cephServiceService, 'list').and.returnValue(paginate_obs);
636         component.ngOnInit();
637         expect(cephServiceSpy).toBeCalledTimes(2);
638         expect(component.action).toBe('Edit');
639         const serviceType = fixture.debugElement.query(By.css('#service_type')).nativeElement;
640         const serviceId = fixture.debugElement.query(By.css('#service_id')).nativeElement;
641         expect(serviceType.disabled).toBeTruthy();
642         expect(serviceId.disabled).toBeTruthy();
643       });
644
645       it('should not edit pools for nvmeof service', () => {
646         component.serviceType = 'nvmeof';
647         formHelper.setValue('service_type', 'nvmeof');
648         component.ngOnInit();
649         fixture.detectChanges();
650         const poolId = fixture.debugElement.query(By.css('#pool')).nativeElement;
651         expect(poolId.disabled).toBeTruthy();
652       });
653     });
654   });
655 });