]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.spec.ts
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / block / rbd-form / rbd-form.component.spec.ts
index 5556a847a6b7d02268f6062b515adc297ae7e86d..8c00c7460ab6a5fc2bccfcbca58cfebcbdc6cec9 100644 (file)
@@ -1,30 +1,50 @@
 import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
 import { ReactiveFormsModule } from '@angular/forms';
+import { By } from '@angular/platform-browser';
 import { ActivatedRoute, Router } from '@angular/router';
 import { RouterTestingModule } from '@angular/router/testing';
-import { TooltipModule } from 'ngx-bootstrap/tooltip';
 
 import { ToastrModule } from 'ngx-toastr';
-
-import { By } from '@angular/platform-browser';
 import { NEVER, of } from 'rxjs';
 import { delay } from 'rxjs/operators';
 
-import { ActivatedRouteStub } from '../../../../testing/activated-route-stub';
-import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
-import { RbdService } from '../../../shared/api/rbd.service';
-import { ImageSpec } from '../../../shared/models/image-spec';
-import { SharedModule } from '../../../shared/shared.module';
+import { Pool } from '~/app/ceph/pool/pool';
+import { PoolService } from '~/app/shared/api/pool.service';
+import { RbdService } from '~/app/shared/api/rbd.service';
+import { ImageSpec } from '~/app/shared/models/image-spec';
+import { SharedModule } from '~/app/shared/shared.module';
+import { ActivatedRouteStub } from '~/testing/activated-route-stub';
+import { configureTestBed } from '~/testing/unit-test-helper';
 import { RbdConfigurationFormComponent } from '../rbd-configuration-form/rbd-configuration-form.component';
 import { RbdImageFeature } from './rbd-feature.interface';
 import { RbdFormMode } from './rbd-form-mode.enum';
