summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/ceph/shared/smart-list/smart-list.component.spec.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/ceph/shared/smart-list/smart-list.component.spec.ts')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/shared/smart-list/smart-list.component.spec.ts264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/shared/smart-list/smart-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/shared/smart-list/smart-list.component.spec.ts
new file mode 100644
index 000000000..54c436ca6
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/shared/smart-list/smart-list.component.spec.ts
@@ -0,0 +1,264 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { SimpleChange, SimpleChanges } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
+import _ from 'lodash';
+import { NgxPipeFunctionModule } from 'ngx-pipe-function';
+import { of } from 'rxjs';
+
+import { OsdService } from '~/app/shared/api/osd.service';
+import {
+ AtaSmartDataV1,
+ IscsiSmartDataV1,
+ NvmeSmartDataV1,
+ SmartDataResult
+} from '~/app/shared/models/smart';
+import { SharedModule } from '~/app/shared/shared.module';
+import { configureTestBed } from '~/testing/unit-test-helper';
+import { SmartListComponent } from './smart-list.component';
+
+describe('OsdSmartListComponent', () => {
+ let component: SmartListComponent;
+ let fixture: ComponentFixture<SmartListComponent>;
+ let osdService: OsdService;
+
+ const SMART_DATA_ATA_VERSION_1_0: AtaSmartDataV1 = require('./fixtures/smart_data_version_1_0_ata_response.json');
+ const SMART_DATA_NVME_VERSION_1_0: NvmeSmartDataV1 = require('./fixtures/smart_data_version_1_0_nvme_response.json');
+ const SMART_DATA_SCSI_VERSION_1_0: IscsiSmartDataV1 = require('./fixtures/smart_data_version_1_0_scsi_response.json');
+
+ /**
+ * Sets attributes for _all_ returned devices according to the given path. The syntax is the same
+ * as used in lodash.set().
+ *
+ * @example
+ * patchData('json_format_version', [2, 0]) // sets the value of `json_format_version` to [2, 0]
+ * // for all devices
+ *
+ * patchData('json_format_version[0]', 2) // same result
+ *
+ * @param path The path to the attribute
+ * @param newValue The new value
+ */
+ const patchData = (path: string, newValue: any): any => {
+ return _.reduce(
+ _.cloneDeep(SMART_DATA_ATA_VERSION_1_0),
+ (result: object, dataObj, deviceId) => {
+ result[deviceId] = _.set<any>(dataObj, path, newValue);
+ return result;
+ },
+ {}
+ );
+ };
+
+ /**
+ * Initializes the component after it spied upon the `getSmartData()` method
+ * of `OsdService`. Determines which data is returned.
+ */
+ const initializeComponentWithData = (
+ dataType: 'hdd_v1' | 'nvme_v1' | 'hdd_v1_scsi',
+ patch: { [path: string]: any } = null,
+ simpleChanges?: SimpleChanges
+ ) => {
+ let data: AtaSmartDataV1 | NvmeSmartDataV1 | IscsiSmartDataV1;
+ switch (dataType) {
+ case 'hdd_v1':
+ data = SMART_DATA_ATA_VERSION_1_0;
+ break;
+ case 'nvme_v1':
+ data = SMART_DATA_NVME_VERSION_1_0;
+ break;
+ case 'hdd_v1_scsi':
+ data = SMART_DATA_SCSI_VERSION_1_0;
+ break;
+ }
+
+ if (_.isObject(patch)) {
+ _.each(patch, (replacement, path) => {
+ data = patchData(path, replacement);
+ });
+ }
+
+ spyOn(osdService, 'getSmartData').and.callFake(() => of(data));
+ component.ngOnInit();
+ const changes: SimpleChanges = simpleChanges || {
+ osdId: new SimpleChange(null, 0, true)
+ };
+ component.ngOnChanges(changes);
+ };
+
+ /**
+ * Verify an alert panel and its attributes.
+ *
+ * @param selector The CSS selector for the alert panel.
+ * @param panelTitle The title should be displayed.
+ * @param panelType Alert level of panel. Can be in `warning` or `info`.
+ * @param panelSize Pass `slim` for slim alert panel.
+ */
+ const verifyAlertPanel = (
+ selector: string,
+ panelTitle: string,
+ panelType: 'warning' | 'info',
+ panelSize?: 'slim'
+ ) => {
+ const alertPanel = fixture.debugElement.query(By.css(selector));
+ expect(component.incompatible).toBe(false);
+ expect(component.loading).toBe(false);
+
+ expect(alertPanel.attributes.type).toBe(panelType);
+ if (panelSize === 'slim') {
+ expect(alertPanel.attributes.title).toBe(panelTitle);
+ expect(alertPanel.attributes.size).toBe(panelSize);
+ } else {
+ const panelText = alertPanel.query(By.css('.alert-panel-text'));
+ expect(panelText.nativeElement.textContent).toBe(panelTitle);
+ }
+ };
+
+ configureTestBed({
+ declarations: [SmartListComponent],
+ imports: [
+ BrowserAnimationsModule,
+ SharedModule,
+ HttpClientTestingModule,
+ NgbNavModule,
+ NgxPipeFunctionModule
+ ]
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SmartListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+
+ osdService = TestBed.inject(OsdService);
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ describe('tests ATA version 1.x', () => {
+ beforeEach(() => initializeComponentWithData('hdd_v1'));
+
+ it('should return with proper keys', () => {
+ _.each(component.data, (smartData, _deviceId) => {
+ expect(_.keys(smartData)).toEqual(['info', 'smart', 'device', 'identifier']);
+ });
+ });
+
+ it('should not contain excluded keys in `info`', () => {
+ const excludes = [
+ 'ata_smart_attributes',
+ 'ata_smart_selective_self_test_log',
+ 'ata_smart_data'
+ ];
+ _.each(component.data, (smartData: SmartDataResult, _deviceId) => {
+ _.each(excludes, (exclude) => expect(smartData.info[exclude]).toBeUndefined());
+ });
+ });
+ });
+
+ describe('tests NVMe version 1.x', () => {
+ beforeEach(() => initializeComponentWithData('nvme_v1'));
+
+ it('should return with proper keys', () => {
+ _.each(component.data, (smartData, _deviceId) => {
+ expect(_.keys(smartData)).toEqual(['info', 'smart', 'device', 'identifier']);
+ });
+ });
+
+ it('should not contain excluded keys in `info`', () => {
+ const excludes = ['nvme_smart_health_information_log'];
+ _.each(component.data, (smartData: SmartDataResult, _deviceId) => {
+ _.each(excludes, (exclude) => expect(smartData.info[exclude]).toBeUndefined());
+ });
+ });
+ });
+
+ describe('tests SCSI version 1.x', () => {
+ beforeEach(() => initializeComponentWithData('hdd_v1_scsi'));
+
+ it('should return with proper keys', () => {
+ _.each(component.data, (smartData, _deviceId) => {
+ expect(_.keys(smartData)).toEqual(['info', 'smart', 'device', 'identifier']);
+ });
+ });
+
+ it('should not contain excluded keys in `info`', () => {
+ const excludes = ['scsi_error_counter_log', 'scsi_grown_defect_list'];
+ _.each(component.data, (smartData: SmartDataResult, _deviceId) => {
+ _.each(excludes, (exclude) => expect(smartData.info[exclude]).toBeUndefined());
+ });
+ });
+ });
+
+ it('should not work for version 2.x', () => {
+ initializeComponentWithData('nvme_v1', { json_format_version: [2, 0] });
+ expect(component.data).toEqual({});
+ expect(component.incompatible).toBeTruthy();
+ });
+
+ it('should display info panel for passed self test', () => {
+ initializeComponentWithData('hdd_v1');
+ fixture.detectChanges();
+ verifyAlertPanel(
+ 'cd-alert-panel#alert-self-test-passed',
+ 'SMART overall-health self-assessment test result',
+ 'info',
+ 'slim'
+ );
+ });
+
+ it('should display warning panel for failed self test', () => {
+ initializeComponentWithData('hdd_v1', { 'smart_status.passed': false });
+ fixture.detectChanges();
+ verifyAlertPanel(
+ 'cd-alert-panel#alert-self-test-failed',
+ 'SMART overall-health self-assessment test result',
+ 'warning',
+ 'slim'
+ );
+ });
+
+ it('should display warning panel for unknown self test', () => {
+ initializeComponentWithData('hdd_v1', { smart_status: undefined });
+ fixture.detectChanges();
+ verifyAlertPanel(
+ 'cd-alert-panel#alert-self-test-unknown',
+ 'SMART overall-health self-assessment test result',
+ 'warning',
+ 'slim'
+ );
+ });
+
+ it('should display info panel for empty device info', () => {
+ initializeComponentWithData('hdd_v1');
+ const deviceId: string = _.keys(component.data)[0];
+ component.data[deviceId]['info'] = {};
+ fixture.detectChanges();
+ component.nav.select(1);
+ fixture.detectChanges();
+ verifyAlertPanel(
+ 'cd-alert-panel#alert-device-info-unavailable',
+ 'No device information available for this device.',
+ 'info'
+ );
+ });
+
+ it('should display info panel for empty SMART data', () => {
+ initializeComponentWithData('hdd_v1');
+ const deviceId: string = _.keys(component.data)[0];
+ component.data[deviceId]['smart'] = {};
+ fixture.detectChanges();
+ component.nav.select(2);
+ fixture.detectChanges();
+ verifyAlertPanel(
+ 'cd-alert-panel#alert-device-smart-data-unavailable',
+ 'No SMART data available for this device.',
+ 'info'
+ );
+ });
+});