]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
66c69ee65ddd183b8827c8a8343660600bf5ca51
[ceph.git] /
1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, TestBed } from '@angular/core/testing';
3 import { By } from '@angular/platform-browser';
4 import { RouterTestingModule } from '@angular/router/testing';
5
6 import { ToastModule } from 'ng2-toastr';
7 import { BsModalRef } from 'ngx-bootstrap/modal';
8 import { of } from 'rxjs';
9
10 import {
11   configureTestBed,
12   FixtureHelper,
13   FormHelper,
14   i18nProviders
15 } from '../../../../testing/unit-test-helper';
16 import { ErasureCodeProfileService } from '../../../shared/api/erasure-code-profile.service';
17 import { ErasureCodeProfile } from '../../../shared/models/erasure-code-profile';
18 import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
19 import { PoolModule } from '../pool.module';
20 import { ErasureCodeProfileFormComponent } from './erasure-code-profile-form.component';
21
22 describe('ErasureCodeProfileFormComponent', () => {
23   let component: ErasureCodeProfileFormComponent;
24   let ecpService: ErasureCodeProfileService;
25   let fixture: ComponentFixture<ErasureCodeProfileFormComponent>;
26   let formHelper: FormHelper;
27   let fixtureHelper: FixtureHelper;
28   let data: {};
29
30   configureTestBed({
31     imports: [HttpClientTestingModule, RouterTestingModule, ToastModule.forRoot(), PoolModule],
32     providers: [ErasureCodeProfileService, BsModalRef, i18nProviders]
33   });
34
35   beforeEach(() => {
36     fixture = TestBed.createComponent(ErasureCodeProfileFormComponent);
37     fixtureHelper = new FixtureHelper(fixture);
38     component = fixture.componentInstance;
39     formHelper = new FormHelper(component.form);
40     ecpService = TestBed.get(ErasureCodeProfileService);
41     data = {
42       failure_domains: ['host', 'osd'],
43       plugins: ['isa', 'jerasure', 'shec', 'lrc'],
44       names: ['ecp1', 'ecp2'],
45       devices: ['ssd', 'hdd']
46     };
47     spyOn(ecpService, 'getInfo').and.callFake(() => of(data));
48     fixture.detectChanges();
49   });
50
51   it('should create', () => {
52     expect(component).toBeTruthy();
53   });
54
55   it('calls listing to get ecps on ngInit', () => {
56     expect(ecpService.getInfo).toHaveBeenCalled();
57     expect(component.names.length).toBe(2);
58   });
59
60   describe('form validation', () => {
61     it(`isn't valid if name is not set`, () => {
62       expect(component.form.invalid).toBeTruthy();
63       formHelper.setValue('name', 'someProfileName');
64       expect(component.form.valid).toBeTruthy();
65     });
66
67     it('sets name invalid', () => {
68       component.names = ['awesomeProfileName'];
69       formHelper.expectErrorChange('name', 'awesomeProfileName', 'uniqueName');
70       formHelper.expectErrorChange('name', 'some invalid text', 'pattern');
71       formHelper.expectErrorChange('name', null, 'required');
72     });
73
74     it('sets k to min error', () => {
75       formHelper.expectErrorChange('k', 0, 'min');
76     });
77
78     it('sets m to min error', () => {
79       formHelper.expectErrorChange('m', 0, 'min');
80     });
81
82     it(`should show all default form controls`, () => {
83       const showDefaults = (plugin) => {
84         formHelper.setValue('plugin', plugin);
85         fixtureHelper.expectIdElementsVisible(
86           [
87             'name',
88             'plugin',
89             'k',
90             'm',
91             'crushFailureDomain',
92             'crushRoot',
93             'crushDeviceClass',
94             'directory'
95           ],
96           true
97         );
98       };
99       showDefaults('jerasure');
100       showDefaults('shec');
101       showDefaults('lrc');
102       showDefaults('isa');
103     });
104
105     describe(`for 'jerasure' plugin (default)`, () => {
106       it(`requires 'm' and 'k'`, () => {
107         formHelper.expectErrorChange('k', null, 'required');
108         formHelper.expectErrorChange('m', null, 'required');
109       });
110
111       it(`should show 'packetSize' and 'technique'`, () => {
112         fixtureHelper.expectIdElementsVisible(['packetSize', 'technique'], true);
113       });
114
115       it(`should not show any other plugin specific form control`, () => {
116         fixtureHelper.expectIdElementsVisible(['c', 'l', 'crushLocality'], false);
117       });
118     });
119
120     describe(`for 'isa' plugin`, () => {
121       beforeEach(() => {
122         formHelper.setValue('plugin', 'isa');
123       });
124
125       it(`does not require 'm' and 'k'`, () => {
126         formHelper.setValue('k', null);
127         formHelper.expectValidChange('k', null);
128         formHelper.expectValidChange('m', null);
129       });
130
131       it(`should show 'technique'`, () => {
132         fixtureHelper.expectIdElementsVisible(['technique'], true);
133         expect(fixture.debugElement.query(By.css('#technique'))).toBeTruthy();
134       });
135
136       it(`should not show any other plugin specific form control`, () => {
137         fixtureHelper.expectIdElementsVisible(['c', 'l', 'crushLocality', 'packetSize'], false);
138       });
139     });
140
141     describe(`for 'lrc' plugin`, () => {
142       beforeEach(() => {
143         formHelper.setValue('plugin', 'lrc');
144       });
145
146       it(`requires 'm', 'l' and 'k'`, () => {
147         formHelper.expectErrorChange('k', null, 'required');
148         formHelper.expectErrorChange('m', null, 'required');
149       });
150
151       it(`should show 'l' and 'crushLocality'`, () => {
152         fixtureHelper.expectIdElementsVisible(['l', 'crushLocality'], true);
153       });
154
155       it(`should not show any other plugin specific form control`, () => {
156         fixtureHelper.expectIdElementsVisible(['c', 'packetSize', 'technique'], false);
157       });
158     });
159
160     describe(`for 'shec' plugin`, () => {
161       beforeEach(() => {
162         formHelper.setValue('plugin', 'shec');
163       });
164
165       it(`does not require 'm' and 'k'`, () => {
166         formHelper.expectValidChange('k', null);
167         formHelper.expectValidChange('m', null);
168       });
169
170       it(`should show 'c'`, () => {
171         fixtureHelper.expectIdElementsVisible(['c'], true);
172       });
173
174       it(`should not show any other plugin specific form control`, () => {
175         fixtureHelper.expectIdElementsVisible(
176           ['l', 'crushLocality', 'packetSize', 'technique'],
177           false
178         );
179       });
180     });
181   });
182
183   describe('submission', () => {
184     let ecp: ErasureCodeProfile;
185
186     const testCreation = () => {
187       fixture.detectChanges();
188       component.onSubmit();
189       expect(ecpService.create).toHaveBeenCalledWith(ecp);
190     };
191
192     beforeEach(() => {
193       ecp = new ErasureCodeProfile();
194       const taskWrapper = TestBed.get(TaskWrapperService);
195       spyOn(taskWrapper, 'wrapTaskAroundCall').and.callThrough();
196       spyOn(ecpService, 'create').and.stub();
197     });
198
199     describe(`'jerasure' usage`, () => {
200       beforeEach(() => {
201         ecp.name = 'jerasureProfile';
202       });
203
204       it('should be able to create a profile with only required fields', () => {
205         formHelper.setMultipleValues(ecp, true);
206         ecp.k = 4;
207         ecp.m = 2;
208         testCreation();
209       });
210
211       it(`does not create with missing 'k' or invalid form`, () => {
212         ecp.k = 0;
213         formHelper.setMultipleValues(ecp, true);
214         component.onSubmit();
215         expect(ecpService.create).not.toHaveBeenCalled();
216       });
217
218       it('should be able to create a profile with m, k, name, directory and packetSize', () => {
219         ecp.m = 3;
220         ecp.directory = '/different/ecp/path';
221         formHelper.setMultipleValues(ecp, true);
222         ecp.k = 4;
223         formHelper.setValue('packetSize', 8192, true);
224         ecp.packetsize = 8192;
225         testCreation();
226       });
227
228       it('should not send the profile with unsupported fields', () => {
229         formHelper.setMultipleValues(ecp, true);
230         ecp.k = 4;
231         ecp.m = 2;
232         formHelper.setValue('crushLocality', 'osd', true);
233         testCreation();
234       });
235     });
236
237     describe(`'isa' usage`, () => {
238       beforeEach(() => {
239         ecp.name = 'isaProfile';
240         ecp.plugin = 'isa';
241       });
242
243       it('should be able to create a profile with only plugin and name', () => {
244         formHelper.setMultipleValues(ecp, true);
245         testCreation();
246       });
247
248       it('should send profile with plugin, name, failure domain and technique only', () => {
249         ecp.technique = 'cauchy';
250         formHelper.setMultipleValues(ecp, true);
251         formHelper.setValue('crushFailureDomain', 'osd', true);
252         ecp['crush-failure-domain'] = 'osd';
253         testCreation();
254       });
255
256       it('should not send the profile with unsupported fields', () => {
257         formHelper.setMultipleValues(ecp, true);
258         formHelper.setValue('packetSize', 'osd', true);
259         testCreation();
260       });
261     });
262
263     describe(`'lrc' usage`, () => {
264       beforeEach(() => {
265         ecp.name = 'lreProfile';
266         ecp.plugin = 'lrc';
267       });
268
269       it('should be able to create a profile with only required fields', () => {
270         formHelper.setMultipleValues(ecp, true);
271         ecp.k = 4;
272         ecp.m = 2;
273         ecp.l = 3;
274         testCreation();
275       });
276
277       it('should send profile with all required fields and crush root and locality', () => {
278         ecp.l = 8;
279         formHelper.setMultipleValues(ecp, true);
280         ecp.k = 4;
281         ecp.m = 2;
282         formHelper.setValue('crushLocality', 'osd', true);
283         formHelper.setValue('crushRoot', 'rack', true);
284         ecp['crush-locality'] = 'osd';
285         ecp['crush-root'] = 'rack';
286         testCreation();
287       });
288
289       it('should not send the profile with unsupported fields', () => {
290         formHelper.setMultipleValues(ecp, true);
291         ecp.k = 4;
292         ecp.m = 2;
293         ecp.l = 3;
294         formHelper.setValue('c', 4, true);
295         testCreation();
296       });
297     });
298
299     describe(`'shec' usage`, () => {
300       beforeEach(() => {
301         ecp.name = 'shecProfile';
302         ecp.plugin = 'shec';
303       });
304
305       it('should be able to create a profile with only plugin and name', () => {
306         formHelper.setMultipleValues(ecp, true);
307         testCreation();
308       });
309
310       it('should send profile with plugin, name, c and crush device class only', () => {
311         ecp.c = 4;
312         formHelper.setMultipleValues(ecp, true);
313         formHelper.setValue('crushDeviceClass', 'ssd', true);
314         ecp['crush-device-class'] = 'ssd';
315         testCreation();
316       });
317
318       it('should not send the profile with unsupported fields', () => {
319         formHelper.setMultipleValues(ecp, true);
320         formHelper.setValue('l', 8, true);
321         testCreation();
322       });
323     });
324   });
325 });