1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ReactiveFormsModule } from '@angular/forms';
3 import { RouterTestingModule } from '@angular/router/testing';
4 import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
5 import { Router } from '@angular/router';
6 import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
8 import { ToastrModule } from 'ngx-toastr';
9 import { of } from 'rxjs';
11 import { NgbActiveModal, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
13 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
14 import { SharedModule } from '~/app/shared/shared.module';
16 import { NvmeofGroupFormComponent } from './nvmeof-group-form.component';
17 import { GridModule, InputModule, SelectModule } from 'carbon-components-angular';
18 import { PoolService } from '~/app/shared/api/pool.service';
19 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
20 import { CephServiceService } from '~/app/shared/api/ceph-service.service';
21 import { FormHelper } from '~/testing/unit-test-helper';
23 describe('NvmeofGroupFormComponent', () => {
24 let component: NvmeofGroupFormComponent;
25 let fixture: ComponentFixture<NvmeofGroupFormComponent>;
26 let form: CdFormGroup;
27 let formHelper: FormHelper;
28 let poolService: PoolService;
29 let taskWrapperService: TaskWrapperService;
30 let cephServiceService: CephServiceService;
34 { pool_name: 'rbd', application_metadata: ['rbd'] },
35 { pool_name: 'rbd', application_metadata: ['rbd'] },
36 { pool_name: 'pool2', application_metadata: ['rgw'] }
39 beforeEach(async () => {
40 await TestBed.configureTestingModule({
41 declarations: [NvmeofGroupFormComponent],
42 providers: [NgbActiveModal],
44 HttpClientTestingModule,
52 ToastrModule.forRoot()
54 schemas: [CUSTOM_ELEMENTS_SCHEMA]
55 }).compileComponents();
57 fixture = TestBed.createComponent(NvmeofGroupFormComponent);
58 component = fixture.componentInstance;
59 poolService = TestBed.inject(PoolService);
60 taskWrapperService = TestBed.inject(TaskWrapperService);
61 cephServiceService = TestBed.inject(CephServiceService);
62 router = TestBed.inject(Router);
64 spyOn(poolService, 'list').and.returnValue(Promise.resolve(mockPools));
67 form = component.groupForm;
68 formHelper = new FormHelper(form);
69 fixture.detectChanges();
72 it('should create', () => {
73 expect(component).toBeTruthy();
76 it('should initialize form with empty fields', () => {
77 expect(form.controls.groupName.value).toBeNull();
78 expect(form.controls.unmanaged.value).toBe(false);
81 it('should set action to CREATE on init', () => {
82 expect(component.action).toBe('Create');
85 it('should set resource to gateway group', () => {
86 expect(component.resource).toBe('gateway group');
89 describe('form validation', () => {
90 it('should require groupName', () => {
91 formHelper.setValue('groupName', '');
92 formHelper.expectError('groupName', 'required');
95 it('should require pool', () => {
96 formHelper.setValue('pool', null);
97 formHelper.expectError('pool', 'required');
100 it('should be valid when groupName and pool are set', () => {
101 formHelper.setValue('groupName', 'test-group');
102 formHelper.setValue('pool', 'rbd');
103 expect(form.valid).toBe(true);
107 describe('loadPools', () => {
108 it('should load pools and filter by rbd application metadata', fakeAsync(() => {
109 component.loadPools();
111 expect(component.pools.length).toBe(2);
112 expect(component.pools.map((p) => p.pool_name)).toEqual(['rbd', 'rbd']);
115 it('should set default pool to rbd if available', fakeAsync(() => {
116 component.groupForm.get('pool').setValue(null);
117 component.loadPools();
119 expect(component.groupForm.get('pool').value).toBe('rbd');
122 it('should set first pool if rbd is not available', fakeAsync(() => {
123 component.groupForm.get('pool').setValue(null);
124 const poolsWithoutRbd = [{ pool_name: 'custom-pool', application_metadata: ['rbd'] }];
125 (poolService.list as jasmine.Spy).and.returnValue(Promise.resolve(poolsWithoutRbd));
126 component.loadPools();
128 expect(component.groupForm.get('pool').value).toBe('custom-pool');
131 it('should handle empty pools', fakeAsync(() => {
132 (poolService.list as jasmine.Spy).and.returnValue(Promise.resolve([]));
133 component.loadPools();
135 expect(component.pools.length).toBe(0);
136 expect(component.poolsLoading).toBe(false);
139 it('should handle pool loading error', fakeAsync(() => {
140 (poolService.list as jasmine.Spy).and.returnValue(Promise.reject('error'));
141 component.loadPools();
143 expect(component.pools).toEqual([]);
144 expect(component.poolsLoading).toBe(false);
148 describe('onSubmit', () => {
150 spyOn(cephServiceService, 'create').and.returnValue(of({}));
151 spyOn(taskWrapperService, 'wrapTaskAroundCall').and.callFake(({ call }) => call);
152 spyOn(router, 'navigateByUrl');
155 it('should not call create if no hosts are selected', () => {
156 component.gatewayNodeComponent = {
157 getSelectedHosts: (): any[] => [],
158 getSelectedHostnames: (): string[] => []
161 component.groupForm.get('groupName').setValue('test-group');
162 component.groupForm.get('pool').setValue('rbd');
163 component.onSubmit();
165 expect(cephServiceService.create).not.toHaveBeenCalled();
168 it('should create service with correct spec', () => {
169 component.gatewayNodeComponent = {
170 getSelectedHosts: (): any[] => [{ hostname: 'host1' }, { hostname: 'host2' }],
171 getSelectedHostnames: (): string[] => ['host1', 'host2']
174 component.groupForm.get('groupName').setValue('defalut');
175 component.groupForm.get('pool').setValue('rbd');
176 component.groupForm.get('unmanaged').setValue(false);
177 component.onSubmit();
179 expect(cephServiceService.create).toHaveBeenCalledWith({
180 service_type: 'nvmeof',
181 service_id: 'rbd.defalut',
185 hosts: ['host1', 'host2']
191 it('should create service with unmanaged flag set to true', () => {
192 component.gatewayNodeComponent = {
193 getSelectedHosts: (): any[] => [{ hostname: 'host1' }],
194 getSelectedHostnames: (): string[] => ['host1']
197 component.groupForm.get('groupName').setValue('unmanaged-group');
198 component.groupForm.get('pool').setValue('rbd');
199 component.groupForm.get('unmanaged').setValue(true);
200 component.onSubmit();
202 expect(cephServiceService.create).toHaveBeenCalledWith(
203 jasmine.objectContaining({
205 group: 'unmanaged-group',
211 it('should navigate to list view on success', () => {
212 component.gatewayNodeComponent = {
213 getSelectedHosts: (): any[] => [{ hostname: 'host1' }],
214 getSelectedHostnames: (): string[] => ['host1']
217 component.groupForm.get('groupName').setValue('test-group');
218 component.groupForm.get('pool').setValue('rbd');
219 component.onSubmit();
221 expect(router.navigateByUrl).toHaveBeenCalledWith('/block/nvmeof/gateways');