]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | import { HttpClientTestingModule } from '@angular/common/http/testing'; |
eafe8130 | 2 | import { ComponentFixture, discardPeriodicTasks, fakeAsync, TestBed } from '@angular/core/testing'; |
11fdf7f2 | 3 | import { ReactiveFormsModule } from '@angular/forms'; |
494da23a | 4 | import { ActivatedRoute, Router } from '@angular/router'; |
11fdf7f2 TL |
5 | import { RouterTestingModule } from '@angular/router/testing'; |
6 | import { TooltipModule } from 'ngx-bootstrap/tooltip'; | |
7 | ||
494da23a | 8 | import { ToastrModule } from 'ngx-toastr'; |
11fdf7f2 TL |
9 | |
10 | import { By } from '@angular/platform-browser'; | |
494da23a | 11 | import { of } from 'rxjs'; |
eafe8130 TL |
12 | import { delay } from 'rxjs/operators'; |
13 | ||
11fdf7f2 TL |
14 | import { ActivatedRouteStub } from '../../../../testing/activated-route-stub'; |
15 | import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper'; | |
16 | import { RbdService } from '../../../shared/api/rbd.service'; | |
9f95a23c | 17 | import { ImageSpec } from '../../../shared/models/image-spec'; |
11fdf7f2 TL |
18 | import { SharedModule } from '../../../shared/shared.module'; |
19 | import { RbdConfigurationFormComponent } from '../rbd-configuration-form/rbd-configuration-form.component'; | |
9f95a23c | 20 | import { RbdImageFeature } from './rbd-feature.interface'; |
11fdf7f2 TL |
21 | import { RbdFormMode } from './rbd-form-mode.enum'; |
22 | import { RbdFormComponent } from './rbd-form.component'; | |
23 | ||
24 | describe('RbdFormComponent', () => { | |
25 | let component: RbdFormComponent; | |
26 | let fixture: ComponentFixture<RbdFormComponent>; | |
27 | let activatedRoute: ActivatedRouteStub; | |
28 | ||
9f95a23c | 29 | const queryNativeElement = (cssSelector: string) => |
494da23a TL |
30 | fixture.debugElement.query(By.css(cssSelector)).nativeElement; |
31 | ||
11fdf7f2 TL |
32 | configureTestBed({ |
33 | imports: [ | |
34 | HttpClientTestingModule, | |
35 | ReactiveFormsModule, | |
36 | RouterTestingModule, | |
494da23a | 37 | ToastrModule.forRoot(), |
11fdf7f2 TL |
38 | SharedModule, |
39 | TooltipModule | |
40 | ], | |
41 | declarations: [RbdFormComponent, RbdConfigurationFormComponent], | |
42 | providers: [ | |
43 | { | |
44 | provide: ActivatedRoute, | |
45 | useValue: new ActivatedRouteStub({ pool: 'foo', name: 'bar', snap: undefined }) | |
46 | }, | |
494da23a TL |
47 | i18nProviders, |
48 | RbdService | |
11fdf7f2 TL |
49 | ] |
50 | }); | |
51 | ||
52 | beforeEach(() => { | |
53 | fixture = TestBed.createComponent(RbdFormComponent); | |
54 | component = fixture.componentInstance; | |
55 | activatedRoute = TestBed.get(ActivatedRoute); | |
56 | }); | |
57 | ||
58 | it('should create', () => { | |
59 | expect(component).toBeTruthy(); | |
60 | }); | |
61 | ||
eafe8130 | 62 | describe('create/edit/clone/copy image', () => { |
9f95a23c TL |
63 | let createAction: jasmine.Spy; |
64 | let editAction: jasmine.Spy; | |
65 | let cloneAction: jasmine.Spy; | |
66 | let copyAction: jasmine.Spy; | |
67 | let rbdServiceGetSpy: jasmine.Spy; | |
eafe8130 TL |
68 | |
69 | beforeEach(() => { | |
70 | createAction = spyOn(component, 'createAction').and.stub(); | |
71 | editAction = spyOn(component, 'editAction').and.stub(); | |
72 | cloneAction = spyOn(component, 'cloneAction').and.stub(); | |
73 | copyAction = spyOn(component, 'copyAction').and.stub(); | |
74 | spyOn(component, 'setResponse').and.stub(); | |
75 | spyOn(TestBed.get(Router), 'navigate').and.stub(); | |
76 | rbdServiceGetSpy = spyOn(TestBed.get(RbdService), 'get'); | |
77 | rbdServiceGetSpy.and.returnValue(of({ pool_name: 'foo', pool_image: 'bar' })); | |
78 | component.mode = undefined; | |
79 | }); | |
80 | ||
81 | it('should create image', () => { | |
82 | component.ngOnInit(); | |
83 | component.submit(); | |
84 | ||
85 | expect(createAction).toHaveBeenCalledTimes(1); | |
86 | expect(editAction).toHaveBeenCalledTimes(0); | |
87 | expect(cloneAction).toHaveBeenCalledTimes(0); | |
88 | expect(copyAction).toHaveBeenCalledTimes(0); | |
89 | }); | |
90 | ||
91 | it('should not edit image if no image data is received', fakeAsync(() => { | |
92 | component.mode = RbdFormMode.editing; | |
93 | rbdServiceGetSpy.and.returnValue( | |
94 | of({ pool_name: 'foo', pool_image: 'bar' }).pipe(delay(100)) | |
95 | ); | |
96 | component.ngOnInit(); | |
97 | component.submit(); | |
98 | ||
99 | expect(createAction).toHaveBeenCalledTimes(0); | |
100 | expect(editAction).toHaveBeenCalledTimes(0); | |
101 | expect(cloneAction).toHaveBeenCalledTimes(0); | |
102 | expect(copyAction).toHaveBeenCalledTimes(0); | |
103 | ||
104 | discardPeriodicTasks(); | |
105 | })); | |
106 | ||
107 | it('should edit image after image data is received', () => { | |
108 | component.mode = RbdFormMode.editing; | |
109 | component.ngOnInit(); | |
110 | component.submit(); | |
111 | ||
112 | expect(createAction).toHaveBeenCalledTimes(0); | |
113 | expect(editAction).toHaveBeenCalledTimes(1); | |
114 | expect(cloneAction).toHaveBeenCalledTimes(0); | |
115 | expect(copyAction).toHaveBeenCalledTimes(0); | |
116 | }); | |
117 | ||
118 | it('should not clone image if no image data is received', fakeAsync(() => { | |
119 | component.mode = RbdFormMode.cloning; | |
120 | rbdServiceGetSpy.and.returnValue( | |
121 | of({ pool_name: 'foo', pool_image: 'bar' }).pipe(delay(100)) | |
122 | ); | |
123 | component.ngOnInit(); | |
124 | component.submit(); | |
125 | ||
126 | expect(createAction).toHaveBeenCalledTimes(0); | |
127 | expect(editAction).toHaveBeenCalledTimes(0); | |
128 | expect(cloneAction).toHaveBeenCalledTimes(0); | |
129 | expect(copyAction).toHaveBeenCalledTimes(0); | |
130 | ||
131 | discardPeriodicTasks(); | |
132 | })); | |
133 | ||
134 | it('should clone image after image data is received', () => { | |
135 | component.mode = RbdFormMode.cloning; | |
136 | component.ngOnInit(); | |
137 | component.submit(); | |
138 | ||
139 | expect(createAction).toHaveBeenCalledTimes(0); | |
140 | expect(editAction).toHaveBeenCalledTimes(0); | |
141 | expect(cloneAction).toHaveBeenCalledTimes(1); | |
142 | expect(copyAction).toHaveBeenCalledTimes(0); | |
143 | }); | |
144 | ||
145 | it('should not copy image if no image data is received', fakeAsync(() => { | |
146 | component.mode = RbdFormMode.copying; | |
147 | rbdServiceGetSpy.and.returnValue( | |
148 | of({ pool_name: 'foo', pool_image: 'bar' }).pipe(delay(100)) | |
149 | ); | |
150 | component.ngOnInit(); | |
151 | component.submit(); | |
152 | ||
153 | expect(createAction).toHaveBeenCalledTimes(0); | |
154 | expect(editAction).toHaveBeenCalledTimes(0); | |
155 | expect(cloneAction).toHaveBeenCalledTimes(0); | |
156 | expect(copyAction).toHaveBeenCalledTimes(0); | |
157 | ||
158 | discardPeriodicTasks(); | |
159 | })); | |
160 | ||
161 | it('should copy image after image data is received', () => { | |
162 | component.mode = RbdFormMode.copying; | |
163 | component.ngOnInit(); | |
164 | component.submit(); | |
165 | ||
166 | expect(createAction).toHaveBeenCalledTimes(0); | |
167 | expect(editAction).toHaveBeenCalledTimes(0); | |
168 | expect(cloneAction).toHaveBeenCalledTimes(0); | |
169 | expect(copyAction).toHaveBeenCalledTimes(1); | |
170 | }); | |
171 | }); | |
172 | ||
11fdf7f2 TL |
173 | describe('should test decodeURIComponent of params', () => { |
174 | let rbdService: RbdService; | |
175 | ||
176 | beforeEach(() => { | |
177 | rbdService = TestBed.get(RbdService); | |
178 | component.mode = RbdFormMode.editing; | |
179 | fixture.detectChanges(); | |
180 | spyOn(rbdService, 'get').and.callThrough(); | |
181 | }); | |
182 | ||
9f95a23c TL |
183 | it('with namespace', () => { |
184 | activatedRoute.setParams({ image_spec: 'foo%2Fbar%2Fbaz' }); | |
185 | ||
186 | expect(rbdService.get).toHaveBeenCalledWith(new ImageSpec('foo', 'bar', 'baz')); | |
187 | }); | |
188 | ||
11fdf7f2 | 189 | it('without snapName', () => { |
9f95a23c | 190 | activatedRoute.setParams({ image_spec: 'foo%2Fbar', snap: undefined }); |
11fdf7f2 | 191 | |
9f95a23c | 192 | expect(rbdService.get).toHaveBeenCalledWith(new ImageSpec('foo', null, 'bar')); |
11fdf7f2 TL |
193 | expect(component.snapName).toBeUndefined(); |
194 | }); | |
195 | ||
196 | it('with snapName', () => { | |
9f95a23c | 197 | activatedRoute.setParams({ image_spec: 'foo%2Fbar', snap: 'baz%2Fbaz' }); |
11fdf7f2 | 198 | |
9f95a23c | 199 | expect(rbdService.get).toHaveBeenCalledWith(new ImageSpec('foo', null, 'bar')); |
11fdf7f2 TL |
200 | expect(component.snapName).toBe('baz/baz'); |
201 | }); | |
202 | }); | |
203 | ||
204 | describe('test image configuration component', () => { | |
205 | it('is visible', () => { | |
206 | fixture.detectChanges(); | |
9f95a23c TL |
207 | expect( |
208 | fixture.debugElement.query(By.css('cd-rbd-configuration-form')).nativeElement.parentElement | |
209 | .hidden | |
210 | ).toBe(true); | |
494da23a TL |
211 | }); |
212 | }); | |
213 | ||
214 | describe('tests for feature flags', () => { | |
9f95a23c TL |
215 | let deepFlatten: any, |
216 | layering: any, | |
217 | exclusiveLock: any, | |
218 | objectMap: any, | |
219 | journaling: any, | |
220 | fastDiff: any; | |
494da23a TL |
221 | const defaultFeatures = [ |
222 | // Supposed to be enabled by default | |
223 | 'deep-flatten', | |
224 | 'exclusive-lock', | |
225 | 'fast-diff', | |
226 | 'layering', | |
227 | 'object-map' | |
228 | ]; | |
229 | const allFeatureNames = [ | |
230 | 'deep-flatten', | |
231 | 'layering', | |
232 | 'exclusive-lock', | |
233 | 'object-map', | |
234 | 'journaling', | |
235 | 'fast-diff' | |
236 | ]; | |
9f95a23c | 237 | const setFeatures = (features: Record<string, RbdImageFeature>) => { |
494da23a TL |
238 | component.features = features; |
239 | component.featuresList = component.objToArray(features); | |
240 | component.createForm(); | |
241 | }; | |
242 | const getFeatureNativeElements = () => allFeatureNames.map((f) => queryNativeElement(`#${f}`)); | |
243 | ||
244 | it('should convert feature flags correctly in the constructor', () => { | |
245 | setFeatures({ | |
246 | one: { desc: 'one', allowEnable: true, allowDisable: true }, | |
247 | two: { desc: 'two', allowEnable: true, allowDisable: true }, | |
248 | three: { desc: 'three', allowEnable: true, allowDisable: true } | |
249 | }); | |
250 | expect(component.featuresList).toEqual([ | |
251 | { desc: 'one', key: 'one', allowDisable: true, allowEnable: true }, | |
252 | { desc: 'two', key: 'two', allowDisable: true, allowEnable: true }, | |
253 | { desc: 'three', key: 'three', allowDisable: true, allowEnable: true } | |
254 | ]); | |
255 | }); | |
256 | ||
257 | describe('test edit form flags', () => { | |
258 | const prepare = (pool: string, image: string, enabledFeatures: string[]): void => { | |
259 | const rbdService = TestBed.get(RbdService); | |
260 | spyOn(rbdService, 'get').and.returnValue( | |
261 | of({ | |
262 | name: image, | |
263 | pool_name: pool, | |
264 | features_name: enabledFeatures | |
265 | }) | |
266 | ); | |
267 | spyOn(rbdService, 'defaultFeatures').and.returnValue(of(defaultFeatures)); | |
268 | component.router = { url: `/block/rbd/edit/${pool}/${image}` } as Router; | |
269 | fixture.detectChanges(); | |
270 | [ | |
271 | deepFlatten, | |
272 | layering, | |
273 | exclusiveLock, | |
274 | objectMap, | |
275 | journaling, | |
276 | fastDiff | |
277 | ] = getFeatureNativeElements(); | |
278 | }; | |
279 | ||
280 | it('should have the interlock feature for flags disabled, if one feature is not set', () => { | |
281 | prepare('rbd', 'foobar', ['deep-flatten', 'exclusive-lock', 'layering', 'object-map']); | |
282 | ||
283 | expect(objectMap.disabled).toBe(false); | |
284 | expect(fastDiff.disabled).toBe(false); | |
285 | ||
286 | expect(objectMap.checked).toBe(true); | |
287 | expect(fastDiff.checked).toBe(false); | |
288 | ||
289 | fastDiff.click(); | |
290 | fastDiff.click(); | |
291 | ||
292 | expect(objectMap.checked).toBe(true); // Shall not be disabled by `fast-diff`! | |
293 | }); | |
294 | ||
295 | it('should not disable object-map when fast-diff is unchecked', () => { | |
296 | prepare('rbd', 'foobar', ['deep-flatten', 'exclusive-lock', 'layering', 'object-map']); | |
297 | ||
298 | fastDiff.click(); | |
299 | fastDiff.click(); | |
300 | ||
301 | expect(objectMap.checked).toBe(true); // Shall not be disabled by `fast-diff`! | |
302 | }); | |
303 | ||
304 | it('should not enable fast-diff when object-map is checked', () => { | |
305 | prepare('rbd', 'foobar', ['deep-flatten', 'exclusive-lock', 'layering', 'object-map']); | |
306 | ||
307 | objectMap.click(); | |
308 | objectMap.click(); | |
309 | ||
310 | expect(fastDiff.checked).toBe(false); // Shall not be disabled by `fast-diff`! | |
311 | }); | |
312 | }); | |
313 | ||
314 | describe('test create form flags', () => { | |
315 | beforeEach(() => { | |
316 | const rbdService = TestBed.get(RbdService); | |
317 | spyOn(rbdService, 'defaultFeatures').and.returnValue(of(defaultFeatures)); | |
318 | component.router = { url: '/block/rbd/create' } as Router; | |
319 | fixture.detectChanges(); | |
320 | [ | |
321 | deepFlatten, | |
322 | layering, | |
323 | exclusiveLock, | |
324 | objectMap, | |
325 | journaling, | |
326 | fastDiff | |
327 | ] = getFeatureNativeElements(); | |
328 | }); | |
329 | ||
330 | it('should initialize the checkboxes correctly', () => { | |
331 | expect(deepFlatten.disabled).toBe(false); | |
332 | expect(layering.disabled).toBe(false); | |
333 | expect(exclusiveLock.disabled).toBe(false); | |
334 | expect(objectMap.disabled).toBe(false); | |
335 | expect(journaling.disabled).toBe(false); | |
336 | expect(fastDiff.disabled).toBe(false); | |
337 | ||
338 | expect(deepFlatten.checked).toBe(true); | |
339 | expect(layering.checked).toBe(true); | |
340 | expect(exclusiveLock.checked).toBe(true); | |
341 | expect(objectMap.checked).toBe(true); | |
342 | expect(journaling.checked).toBe(false); | |
343 | expect(fastDiff.checked).toBe(true); | |
344 | }); | |
345 | ||
346 | it('should disable features if their requirements are not met (exclusive-lock)', () => { | |
347 | exclusiveLock.click(); // unchecks exclusive-lock | |
348 | expect(objectMap.disabled).toBe(true); | |
349 | expect(journaling.disabled).toBe(true); | |
350 | expect(fastDiff.disabled).toBe(true); | |
351 | }); | |
352 | ||
353 | it('should disable features if their requirements are not met (object-map)', () => { | |
354 | objectMap.click(); // unchecks object-map | |
355 | expect(fastDiff.disabled).toBe(true); | |
356 | }); | |
11fdf7f2 TL |
357 | }); |
358 | }); | |
359 | }); |