]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-flags-indiv-modal/osd-flags-indiv-modal.component.spec.ts
import 15.2.9
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / cluster / osd / osd-flags-indiv-modal / osd-flags-indiv-modal.component.spec.ts
1 import { HttpClientTestingModule, HttpTestingController } 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 { BsModalRef, ModalModule } from 'ngx-bootstrap/modal';
7 import { ToastrModule } from 'ngx-toastr';
8 import { of as observableOf } from 'rxjs';
9
10 import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper';
11 import { OsdService } from '../../../../shared/api/osd.service';
12 import { NotificationType } from '../../../../shared/enum/notification-type.enum';
13 import { Flag } from '../../../../shared/models/flag';
14 import { NotificationService } from '../../../../shared/services/notification.service';
15 import { SharedModule } from '../../../../shared/shared.module';
16 import { OsdFlagsIndivModalComponent } from './osd-flags-indiv-modal.component';
17
18 describe('OsdFlagsIndivModalComponent', () => {
19 let component: OsdFlagsIndivModalComponent;
20 let fixture: ComponentFixture<OsdFlagsIndivModalComponent>;
21 let httpTesting: HttpTestingController;
22 let osdService: OsdService;
23
24 configureTestBed({
25 imports: [
26 HttpClientTestingModule,
27 ReactiveFormsModule,
28 SharedModule,
29 ToastrModule.forRoot(),
30 ModalModule.forRoot(),
31 RouterTestingModule
32 ],
33 declarations: [OsdFlagsIndivModalComponent],
34 providers: [BsModalRef, i18nProviders]
35 });
36
37 beforeEach(() => {
38 httpTesting = TestBed.get(HttpTestingController);
39 fixture = TestBed.createComponent(OsdFlagsIndivModalComponent);
40 component = fixture.componentInstance;
41 osdService = TestBed.get(OsdService);
42 });
43
44 it('should create', () => {
45 expect(component).toBeTruthy();
46 });
47
48 describe('getActivatedIndivFlags', () => {
49 function checkFlagsCount(
50 counts: { [key: string]: number },
51 expected: { [key: string]: number }
52 ) {
53 Object.entries(expected).forEach(([expectedKey, expectedValue]) => {
54 expect(counts[expectedKey]).toBe(expectedValue);
55 });
56 }
57
58 it('should count correctly if no flag has been set', () => {
59 component.selected = generateSelected();
60 const countedFlags = component.getActivatedIndivFlags();
61 checkFlagsCount(countedFlags, { noup: 0, nodown: 0, noin: 0, noout: 0 });
62 });
63
64 it('should count correctly if some of the flags have been set', () => {
65 component.selected = generateSelected([['noin'], ['noin', 'noout'], ['nodown']]);
66 const countedFlags = component.getActivatedIndivFlags();
67 checkFlagsCount(countedFlags, { noup: 0, nodown: 1, noin: 2, noout: 1 });
68 });
69 });
70
71 describe('changeValue', () => {
72 it('should change value correctly and set indeterminate to false', () => {
73 const testFlag = component.flags[0];
74 const value = testFlag.value;
75 component.changeValue(testFlag);
76 expect(testFlag.value).toBe(!value);
77 expect(testFlag.indeterminate).toBeFalsy();
78 });
79 });
80
81 describe('resetSelection', () => {
82 it('should set a new flags object by deep cloning the initial selection', () => {
83 component.resetSelection();
84 expect(component.flags === component.initialSelection).toBeFalsy();
85 });
86 });
87
88 describe('OSD single-select', () => {
89 beforeEach(() => {
90 component.selected = [{ osd: 0 }];
91 });
92
93 describe('ngOnInit', () => {
94 it('should clone flags as initial selection', () => {
95 expect(component.flags === component.initialSelection).toBeFalsy();
96 });
97
98 it('should initialize form correctly if no individual and global flags are set', () => {
99 component.selected[0]['state'] = ['exists', 'up'];
100 spyOn(osdService, 'getFlags').and.callFake(() => observableOf([]));
101 fixture.detectChanges();
102 checkFlags(component.flags);
103 });
104
105 it('should initialize form correctly if individual but no global flags are set', () => {
106 component.selected[0]['state'] = ['exists', 'noout', 'up'];
107 spyOn(osdService, 'getFlags').and.callFake(() => observableOf([]));
108 fixture.detectChanges();
109 const expected = {
110 noout: { value: true, clusterWide: false, indeterminate: false }
111 };
112 checkFlags(component.flags, expected);
113 });
114
115 it('should initialize form correctly if multiple individual but no global flags are set', () => {
116 component.selected[0]['state'] = ['exists', 'noin', 'noout', 'up'];
117 spyOn(osdService, 'getFlags').and.callFake(() => observableOf([]));
118 fixture.detectChanges();
119 const expected = {
120 noout: { value: true, clusterWide: false, indeterminate: false },
121 noin: { value: true, clusterWide: false, indeterminate: false }
122 };
123 checkFlags(component.flags, expected);
124 });
125
126 it('should initialize form correctly if no individual but global flags are set', () => {
127 component.selected[0]['state'] = ['exists', 'up'];
128 spyOn(osdService, 'getFlags').and.callFake(() => observableOf(['noout']));
129 fixture.detectChanges();
130 const expected = {
131 noout: { value: false, clusterWide: true, indeterminate: false }
132 };
133 checkFlags(component.flags, expected);
134 });
135 });
136
137 describe('submitAction', () => {
138 let notificationType: NotificationType;
139 let notificationService: NotificationService;
140 let bsModalRef: BsModalRef;
141 let flags: object;
142
143 beforeEach(() => {
144 notificationService = TestBed.get(NotificationService);
145 spyOn(notificationService, 'show').and.callFake((type) => {
146 notificationType = type;
147 });
148 bsModalRef = TestBed.get(BsModalRef);
149 spyOn(bsModalRef, 'hide').and.callThrough();
150 flags = {
151 nodown: false,
152 noin: false,
153 noout: false,
154 noup: false
155 };
156 });
157
158 it('should submit an activated flag', () => {
159 const code = component.flags[0].code;
160 component.flags[0].value = true;
161 component.submitAction();
162 flags[code] = true;
163
164 const req = httpTesting.expectOne('api/osd/flags/individual');
165 req.flush({ flags, ids: [0] });
166 expect(req.request.body).toEqual({ flags, ids: [0] });
167 expect(notificationType).toBe(NotificationType.success);
168 expect(component.activeModal.hide).toHaveBeenCalledTimes(1);
169 });
170
171 it('should submit multiple flags', () => {
172 const codes = [component.flags[0].code, component.flags[1].code];
173 component.flags[0].value = true;
174 component.flags[1].value = true;
175 component.submitAction();
176 flags[codes[0]] = true;
177 flags[codes[1]] = true;
178
179 const req = httpTesting.expectOne('api/osd/flags/individual');
180 req.flush({ flags, ids: [0] });
181 expect(req.request.body).toEqual({ flags, ids: [0] });
182 expect(notificationType).toBe(NotificationType.success);
183 expect(component.activeModal.hide).toHaveBeenCalledTimes(1);
184 });
185
186 it('should hide modal if request fails', () => {
187 component.flags = [];
188 component.submitAction();
189 const req = httpTesting.expectOne('api/osd/flags/individual');
190 req.flush([], { status: 500, statusText: 'failure' });
191 expect(notificationService.show).toHaveBeenCalledTimes(0);
192 expect(component.activeModal.hide).toHaveBeenCalledTimes(1);
193 });
194 });
195 });
196
197 describe('OSD multi-select', () => {
198 describe('ngOnInit', () => {
199 it('should initialize form correctly if same individual and no global flags are set', () => {
200 component.selected = generateSelected([['noin'], ['noin'], ['noin']]);
201 spyOn(osdService, 'getFlags').and.callFake(() => observableOf([]));
202 fixture.detectChanges();
203 const expected = {
204 noin: { value: true, clusterWide: false, indeterminate: false }
205 };
206 checkFlags(component.flags, expected);
207 });
208
209 it('should initialize form correctly if different individual and no global flags are set', () => {
210 component.selected = generateSelected([['noin'], ['noout'], ['noin']]);
211 spyOn(osdService, 'getFlags').and.callFake(() => observableOf([]));
212 fixture.detectChanges();
213 const expected = {
214 noin: { value: false, clusterWide: false, indeterminate: true },
215 noout: { value: false, clusterWide: false, indeterminate: true }
216 };
217 checkFlags(component.flags, expected);
218 });
219
220 it('should initialize form correctly if different and same individual and no global flags are set', () => {
221 component.selected = generateSelected([
222 ['noin', 'nodown'],
223 ['noout', 'nodown'],
224 ['noin', 'nodown']
225 ]);
226 spyOn(osdService, 'getFlags').and.callFake(() => observableOf([]));
227 fixture.detectChanges();
228 const expected = {
229 noin: { value: false, clusterWide: false, indeterminate: true },
230 noout: { value: false, clusterWide: false, indeterminate: true },
231 nodown: { value: true, clusterWide: false, indeterminate: false }
232 };
233 checkFlags(component.flags, expected);
234 });
235
236 it('should initialize form correctly if a flag is set for all OSDs individually and globally', () => {
237 component.selected = generateSelected([
238 ['noin', 'nodown'],
239 ['noout', 'nodown'],
240 ['noin', 'nodown']
241 ]);
242 spyOn(osdService, 'getFlags').and.callFake(() => observableOf(['noout']));
243 fixture.detectChanges();
244 const expected = {
245 noin: { value: false, clusterWide: false, indeterminate: true },
246 noout: { value: false, clusterWide: true, indeterminate: true },
247 nodown: { value: true, clusterWide: false, indeterminate: false }
248 };
249 checkFlags(component.flags, expected);
250 });
251
252 it('should initialize form correctly if different individual and global flags are set', () => {
253 component.selected = generateSelected([
254 ['noin', 'nodown', 'noout'],
255 ['noout', 'nodown'],
256 ['noin', 'nodown', 'noout']
257 ]);
258 spyOn(osdService, 'getFlags').and.callFake(() => observableOf(['noout']));
259 fixture.detectChanges();
260 const expected = {
261 noin: { value: false, clusterWide: false, indeterminate: true },
262 noout: { value: true, clusterWide: true, indeterminate: false },
263 nodown: { value: true, clusterWide: false, indeterminate: false }
264 };
265 checkFlags(component.flags, expected);
266 });
267 });
268
269 describe('submitAction', () => {
270 let notificationType: NotificationType;
271 let notificationService: NotificationService;
272 let bsModalRef: BsModalRef;
273 let flags: object;
274
275 beforeEach(() => {
276 notificationService = TestBed.get(NotificationService);
277 spyOn(notificationService, 'show').and.callFake((type) => {
278 notificationType = type;
279 });
280 bsModalRef = TestBed.get(BsModalRef);
281 spyOn(bsModalRef, 'hide').and.callThrough();
282 flags = {
283 nodown: false,
284 noin: false,
285 noout: false,
286 noup: false
287 };
288 });
289
290 it('should submit an activated flag for multiple OSDs', () => {
291 component.selected = generateSelected();
292 const code = component.flags[0].code;
293 const submittedIds = [0, 1, 2];
294 component.flags[0].value = true;
295 component.submitAction();
296 flags[code] = true;
297
298 const req = httpTesting.expectOne('api/osd/flags/individual');
299 req.flush({ flags, ids: submittedIds });
300 expect(req.request.body).toEqual({ flags, ids: submittedIds });
301 expect(notificationType).toBe(NotificationType.success);
302 expect(component.activeModal.hide).toHaveBeenCalledTimes(1);
303 });
304
305 it('should submit multiple flags for multiple OSDs', () => {
306 component.selected = generateSelected();
307 const codes = [component.flags[0].code, component.flags[1].code];
308 const submittedIds = [0, 1, 2];
309 component.flags[0].value = true;
310 component.flags[1].value = true;
311 component.submitAction();
312 flags[codes[0]] = true;
313 flags[codes[1]] = true;
314
315 const req = httpTesting.expectOne('api/osd/flags/individual');
316 req.flush({ flags, ids: submittedIds });
317 expect(req.request.body).toEqual({ flags, ids: submittedIds });
318 expect(notificationType).toBe(NotificationType.success);
319 expect(component.activeModal.hide).toHaveBeenCalledTimes(1);
320 });
321 });
322 });
323
324 function checkFlags(flags: Flag[], expected: object = {}) {
325 flags.forEach((flag) => {
326 let value = false;
327 let clusterWide = false;
328 let indeterminate = false;
329 if (Object.keys(expected).includes(flag.code)) {
330 value = expected[flag.code]['value'];
331 clusterWide = expected[flag.code]['clusterWide'];
332 indeterminate = expected[flag.code]['indeterminate'];
333 }
334 expect(flag.value).toBe(value);
335 expect(flag.clusterWide).toBe(clusterWide);
336 expect(flag.indeterminate).toBe(indeterminate);
337 });
338 }
339
340 function generateSelected(flags: string[][] = []) {
341 const defaultFlags = ['exists', 'up'];
342 const osds = [];
343 const count = flags.length || 3;
344 for (let i = 0; i < count; i++) {
345 const osd = {
346 osd: i,
347 state: defaultFlags.concat(flags[i]) || defaultFlags
348 };
349 osds.push(osd);
350 }
351 return osds;
352 }
353 });