]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-list/nfs-list.component.spec.ts
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / nfs / nfs-list / nfs-list.component.spec.ts
1 import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
2 import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
3 import { By } from '@angular/platform-browser';
4 import { RouterTestingModule } from '@angular/router/testing';
5
6 import { TabsModule } from 'ngx-bootstrap/tabs';
7 import { ToastrModule } from 'ngx-toastr';
8 import { BehaviorSubject, of } from 'rxjs';
9
10 import {
11 configureTestBed,
12 i18nProviders,
13 PermissionHelper
14 } from '../../../../testing/unit-test-helper';
15 import { NfsService } from '../../../shared/api/nfs.service';
16 import { TableActionsComponent } from '../../../shared/datatable/table-actions/table-actions.component';
17 import { ExecutingTask } from '../../../shared/models/executing-task';
18 import { SummaryService } from '../../../shared/services/summary.service';
19 import { TaskListService } from '../../../shared/services/task-list.service';
20 import { SharedModule } from '../../../shared/shared.module';
21 import { NfsDetailsComponent } from '../nfs-details/nfs-details.component';
22 import { NfsListComponent } from './nfs-list.component';
23
24 describe('NfsListComponent', () => {
25 let component: NfsListComponent;
26 let fixture: ComponentFixture<NfsListComponent>;
27 let summaryService: SummaryService;
28 let nfsService: NfsService;
29 let httpTesting: HttpTestingController;
30
31 const refresh = (data) => {
32 summaryService['summaryDataSource'].next(data);
33 };
34
35 configureTestBed(
36 {
37 declarations: [NfsListComponent, NfsDetailsComponent],
38 imports: [
39 HttpClientTestingModule,
40 RouterTestingModule,
41 SharedModule,
42 ToastrModule.forRoot(),
43 TabsModule.forRoot()
44 ],
45 providers: [TaskListService, i18nProviders]
46 },
47 true
48 );
49
50 beforeEach(() => {
51 fixture = TestBed.createComponent(NfsListComponent);
52 component = fixture.componentInstance;
53 summaryService = TestBed.get(SummaryService);
54 nfsService = TestBed.get(NfsService);
55 httpTesting = TestBed.get(HttpTestingController);
56
57 // this is needed because summaryService isn't being reset after each test.
58 summaryService['summaryDataSource'] = new BehaviorSubject(null);
59 summaryService['summaryData$'] = summaryService['summaryDataSource'].asObservable();
60 });
61
62 it('should create', () => {
63 expect(component).toBeTruthy();
64 });
65
66 describe('after ngOnInit', () => {
67 beforeEach(() => {
68 fixture.detectChanges();
69 spyOn(nfsService, 'list').and.callThrough();
70 httpTesting.expectOne('api/nfs-ganesha/daemon').flush([]);
71 httpTesting.expectOne('api/summary');
72 });
73
74 afterEach(() => {
75 httpTesting.verify();
76 });
77
78 it('should load exports on init', () => {
79 refresh({});
80 httpTesting.expectOne('api/nfs-ganesha/export');
81 expect(nfsService.list).toHaveBeenCalled();
82 });
83
84 it('should not load images on init because no data', () => {
85 refresh(undefined);
86 expect(nfsService.list).not.toHaveBeenCalled();
87 });
88
89 it('should call error function on init when summary service fails', () => {
90 spyOn(component.table, 'reset');
91 summaryService['summaryDataSource'].error(undefined);
92 expect(component.table.reset).toHaveBeenCalled();
93 });
94 });
95
96 describe('handling of executing tasks', () => {
97 let exports: any[];
98
99 const addExport = (export_id) => {
100 const model = {
101 export_id: export_id,
102 path: 'path_' + export_id,
103 fsal: 'fsal_' + export_id,
104 cluster_id: 'cluster_' + export_id
105 };
106 exports.push(model);
107 };
108
109 const addTask = (name: string, export_id: string) => {
110 const task = new ExecutingTask();
111 task.name = name;
112 switch (task.name) {
113 case 'nfs/create':
114 task.metadata = {
115 path: 'path_' + export_id,
116 fsal: 'fsal_' + export_id,
117 cluster_id: 'cluster_' + export_id
118 };
119 break;
120 default:
121 task.metadata = {
122 cluster_id: 'cluster_' + export_id,
123 export_id: export_id
124 };
125 break;
126 }
127 summaryService.addRunningTask(task);
128 };
129
130 const expectExportTasks = (expo: any, executing: string) => {
131 expect(expo.cdExecuting).toEqual(executing);
132 };
133
134 beforeEach(() => {
135 exports = [];
136 addExport('a');
137 addExport('b');
138 addExport('c');
139 component.exports = exports;
140 refresh({ executing_tasks: [], finished_tasks: [] });
141 spyOn(nfsService, 'list').and.callFake(() => of(exports));
142 fixture.detectChanges();
143
144 const req = httpTesting.expectOne('api/nfs-ganesha/daemon');
145 req.flush([]);
146 });
147
148 it('should gets all exports without tasks', () => {
149 expect(component.exports.length).toBe(3);
150 expect(component.exports.every((expo) => !expo.cdExecuting)).toBeTruthy();
151 });
152
153 it('should add a new export from a task', fakeAsync(() => {
154 addTask('nfs/create', 'd');
155 tick();
156 expect(component.exports.length).toBe(4);
157 expectExportTasks(component.exports[0], undefined);
158 expectExportTasks(component.exports[1], undefined);
159 expectExportTasks(component.exports[2], undefined);
160 expectExportTasks(component.exports[3], 'Creating');
161 }));
162
163 it('should show when an existing export is being modified', () => {
164 addTask('nfs/edit', 'a');
165 addTask('nfs/delete', 'b');
166 expect(component.exports.length).toBe(3);
167 expectExportTasks(component.exports[0], 'Updating');
168 expectExportTasks(component.exports[1], 'Deleting');
169 });
170 });
171
172 describe('show action buttons and drop down actions depending on permissions', () => {
173 let tableActions: TableActionsComponent;
174 let scenario: { fn; empty; single };
175 let permissionHelper: PermissionHelper;
176
177 const getTableActionComponent = (): TableActionsComponent => {
178 fixture.detectChanges();
179 return fixture.debugElement.query(By.directive(TableActionsComponent)).componentInstance;
180 };
181
182 beforeEach(() => {
183 permissionHelper = new PermissionHelper(component.permission, () =>
184 getTableActionComponent()
185 );
186 scenario = {
187 fn: () => tableActions.getCurrentButton().name,
188 single: 'Edit',
189 empty: 'Add'
190 };
191 });
192
193 describe('with all', () => {
194 beforeEach(() => {
195 tableActions = permissionHelper.setPermissionsAndGetActions(1, 1, 1);
196 });
197
198 it(`shows 'Edit' for single selection else 'Add' as main action`, () =>
199 permissionHelper.testScenarios(scenario));
200
201 it('shows all actions', () => {
202 expect(tableActions.tableActions.length).toBe(3);
203 expect(tableActions.tableActions).toEqual(component.tableActions);
204 });
205 });
206
207 describe('with read, create and update', () => {
208 beforeEach(() => {
209 tableActions = permissionHelper.setPermissionsAndGetActions(1, 1, 0);
210 });
211
212 it(`shows 'Edit' for single selection else 'Add' as main action`, () =>
213 permissionHelper.testScenarios(scenario));
214
215 it(`shows all actions except for 'Delete'`, () => {
216 expect(tableActions.tableActions.length).toBe(2);
217 component.tableActions.pop();
218 expect(tableActions.tableActions).toEqual(component.tableActions);
219 });
220 });
221
222 describe('with read, create and delete', () => {
223 beforeEach(() => {
224 tableActions = permissionHelper.setPermissionsAndGetActions(1, 0, 1);
225 });
226
227 it(`shows 'Delete' for single selection else 'Add' as main action`, () => {
228 scenario.single = 'Delete';
229 permissionHelper.testScenarios(scenario);
230 });
231
232 it(`shows 'Add', and 'Delete' action`, () => {
233 expect(tableActions.tableActions.length).toBe(2);
234 expect(tableActions.tableActions).toEqual([
235 component.tableActions[0],
236 component.tableActions[2]
237 ]);
238 });
239 });
240
241 describe('with read, edit and delete', () => {
242 beforeEach(() => {
243 tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 1);
244 });
245
246 it(`shows always 'Edit' as main action`, () => {
247 scenario.empty = 'Edit';
248 permissionHelper.testScenarios(scenario);
249 });
250
251 it(`shows 'Edit' and 'Delete' actions`, () => {
252 expect(tableActions.tableActions.length).toBe(2);
253 expect(tableActions.tableActions).toEqual([
254 component.tableActions[1],
255 component.tableActions[2]
256 ]);
257 });
258 });
259
260 describe('with read and create', () => {
261 beforeEach(() => {
262 tableActions = permissionHelper.setPermissionsAndGetActions(1, 0, 0);
263 });
264
265 it(`always shows 'Add' as main action`, () => {
266 scenario.single = 'Add';
267 permissionHelper.testScenarios(scenario);
268 });
269
270 it(`shows 'Add' action`, () => {
271 expect(tableActions.tableActions.length).toBe(1);
272 expect(tableActions.tableActions).toEqual([component.tableActions[0]]);
273 });
274 });
275
276 describe('with read and edit', () => {
277 beforeEach(() => {
278 tableActions = permissionHelper.setPermissionsAndGetActions(0, 1, 0);
279 });
280
281 it(`shows always 'Edit' as main action`, () => {
282 scenario.empty = 'Edit';
283 permissionHelper.testScenarios(scenario);
284 });
285
286 it(`shows 'Edit' action`, () => {
287 expect(tableActions.tableActions.length).toBe(1);
288 expect(tableActions.tableActions).toEqual([component.tableActions[1]]);
289 });
290 });
291
292 describe('with read and delete', () => {
293 beforeEach(() => {
294 tableActions = permissionHelper.setPermissionsAndGetActions(0, 0, 1);
295 });
296
297 it(`shows always 'Delete' as main action`, () => {
298 scenario.single = 'Delete';
299 scenario.empty = 'Delete';
300 permissionHelper.testScenarios(scenario);
301 });
302
303 it(`shows 'Delete' action`, () => {
304 expect(tableActions.tableActions.length).toBe(1);
305 expect(tableActions.tableActions).toEqual([component.tableActions[2]]);
306 });
307 });
308
309 describe('with only read', () => {
310 beforeEach(() => {
311 tableActions = permissionHelper.setPermissionsAndGetActions(0, 0, 0);
312 });
313
314 it('shows no main action', () => {
315 permissionHelper.testScenarios({
316 fn: () => tableActions.getCurrentButton(),
317 single: undefined,
318 empty: undefined
319 });
320 });
321
322 it('shows no actions', () => {
323 expect(tableActions.tableActions.length).toBe(0);
324 expect(tableActions.tableActions).toEqual([]);
325 });
326 });
327 });
328 });