]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
b5510c6649f28d9e36c61ab5dff550ce6e38bd3c
[ceph.git] /
1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, TestBed } from '@angular/core/testing';
3 import { ReactiveFormsModule } from '@angular/forms';
4
5 import * as _ from 'lodash';
6 import { PopoverModule } from 'ngx-bootstrap/popover';
7 import { of as observableOf } from 'rxjs';
8
9 import { configureTestBed } from '../../../../testing/unit-test-helper';
10 import { ConfigurationService } from '../../api/configuration.service';
11 import { CdFormGroup } from '../../forms/cd-form-group';
12 import { HelperComponent } from '../helper/helper.component';
13 import { ConfigOptionComponent } from './config-option.component';
14
15 describe('ConfigOptionComponent', () => {
16   let component: ConfigOptionComponent;
17   let fixture: ComponentFixture<ConfigOptionComponent>;
18   let configurationService: ConfigurationService;
19   let oNames: Array<string>;
20
21   configureTestBed({
22     declarations: [ConfigOptionComponent, HelperComponent],
23     imports: [PopoverModule.forRoot(), ReactiveFormsModule, HttpClientTestingModule],
24     providers: [ConfigurationService]
25   });
26
27   beforeEach(() => {
28     fixture = TestBed.createComponent(ConfigOptionComponent);
29     component = fixture.componentInstance;
30     fixture.detectChanges();
31     configurationService = TestBed.inject(ConfigurationService);
32
33     const configOptions: Record<string, any> = [
34       {
35         name: 'osd_scrub_auto_repair_num_errors',
36         type: 'uint',
37         level: 'advanced',
38         desc: 'Maximum number of detected errors to automatically repair',
39         long_desc: '',
40         default: 5,
41         daemon_default: '',
42         tags: [],
43         services: [],
44         see_also: ['osd_scrub_auto_repair'],
45         min: '',
46         max: '',
47         can_update_at_runtime: true,
48         flags: []
49       },
50       {
51         name: 'osd_debug_deep_scrub_sleep',
52         type: 'float',
53         level: 'dev',
54         desc:
55           'Inject an expensive sleep during deep scrub IO to make it easier to induce preemption',
56         long_desc: '',
57         default: 0,
58         daemon_default: '',
59         tags: [],
60         services: [],
61         see_also: [],
62         min: '',
63         max: '',
64         can_update_at_runtime: true,
65         flags: []
66       },
67       {
68         name: 'osd_heartbeat_interval',
69         type: 'int',
70         level: 'advanced',
71         desc: 'Interval (in seconds) between peer pings',
72         long_desc: '',
73         default: 6,
74         daemon_default: '',
75         tags: [],
76         services: [],
77         see_also: [],
78         min: 1,
79         max: 86400,
80         can_update_at_runtime: true,
81         flags: [],
82         value: [
83           {
84             section: 'osd',
85             value: 6
86           }
87         ]
88       },
89       {
90         name: 'bluestore_compression_algorithm',
91         type: 'str',
92         level: 'advanced',
93         desc: 'Default compression algorithm to use when writing object data',
94         long_desc:
95           'This controls the default compressor to use (if any) if the ' +
96           'per-pool property is not set.  Note that zstd is *not* recommended for ' +
97           'bluestore due to high CPU overhead when compressing small amounts of data.',
98         default: 'snappy',
99         daemon_default: '',
100         tags: [],
101         services: [],
102         see_also: [],
103         enum_values: ['', 'snappy', 'zlib', 'zstd', 'lz4'],
104         min: '',
105         max: '',
106         can_update_at_runtime: true,
107         flags: ['runtime']
108       },
109       {
110         name: 'rbd_discard_on_zeroed_write_same',
111         type: 'bool',
112         level: 'advanced',
113         desc: 'discard data on zeroed write same instead of writing zero',
114         long_desc: '',
115         default: true,
116         daemon_default: '',
117         tags: [],
118         services: ['rbd'],
119         see_also: [],
120         min: '',
121         max: '',
122         can_update_at_runtime: true,
123         flags: []
124       },
125       {
126         name: 'rbd_journal_max_payload_bytes',
127         type: 'size',
128         level: 'advanced',
129         desc: 'maximum journal payload size before splitting',
130         long_desc: '',
131         daemon_default: '',
132         tags: [],
133         services: ['rbd'],
134         see_also: [],
135         min: '',
136         max: '',
137         can_update_at_runtime: true,
138         flags: [],
139         default: '16384'
140       },
141       {
142         name: 'cluster_addr',
143         type: 'addr',
144         level: 'basic',
145         desc: 'cluster-facing address to bind to',
146         long_desc: '',
147         daemon_default: '',
148         tags: ['network'],
149         services: ['osd'],
150         see_also: [],
151         min: '',
152         max: '',
153         can_update_at_runtime: false,
154         flags: [],
155         default: '-'
156       },
157       {
158         name: 'fsid',
159         type: 'uuid',
160         level: 'basic',
161         desc: 'cluster fsid (uuid)',
162         long_desc: '',
163         daemon_default: '',
164         tags: ['service'],
165         services: ['common'],
166         see_also: [],
167         min: '',
168         max: '',
169         can_update_at_runtime: false,
170         flags: ['no_mon_update'],
171         default: '00000000-0000-0000-0000-000000000000'
172       },
173       {
174         name: 'mgr_tick_period',
175         type: 'secs',
176         level: 'advanced',
177         desc: 'Period in seconds of beacon messages to monitor',
178         long_desc: '',
179         daemon_default: '',
180         tags: [],
181         services: ['mgr'],
182         see_also: [],
183         min: '',
184         max: '',
185         can_update_at_runtime: true,
186         flags: [],
187         default: '2'
188       }
189     ];
190
191     spyOn(configurationService, 'filter').and.returnValue(observableOf(configOptions));
192     oNames = _.map(configOptions, 'name');
193     component.optionNames = oNames;
194     component.optionsForm = new CdFormGroup({});
195     component.optionsFormGroupName = 'testFormGroupName';
196     component.ngOnInit();
197   });
198
199   it('should create', () => {
200     expect(component).toBeTruthy();
201   });
202
203   describe('optionNameToText', () => {
204     it('should format config option names correctly', () => {
205       const configOptionNames = {
206         osd_scrub_auto_repair_num_errors: 'Scrub Auto Repair Num Errors',
207         osd_debug_deep_scrub_sleep: 'Debug Deep Scrub Sleep',
208         osd_heartbeat_interval: 'Heartbeat Interval',
209         bluestore_compression_algorithm: 'Bluestore Compression Algorithm',
210         rbd_discard_on_zeroed_write_same: 'Rbd Discard On Zeroed Write Same',
211         rbd_journal_max_payload_bytes: 'Rbd Journal Max Payload Bytes',
212         cluster_addr: 'Cluster Addr',
213         fsid: 'Fsid',
214         mgr_tick_period: 'Tick Period'
215       };
216
217       component.options.forEach((option) => {
218         expect(option.text).toEqual(configOptionNames[option.name]);
219       });
220     });
221   });
222
223   describe('createForm', () => {
224     it('should set the optionsFormGroupName correctly', () => {
225       expect(component.optionsFormGroupName).toEqual('testFormGroupName');
226     });
227
228     it('should create a FormControl for every config option', () => {
229       component.options.forEach((option) => {
230         expect(Object.keys(component.optionsFormGroup.controls)).toContain(option.name);
231       });
232     });
233   });
234
235   describe('loadStorageData', () => {
236     it('should create a list of config options by names', () => {
237       expect(component.options.length).toEqual(9);
238
239       component.options.forEach((option) => {
240         expect(oNames).toContain(option.name);
241       });
242     });
243
244     it('should add all needed attributes to every config option', () => {
245       component.options.forEach((option) => {
246         const optionKeys = Object.keys(option);
247         expect(optionKeys).toContain('text');
248         expect(optionKeys).toContain('additionalTypeInfo');
249         expect(optionKeys).toContain('value');
250
251         if (option.type !== 'bool' && option.type !== 'str') {
252           expect(optionKeys).toContain('patternHelpText');
253         }
254
255         if (option.name === 'osd_heartbeat_interval') {
256           expect(optionKeys).toContain('maxValue');
257           expect(optionKeys).toContain('minValue');
258         }
259       });
260     });
261
262     it('should set minValue and maxValue correctly', () => {
263       component.options.forEach((option) => {
264         if (option.name === 'osd_heartbeat_interval') {
265           expect(option.minValue).toEqual(1);
266           expect(option.maxValue).toEqual(86400);
267         }
268       });
269     });
270
271     it('should set the value attribute correctly', () => {
272       component.options.forEach((option) => {
273         if (option.name === 'osd_heartbeat_interval') {
274           const value = option.value;
275           expect(value).toBeDefined();
276           expect(value).toEqual({ section: 'osd', value: 6 });
277         } else {
278           expect(option.value).toBeUndefined();
279         }
280       });
281     });
282
283     it('should set the FormControl value correctly', () => {
284       component.options.forEach((option) => {
285         const value = component.optionsFormGroup.getValue(option.name);
286         if (option.name === 'osd_heartbeat_interval') {
287           expect(value).toBeDefined();
288           expect(value).toEqual(6);
289         } else {
290           expect(value).toBeNull();
291         }
292       });
293     });
294   });
295 });