1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, discardPeriodicTasks, fakeAsync, TestBed } from '@angular/core/testing';
3 import { ReactiveFormsModule } from '@angular/forms';
4 import { ActivatedRoute, Router } from '@angular/router';
5 import { RouterTestingModule } from '@angular/router/testing';
6 import { TooltipModule } from 'ngx-bootstrap/tooltip';
8 import { ToastrModule } from 'ngx-toastr';
10 import { By } from '@angular/platform-browser';
11 import { of } from 'rxjs';
12 import { delay } from 'rxjs/operators';
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';
17 import { ImageSpec } from '../../../shared/models/image-spec';
18 import { SharedModule } from '../../../shared/shared.module';
19 import { RbdConfigurationFormComponent } from '../rbd-configuration-form/rbd-configuration-form.component';
20 import { RbdImageFeature } from './rbd-feature.interface';
21 import { RbdFormMode } from './rbd-form-mode.enum';
22 import { RbdFormComponent } from './rbd-form.component';
24 describe('RbdFormComponent', () => {
25 let component: RbdFormComponent;
26 let fixture: ComponentFixture<RbdFormComponent>;
27 let activatedRoute: ActivatedRouteStub;
29 const queryNativeElement = (cssSelector: string) =>
30 fixture.debugElement.query(By.css(cssSelector)).nativeElement;
34 HttpClientTestingModule,
37 ToastrModule.forRoot(),
41 declarations: [RbdFormComponent, RbdConfigurationFormComponent],
44 provide: ActivatedRoute,
45 useValue: new ActivatedRouteStub({ pool: 'foo', name: 'bar', snap: undefined })
53 fixture = TestBed.createComponent(RbdFormComponent);
54 component = fixture.componentInstance;
55 activatedRoute = TestBed.get(ActivatedRoute);
58 it('should create', () => {
59 expect(component).toBeTruthy();
62 describe('create/edit/clone/copy image', () => {
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;
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;
81 it('should create image', () => {
85 expect(createAction).toHaveBeenCalledTimes(1);
86 expect(editAction).toHaveBeenCalledTimes(0);
87 expect(cloneAction).toHaveBeenCalledTimes(0);
88 expect(copyAction).toHaveBeenCalledTimes(0);
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))
99 expect(createAction).toHaveBeenCalledTimes(0);
100 expect(editAction).toHaveBeenCalledTimes(0);
101 expect(cloneAction).toHaveBeenCalledTimes(0);
102 expect(copyAction).toHaveBeenCalledTimes(0);
104 discardPeriodicTasks();
107 it('should edit image after image data is received', () => {
108 component.mode = RbdFormMode.editing;
109 component.ngOnInit();
112 expect(createAction).toHaveBeenCalledTimes(0);
113 expect(editAction).toHaveBeenCalledTimes(1);
114 expect(cloneAction).toHaveBeenCalledTimes(0);
115 expect(copyAction).toHaveBeenCalledTimes(0);
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))
123 component.ngOnInit();
126 expect(createAction).toHaveBeenCalledTimes(0);
127 expect(editAction).toHaveBeenCalledTimes(0);
128 expect(cloneAction).toHaveBeenCalledTimes(0);
129 expect(copyAction).toHaveBeenCalledTimes(0);
131 discardPeriodicTasks();
134 it('should clone image after image data is received', () => {
135 component.mode = RbdFormMode.cloning;
136 component.ngOnInit();
139 expect(createAction).toHaveBeenCalledTimes(0);
140 expect(editAction).toHaveBeenCalledTimes(0);
141 expect(cloneAction).toHaveBeenCalledTimes(1);
142 expect(copyAction).toHaveBeenCalledTimes(0);
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))
150 component.ngOnInit();
153 expect(createAction).toHaveBeenCalledTimes(0);
154 expect(editAction).toHaveBeenCalledTimes(0);
155 expect(cloneAction).toHaveBeenCalledTimes(0);
156 expect(copyAction).toHaveBeenCalledTimes(0);
158 discardPeriodicTasks();
161 it('should copy image after image data is received', () => {
162 component.mode = RbdFormMode.copying;
163 component.ngOnInit();
166 expect(createAction).toHaveBeenCalledTimes(0);
167 expect(editAction).toHaveBeenCalledTimes(0);
168 expect(cloneAction).toHaveBeenCalledTimes(0);
169 expect(copyAction).toHaveBeenCalledTimes(1);
173 describe('should test decodeURIComponent of params', () => {
174 let rbdService: RbdService;
177 rbdService = TestBed.get(RbdService);
178 component.mode = RbdFormMode.editing;
179 fixture.detectChanges();
180 spyOn(rbdService, 'get').and.callThrough();
183 it('with namespace', () => {
184 activatedRoute.setParams({ image_spec: 'foo%2Fbar%2Fbaz' });
186 expect(rbdService.get).toHaveBeenCalledWith(new ImageSpec('foo', 'bar', 'baz'));
189 it('without snapName', () => {
190 activatedRoute.setParams({ image_spec: 'foo%2Fbar', snap: undefined });
192 expect(rbdService.get).toHaveBeenCalledWith(new ImageSpec('foo', null, 'bar'));
193 expect(component.snapName).toBeUndefined();
196 it('with snapName', () => {
197 activatedRoute.setParams({ image_spec: 'foo%2Fbar', snap: 'baz%2Fbaz' });
199 expect(rbdService.get).toHaveBeenCalledWith(new ImageSpec('foo', null, 'bar'));
200 expect(component.snapName).toBe('baz/baz');
204 describe('test image configuration component', () => {
205 it('is visible', () => {
206 fixture.detectChanges();
208 fixture.debugElement.query(By.css('cd-rbd-configuration-form')).nativeElement.parentElement
214 describe('tests for feature flags', () => {
215 let deepFlatten: any,
221 const defaultFeatures = [
222 // Supposed to be enabled by default
229 const allFeatureNames = [
237 const setFeatures = (features: Record<string, RbdImageFeature>) => {
238 component.features = features;
239 component.featuresList = component.objToArray(features);
240 component.createForm();
242 const getFeatureNativeElements = () => allFeatureNames.map((f) => queryNativeElement(`#${f}`));
244 it('should convert feature flags correctly in the constructor', () => {
246 one: { desc: 'one', allowEnable: true, allowDisable: true },
247 two: { desc: 'two', allowEnable: true, allowDisable: true },
248 three: { desc: 'three', allowEnable: true, allowDisable: true }
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 }
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(
264 features_name: enabledFeatures
267 spyOn(rbdService, 'defaultFeatures').and.returnValue(of(defaultFeatures));
268 component.router = { url: `/block/rbd/edit/${pool}/${image}` } as Router;
269 fixture.detectChanges();
277 ] = getFeatureNativeElements();
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']);
283 expect(objectMap.disabled).toBe(false);
284 expect(fastDiff.disabled).toBe(false);
286 expect(objectMap.checked).toBe(true);
287 expect(fastDiff.checked).toBe(false);
292 expect(objectMap.checked).toBe(true); // Shall not be disabled by `fast-diff`!
295 it('should not disable object-map when fast-diff is unchecked', () => {
296 prepare('rbd', 'foobar', ['deep-flatten', 'exclusive-lock', 'layering', 'object-map']);
301 expect(objectMap.checked).toBe(true); // Shall not be disabled by `fast-diff`!
304 it('should not enable fast-diff when object-map is checked', () => {
305 prepare('rbd', 'foobar', ['deep-flatten', 'exclusive-lock', 'layering', 'object-map']);
310 expect(fastDiff.checked).toBe(false); // Shall not be disabled by `fast-diff`!
314 describe('test create form flags', () => {
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();
327 ] = getFeatureNativeElements();
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);
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);
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);
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);