From 8f65f0e905177b0dd212f54d7799fffd9052d4d2 Mon Sep 17 00:00:00 2001 From: pujaoshahu Date: Thu, 9 Jan 2025 10:44:43 +0530 Subject: [PATCH] mgr/dashboard: Add RGW topic listing in dashboard Fixes: https://tracker.ceph.com/issues/69143 Signed-off-by: pujaoshahu --- src/pybind/mgr/dashboard/controllers/rgw.py | 2 +- .../rgw-topic-details.component.html | 89 ++++++++++++++++++ .../rgw-topic-details.component.scss | 0 .../rgw-topic-details.component.spec.ts | 94 +++++++++++++++++++ .../rgw-topic-details.component.ts | 29 ++++++ .../rgw-topic-list.component.html | 15 +++ .../rgw-topic-list.component.scss | 0 .../rgw-topic-list.component.spec.ts | 55 +++++++++++ .../rgw-topic-list.component.ts | 89 ++++++++++++++++++ .../frontend/src/app/ceph/rgw/rgw.module.ts | 15 ++- .../navigation/navigation.component.html | 13 ++- .../navigation/navigation.component.spec.ts | 9 +- .../app/shared/api/rgw-topic.service.spec.ts | 56 +++++++++++ .../src/app/shared/api/rgw-topic.service.ts | 24 +++++ .../src/app/shared/models/topic.model.ts | 31 ++++++ src/pybind/mgr/dashboard/tests/test_rgw.py | 43 ++++----- 16 files changed, 530 insertions(+), 34 deletions(-) create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.html create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.scss create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.html create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.scss create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-topic.service.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-topic.service.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/models/topic.model.ts diff --git a/src/pybind/mgr/dashboard/controllers/rgw.py b/src/pybind/mgr/dashboard/controllers/rgw.py index 4c8d0b5e1eb93..10e6d0dbbc678 100755 --- a/src/pybind/mgr/dashboard/controllers/rgw.py +++ b/src/pybind/mgr/dashboard/controllers/rgw.py @@ -1506,7 +1506,7 @@ class RgwTopic(RESTController): def list(self, uid: Optional[str] = None, tenant: Optional[str] = None): rgw_topic_instance = RgwTopicmanagement() result = rgw_topic_instance.list_topics(uid, tenant) - return result + return result['topics'] if 'topics' in result else [] @EndpointDoc( "Get RGW Topic", diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.html new file mode 100644 index 0000000000000..dec284392da59 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.html @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Push endpoint arguments{{ selection?.dest?.push_endpoint_args }}
Push endpoint topic{{ selection?.dest?.push_endpoint_topic}}
Push endpoint{{ selection?.dest?.push_endpoint }}
Stored secret{{ selection?.dest?.stored_secret}}
Persistent{{ selection?.dest?.persistent }}
Persistent queue{{ selection?.dest?.persistent_queue }}
Time to live{{ selection?.dest?.time_to_live }}
Max retries{{ selection?.dest?.max_retries }}
Retry sleep duration{{ selection?.dest?.retry_sleep_duration }}
Opaque data{{ selection?.opaqueData }}
+
+ +
+ + + + + + + +
Policy
{{ policy | json  }}
+
+
+ + + + + + + + +
Subscribed buckets
{{ selection.subscribed_buckets | json}}
+
+
+
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.scss new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.spec.ts new file mode 100644 index 0000000000000..85b1b1b00fa43 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.spec.ts @@ -0,0 +1,94 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { RgwTopicDetailsComponent } from './rgw-topic-details.component'; +import { TopicDetails } from '~/app/shared/models/topic.model'; + +interface Destination { + push_endpoint: string; + push_endpoint_args: string; + push_endpoint_topic: string; + stored_secret: string; + persistent: boolean; + persistent_queue: string; + time_to_live: number; + max_retries: number; + retry_sleep_duration: number; +} + +const mockDestination: Destination = { + push_endpoint: 'http://localhost:8080', + push_endpoint_args: 'args', + push_endpoint_topic: 'topic', + stored_secret: 'secret', + persistent: true, + persistent_queue: 'queue', + time_to_live: 3600, + max_retries: 5, + retry_sleep_duration: 10 +}; + +describe('RgwTopicDetailsComponent', () => { + let component: RgwTopicDetailsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [RgwTopicDetailsComponent] + }).compileComponents(); + + fixture = TestBed.createComponent(RgwTopicDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should parse policy string correctly', () => { + const mockSelection: TopicDetails = { + name: 'testHttp', + owner: 'ownerName', + arn: 'arnValue', + dest: mockDestination, + policy: '{"key": "value"}', + opaqueData: 'test@12345', + subscribed_buckets: [] + }; + + component.selection = mockSelection; + component.ngOnChanges({ + selection: { + currentValue: mockSelection, + previousValue: null, + firstChange: true, + isFirstChange: () => true + } + }); + + expect(component.policy).toEqual({ key: 'value' }); + }); + + it('should set policy to empty object if policy is not a string', () => { + const mockSelection: TopicDetails = { + name: 'testHttp', + owner: 'ownerName', + arn: 'arnValue', + dest: mockDestination, + policy: '{}', + subscribed_buckets: [], + opaqueData: '' + }; + + component.selection = mockSelection; + component.ngOnChanges({ + selection: { + currentValue: mockSelection, + previousValue: null, + firstChange: true, + isFirstChange: () => true + } + }); + + expect(component.policy).toEqual({}); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.ts new file mode 100644 index 0000000000000..359c927ae4609 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-details/rgw-topic-details.component.ts @@ -0,0 +1,29 @@ +import { Component, Input, SimpleChanges, OnChanges } from '@angular/core'; + +import { TopicDetails } from '~/app/shared/models/topic.model'; +import * as _ from 'lodash'; + +@Component({ + selector: 'cd-rgw-topic-details', + templateUrl: './rgw-topic-details.component.html', + styleUrls: ['./rgw-topic-details.component.scss'] +}) +export class RgwTopicDetailsComponent implements OnChanges { + @Input() + selection: TopicDetails; + policy: string; + constructor() {} + ngOnChanges(changes: SimpleChanges): void { + if (changes['selection'] && this.selection) { + if (_.isString(this.selection.policy)) { + try { + this.policy = JSON.parse(this.selection.policy); + } catch (e) { + this.policy = '{}'; + } + } else { + this.policy = this.selection.policy || {}; + } + } + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.html new file mode 100644 index 0000000000000..22fce6e40a78c --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.html @@ -0,0 +1,15 @@ + + + + + diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.scss new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.spec.ts new file mode 100644 index 0000000000000..c87427862dd4e --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.spec.ts @@ -0,0 +1,55 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RgwTopicListComponent } from './rgw-topic-list.component'; +import { RgwTopicService } from '~/app/shared/api/rgw-topic.service'; +import { SharedModule } from '~/app/shared/shared.module'; +import { configureTestBed } from '~/testing/unit-test-helper'; +import { RgwTopicDetailsComponent } from '../rgw-topic-details/rgw-topic-details.component'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { RouterTestingModule } from '@angular/router/testing'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ToastrModule } from 'ngx-toastr'; +describe('RgwTopicListComponent', () => { + let component: RgwTopicListComponent; + let fixture: ComponentFixture; + let rgwtTopicService: RgwTopicService; + let rgwTopicServiceListSpy: jasmine.Spy; + + configureTestBed({ + declarations: [RgwTopicListComponent, RgwTopicDetailsComponent], + imports: [BrowserAnimationsModule, RouterTestingModule, HttpClientTestingModule, SharedModule] + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + BrowserAnimationsModule, + SharedModule, + HttpClientTestingModule, + ToastrModule.forRoot(), + RouterTestingModule + ], + + declarations: [RgwTopicListComponent] + }).compileComponents(); + + fixture = TestBed.createComponent(RgwTopicListComponent); + component = fixture.componentInstance; + rgwtTopicService = TestBed.inject(RgwTopicService); + rgwTopicServiceListSpy = spyOn(rgwtTopicService, 'listTopic').and.callThrough(); + fixture = TestBed.createComponent(RgwTopicListComponent); + component = fixture.componentInstance; + spyOn(component, 'setTableRefreshTimeout').and.stub(); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + expect(rgwTopicServiceListSpy).toHaveBeenCalledTimes(1); + }); + + it('should call listTopic on ngOnInit', () => { + component.ngOnInit(); + expect(rgwTopicServiceListSpy).toHaveBeenCalled(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.ts new file mode 100644 index 0000000000000..4c3dace75cec7 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-topic-list/rgw-topic-list.component.ts @@ -0,0 +1,89 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import _ from 'lodash'; + +import { ActionLabelsI18n } from '~/app/shared/constants/app.constants'; +import { TableComponent } from '~/app/shared/datatable/table/table.component'; +import { CdTableAction } from '~/app/shared/models/cd-table-action'; +import { CdTableColumn } from '~/app/shared/models/cd-table-column'; +import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context'; +import { ListWithDetails } from '~/app/shared/classes/list-with-details.class'; +import { Permission } from '~/app/shared/models/permissions'; + +import { AuthStorageService } from '~/app/shared/services/auth-storage.service'; +import { RgwTopicService } from '~/app/shared/api/rgw-topic.service'; + +import { CdTableSelection } from '~/app/shared/models/cd-table-selection'; +import { BehaviorSubject, Observable, of } from 'rxjs'; +import { Topic } from '~/app/shared/models/topic.model'; +import { catchError, shareReplay, switchMap } from 'rxjs/operators'; + +@Component({ + selector: 'cd-rgw-topic-list', + templateUrl: './rgw-topic-list.component.html', + styleUrls: ['./rgw-topic-list.component.scss'] +}) +export class RgwTopicListComponent extends ListWithDetails implements OnInit { + @ViewChild('table', { static: true }) + table: TableComponent; + columns: CdTableColumn[]; + permission: Permission; + tableActions: CdTableAction[]; + context: CdTableFetchDataContext; + errorMessage: string; + selection: CdTableSelection = new CdTableSelection(); + topic$: Observable; + subject = new BehaviorSubject([]); + name: string; + constructor( + private authStorageService: AuthStorageService, + public actionLabels: ActionLabelsI18n, + private rgwTopicService: RgwTopicService + ) { + super(); + this.permission = this.authStorageService.getPermissions().rgw; + } + + ngOnInit() { + this.columns = [ + { + name: $localize`Name`, + prop: 'name', + flexGrow: 2 + }, + { + name: $localize`Owner`, + prop: 'owner', + flexGrow: 2 + }, + { + name: $localize`Amazon resource name`, + prop: 'arn', + flexGrow: 2 + }, + { + name: $localize`Push endpoint`, + prop: 'dest.push_endpoint', + flexGrow: 2 + } + ]; + this.topic$ = this.subject.pipe( + switchMap(() => + this.rgwTopicService.listTopic().pipe( + catchError(() => { + this.context.error(); + return of(null); + }) + ) + ), + shareReplay(1) + ); + } + + fetchData() { + this.subject.next([]); + } + + updateSelection(selection: CdTableSelection) { + this.selection = selection; + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts index c5aeef5e91fb7..83a0414b000b1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts @@ -96,6 +96,8 @@ import { RgwBucketLifecycleListComponent } from './rgw-bucket-lifecycle-list/rgw import { RgwRateLimitComponent } from './rgw-rate-limit/rgw-rate-limit.component'; import { RgwRateLimitDetailsComponent } from './rgw-rate-limit-details/rgw-rate-limit-details.component'; import { NfsClusterComponent } from '../nfs/nfs-cluster/nfs-cluster.component'; +import { RgwTopicListComponent } from './rgw-topic-list/rgw-topic-list.component'; +import { RgwTopicDetailsComponent } from './rgw-topic-details/rgw-topic-details.component'; @NgModule({ imports: [ @@ -128,11 +130,11 @@ import { NfsClusterComponent } from '../nfs/nfs-cluster/nfs-cluster.component'; SelectModule, NumberModule, TabsModule, - RadioModule, TagModule, TooltipModule, ComboBoxModule, - ToggletipModule + ToggletipModule, + RadioModule ], exports: [ RgwDaemonDetailsComponent, @@ -193,7 +195,9 @@ import { NfsClusterComponent } from '../nfs/nfs-cluster/nfs-cluster.component'; RgwStorageClassFormComponent, RgwBucketTieringFormComponent, RgwBucketLifecycleListComponent, - RgwRateLimitDetailsComponent + RgwRateLimitDetailsComponent, + RgwTopicListComponent, + RgwTopicDetailsComponent ], providers: [TitleCasePipe] }) @@ -392,6 +396,11 @@ const routes: Routes = [ path: 'configuration', data: { breadcrumbs: 'Configuration' }, children: [{ path: '', component: RgwConfigurationPageComponent }] + }, + { + path: 'topic', + data: { breadcrumbs: 'Topic' }, + children: [{ path: '', component: RgwTopicListComponent }] } ]; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html index 53d36bd1c849e..8bd4895eb646f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html @@ -208,16 +208,21 @@ i18n-title [useRouter]="true" class="tc_submenuitem tc_submenuitem_rgw_overview">Overview + Users Buckets - Users + title="Topics" + i18n-title + class="tc_submenuitem tc_submenuitem_rgw_topics">Topics { [ '.tc_menuitem_rgw', '.tc_submenuitem_rgw_daemons', + '.tc_submenuitem_rgw_users', '.tc_submenuitem_rgw_buckets', - '.tc_submenuitem_rgw_users' + '.tc_submenuitem_rgw_topics' ] ] ]; @@ -185,8 +186,9 @@ describe('NavigationComponent', () => { [ '.tc_menuitem_rgw', '.tc_submenuitem_rgw_daemons', + '.tc_submenuitem_rgw_users', '.tc_submenuitem_rgw_buckets', - '.tc_submenuitem_rgw_users' + '.tc_submenuitem_rgw_topics' ] ] ]; @@ -246,8 +248,9 @@ describe('NavigationComponent', () => { '.tc_submenuitem_block_iscsi': 'iSCSI', '.tc_submenuitem_block_nvme': 'NVMe/TCP', '.tc_submenuitem_rgw_overview': 'Overview', - '.tc_submenuitem_rgw_buckets': 'Buckets', '.tc_submenuitem_rgw_users': 'Users', + '.tc_submenuitem_rgw_buckets': 'Buckets', + '.tc_submenuitem_rgw_topics': 'Topics', '.tc_submenuitem_rgw_multi-site': 'Multi-site', '.tc_submenuitem_rgw_daemons': 'Gateways', '.tc_submenuitem_rgw_nfs': 'NFS', diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-topic.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-topic.service.spec.ts new file mode 100644 index 0000000000000..b30cf0443c89c --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-topic.service.spec.ts @@ -0,0 +1,56 @@ +import { TestBed } from '@angular/core/testing'; + +import { RgwTopicService } from './rgw-topic.service'; +import { configureTestBed } from '~/testing/unit-test-helper'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +describe('RgwTopicService', () => { + let service: RgwTopicService; + let httpTesting: HttpTestingController; + configureTestBed({ + imports: [HttpClientTestingModule] + }); + configureTestBed({ + imports: [HttpClientTestingModule], + providers: [RgwTopicService] + }); + + beforeEach(() => { + service = TestBed.inject(RgwTopicService); + httpTesting = TestBed.inject(HttpTestingController); + }); + + afterEach(() => { + httpTesting.verify(); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should call list with empty result', () => { + let result; + service.listTopic().subscribe((resp) => { + result = resp; + }); + const req = httpTesting.expectOne(`api/rgw/topic`); + expect(req.request.method).toBe('GET'); + req.flush([]); + expect(result).toEqual([]); + }); + it('should call list with result', () => { + service.listTopic().subscribe((resp) => { + let result = resp; + return result; + }); + let req = httpTesting.expectOne(`api/rgw/topic`); + expect(req.request.method).toBe('GET'); + req.flush(['foo', 'bar']); + }); + + it('should call get', () => { + service.getTopic('foo').subscribe(); + const req = httpTesting.expectOne(`api/rgw/topic/foo`); + expect(req.request.method).toBe('GET'); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-topic.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-topic.service.ts new file mode 100644 index 0000000000000..8de7b32c04dbd --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-topic.service.ts @@ -0,0 +1,24 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { ApiClient } from './api-client'; +import { Topic } from '~/app/shared/models/topic.model'; + +@Injectable({ + providedIn: 'root' +}) +export class RgwTopicService extends ApiClient { + baseURL = 'api/rgw/topic'; + + constructor(private http: HttpClient) { + super(); + } + + listTopic(): Observable { + return this.http.get(this.baseURL); + } + + getTopic(name: string) { + return this.http.get(`${this.baseURL}/${name}`); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/topic.model.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/topic.model.ts new file mode 100644 index 0000000000000..31aa7b61c1225 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/topic.model.ts @@ -0,0 +1,31 @@ +interface Destination { + push_endpoint: string; + push_endpoint_args: string; + push_endpoint_topic: string; + stored_secret: string; + persistent: boolean; + persistent_queue: string; + time_to_live: number; + max_retries: number; + retry_sleep_duration: number; +} + +export interface Topic { + owner: string; + name: string; + arn: string; + dest: Destination; + opaqueData: string; + policy: string | {}; + subscribed_buckets: any[]; +} + +export interface TopicDetails { + owner: string; + name: string; + arn: string; + dest: Destination; + opaqueData: string; + policy: string; + subscribed_buckets: string[]; +} diff --git a/src/pybind/mgr/dashboard/tests/test_rgw.py b/src/pybind/mgr/dashboard/tests/test_rgw.py index 298b6a4c21361..00b2f5aff8818 100644 --- a/src/pybind/mgr/dashboard/tests/test_rgw.py +++ b/src/pybind/mgr/dashboard/tests/test_rgw.py @@ -535,28 +535,25 @@ class TestRgwTopicController(ControllerTestCase): def test_list_topic_with_details(self, mock_list_topics): mock_return_value = [ { - "topic": { - "owner": "dashboard", - "name": "HttpTest", - "dest": { - "push_endpoint": "https://10.0.66.13:443", - "push_endpoint_args": "verify_ssl=true", - "push_endpoint_topic": "HttpTest", - "stored_secret": False, - "persistent": True, - "persistent_queue": ":HttpTest", - "time_to_live": "5", - "max_retries": "2", - "retry_sleep_duration": "2" - }, - "arn": "arn:aws:sns:zg1-realm1::HttpTest", - "opaqueData": "test123", - "policy": "{}", - "subscribed_buckets": [] - } + "owner": "dashboard", + "name": "HttpTest", + "dest": { + "push_endpoint": "https://10.0.66.13:443", + "push_endpoint_args": "verify_ssl=true", + "push_endpoint_topic": "HttpTest", + "stored_secret": False, + "persistent": True, + "persistent_queue": ":HttpTest", + "time_to_live": "5", + "max_retries": "2", + "retry_sleep_duration": "2" + }, + "arn": "arn:aws:sns:zg1-realm1::HttpTest", + "opaqueData": "test123", + "policy": "{}", + "subscribed_buckets": [] } ] - mock_list_topics.return_value = mock_return_value controller = RgwTopic() result = controller.list(True, None) @@ -565,8 +562,8 @@ class TestRgwTopicController(ControllerTestCase): @patch('dashboard.controllers.rgw.RgwTopic.get') def test_get_topic(self, mock_get_topic): - mock_return_value = { - "topic": { + mock_return_value = [ + { "owner": "dashboard", "name": "HttpTest", "dest": { @@ -585,7 +582,7 @@ class TestRgwTopicController(ControllerTestCase): "policy": "{}", "subscribed_buckets": [] } - } + ] mock_get_topic.return_value = mock_return_value controller = RgwTopic() -- 2.39.5