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';
6 import { ToastrModule } from 'ngx-toastr';
7 import { SimplebarAngularModule } from 'simplebar-angular';
8 import { of } from 'rxjs';
10 import { Permission, Permissions } from '~/app/shared/models/permissions';
11 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
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';
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']))
36 function onlyPermitted(enabledPermissions: string[] = []): any {
37 const permissions: Permissions = new Permissions({});
38 enabledPermissions.forEach((key) => (permissions[key] = new Permission(['read'])));
42 function everythingEnabledExcept(features: Features[] = []): FeatureTogglesMap {
43 const featureTogglesMap: FeatureTogglesMap = new FeatureTogglesMap();
44 features.forEach((key) => (featureTogglesMap[key] = false));
45 return featureTogglesMap;
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))
53 return featureTogglesMap;
56 describe('NavigationComponent', () => {
57 let component: NavigationComponent;
58 let fixture: ComponentFixture<NavigationComponent>;
63 NotificationsComponent,
64 AdministrationComponent,
65 DashboardHelpComponent,
69 HttpClientTestingModule,
71 ToastrModule.forRoot(),
73 SimplebarAngularModule,
76 providers: [AuthStorageService, SummaryService, FeatureTogglesService, PrometheusAlertService]
80 spyOn(TestBed.inject(AuthStorageService), 'getPermissions').and.callFake(() =>
81 everythingPermittedExcept()
84 spyOn(TestBed.inject(FeatureTogglesService), 'get').and.callFake(() =>
85 of(everythingEnabledExcept())
87 spyOn(TestBed.inject(SummaryService), 'subscribe').and.callFake(() =>
88 of({ health: { status: 'HEALTH_OK' } })
90 spyOn(TestBed.inject(PrometheusAlertService), 'getAlerts').and.callFake(() => of([]));
91 fixture = TestBed.createComponent(NavigationComponent);
92 component = fixture.componentInstance;
93 fixture.detectChanges();
100 describe('Test Permissions', () => {
101 const testCases: [string[], string[]][] = [
105 '.tc_submenuitem_hosts',
106 '.tc_submenuitem_cluster_inventory',
107 '.tc_submenuitem_cluster_services'
110 [['monitor'], ['.tc_submenuitem_cluster_monitor']],
111 [['osd'], ['.tc_submenuitem_osds', '.tc_submenuitem_crush']],
115 '.tc_submenuitem_configuration',
116 '.tc_submenuitem_modules',
117 '.tc_submenuitem_users',
118 '.tc_submenuitem_upgrade'
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']],
134 '.tc_submenuitem_rgw_daemons',
135 '.tc_submenuitem_rgw_buckets',
136 '.tc_submenuitem_rgw_users'
141 for (const [disabledPermissions, selectors] of testCases) {
142 it(`When disabled permissions: ${JSON.stringify(
144 )} => hidden: "${selectors}"`, () => {
145 component.permissions = everythingPermittedExcept(disabledPermissions);
146 component.enabledFeature$ = of(everythingEnabledExcept());
148 fixture.detectChanges();
149 for (const selector of selectors) {
150 expect(fixture.debugElement.query(By.css(selector))).toBeFalsy();
155 for (const [enabledPermissions, selectors] of testCases) {
156 it(`When enabled permissions: ${JSON.stringify(
158 )} => visible: "${selectors}"`, () => {
159 component.permissions = onlyPermitted(enabledPermissions);
160 component.enabledFeature$ = of(everythingEnabledExcept());
162 fixture.detectChanges();
163 for (const selector of selectors) {
164 expect(fixture.debugElement.query(By.css(selector))).toBeTruthy();
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']],
182 '.tc_submenuitem_rgw_daemons',
183 '.tc_submenuitem_rgw_buckets',
184 '.tc_submenuitem_rgw_users'
189 for (const [disabledFeatures, selectors] of testCases) {
190 it(`When disabled features: ${JSON.stringify(
192 )} => hidden: "${selectors}"`, () => {
193 component.enabledFeature$ = of(everythingEnabledExcept(disabledFeatures));
194 component.permissions = everythingPermittedExcept();
196 fixture.detectChanges();
197 for (const selector of selectors) {
198 expect(fixture.debugElement.query(By.css(selector))).toBeFalsy();
203 for (const [enabledFeatures, selectors] of testCases) {
204 it(`When enabled features: ${JSON.stringify(
206 )} => visible: "${selectors}"`, () => {
207 component.enabledFeature$ = of(onlyEnabled(enabledFeatures));
208 component.permissions = everythingPermittedExcept();
210 fixture.detectChanges();
211 for (const selector of selectors) {
212 expect(fixture.debugElement.query(By.css(selector))).toBeTruthy();
218 describe('showTopNotification', () => {
219 const notification1 = 'notificationName1';
220 const notification2 = 'notificationName2';
223 component.notifications = [];
226 it('should show notification', () => {
227 component.showTopNotification(notification1, true);
228 expect(component.notifications.includes(notification1)).toBeTruthy();
229 expect(component.notifications.length).toBe(1);
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);
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);
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);
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);
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();