+import { RbdFormResponseModel } from './rbd-form-response.model';
 import { RbdFormComponent } from './rbd-form.component';
 
 describe('RbdFormComponent', () => {
+  const urlPrefix = {
+    create: '/block/rbd/create',
+    edit: '/block/rbd/edit',
+    clone: '/block/rbd/clone',
+    copy: '/block/rbd/copy'
+  };
   let component: RbdFormComponent;
   let fixture: ComponentFixture<RbdFormComponent>;
   let activatedRoute: ActivatedRouteStub;
+  const mock: { rbd: RbdFormResponseModel; pools: Pool[]; defaultFeatures: string[] } = {
+    rbd: {} as RbdFormResponseModel,
+    pools: [],
+    defaultFeatures: []
+  };
+
+  const setRouterUrl = (
+    action: 'create' | 'edit' | 'clone' | 'copy',
+    poolName?: string,
+    imageName?: string
+  ) => {
+    component['routerUrl'] = [urlPrefix[action], poolName, imageName].filter((x) => x).join('/');
+  };
 
   const queryNativeElement = (cssSelector: string) =>
     fixture.debugElement.query(By.css(cssSelector)).nativeElement;
@@ -35,8 +55,7 @@ describe('RbdFormComponent', () => {
       ReactiveFormsModule,
       RouterTestingModule,
       ToastrModule.forRoot(),
-      SharedModule,
-      TooltipModule
+      SharedModule
     ],
     declarations: [RbdFormComponent, RbdConfigurationFormComponent],
     providers: [
@@ -44,7 +63,6 @@ describe('RbdFormComponent', () => {
         provide: ActivatedRoute,
         useValue: new ActivatedRouteStub({ pool: 'foo', name: 'bar', snap: undefined })
       },
-      i18nProviders,
       RbdService
     ]
   });
@@ -52,7 +70,9 @@ describe('RbdFormComponent', () => {
   beforeEach(() => {
     fixture = TestBed.createComponent(RbdFormComponent);
     component = fixture.componentInstance;
-    activatedRoute = TestBed.get(ActivatedRoute);
+    activatedRoute = <ActivatedRouteStub>TestBed.inject(ActivatedRoute);
+
+    component.loadingReady();
   });
 
   it('should create', () => {
@@ -69,6 +89,19 @@ describe('RbdFormComponent', () => {
 
     const DELAY = 100;
 
+    const getPool = (
+      pool_name: string,
+      type: 'replicated' | 'erasure',
+      flags_names: string,
+      application_metadata: string[]
+    ): Pool =>
+      ({
+        pool_name,
+        flags_names,
+        application_metadata,
+        type
+      } as Pool);
+
     beforeEach(() => {
       createAction = spyOn(component, 'createAction').and.returnValue(of(null));
       editAction = spyOn(component, 'editAction');
@@ -76,9 +109,18 @@ describe('RbdFormComponent', () => {
       cloneAction = spyOn(component, 'cloneAction').and.returnValue(of(null));
       copyAction = spyOn(component, 'copyAction').and.returnValue(of(null));
       spyOn(component, 'setResponse').and.stub();
-      routerNavigate = spyOn(TestBed.get(Router), 'navigate').and.stub();
-      rbdServiceGetSpy = spyOn(TestBed.get(RbdService), 'get');
-      rbdServiceGetSpy.and.returnValue(of({ pool_name: 'foo', pool_image: 'bar' }));
+      routerNavigate = spyOn(TestBed.inject(Router), 'navigate').and.stub();
+      mock.pools = [
+        getPool('one', 'replicated', '', []),
+        getPool('two', 'replicated', '', ['rbd']),
+        getPool('three', 'replicated', '', ['rbd']),
+        getPool('four', 'erasure', '', ['rbd']),
+        getPool('four', 'erasure', 'ec_overwrites', ['rbd'])
+      ];
+      spyOn(TestBed.inject(PoolService), 'list').and.callFake(() => of(mock.pools));
+      rbdServiceGetSpy = spyOn(TestBed.inject(RbdService), 'get');
+      mock.rbd = ({ pool_name: 'foo', pool_image: 'bar' } as any) as RbdFormResponseModel;
+      rbdServiceGetSpy.and.returnValue(of(mock.rbd));
       component.mode = undefined;
     });
 
@@ -94,13 +136,13 @@ describe('RbdFormComponent', () => {
     });
 
     it('should unsubscribe right after image data is received', () => {
-      component.mode = RbdFormMode.editing;
-      rbdServiceGetSpy.and.returnValue(of({ pool_name: 'foo', pool_image: 'bar' }));
+      setRouterUrl('edit', 'foo', 'bar');
+      rbdServiceGetSpy.and.returnValue(of(mock.rbd));
       editAction.and.returnValue(NEVER);
-      component.ngOnInit();
-      component.submit();
-
       expect(component['rbdImage'].observers.length).toEqual(0);
+      component.ngOnInit(); // Subscribes to image once during init
+      component.submit();
+      expect(component['rbdImage'].observers.length).toEqual(1);
       expect(createAction).toHaveBeenCalledTimes(0);
       expect(editAction).toHaveBeenCalledTimes(1);
       expect(cloneAction).toHaveBeenCalledTimes(0);
@@ -109,10 +151,8 @@ describe('RbdFormComponent', () => {
     });
 
     it('should not edit image if no image data is received', fakeAsync(() => {
-      component.mode = RbdFormMode.editing;
-      rbdServiceGetSpy.and.returnValue(
-        of({ pool_name: 'foo', pool_image: 'bar' }).pipe(delay(DELAY))
-      );
+      setRouterUrl('edit', 'foo', 'bar');
+      rbdServiceGetSpy.and.returnValue(of(mock.rbd).pipe(delay(DELAY)));
       component.ngOnInit();
       component.submit();
 
@@ -125,8 +165,38 @@ describe('RbdFormComponent', () => {
       tick(DELAY);
     }));
 
+    describe('disable data pools', () => {
+      beforeEach(() => {
+        component.ngOnInit();
+      });
+
+      it('should be enabled with more than 1 pool', () => {
+        component['handleExternalData'](mock);
+        expect(component.allDataPools.length).toBe(3);
+        expect(component.rbdForm.get('useDataPool').disabled).toBe(false);
+
+        mock.pools.pop();
+        component['handleExternalData'](mock);
+        expect(component.allDataPools.length).toBe(2);
+        expect(component.rbdForm.get('useDataPool').disabled).toBe(false);
+      });
+
+      it('should be disabled with 1 pool', () => {
+        mock.pools = [mock.pools[0]];
+        component['handleExternalData'](mock);
+        expect(component.rbdForm.get('useDataPool').disabled).toBe(true);
+      });
+
+      // Reason for 2 tests - useDataPool is not re-enabled anywhere else
+      it('should be disabled without any pool', () => {
+        mock.pools = [];
+        component['handleExternalData'](mock);
+        expect(component.rbdForm.get('useDataPool').disabled).toBe(true);
+      });
+    });
+
     it('should edit image after image data is received', () => {
-      component.mode = RbdFormMode.editing;
+      setRouterUrl('edit', 'foo', 'bar');
       component.ngOnInit();
       component.submit();
 
@@ -138,10 +208,8 @@ describe('RbdFormComponent', () => {
     });
 
     it('should not clone image if no image data is received', fakeAsync(() => {
-      component.mode = RbdFormMode.cloning;
-      rbdServiceGetSpy.and.returnValue(
-        of({ pool_name: 'foo', pool_image: 'bar' }).pipe(delay(DELAY))
-      );
+      setRouterUrl('clone', 'foo', 'bar');
+      rbdServiceGetSpy.and.returnValue(of(mock.rbd).pipe(delay(DELAY)));
       component.ngOnInit();
       component.submit();
 
@@ -155,7 +223,7 @@ describe('RbdFormComponent', () => {
     }));
 
     it('should clone image after image data is received', () => {
-      component.mode = RbdFormMode.cloning;
+      setRouterUrl('clone', 'foo', 'bar');
       component.ngOnInit();
       component.submit();
 
@@ -167,10 +235,8 @@ describe('RbdFormComponent', () => {
     });
 
     it('should not copy image if no image data is received', fakeAsync(() => {
-      component.mode = RbdFormMode.copying;
-      rbdServiceGetSpy.and.returnValue(
-        of({ pool_name: 'foo', pool_image: 'bar' }).pipe(delay(DELAY))
-      );
+      setRouterUrl('copy', 'foo', 'bar');
+      rbdServiceGetSpy.and.returnValue(of(mock.rbd).pipe(delay(DELAY)));
       component.ngOnInit();
       component.submit();
 
@@ -184,7 +250,7 @@ describe('RbdFormComponent', () => {
     }));
 
     it('should copy image after image data is received', () => {
-      component.mode = RbdFormMode.copying;
+      setRouterUrl('copy', 'foo', 'bar');
       component.ngOnInit();
       component.submit();
 
@@ -200,7 +266,7 @@ describe('RbdFormComponent', () => {
     let rbdService: RbdService;
 
     beforeEach(() => {
-      rbdService = TestBed.get(RbdService);
+      rbdService = TestBed.inject(RbdService);
       component.mode = RbdFormMode.editing;
       fixture.detectChanges();
       spyOn(rbdService, 'get').and.callThrough();
@@ -282,7 +348,7 @@ describe('RbdFormComponent', () => {
 
     describe('test edit form flags', () => {
       const prepare = (pool: string, image: string, enabledFeatures: string[]): void => {
-        const rbdService = TestBed.get(RbdService);
+        const rbdService = TestBed.inject(RbdService);
         spyOn(rbdService, 'get').and.returnValue(
           of({
             name: image,
@@ -291,7 +357,7 @@ describe('RbdFormComponent', () => {
           })
         );
         spyOn(rbdService, 'defaultFeatures').and.returnValue(of(defaultFeatures));
-        component.router = { url: `/block/rbd/edit/${pool}/${image}` } as Router;
+        setRouterUrl('edit', pool, image);
         fixture.detectChanges();
         [
           deepFlatten,
@@ -339,9 +405,9 @@ describe('RbdFormComponent', () => {
 
     describe('test create form flags', () => {
       beforeEach(() => {
-        const rbdService = TestBed.get(RbdService);
+        const rbdService = TestBed.inject(RbdService);
         spyOn(rbdService, 'defaultFeatures').and.returnValue(of(defaultFeatures));
-        component.router = { url: '/block/rbd/create' } as Router;
+        setRouterUrl('create');
         fixture.detectChanges();
         [
           deepFlatten,