]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.spec.ts
update ceph source to reef 18.2.1
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / core / navigation / navigation / navigation.component.spec.ts
1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, TestBed } from '@angular/core/testing';
3 import { By } from '@angular/platform-browser';
4 import { RouterTestingModule } from '@angular/router/testing';
5
6 import { ToastrModule } from 'ngx-toastr';
7 import { SimplebarAngularModule } from 'simplebar-angular';
8 import { of } from 'rxjs';
9
10 import { Permission, Permissions } from '~/app/shared/models/permissions';
11 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
12 import {
13 Features,
14 FeatureTogglesMap,
15 FeatureTogglesService
16 } from '~/app/shared/services/feature-toggles.service';
17 import { PrometheusAlertService } from '~/app/shared/services/prometheus-alert.service';
18 import { SummaryService } from '~/app/shared/services/summary.service';
19 import { SharedModule } from '~/app/shared/shared.module';
20 import { configureTestBed } from '~/testing/unit-test-helper';
21 import { NavigationComponent } from './navigation.component';
22 import { NotificationsComponent } from '../notifications/notifications.component';
23 import { AdministrationComponent } from '../administration/administration.component';
24 import { IdentityComponent } from '../identity/identity.component';
25 import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
26 import { DashboardHelpComponent } from '../dashboard-help/dashboard-help.component';
27
28 function everythingPermittedExcept(disabledPermissions: string[] = []): any {
29 const permissions: Permissions = new Permissions({});
30 Object.keys(permissions).forEach(
31 (key) => (permissions[key] = new Permission(disabledPermissions.includes(key) ? [] : ['read']))
32 );
33 return permissions;
34 }
35
36 function onlyPermitted(enabledPermissions: string[] = []): any {
37 const permissions: Permissions = new Permissions({});
38 enabledPermissions.forEach((key) => (permissions[key] = new Permission(['read'])));
39 return permissions;
40 }
41
42 function everythingEnabledExcept(features: Features[] = []): FeatureTogglesMap {
43 const featureTogglesMap: FeatureTogglesMap = new FeatureTogglesMap();
44 features.forEach((key) => (featureTogglesMap[key] = false));
45 return featureTogglesMap;
46 }
47
48 function onlyEnabled(features: Features[] = []): FeatureTogglesMap {
49 const featureTogglesMap: FeatureTogglesMap = new FeatureTogglesMap();
50 Object.keys(featureTogglesMap).forEach(
51 (key) => (featureTogglesMap[key] = features.includes(<Features>key))
52 );
53 return featureTogglesMap;
54 }
55
56 describe('NavigationComponent', () => {
57 let component: NavigationComponent;
58 let fixture: ComponentFixture<NavigationComponent>;
59
60 configureTestBed({
61 declarations: [
62 NavigationComponent,
63 NotificationsComponent,
64 AdministrationComponent,
65 DashboardHelpComponent,
66 IdentityComponent
67 ],
68 imports: [
69 HttpClientTestingModule,
70 SharedModule,
71 ToastrModule.forRoot(),
72 RouterTestingModule,
73 SimplebarAngularModule,
74 NgbModule
75 ],
76 providers: [AuthStorageService, SummaryService, FeatureTogglesService, PrometheusAlertService]
77 });
78
79 beforeEach(() => {
80 spyOn(TestBed.inject(AuthStorageService), 'getPermissions').and.callFake(() =>
81 everythingPermittedExcept()
82 );
83
84 spyOn(TestBed.inject(FeatureTogglesService), 'get').and.callFake(() =>
85 of(everythingEnabledExcept())
86 );
87 spyOn(TestBed.inject(SummaryService), 'subscribe').and.callFake(() =>
88 of({ health: { status: 'HEALTH_OK' } })
89 );
90 spyOn(TestBed.inject(PrometheusAlertService), 'getAlerts').and.callFake(() => of([]));
91 fixture = TestBed.createComponent(NavigationComponent);
92 component = fixture.componentInstance;
93 fixture.detectChanges();
94 });
95
96 afterEach(() => {
97 fixture.destroy();
98 });
99
100 describe('Test Permissions', () => {
101 const testCases: [string[], string[]][] = [
102 [
103 ['hosts'],
104 [
105 '.tc_submenuitem_hosts',
106 '.tc_submenuitem_cluster_inventory',
107 '.tc_submenuitem_cluster_services'
108 ]
109 ],
110 [['monitor'], ['.tc_submenuitem_cluster_monitor']],
111 [['osd'], ['.tc_submenuitem_osds', '.tc_submenuitem_crush']],
112 [
113 ['configOpt'],
114 [
115 '.tc_submenuitem_configuration',
116 '.tc_submenuitem_modules',
117 '.tc_submenuitem_users',
118 '.tc_submenuitem_upgrade'
119 ]
120 ],
121 [['log'], ['.tc_submenuitem_log']],
122 [['prometheus'], ['.tc_submenuitem_monitoring']],
123 [['pool'], ['.tc_menuitem_pool']],
124 [['rbdImage'], ['.tc_submenuitem_block_images']],
125 [['rbdMirroring'], ['.tc_submenuitem_block_mirroring']],
126 [['iscsi'], ['.tc_submenuitem_block_iscsi']],
127 [['rbdImage', 'rbdMirroring', 'iscsi'], ['.tc_menuitem_block']],
128 [['nfs'], ['.tc_menuitem_nfs']],
129 [['cephfs'], ['.tc_menuitem_cephfs']],
130 [
131 ['rgw'],
132 [
133 '.tc_menuitem_rgw',
134 '.tc_submenuitem_rgw_daemons',
135 '.tc_submenuitem_rgw_buckets',
136 '.tc_submenuitem_rgw_users'
137 ]
138 ]
139 ];
140
141 for (const [disabledPermissions, selectors] of testCases) {
142 it(`When disabled permissions: ${JSON.stringify(
143 disabledPermissions
144 )} => hidden: "${selectors}"`, () => {
145 component.permissions = everythingPermittedExcept(disabledPermissions);
146 component.enabledFeature$ = of(everythingEnabledExcept());
147
148 fixture.detectChanges();
149 for (const selector of selectors) {
150 expect(fixture.debugElement.query(By.css(selector))).toBeFalsy();
151 }
152 });
153 }
154
155 for (const [enabledPermissions, selectors] of testCases) {
156 it(`When enabled permissions: ${JSON.stringify(
157 enabledPermissions
158 )} => visible: "${selectors}"`, () => {
159 component.permissions = onlyPermitted(enabledPermissions);
160 component.enabledFeature$ = of(everythingEnabledExcept());
161
162 fixture.detectChanges();
163 for (const selector of selectors) {
164 expect(fixture.debugElement.query(By.css(selector))).toBeTruthy();
165 }
166 });
167 }
168 });
169
170 describe('Test FeatureToggles', () => {
171 const testCases: [Features[], string[]][] = [
172 [['rbd'], ['.tc_submenuitem_block_images']],
173 [['mirroring'], ['.tc_submenuitem_block_mirroring']],
174 [['iscsi'], ['.tc_submenuitem_block_iscsi']],
175 [['rbd', 'mirroring', 'iscsi'], ['.tc_menuitem_block']],
176 [['nfs'], ['.tc_menuitem_nfs']],
177 [['cephfs'], ['.tc_menuitem_cephfs']],
178 [
179 ['rgw'],
180 [
181 '.tc_menuitem_rgw',
182 '.tc_submenuitem_rgw_daemons',
183 '.tc_submenuitem_rgw_buckets',
184 '.tc_submenuitem_rgw_users'
185 ]
186 ]
187 ];
188
189 for (const [disabledFeatures, selectors] of testCases) {
190 it(`When disabled features: ${JSON.stringify(
191 disabledFeatures
192 )} => hidden: "${selectors}"`, () => {
193 component.enabledFeature$ = of(everythingEnabledExcept(disabledFeatures));
194 component.permissions = everythingPermittedExcept();
195
196 fixture.detectChanges();
197 for (const selector of selectors) {
198 expect(fixture.debugElement.query(By.css(selector))).toBeFalsy();
199 }
200 });
201 }
202
203 for (const [enabledFeatures, selectors] of testCases) {
204 it(`When enabled features: ${JSON.stringify(
205 enabledFeatures
206 )} => visible: "${selectors}"`, () => {
207 component.enabledFeature$ = of(onlyEnabled(enabledFeatures));
208 component.permissions = everythingPermittedExcept();
209
210 fixture.detectChanges();
211 for (const selector of selectors) {
212 expect(fixture.debugElement.query(By.css(selector))).toBeTruthy();
213 }
214 });
215 }
216 });
217
218 describe('showTopNotification', () => {
219 const notification1 = 'notificationName1';
220 const notification2 = 'notificationName2';
221
222 beforeEach(() => {
223 component.notifications = [];
224 });
225
226 it('should show notification', () => {
227 component.showTopNotification(notification1, true);
228 expect(component.notifications.includes(notification1)).toBeTruthy();
229 expect(component.notifications.length).toBe(1);
230 });
231
232 it('should not add a second notification if it is already shown', () => {
233 component.showTopNotification(notification1, true);
234 component.showTopNotification(notification1, true);
235 expect(component.notifications.includes(notification1)).toBeTruthy();
236 expect(component.notifications.length).toBe(1);
237 });
238
239 it('should add a second notification if the first one is different', () => {
240 component.showTopNotification(notification1, true);
241 component.showTopNotification(notification2, true);
242 expect(component.notifications.includes(notification1)).toBeTruthy();
243 expect(component.notifications.includes(notification2)).toBeTruthy();
244 expect(component.notifications.length).toBe(2);
245 });
246
247 it('should hide an active notification', () => {
248 component.showTopNotification(notification1, true);
249 expect(component.notifications.includes(notification1)).toBeTruthy();
250 expect(component.notifications.length).toBe(1);
251 component.showTopNotification(notification1, false);
252 expect(component.notifications.length).toBe(0);
253 });
254
255 it('should not fail if it tries to hide an inactive notification', () => {
256 expect(() => component.showTopNotification(notification1, false)).not.toThrow();
257 expect(component.notifications.length).toBe(0);
258 });
259
260 it('should keep other notifications if it hides one', () => {
261 component.showTopNotification(notification1, true);
262 component.showTopNotification(notification2, true);
263 expect(component.notifications.length).toBe(2);
264 component.showTopNotification(notification2, false);
265 expect(component.notifications.length).toBe(1);
266 expect(component.notifications.includes(notification1)).toBeTruthy();
267 });
268 });
269 });