diff options
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.ts | 309 |
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: '' } + } + }); + }); +}); |