summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts
new file mode 100644
index 000000000..51998cf0b
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts
@@ -0,0 +1,309 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { RouterTestingModule } from '@angular/router/testing';
+
+import { TreeModule } from '@circlon/angular-tree-component';
+import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
+import { ToastrModule } from 'ngx-toastr';
+import { BehaviorSubject, of } from 'rxjs';
+
+import { IscsiService } from '~/app/shared/api/iscsi.service';
+import { TableActionsComponent } from '~/app/shared/datatable/table-actions/table-actions.component';
+import { CdTableAction } from '~/app/shared/models/cd-table-action';
+import { ExecutingTask } from '~/app/shared/models/executing-task';
+import { SummaryService } from '~/app/shared/services/summary.service';
+import { TaskListService } from '~/app/shared/services/task-list.service';
+import { SharedModule } from '~/app/shared/shared.module';
+import { configureTestBed, expectItemTasks, PermissionHelper } from '~/testing/unit-test-helper';
+import { IscsiTabsComponent } from '../iscsi-tabs/iscsi-tabs.component';
+import { IscsiTargetDetailsComponent } from '../iscsi-target-details/iscsi-target-details.component';
+import { IscsiTargetListComponent } from './iscsi-target-list.component';
+
+describe('IscsiTargetListComponent', () => {
+ let component: IscsiTargetListComponent;
+ let fixture: ComponentFixture<IscsiTargetListComponent>;
+ let summaryService: SummaryService;
+ let iscsiService: IscsiService;
+
+ const refresh = (data: any) => {
+ summaryService['summaryDataSource'].next(data);
+ };
+
+ configureTestBed({
+ imports: [
+ BrowserAnimationsModule,
+ HttpClientTestingModule,
+ RouterTestingModule,
+ SharedModule,
+ TreeModule,
+ ToastrModule.forRoot(),
+ NgbNavModule
+ ],
+ declarations: [IscsiTargetListComponent, IscsiTabsComponent, IscsiTargetDetailsComponent],
+ providers: [TaskListService]
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(IscsiTargetListComponent);
+ component = fixture.componentInstance;
+ summaryService = TestBed.inject(SummaryService);
+ iscsiService = TestBed.inject(IscsiService);
+
+ // this is needed because summaryService isn't being reset after each test.
+ summaryService['summaryDataSource'] = new BehaviorSubject(null);
+ summaryService['summaryData$'] = summaryService['summaryDataSource'].asObservable();
+
+ spyOn(iscsiService, 'status').and.returnValue(of({ available: true }));
+ spyOn(iscsiService, 'version').and.returnValue(of({ ceph_iscsi_config_version: 11 }));
+ spyOn(component, 'setTableRefreshTimeout').and.stub();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ describe('after ngOnInit', () => {
+ beforeEach(() => {
+ spyOn(iscsiService, 'listTargets').and.callThrough();
+ fixture.detectChanges();
+ });
+
+ it('should load targets on init', () => {
+ refresh({});
+ expect(iscsiService.status).toHaveBeenCalled();
+ expect(iscsiService.listTargets).toHaveBeenCalled();
+ });
+
+ it('should not load targets on init because no data', () => {
+ refresh(undefined);
+ expect(iscsiService.listTargets).not.toHaveBeenCalled();
+ });
+
+ it('should call error function on init when summary service fails', () => {
+ spyOn(component.table, 'reset');
+ summaryService['summaryDataSource'].error(undefined);
+ expect(component.table.reset).toHaveBeenCalled();
+ });
+
+ it('should call settings on the getTargets methods', () => {
+ spyOn(iscsiService, 'settings').and.callThrough();
+ component.getTargets();
+ expect(iscsiService.settings).toHaveBeenCalled();
+ });
+ });
+
+ describe('handling of executing tasks', () => {
+ let targets: any[];
+
+ const addTarget = (name: string) => {
+ const model: any = {
+ target_iqn: name,
+ portals: [{ host: 'node1', ip: '192.168.100.201' }],
+ disks: [{ pool: 'rbd', image: 'disk_1', controls: {} }],
+ clients: [
+ {
+ client_iqn: 'iqn.1994-05.com.redhat:rh7-client',
+ luns: [{ pool: 'rbd', image: 'disk_1' }],
+ auth: {
+ user: 'myiscsiusername',
+ password: 'myiscsipassword',
+ mutual_user: null,
+ mutual_password: null
+ }
+ }
+ ],
+ groups: [],
+ target_controls: {}
+ };
+ targets.push(model);
+ };
+
+ const addTask = (name: string, target_iqn: string) => {
+ const task = new ExecutingTask();
+ task.name = name;
+ switch (task.name) {
+ case 'iscsi/target/create':
+ task.metadata = {
+ target_iqn: target_iqn
+ };
+ break;
+ case 'iscsi/target/delete':
+ task.metadata = {
+ target_iqn: target_iqn
+ };
+ break;
+ default:
+ task.metadata = {
+ target_iqn: target_iqn
+ };
+ break;
+ }
+ summaryService.addRunningTask(task);
+ };
+
+ beforeEach(() => {
+ targets = [];
+ addTarget('iqn.a');
+ addTarget('iqn.b');
+ addTarget('iqn.c');
+
+ component.targets = targets;
+ refresh({ executing_tasks: [], finished_tasks: [] });
+ spyOn(iscsiService, 'listTargets').and.callFake(() => of(targets));
+ fixture.detectChanges();
+ });
+
+ it('should gets all targets without tasks', () => {
+ expect(component.targets.length).toBe(3);
+ expect(component.targets.every((target) => !target.cdExecuting)).toBeTruthy();
+ });
+
+ it('should add a new target from a task', () => {
+ addTask('iscsi/target/create', 'iqn.d');
+ expect(component.targets.length).toBe(4);
+ expectItemTasks(component.targets[0], undefined);
+ expectItemTasks(component.targets[1], undefined);
+ expectItemTasks(component.targets[2], undefined);
+ expectItemTasks(component.targets[3], 'Creating');
+ });
+
+ it('should show when an existing target is being modified', () => {
+ addTask('iscsi/target/delete', 'iqn.b');
+ expect(component.targets.length).toBe(3);
+ expectItemTasks(component.targets[1], 'Deleting');
+ });
+ });
+
+ describe('handling of actions', () => {
+ beforeEach(() => {
+ fixture.detectChanges();
+ });
+
+ let action: CdTableAction;
+
+ const getAction = (name: string): CdTableAction => {
+ return component.tableActions.find((tableAction) => tableAction.name === name);
+ };
+
+ describe('edit', () => {
+ beforeEach(() => {
+ action = getAction('Edit');
+ });
+
+ it('should be disabled if no gateways', () => {
+ component.selection.selected = [
+ {
+ id: '-1'
+ }
+ ];
+ expect(action.disable(undefined)).toBe('Unavailable gateway(s)');
+ });
+
+ it('should be enabled if active sessions', () => {
+ component.selection.selected = [
+ {
+ id: '-1',
+ info: {
+ num_sessions: 1
+ }
+ }
+ ];
+ expect(action.disable(undefined)).toBeFalsy();
+ });
+
+ it('should be enabled if no active sessions', () => {
+ component.selection.selected = [
+ {
+ id: '-1',
+ info: {
+ num_sessions: 0
+ }
+ }
+ ];
+ expect(action.disable(undefined)).toBeFalsy();
+ });
+ });
+
+ describe('delete', () => {
+ beforeEach(() => {
+ action = getAction('Delete');
+ });
+
+ it('should be disabled if no gateways', () => {
+ component.selection.selected = [
+ {
+ id: '-1'
+ }
+ ];
+ expect(action.disable(undefined)).toBe('Unavailable gateway(s)');
+ });
+
+ it('should be disabled if active sessions', () => {
+ component.selection.selected = [
+ {
+ id: '-1',
+ info: {
+ num_sessions: 1
+ }
+ }
+ ];
+ expect(action.disable(undefined)).toBe('Target has active sessions');
+ });
+
+ it('should be enabled if no active sessions', () => {
+ component.selection.selected = [
+ {
+ id: '-1',
+ info: {
+ num_sessions: 0
+ }
+ }
+ ];
+ expect(action.disable(undefined)).toBeFalsy();
+ });
+ });
+ });
+
+ it('should test all TableActions combinations', () => {
+ const permissionHelper: PermissionHelper = new PermissionHelper(component.permission);
+ const tableActions: TableActionsComponent = permissionHelper.setPermissionsAndGetActions(
+ component.tableActions
+ );
+
+ expect(tableActions).toEqual({
+ 'create,update,delete': {
+ actions: ['Create', 'Edit', 'Delete'],
+ primary: { multiple: 'Create', executing: 'Edit', single: 'Edit', no: 'Create' }
+ },
+ 'create,update': {
+ actions: ['Create', 'Edit'],
+ primary: { multiple: 'Create', executing: 'Edit', single: 'Edit', no: 'Create' }
+ },
+ 'create,delete': {
+ actions: ['Create', 'Delete'],
+ primary: { multiple: 'Create', executing: 'Delete', single: 'Delete', no: 'Create' }
+ },
+ create: {
+ actions: ['Create'],
+ primary: { multiple: 'Create', executing: 'Create', single: 'Create', no: 'Create' }
+ },
+ 'update,delete': {
+ actions: ['Edit', 'Delete'],
+ primary: { multiple: 'Edit', executing: 'Edit', single: 'Edit', no: 'Edit' }
+ },
+ update: {
+ actions: ['Edit'],
+ primary: { multiple: 'Edit', executing: 'Edit', single: 'Edit', no: 'Edit' }
+ },
+ delete: {
+ actions: ['Delete'],
+ primary: { multiple: 'Delete', executing: 'Delete', single: 'Delete', no: 'Delete' }
+ },
+ 'no-permissions': {
+ actions: [],
+ primary: { multiple: '', executing: '', single: '', no: '' }
+ }
+ });
+ });
+});