cls._radosgw_admin_cmd(['user', 'rm', '--uid=teuth-test-user', '--purge-data'])
super(RgwTestCase, cls).tearDownClass()
- def get_rgw_user(self, uid):
- return self._get('/api/rgw/user/{}'.format(uid))
+ def get_rgw_user(self, uid, stats=True):
+ return self._get('/api/rgw/user/{}?stats={}'.format(uid, stats))
class RgwApiCredentialsTest(RgwTestCase):
self.assertStatus(200)
self._assert_user_data(data)
self.assertEqual(data['user_id'], 'admin')
+ self.assertTrue(data['stats'])
+ self.assertIsInstance(data['stats'], dict)
+ # Test without stats.
+ data = self.get_rgw_user('admin', False)
+ self.assertStatus(200)
+ self._assert_user_data(data)
+ self.assertEqual(data['user_id'], 'admin')
def test_list(self):
data = self._get('/api/rgw/user')
marker = result['marker']
return users
- def get(self, uid, daemon_name=None):
- # type: (str, Optional[str]) -> dict
- result = self.proxy(daemon_name, 'GET', 'user', {'uid': uid})
+ def get(self, uid, daemon_name=None, stats=True) -> dict:
+ query_params = '?stats' if stats else ''
+ result = self.proxy(daemon_name, 'GET', 'user{}'.format(query_params),
+ {'uid': uid, 'stats': stats})
if not self._keys_allowed():
del result['keys']
del result['swift_keys']
[used]="row.bucket_size">
</cd-usage-bar>
- <ng-template #noSizeQuota>No Limit</ng-template>
+ <ng-template #noSizeQuota
+ i18n>No Limit</ng-template>
</ng-template>
<ng-template #bucketObjectTpl
[isBinary]="false">
</cd-usage-bar>
- <ng-template #noObjectQuota>No Limit</ng-template>
+ <ng-template #noObjectQuota
+ i18n>No Limit</ng-template>
</ng-template>
beforeEach(() => {
rgwBucketService = TestBed.inject(RgwBucketService);
rgwBucketServiceListSpy = spyOn(rgwBucketService, 'list');
- rgwBucketServiceListSpy.and.returnValue(of(null));
+ rgwBucketServiceListSpy.and.returnValue(of([]));
fixture = TestBed.createComponent(RgwBucketListComponent);
component = fixture.componentInstance;
+ spyOn(component, 'timeConditionReached').and.stub();
+ fixture.detectChanges();
});
it('should create', () => {
- fixture.detectChanges();
expect(component).toBeTruthy();
+ expect(rgwBucketServiceListSpy).toHaveBeenCalledTimes(1);
});
it('should test all TableActions combinations', () => {
}
])
);
- fixture.detectChanges();
+ component.getBucketList(null);
+ expect(rgwBucketServiceListSpy).toHaveBeenCalledTimes(2);
expect(component.buckets).toEqual([
{
bucket: 'bucket',
}
]);
});
+
it('should usage bars only if quota enabled', () => {
rgwBucketServiceListSpy.and.returnValue(
of([
}
])
);
+ component.getBucketList(null);
+ expect(rgwBucketServiceListSpy).toHaveBeenCalledTimes(2);
fixture.detectChanges();
const usageBars = fixture.debugElement.nativeElement.querySelectorAll('cd-usage-bar');
expect(usageBars.length).toBe(2);
});
+
it('should not show any usage bars if quota disabled', () => {
rgwBucketServiceListSpy.and.returnValue(
of([
}
])
);
+ component.getBucketList(null);
+ expect(rgwBucketServiceListSpy).toHaveBeenCalledTimes(2);
fixture.detectChanges();
const usageBars = fixture.debugElement.nativeElement.querySelectorAll('cd-usage-bar');
expect(usageBars.length).toBe(0);
-import {
- ChangeDetectorRef,
- Component,
- NgZone,
- OnInit,
- TemplateRef,
- ViewChild
-} from '@angular/core';
+import { Component, NgZone, OnInit, TemplateRef, ViewChild } from '@angular/core';
import _ from 'lodash';
import { forkJoin as observableForkJoin, Observable, Subscriber } from 'rxjs';
private modalService: ModalService,
private urlBuilder: URLBuilderService,
public actionLabels: ActionLabelsI18n,
- private ngZone: NgZone,
- private changeDetectorRef: ChangeDetectorRef
+ private ngZone: NgZone
) {
super();
- this.permission = this.authStorageService.getPermissions().rgw;
- const getBucketUri = () =>
- this.selection.first() && `${encodeURIComponent(this.selection.first().bid)}`;
- const addAction: CdTableAction = {
- permission: 'create',
- icon: Icons.add,
- routerLink: () => this.urlBuilder.getCreate(),
- name: this.actionLabels.CREATE,
- canBePrimary: (selection: CdTableSelection) => !selection.hasSelection
- };
- const editAction: CdTableAction = {
- permission: 'update',
- icon: Icons.edit,
- routerLink: () => this.urlBuilder.getEdit(getBucketUri()),
- name: this.actionLabels.EDIT
- };
- const deleteAction: CdTableAction = {
- permission: 'delete',
- icon: Icons.destroy,
- click: () => this.deleteAction(),
- disable: () => !this.selection.hasSelection,
- name: this.actionLabels.DELETE,
- canBePrimary: (selection: CdTableSelection) => selection.hasMultiSelection
- };
- this.tableActions = [addAction, editAction, deleteAction];
- this.timeConditionReached();
}
ngOnInit() {
+ this.permission = this.authStorageService.getPermissions().rgw;
this.columns = [
{
name: $localize`Name`,
flexGrow: 0.8
}
];
+ const getBucketUri = () =>
+ this.selection.first() && `${encodeURIComponent(this.selection.first().bid)}`;
+ const addAction: CdTableAction = {
+ permission: 'create',
+ icon: Icons.add,
+ routerLink: () => this.urlBuilder.getCreate(),
+ name: this.actionLabels.CREATE,
+ canBePrimary: (selection: CdTableSelection) => !selection.hasSelection
+ };
+ const editAction: CdTableAction = {
+ permission: 'update',
+ icon: Icons.edit,
+ routerLink: () => this.urlBuilder.getEdit(getBucketUri()),
+ name: this.actionLabels.EDIT
+ };
+ const deleteAction: CdTableAction = {
+ permission: 'delete',
+ icon: Icons.destroy,
+ click: () => this.deleteAction(),
+ disable: () => !this.selection.hasSelection,
+ name: this.actionLabels.DELETE,
+ canBePrimary: (selection: CdTableSelection) => selection.hasMultiSelection
+ };
+ this.tableActions = [addAction, editAction, deleteAction];
+ this.timeConditionReached();
}
transformBucketData() {
(resp: object[]) => {
this.buckets = resp;
this.transformBucketData();
- this.changeDetectorRef.detectChanges();
},
() => {
context.error();
[selection]="expandedRow">
</cd-rgw-user-details>
</cd-table>
+
+<ng-template #userSizeTpl
+ let-row="row">
+ <cd-usage-bar *ngIf="row.user_quota.max_size > 0 && row.user_quota.enabled; else noSizeQuota"
+ [total]="row.user_quota.max_size"
+ [used]="row.stats.size_actual">
+ </cd-usage-bar>
+
+ <ng-template #noSizeQuota
+ i18n>No Limit</ng-template>
+</ng-template>
+
+<ng-template #userObjectTpl
+ let-row="row">
+ <cd-usage-bar *ngIf="row.user_quota.max_objects > 0 && row.user_quota.enabled; else noObjectQuota"
+ [total]="row.user_quota.max_objects"
+ [used]="row.stats.num_objects"
+ [isBinary]="false">
+ </cd-usage-bar>
+
+ <ng-template #noObjectQuota
+ i18n>No Limit</ng-template>
+</ng-template>
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterTestingModule } from '@angular/router/testing';
+import { of } from 'rxjs';
+
+import { RgwUserService } from '~/app/shared/api/rgw-user.service';
import { TableActionsComponent } from '~/app/shared/datatable/table-actions/table-actions.component';
import { SharedModule } from '~/app/shared/shared.module';
import { configureTestBed, PermissionHelper } from '~/testing/unit-test-helper';
describe('RgwUserListComponent', () => {
let component: RgwUserListComponent;
let fixture: ComponentFixture<RgwUserListComponent>;
+ let rgwUserService: RgwUserService;
+ let rgwUserServiceListSpy: jasmine.Spy;
configureTestBed({
declarations: [RgwUserListComponent],
});
beforeEach(() => {
+ rgwUserService = TestBed.inject(RgwUserService);
+ rgwUserServiceListSpy = spyOn(rgwUserService, 'list');
+ rgwUserServiceListSpy.and.returnValue(of([]));
fixture = TestBed.createComponent(RgwUserListComponent);
component = fixture.componentInstance;
+ spyOn(component, 'timeConditionReached').and.stub();
+ fixture.detectChanges();
});
it('should create', () => {
- fixture.detectChanges();
expect(component).toBeTruthy();
+ expect(rgwUserServiceListSpy).toHaveBeenCalledTimes(1);
});
it('should test all TableActions combinations', () => {
}
});
});
+
+ it('should test if rgw-user data is tranformed correctly', () => {
+ rgwUserServiceListSpy.and.returnValue(
+ of([
+ {
+ user_id: 'testid',
+ stats: {
+ size_actual: 6,
+ num_objects: 6
+ },
+ user_quota: {
+ max_size: 20,
+ max_objects: 10,
+ enabled: true
+ }
+ }
+ ])
+ );
+ component.getUserList(null);
+ expect(rgwUserServiceListSpy).toHaveBeenCalledTimes(2);
+ expect(component.users).toEqual([
+ {
+ user_id: 'testid',
+ stats: {
+ size_actual: 6,
+ num_objects: 6
+ },
+ user_quota: {
+ max_size: 20,
+ max_objects: 10,
+ enabled: true
+ }
+ }
+ ]);
+ });
+
+ it('should usage bars only if quota enabled', () => {
+ rgwUserServiceListSpy.and.returnValue(
+ of([
+ {
+ user_id: 'testid',
+ stats: {
+ size_actual: 6,
+ num_objects: 6
+ },
+ user_quota: {
+ max_size: 1024,
+ max_objects: 10,
+ enabled: true
+ }
+ }
+ ])
+ );
+ component.getUserList(null);
+ expect(rgwUserServiceListSpy).toHaveBeenCalledTimes(2);
+ fixture.detectChanges();
+ const usageBars = fixture.debugElement.nativeElement.querySelectorAll('cd-usage-bar');
+ expect(usageBars.length).toBe(2);
+ });
+
+ it('should not show any usage bars if quota disabled', () => {
+ rgwUserServiceListSpy.and.returnValue(
+ of([
+ {
+ user_id: 'testid',
+ stats: {
+ size_actual: 6,
+ num_objects: 6
+ },
+ user_quota: {
+ max_size: 1024,
+ max_objects: 10,
+ enabled: false
+ }
+ }
+ ])
+ );
+ component.getUserList(null);
+ expect(rgwUserServiceListSpy).toHaveBeenCalledTimes(2);
+ fixture.detectChanges();
+ const usageBars = fixture.debugElement.nativeElement.querySelectorAll('cd-usage-bar');
+ expect(usageBars.length).toBe(0);
+ });
});
-import { Component, NgZone, ViewChild } from '@angular/core';
+import { Component, NgZone, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import * as _ from 'lodash';
import { forkJoin as observableForkJoin, Observable, Subscriber } from 'rxjs';
import { RgwUserService } from '~/app/shared/api/rgw-user.service';
styleUrls: ['./rgw-user-list.component.scss'],
providers: [{ provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) }]
})
-export class RgwUserListComponent extends ListWithDetails {
+export class RgwUserListComponent extends ListWithDetails implements OnInit {
@ViewChild(TableComponent, { static: true })
table: TableComponent;
+ @ViewChild('userSizeTpl', { static: true })
+ userSizeTpl: TemplateRef<any>;
+ @ViewChild('userObjectTpl', { static: true })
+ userObjectTpl: TemplateRef<any>;
permission: Permission;
tableActions: CdTableAction[];
columns: CdTableColumn[] = [];
private ngZone: NgZone
) {
super();
+ }
+
+ ngOnInit() {
this.permission = this.authStorageService.getPermissions().rgw;
this.columns = [
{
'-1': $localize`Disabled`,
0: $localize`Unlimited`
}
+ },
+ {
+ name: $localize`Capacity Limit %`,
+ prop: 'size_usage',
+ cellTemplate: this.userSizeTpl,
+ flexGrow: 0.8
+ },
+ {
+ name: $localize`Object Limit %`,
+ prop: 'object_usage',
+ cellTemplate: this.userObjectTpl,
+ flexGrow: 0.8
}
];
const getUserUri = () =>
name: daemon_name
schema:
type: string
+ - default: true
+ in: query
+ name: stats
+ schema:
+ type: boolean
responses:
'200':
content: