This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new bf2cbb213 fix(mock): isolate consumer groups by instance (#2880)
bf2cbb213 is described below

commit bf2cbb213e7a47a54abe77ff0b3c6c03112c5f9b
Author: btlqql <[email protected]>
AuthorDate: Wed Sep 2 17:15:21 2026 +0800

    fix(mock): isolate consumer groups by instance (#2880)
---
 web/src/services/consumerService.test.ts | 40 ++++++++++++++++++++++++++++++++
 web/src/services/consumerService.ts      | 22 +++++++++++++++---
 2 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/web/src/services/consumerService.test.ts 
b/web/src/services/consumerService.test.ts
index 44463d470..7e5d59597 100644
--- a/web/src/services/consumerService.test.ts
+++ b/web/src/services/consumerService.test.ts
@@ -18,6 +18,7 @@
 import { describe, expect, it, vi } from 'vitest';
 import {
   createConsumerGroup,
+  deleteConsumerGroup,
   getConsumerGroup,
   getConsumerProgress,
   getConsumerStack,
@@ -26,6 +27,7 @@ import {
   listConsumerGroupPage,
   listConsumerGroups,
   previewConsumerOffsetReset,
+  refreshConsumerGroup,
 } from './consumerService';
 
 const { mode, metadataApi } = vi.hoisted(() => ({
@@ -271,6 +273,44 @@ describe('consumer service mock data', () => {
     expect(detail).not.toBe(created);
   });
 
+  it('isolates mock consumer groups with the same name by instance', async () 
=> {
+    const name = 'cg-shared-instance-scope-test';
+    await createConsumerGroup({ name, instanceId: 'instance-a', namespace: 
'namespace-a' });
+    await createConsumerGroup({ name, instanceId: 'instance-b', namespace: 
'namespace-b' });
+
+    try {
+      await expect(
+        createConsumerGroup({ name, instanceId: 'instance-a' }),
+      ).rejects.toThrow(`Consumer group already exists: ${name}`);
+
+      const instanceAGroups = await listConsumerGroups({ instanceId: 
'instance-a', search: name });
+      const instanceBGroups = await listConsumerGroups({ instanceId: 
'instance-b', search: name });
+      expect(instanceAGroups).toHaveLength(1);
+      expect(instanceAGroups[0].namespace).toBe('namespace-a');
+      expect(instanceBGroups).toHaveLength(1);
+      expect(instanceBGroups[0].namespace).toBe('namespace-b');
+      await expect(getConsumerGroup(name, 
'instance-a')).resolves.toMatchObject({
+        instanceId: 'instance-a',
+        namespace: 'namespace-a',
+      });
+      await expect(refreshConsumerGroup(name, 
'instance-b')).resolves.toMatchObject({
+        instanceId: 'instance-b',
+        namespace: 'namespace-b',
+      });
+
+      await deleteConsumerGroup(name, 'instance-a');
+      await expect(getConsumerGroup(name, 'instance-a')).rejects.toThrow(
+        `Consumer group not found: ${name}`,
+      );
+      await expect(getConsumerGroup(name, 
'instance-b')).resolves.toMatchObject({
+        instanceId: 'instance-b',
+      });
+    } finally {
+      await deleteConsumerGroup(name, 'instance-a');
+      await deleteConsumerGroup(name, 'instance-b');
+    }
+  });
+
   it('forwards the selected instance when loading consumer group details in 
API mode', async () => {
     mode.mock = false;
     const detail = {
diff --git a/web/src/services/consumerService.ts 
b/web/src/services/consumerService.ts
index 098b0de67..54ba4a3e0 100644
--- a/web/src/services/consumerService.ts
+++ b/web/src/services/consumerService.ts
@@ -81,6 +81,9 @@ const normalizeConsumerGroup = <T extends 
ConsumerGroup>(group: T): T => ({
 
 function filterConsumerGroups(params?: ConsumerGroupQuery): ConsumerGroup[] {
   let result = [...consumerGroupsState];
+  if (params?.instanceId) {
+    result = result.filter((group) => group.instanceId === params.instanceId);
+  }
   if (params?.clusterId) result = result.filter((group) => group.clusterId === 
params.clusterId);
   if (params?.search) {
     const kw = params.search.trim().toLowerCase();
@@ -164,7 +167,9 @@ export async function getConsumerGroup(
   instanceId?: string,
 ): Promise<ConsumerGroupDetail> {
   if (isMockMode()) {
-    const group = mockConsumerGroups.find((item) => item.name === name);
+    const group = mockConsumerGroups.find(
+      (item) => item.name === name && (!instanceId || item.instanceId === 
instanceId),
+    );
     if (!group) throw new Error(`Consumer group not found: ${name}`);
     return copyConsumerGroup(group as unknown as ConsumerGroupDetail) as 
ConsumerGroupDetail;
   }
@@ -196,7 +201,9 @@ export async function refreshConsumerGroup(
   instanceId?: string,
 ): Promise<ConsumerGroup | null> {
   if (isMockMode()) {
-    const group = mockConsumerGroups.find((item) => item.name === name);
+    const group = mockConsumerGroups.find(
+      (item) => item.name === name && (!instanceId || item.instanceId === 
instanceId),
+    );
     return group ? copyConsumerGroup(group) : null;
   }
   const data = await metadataApi.refreshConsumerGroup(name, instanceId);
@@ -234,9 +241,16 @@ export async function getConsumerStack(
 
 export async function createConsumerGroup(data: Partial<ConsumerGroup>): 
Promise<ConsumerGroup> {
   if (isMockMode()) {
+    const instanceId = data.instanceId ?? '';
+    const duplicate = consumerGroupsState.some(
+      (group) => group.name === data.name && group.instanceId === instanceId,
+    );
+    if (duplicate) throw new Error(`Consumer group already exists: 
${data.name}`);
+
     const now = new Date().toISOString();
     const group = {
       name: data.name ?? '',
+      instanceId,
       namespace: data.namespace ?? 'default',
       clusterId: data.clusterId ?? '',
       subscriptionMode: data.subscriptionMode ?? 'Push',
@@ -294,7 +308,9 @@ export async function exportConsumerGroups(params: 
ConsumerGroupExportQuery = {}
 
 export async function deleteConsumerGroup(name: string, instanceId?: string): 
Promise<void> {
   if (isMockMode()) {
-    const idx = consumerGroupsState.findIndex((group) => group.name === name);
+    const idx = consumerGroupsState.findIndex(
+      (group) => group.name === name && (!instanceId || group.instanceId === 
instanceId),
+    );
     if (idx >= 0) consumerGroupsState.splice(idx, 1);
     return;
   }

Reply via email to