1 import { HttpClientTestingModule } from '@angular/common/http/testing';
2 import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
3 import { ReactiveFormsModule } from '@angular/forms';
4 import { Router } from '@angular/router';
5 import { RouterTestingModule } from '@angular/router/testing';
7 import * as _ from 'lodash';
8 import { ToastrModule } from 'ngx-toastr';
9 import { of as observableOf, throwError } from 'rxjs';
11 import { configureTestBed, FormHelper, i18nProviders } from '../../../../testing/unit-test-helper';
12 import { RgwBucketService } from '../../../shared/api/rgw-bucket.service';
13 import { RgwSiteService } from '../../../shared/api/rgw-site.service';
14 import { NotificationType } from '../../../shared/enum/notification-type.enum';
15 import { NotificationService } from '../../../shared/services/notification.service';
16 import { SharedModule } from '../../../shared/shared.module';
17 import { RgwBucketMfaDelete } from '../models/rgw-bucket-mfa-delete';
18 import { RgwBucketVersioning } from '../models/rgw-bucket-versioning';
19 import { RgwBucketFormComponent } from './rgw-bucket-form.component';
21 describe('RgwBucketFormComponent', () => {
22 let component: RgwBucketFormComponent;
23 let fixture: ComponentFixture<RgwBucketFormComponent>;
24 let rgwBucketService: RgwBucketService;
25 let getPlacementTargetsSpy: jasmine.Spy;
26 let rgwBucketServiceGetSpy: jasmine.Spy;
27 let formHelper: FormHelper;
30 declarations: [RgwBucketFormComponent],
32 HttpClientTestingModule,
36 ToastrModule.forRoot()
38 providers: [i18nProviders]
42 fixture = TestBed.createComponent(RgwBucketFormComponent);
43 component = fixture.componentInstance;
44 rgwBucketService = TestBed.get(RgwBucketService);
45 rgwBucketServiceGetSpy = spyOn(rgwBucketService, 'get');
46 getPlacementTargetsSpy = spyOn(TestBed.get(RgwSiteService), 'get');
47 formHelper = new FormHelper(component.bucketForm);
50 it('should create', () => {
51 expect(component).toBeTruthy();
54 describe('bucketNameValidator', () => {
55 const testValidator = (name: string, valid: boolean, expectedError?: string) => {
56 rgwBucketServiceGetSpy.and.returnValue(throwError('foo'));
57 formHelper.setValue('bid', name, true);
60 formHelper.expectValid('bid');
62 formHelper.expectError('bid', expectedError);
66 it('should validate empty name', fakeAsync(() => {
67 formHelper.expectErrorChange('bid', '', 'required', true);
70 it('bucket names cannot be formatted as IP address', fakeAsync(() => {
71 const testIPs = ['1.1.1.01', '001.1.1.01', '127.0.0.1'];
72 for (const ip of testIPs) {
73 testValidator(ip, false, 'ipAddress');
77 it('bucket name must be >= 3 characters long (1/2)', fakeAsync(() => {
78 testValidator('ab', false, 'shouldBeInRange');
81 it('bucket name must be >= 3 characters long (2/2)', fakeAsync(() => {
82 testValidator('abc', true);
85 it('bucket name must be <= than 63 characters long (1/2)', fakeAsync(() => {
86 testValidator(_.repeat('a', 64), false, 'shouldBeInRange');
89 it('bucket name must be <= than 63 characters long (2/2)', fakeAsync(() => {
90 testValidator(_.repeat('a', 63), true);
93 it('bucket names must not contain uppercase characters or underscores (1/2)', fakeAsync(() => {
94 testValidator('iAmInvalid', false, 'containsUpperCase');
97 it('bucket names can only contain lowercase letters, numbers, and hyphens', fakeAsync(() => {
98 testValidator('$$$', false, 'onlyLowerCaseAndNumbers');
101 it('bucket names must not contain uppercase characters or underscores (2/2)', fakeAsync(() => {
102 testValidator('i_am_invalid', false, 'containsUpperCase');
105 it('bucket names must start and end with letters or numbers', fakeAsync(() => {
106 testValidator('abcd-', false, 'lowerCaseOrNumber');
109 it('bucket names with invalid labels (1/3)', fakeAsync(() => {
110 testValidator('abc.1def.Ghi2', false, 'containsUpperCase');
113 it('bucket names with invalid labels (2/3)', fakeAsync(() => {
114 testValidator('abc.1_xy', false, 'containsUpperCase');
117 it('bucket names with invalid labels (3/3)', fakeAsync(() => {
118 testValidator('abc.*def', false, 'lowerCaseOrNumber');
121 it('bucket names must be a series of one or more labels and can contain lowercase letters, numbers, and hyphens (1/3)', fakeAsync(() => {
122 testValidator('xyz.abc', true);
125 it('bucket names must be a series of one or more labels and can contain lowercase letters, numbers, and hyphens (2/3)', fakeAsync(() => {
126 testValidator('abc.1-def', true);
129 it('bucket names must be a series of one or more labels and can contain lowercase letters, numbers, and hyphens (3/3)', fakeAsync(() => {
130 testValidator('abc.ghi2', true);
133 it('bucket names must be unique', fakeAsync(() => {
134 testValidator('bucket-name-is-unique', true);
137 it('should get zonegroup and placement targets', () => {
138 const payload: Record<string, any> = {
139 zonegroup: 'default',
142 name: 'default-placement',
143 data_pool: 'default.rgw.buckets.data'
146 name: 'placement-target2',
147 data_pool: 'placement-target2.rgw.buckets.data'
151 getPlacementTargetsSpy.and.returnValue(observableOf(payload));
152 fixture.detectChanges();
154 expect(component.zonegroup).toBe(payload.zonegroup);
155 const placementTargets = [];
156 for (const placementTarget of payload['placement_targets']) {
159 ] = `${placementTarget['name']} (pool: ${placementTarget['data_pool']})`;
160 placementTargets.push(placementTarget);
162 expect(component.placementTargets).toEqual(placementTargets);
166 describe('submit form', () => {
167 let notificationService: NotificationService;
170 spyOn(TestBed.get(Router), 'navigate').and.stub();
171 notificationService = TestBed.get(NotificationService);
172 spyOn(notificationService, 'show');
175 it('should validate name', () => {
176 component.editing = false;
177 component.createForm();
178 const control = component.bucketForm.get('bid');
179 expect(_.isFunction(control.asyncValidator)).toBeTruthy();
182 it('should not validate name', () => {
183 component.editing = true;
184 component.createForm();
185 const control = component.bucketForm.get('bid');
186 expect(control.asyncValidator).toBeNull();
189 it('tests create success notification', () => {
190 spyOn(rgwBucketService, 'create').and.returnValue(observableOf([]));
191 component.editing = false;
192 component.bucketForm.markAsDirty();
194 expect(notificationService.show).toHaveBeenCalledWith(
195 NotificationType.success,
196 'Created Object Gateway bucket ""'
200 it('tests update success notification', () => {
201 spyOn(rgwBucketService, 'update').and.returnValue(observableOf([]));
202 component.editing = true;
203 component.bucketForm.markAsDirty();
205 expect(notificationService.show).toHaveBeenCalledWith(
206 NotificationType.success,
207 'Updated Object Gateway bucket "".'
212 describe('mfa credentials', () => {
213 const checkMfaCredentialsVisibility = (
214 fakeResponse: object,
215 versioningChecked: boolean,
216 mfaDeleteChecked: boolean,
217 expectedVisibility: boolean
219 component['route'].params = observableOf({ bid: 'bid' });
220 component.editing = true;
221 rgwBucketServiceGetSpy.and.returnValue(observableOf(fakeResponse));
222 component.ngOnInit();
223 component.isVersioningEnabled = versioningChecked;
224 component.isMfaDeleteEnabled = mfaDeleteChecked;
225 fixture.detectChanges();
227 const mfaTokenSerial = fixture.debugElement.nativeElement.querySelector('#mfa-token-serial');
228 const mfaTokenPin = fixture.debugElement.nativeElement.querySelector('#mfa-token-pin');
229 if (expectedVisibility) {
230 expect(mfaTokenSerial).toBeTruthy();
231 expect(mfaTokenPin).toBeTruthy();
233 expect(mfaTokenSerial).toBeFalsy();
234 expect(mfaTokenPin).toBeFalsy();
238 it('inputs should be visible when required', () => {
239 checkMfaCredentialsVisibility(
241 versioning: RgwBucketVersioning.SUSPENDED,
242 mfa_delete: RgwBucketMfaDelete.DISABLED
248 checkMfaCredentialsVisibility(
250 versioning: RgwBucketVersioning.SUSPENDED,
251 mfa_delete: RgwBucketMfaDelete.DISABLED
257 checkMfaCredentialsVisibility(
259 versioning: RgwBucketVersioning.ENABLED,
260 mfa_delete: RgwBucketMfaDelete.DISABLED
266 checkMfaCredentialsVisibility(
268 versioning: RgwBucketVersioning.ENABLED,
269 mfa_delete: RgwBucketMfaDelete.ENABLED
275 checkMfaCredentialsVisibility(
277 versioning: RgwBucketVersioning.SUSPENDED,
278 mfa_delete: RgwBucketMfaDelete.DISABLED
284 checkMfaCredentialsVisibility(
286 versioning: RgwBucketVersioning.SUSPENDED,
287 mfa_delete: RgwBucketMfaDelete.ENABLED
293 checkMfaCredentialsVisibility(
295 versioning: RgwBucketVersioning.SUSPENDED,
296 mfa_delete: RgwBucketMfaDelete.ENABLED
302 checkMfaCredentialsVisibility(
304 versioning: RgwBucketVersioning.ENABLED,
305 mfa_delete: RgwBucketMfaDelete.ENABLED
314 describe('object locking', () => {
315 const setDaysAndYears = (fn: (name: string) => void) => {
316 ['lock_retention_period_days', 'lock_retention_period_years'].forEach(fn);
319 const expectPatternLockError = (value: string) => {
320 formHelper.setValue('lock_enabled', true, true);
321 setDaysAndYears((name: string) => {
322 formHelper.setValue(name, value);
323 formHelper.expectError(name, 'pattern');
327 const expectValidLockInputs = (enabled: boolean, mode: string, days: string, years: string) => {
328 formHelper.setValue('lock_enabled', enabled);
329 formHelper.setValue('lock_mode', mode);
330 formHelper.setValue('lock_retention_period_days', days);
331 formHelper.setValue('lock_retention_period_years', years);
335 'lock_retention_period_days',
336 'lock_retention_period_years'
337 ].forEach((name) => {
338 const control = component.bucketForm.get(name);
339 expect(control.valid).toBeTruthy();
340 expect(control.errors).toBeNull();
344 it('should check lock enabled checkbox [mode=create]', () => {
345 component.createForm();
346 const control = component.bucketForm.get('lock_enabled');
347 expect(control.disabled).toBeFalsy();
350 it('should check lock enabled checkbox [mode=edit]', () => {
351 component.editing = true;
352 component.createForm();
353 const control = component.bucketForm.get('lock_enabled');
354 expect(control.disabled).toBeTruthy();
357 it('should have the "eitherDaysOrYears" error', () => {
358 formHelper.setValue('lock_enabled', true);
359 setDaysAndYears((name: string) => {
360 const control = component.bucketForm.get(name);
361 control.updateValueAndValidity();
362 expect(control.value).toBe(0);
363 expect(control.invalid).toBeTruthy();
364 formHelper.expectError(control, 'eitherDaysOrYears');
368 it('should have the "pattern" error [1]', () => {
369 expectPatternLockError('-1');
372 it('should have the "pattern" error [2]', () => {
373 expectPatternLockError('1.2');
376 it('should have valid values [1]', () => {
377 expectValidLockInputs(true, 'Governance', '0', '1');
380 it('should have valid values [2]', () => {
381 expectValidLockInputs(false, 'Compliance', '100', '0');