summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.spec.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.spec.ts')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.spec.ts309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.spec.ts
new file mode 100644
index 000000000..725fc953f
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.spec.ts
@@ -0,0 +1,309 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { RouterTestingModule } from '@angular/router/testing';
+
+import { ToastrModule } from 'ngx-toastr';
+import { BehaviorSubject, of } from 'rxjs';
+
+import { InventoryDevice } from '~/app/ceph/cluster/inventory/inventory-devices/inventory-device.model';
+import { InventoryDevicesComponent } from '~/app/ceph/cluster/inventory/inventory-devices/inventory-devices.component';
+import { DashboardModule } from '~/app/ceph/dashboard/dashboard.module';
+import { HostService } from '~/app/shared/api/host.service';
+import { OrchestratorService } from '~/app/shared/api/orchestrator.service';
+import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
+import {
+ DeploymentOptions,
+ OsdDeploymentOptions
+} from '~/app/shared/models/osd-deployment-options';
+import { SummaryService } from '~/app/shared/services/summary.service';
+import { SharedModule } from '~/app/shared/shared.module';
+import { configureTestBed, FixtureHelper, FormHelper } from '~/testing/unit-test-helper';
+import { DevicesSelectionChangeEvent } from '../osd-devices-selection-groups/devices-selection-change-event.interface';
+import { DevicesSelectionClearEvent } from '../osd-devices-selection-groups/devices-selection-clear-event.interface';
+import { OsdDevicesSelectionGroupsComponent } from '../osd-devices-selection-groups/osd-devices-selection-groups.component';
+import { OsdFormComponent } from './osd-form.component';
+
+describe('OsdFormComponent', () => {
+ let form: CdFormGroup;
+ let component: OsdFormComponent;
+ let formHelper: FormHelper;
+ let fixture: ComponentFixture<OsdFormComponent>;
+ let fixtureHelper: FixtureHelper;
+ let orchService: OrchestratorService;
+ let hostService: HostService;
+ let summaryService: SummaryService;
+ const devices: InventoryDevice[] = [
+ {
+ hostname: 'node0',
+ uid: '1',
+
+ path: '/dev/sda',
+ sys_api: {
+ vendor: 'VENDOR',
+ model: 'MODEL',
+ size: 1024,
+ rotational: 'false',
+ human_readable_size: '1 KB'
+ },
+ available: true,
+ rejected_reasons: [''],
+ device_id: 'VENDOR-MODEL-ID',
+ human_readable_type: 'nvme/ssd',
+ osd_ids: []
+ }
+ ];
+
+ const deploymentOptions: DeploymentOptions = {
+ options: {
+ cost_capacity: {
+ name: OsdDeploymentOptions.COST_CAPACITY,
+ available: true,
+ capacity: 0,
+ used: 0,
+ hdd_used: 0,
+ ssd_used: 0,
+ nvme_used: 0,
+ title: 'Cost/Capacity-optimized',
+ desc: 'All the available HDDs are selected'
+ },
+ throughput_optimized: {
+ name: OsdDeploymentOptions.THROUGHPUT,
+ available: false,
+ capacity: 0,
+ used: 0,
+ hdd_used: 0,
+ ssd_used: 0,
+ nvme_used: 0,
+ title: 'Throughput-optimized',
+ desc: 'HDDs/SSDs are selected for data devices and SSDs/NVMes for DB/WAL devices'
+ },
+ iops_optimized: {
+ name: OsdDeploymentOptions.IOPS,
+ available: false,
+ capacity: 0,
+ used: 0,
+ hdd_used: 0,
+ ssd_used: 0,
+ nvme_used: 0,
+ title: 'IOPS-optimized',
+ desc: 'All the available NVMes are selected'
+ }
+ },
+ recommended_option: OsdDeploymentOptions.COST_CAPACITY
+ };
+
+ const expectPreviewButton = (enabled: boolean) => {
+ const debugElement = fixtureHelper.getElementByCss('.tc_submitButton');
+ expect(debugElement.nativeElement.disabled).toBe(!enabled);
+ };
+
+ const selectDevices = (type: string) => {
+ const event: DevicesSelectionChangeEvent = {
+ type: type,
+ filters: [],
+ data: devices,
+ dataOut: []
+ };
+ component.onDevicesSelected(event);
+ if (type === 'data') {
+ component.dataDeviceSelectionGroups.devices = devices;
+ } else if (type === 'wal') {
+ component.walDeviceSelectionGroups.devices = devices;
+ } else if (type === 'db') {
+ component.dbDeviceSelectionGroups.devices = devices;
+ }
+ fixture.detectChanges();
+ };
+
+ const clearDevices = (type: string) => {
+ const event: DevicesSelectionClearEvent = {
+ type: type,
+ clearedDevices: []
+ };
+ component.onDevicesCleared(event);
+ fixture.detectChanges();
+ };
+
+ const features = ['encrypted'];
+ const checkFeatures = (enabled: boolean) => {
+ for (const feature of features) {
+ const element = fixtureHelper.getElementByCss(`#${feature}`).nativeElement;
+ expect(element.disabled).toBe(!enabled);
+ expect(element.checked).toBe(false);
+ }
+ };
+
+ configureTestBed({
+ imports: [
+ BrowserAnimationsModule,
+ HttpClientTestingModule,
+ FormsModule,
+ SharedModule,
+ RouterTestingModule,
+ ReactiveFormsModule,
+ ToastrModule.forRoot(),
+ DashboardModule
+ ],
+ declarations: [OsdFormComponent, OsdDevicesSelectionGroupsComponent, InventoryDevicesComponent]
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(OsdFormComponent);
+ fixtureHelper = new FixtureHelper(fixture);
+ component = fixture.componentInstance;
+ form = component.form;
+ formHelper = new FormHelper(form);
+ orchService = TestBed.inject(OrchestratorService);
+ hostService = TestBed.inject(HostService);
+ summaryService = TestBed.inject(SummaryService);
+ summaryService['summaryDataSource'] = new BehaviorSubject(null);
+ summaryService['summaryData$'] = summaryService['summaryDataSource'].asObservable();
+ summaryService['summaryDataSource'].next({ version: 'master' });
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ describe('without orchestrator', () => {
+ beforeEach(() => {
+ spyOn(orchService, 'status').and.returnValue(of({ available: false }));
+ spyOn(hostService, 'inventoryDeviceList').and.callThrough();
+ fixture.detectChanges();
+ });
+
+ it('should display info panel to document', () => {
+ fixtureHelper.expectElementVisible('cd-alert-panel', true);
+ fixtureHelper.expectElementVisible('.col-sm-10 form', false);
+ });
+
+ it('should not call inventoryDeviceList', () => {
+ expect(hostService.inventoryDeviceList).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('with orchestrator', () => {
+ beforeEach(() => {
+ component.simpleDeployment = false;
+ spyOn(orchService, 'status').and.returnValue(of({ available: true }));
+ spyOn(hostService, 'inventoryDeviceList').and.returnValue(of([]));
+ component.deploymentOptions = deploymentOptions;
+ fixture.detectChanges();
+ });
+
+ it('should display the accordion', () => {
+ fixtureHelper.expectElementVisible('.card-body .accordion', true);
+ });
+
+ it('should display the three deployment scenarios', () => {
+ fixtureHelper.expectElementVisible('#cost_capacity', true);
+ fixtureHelper.expectElementVisible('#throughput_optimized', true);
+ fixtureHelper.expectElementVisible('#iops_optimized', true);
+ });
+
+ it('should only disable the options that are not available', () => {
+ let radioBtn = fixtureHelper.getElementByCss('#throughput_optimized').nativeElement;
+ expect(radioBtn.disabled).toBeTruthy();
+ radioBtn = fixtureHelper.getElementByCss('#iops_optimized').nativeElement;
+ expect(radioBtn.disabled).toBeTruthy();
+
+ // Make the throughput_optimized option available and verify the option is not disabled
+ deploymentOptions.options['throughput_optimized'].available = true;
+ fixture.detectChanges();
+ radioBtn = fixtureHelper.getElementByCss('#throughput_optimized').nativeElement;
+ expect(radioBtn.disabled).toBeFalsy();
+ });
+
+ it('should be a Recommended option only when it is recommended by backend', () => {
+ const label = fixtureHelper.getElementByCss('#label_cost_capacity').nativeElement;
+ const throughputLabel = fixtureHelper.getElementByCss('#label_throughput_optimized')
+ .nativeElement;
+
+ expect(label.innerHTML).toContain('Recommended');
+ expect(throughputLabel.innerHTML).not.toContain('Recommended');
+
+ deploymentOptions.recommended_option = OsdDeploymentOptions.THROUGHPUT;
+ fixture.detectChanges();
+ expect(throughputLabel.innerHTML).toContain('Recommended');
+ expect(label.innerHTML).not.toContain('Recommended');
+ });
+
+ it('should display form', () => {
+ fixtureHelper.expectElementVisible('cd-alert-panel', false);
+ fixtureHelper.expectElementVisible('.card-body form', true);
+ });
+
+ describe('without data devices selected', () => {
+ it('should disable preview button', () => {
+ expectPreviewButton(false);
+ });
+
+ it('should not display shared devices slots', () => {
+ fixtureHelper.expectElementVisible('#walSlots', false);
+ fixtureHelper.expectElementVisible('#dbSlots', false);
+ });
+
+ it('should disable the checkboxes', () => {
+ checkFeatures(false);
+ });
+ });
+
+ describe('with data devices selected', () => {
+ beforeEach(() => {
+ selectDevices('data');
+ });
+
+ it('should enable preview button', () => {
+ expectPreviewButton(true);
+ });
+
+ it('should not display shared devices slots', () => {
+ fixtureHelper.expectElementVisible('#walSlots', false);
+ fixtureHelper.expectElementVisible('#dbSlots', false);
+ });
+
+ it('should enable the checkboxes', () => {
+ checkFeatures(true);
+ });
+
+ it('should disable the checkboxes after clearing data devices', () => {
+ clearDevices('data');
+ checkFeatures(false);
+ });
+
+ describe('with shared devices selected', () => {
+ beforeEach(() => {
+ selectDevices('wal');
+ selectDevices('db');
+ });
+
+ it('should display slots', () => {
+ fixtureHelper.expectElementVisible('#walSlots', true);
+ fixtureHelper.expectElementVisible('#dbSlots', true);
+ });
+
+ it('validate slots', () => {
+ for (const control of ['walSlots', 'dbSlots']) {
+ formHelper.expectValid(control);
+ formHelper.expectValidChange(control, 1);
+ formHelper.expectErrorChange(control, -1, 'min');
+ }
+ });
+
+ describe('test clearing data devices', () => {
+ beforeEach(() => {
+ clearDevices('data');
+ });
+
+ it('should not display shared devices slots and should disable checkboxes', () => {
+ fixtureHelper.expectElementVisible('#walSlots', false);
+ fixtureHelper.expectElementVisible('#dbSlots', false);
+ checkFeatures(false);
+ });
+ });
+ });
+ });
+ });
+});