]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-recv-speed-modal/osd-recv-speed-modal.component.spec.ts
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / cluster / osd / osd-recv-speed-modal / osd-recv-speed-modal.component.spec.ts
1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, TestBed } from '@angular/core/testing';
3 import { ReactiveFormsModule } from '@angular/forms';
4 import { RouterTestingModule } from '@angular/router/testing';
5
6 import * as _ from 'lodash';
7 import { BsModalRef, ModalModule } from 'ngx-bootstrap/modal';
8 import { ToastrModule } from 'ngx-toastr';
9 import { of as observableOf } from 'rxjs';
10
11 import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper';
12 import { ConfigurationService } from '../../../../shared/api/configuration.service';
13 import { SharedModule } from '../../../../shared/shared.module';
14 import { OsdRecvSpeedModalComponent } from './osd-recv-speed-modal.component';
15
16 describe('OsdRecvSpeedModalComponent', () => {
17 let component: OsdRecvSpeedModalComponent;
18 let fixture: ComponentFixture<OsdRecvSpeedModalComponent>;
19 let configurationService: ConfigurationService;
20
21 configureTestBed({
22 imports: [
23 HttpClientTestingModule,
24 ModalModule.forRoot(),
25 ReactiveFormsModule,
26 RouterTestingModule,
27 SharedModule,
28 ToastrModule.forRoot()
29 ],
30 declarations: [OsdRecvSpeedModalComponent],
31 providers: [BsModalRef, i18nProviders]
32 });
33
34 let configOptions = [];
35
36 beforeEach(() => {
37 fixture = TestBed.createComponent(OsdRecvSpeedModalComponent);
38 component = fixture.componentInstance;
39 fixture.detectChanges();
40 configurationService = TestBed.get(ConfigurationService);
41 configOptions = [
42 {
43 name: 'osd_max_backfills',
44 desc: '',
45 type: 'uint',
46 default: 1
47 },
48 {
49 name: 'osd_recovery_max_active',
50 desc: '',
51 type: 'uint',
52 default: 3
53 },
54 {
55 name: 'osd_recovery_max_single_start',
56 desc: '',
57 type: 'uint',
58 default: 1
59 },
60 {
61 name: 'osd_recovery_sleep',
62 desc: 'Time in seconds to sleep before next recovery or backfill op',
63 type: 'float',
64 default: 0
65 }
66 ];
67 spyOn(configurationService, 'filter').and.returnValue(observableOf(configOptions));
68 });
69
70 it('should create', () => {
71 expect(component).toBeTruthy();
72 });
73
74 describe('ngOnInit', () => {
75 let setPriority;
76 let setValidators;
77
78 beforeEach(() => {
79 setPriority = spyOn(component, 'setPriority').and.callThrough();
80 setValidators = spyOn(component, 'setValidators').and.callThrough();
81 component.ngOnInit();
82 });
83
84 it('should call setValidators', () => {
85 expect(setValidators).toHaveBeenCalled();
86 });
87
88 it('should get and set priority correctly', () => {
89 const defaultPriority = _.find(component.priorities, (p) => {
90 return _.isEqual(p.name, 'default');
91 });
92 expect(setPriority).toHaveBeenCalledWith(defaultPriority);
93 });
94
95 it('should set descriptions correctly', () => {
96 expect(component.priorityAttrs['osd_max_backfills'].desc).toBe('');
97 expect(component.priorityAttrs['osd_recovery_max_active'].desc).toBe('');
98 expect(component.priorityAttrs['osd_recovery_max_single_start'].desc).toBe('');
99 expect(component.priorityAttrs['osd_recovery_sleep'].desc).toBe(
100 'Time in seconds to sleep before next recovery or backfill op'
101 );
102 });
103 });
104
105 describe('setPriority', () => {
106 it('should prepare the form for a custom priority', () => {
107 const customPriority = {
108 name: 'custom',
109 text: 'Custom',
110 values: {
111 osd_max_backfills: 1,
112 osd_recovery_max_active: 4,
113 osd_recovery_max_single_start: 1,
114 osd_recovery_sleep: 1
115 }
116 };
117
118 component.setPriority(customPriority);
119
120 const customInPriorities = _.find(component.priorities, (p) => {
121 return p.name === 'custom';
122 });
123
124 expect(customInPriorities).not.toBeNull();
125 expect(component.osdRecvSpeedForm.getValue('priority')).toBe('custom');
126 expect(component.osdRecvSpeedForm.getValue('osd_max_backfills')).toBe(1);
127 expect(component.osdRecvSpeedForm.getValue('osd_recovery_max_active')).toBe(4);
128 expect(component.osdRecvSpeedForm.getValue('osd_recovery_max_single_start')).toBe(1);
129 expect(component.osdRecvSpeedForm.getValue('osd_recovery_sleep')).toBe(1);
130 });
131
132 it('should prepare the form for a none custom priority', () => {
133 const lowPriority = {
134 name: 'low',
135 text: 'Low',
136 values: {
137 osd_max_backfills: 1,
138 osd_recovery_max_active: 1,
139 osd_recovery_max_single_start: 1,
140 osd_recovery_sleep: 0.5
141 }
142 };
143
144 component.setPriority(lowPriority);
145
146 const customInPriorities = _.find(component.priorities, (p) => {
147 return p.name === 'custom';
148 });
149
150 expect(customInPriorities).toBeUndefined();
151 expect(component.osdRecvSpeedForm.getValue('priority')).toBe('low');
152 expect(component.osdRecvSpeedForm.getValue('osd_max_backfills')).toBe(1);
153 expect(component.osdRecvSpeedForm.getValue('osd_recovery_max_active')).toBe(1);
154 expect(component.osdRecvSpeedForm.getValue('osd_recovery_max_single_start')).toBe(1);
155 expect(component.osdRecvSpeedForm.getValue('osd_recovery_sleep')).toBe(0.5);
156 });
157 });
158
159 describe('detectPriority', () => {
160 const configOptionsLow = {
161 osd_max_backfills: 1,
162 osd_recovery_max_active: 1,
163 osd_recovery_max_single_start: 1,
164 osd_recovery_sleep: 0.5
165 };
166
167 const configOptionsDefault = {
168 osd_max_backfills: 1,
169 osd_recovery_max_active: 3,
170 osd_recovery_max_single_start: 1,
171 osd_recovery_sleep: 0
172 };
173
174 const configOptionsHigh = {
175 osd_max_backfills: 4,
176 osd_recovery_max_active: 4,
177 osd_recovery_max_single_start: 4,
178 osd_recovery_sleep: 0
179 };
180
181 const configOptionsCustom = {
182 osd_max_backfills: 1,
183 osd_recovery_max_active: 2,
184 osd_recovery_max_single_start: 1,
185 osd_recovery_sleep: 0
186 };
187
188 const configOptionsIncomplete = {
189 osd_max_backfills: 1,
190 osd_recovery_max_single_start: 1,
191 osd_recovery_sleep: 0
192 };
193
194 it('should return priority "low" if the config option values have been set accordingly', () => {
195 component.detectPriority(configOptionsLow, (priority) => {
196 expect(priority.name).toBe('low');
197 });
198 expect(component.osdRecvSpeedForm.getValue('customizePriority')).toBeFalsy();
199 });
200
201 it('should return priority "default" if the config option values have been set accordingly', () => {
202 component.detectPriority(configOptionsDefault, (priority) => {
203 expect(priority.name).toBe('default');
204 });
205 expect(component.osdRecvSpeedForm.getValue('customizePriority')).toBeFalsy();
206 });
207
208 it('should return priority "high" if the config option values have been set accordingly', () => {
209 component.detectPriority(configOptionsHigh, (priority) => {
210 expect(priority.name).toBe('high');
211 });
212 expect(component.osdRecvSpeedForm.getValue('customizePriority')).toBeFalsy();
213 });
214
215 it('should return priority "custom" if the config option values do not match any priority', () => {
216 component.detectPriority(configOptionsCustom, (priority) => {
217 expect(priority.name).toBe('custom');
218 });
219 expect(component.osdRecvSpeedForm.getValue('customizePriority')).toBeTruthy();
220 });
221
222 it('should return no priority if the config option values are incomplete', () => {
223 component.detectPriority(configOptionsIncomplete, (priority) => {
224 expect(priority.name).toBeNull();
225 });
226 expect(component.osdRecvSpeedForm.getValue('customizePriority')).toBeFalsy();
227 });
228 });
229
230 describe('getCurrentValues', () => {
231 it('should return default values if no value has been set by the user', () => {
232 const currentValues = component.getCurrentValues(configOptions);
233 configOptions.forEach((configOption) => {
234 const configOptionValue = currentValues.values[configOption.name];
235 expect(configOptionValue).toBe(configOption.default);
236 });
237 });
238
239 it('should return the values set by the user if they exist', () => {
240 configOptions.forEach((configOption) => {
241 configOption['value'] = [{ section: 'osd', value: 7 }];
242 });
243
244 const currentValues = component.getCurrentValues(configOptions);
245 Object.values(currentValues.values).forEach((configValue) => {
246 expect(configValue).toBe(7);
247 });
248 });
249
250 it('should return the default value if one is missing', () => {
251 for (let i = 1; i < configOptions.length; i++) {
252 configOptions[i]['value'] = [{ section: 'osd', value: 7 }];
253 }
254
255 const currentValues = component.getCurrentValues(configOptions);
256 Object.entries(currentValues.values).forEach(([configName, configValue]) => {
257 if (configName === 'osd_max_backfills') {
258 expect(configValue).toBe(1);
259 } else {
260 expect(configValue).toBe(7);
261 }
262 });
263 });
264
265 it('should return nothing if neither value nor default value is given', () => {
266 configOptions[0].default = null;
267 const currentValues = component.getCurrentValues(configOptions);
268 expect(currentValues.values).not.toContain('osd_max_backfills');
269 });
270 });
271
272 describe('setDescription', () => {
273 it('should set the description if one is given', () => {
274 component.setDescription(configOptions);
275 Object.keys(component.priorityAttrs).forEach((configOptionName) => {
276 if (configOptionName === 'osd_recovery_sleep') {
277 expect(component.priorityAttrs[configOptionName].desc).toBe(
278 'Time in seconds to sleep before next recovery or backfill op'
279 );
280 } else {
281 expect(component.priorityAttrs[configOptionName].desc).toBe('');
282 }
283 });
284 });
285 });
286
287 describe('setValidators', () => {
288 it('should set needed validators for config option', () => {
289 component.setValidators(configOptions);
290 configOptions.forEach((configOption) => {
291 const control = component.osdRecvSpeedForm.controls[configOption.name];
292
293 if (configOption.type === 'float') {
294 expect(component.priorityAttrs[configOption.name].patternHelpText).toBe(
295 'The entered value needs to be a number or decimal.'
296 );
297 } else {
298 expect(component.priorityAttrs[configOption.name].minValue).toBe(0);
299 expect(component.priorityAttrs[configOption.name].patternHelpText).toBe(
300 'The entered value needs to be an unsigned number.'
301 );
302
303 control.setValue(-1);
304 expect(control.hasError('min')).toBeTruthy();
305 }
306
307 control.setValue(null);
308 expect(control.hasError('required')).toBeTruthy();
309 control.setValue('E');
310 expect(control.hasError('pattern')).toBeTruthy();
311 control.setValue(3);
312 expect(control.hasError('required')).toBeFalsy();
313 expect(control.hasError('min')).toBeFalsy();
314 expect(control.hasError('pattern')).toBeFalsy();
315 });
316 });
317 });
318 });