Wang1rrr opened a new issue, #4868:
URL: https://github.com/apache/rocketmq-dashboard/issues/4868

   ### Before Creating the Bug Report
   
   - [x] I have searched the [open 
issues](https://github.com/apache/rocketmq-dashboard/issues) of this repository 
and believe that this is not a duplicate.
   - [x] This is a defect in RocketMQ Studio, not a usage question and not a 
defect in another Apache RocketMQ repository.
   - [x] I can reproduce this on the current `rocketmq-studio` branch (the 
Studio trunk the pull request template points at), commit 
`4c697f07acde460e2344375cb1f82669f5b270fd`.
   
   ### Studio Version
   
   ```
   branch: rocketmq-studio
   git commit id: 4c697f07acde460e2344375cb1f82669f5b270fd
   deployed as: built from source
   ```
   
   ### Runtime Environment
   
   ```
   OS: Windows 11 (development box); the defect is a contract declaration, so 
the host does not matter
   MySQL: not required - reproduced from the sources and from the web unit tests
   browser (for UI issues): any; the affected console page is 
web/src/pages/instance/topic.tsx
   ```
   
   ### Connected RocketMQ Cluster
   
   ```
   RocketMQ version: any - all three providers (Apache, Aliyun, Tencent) build 
the same VO
   access mode: Direct / Proxy Local / Proxy Cluster / cloud - the response 
shape is identical
   deployment: any cluster where the console can send a test message to a topic
   ```
   
   ### Build Toolchain
   
   ```
   node: v22 (web/ package.json engines), npm ci from web/package-lock.json
   java: 21 (server/pom.xml, maven.compiler.release=21)
   ```
   
   ### Describe the Bug
   
   `POST /api/topics/send` answers with `SendMessageVO`, whose `sendTime` is a 
primitive `long` 
(`server/src/main/java/org/apache/rocketmq/studio/instance/topic/SendMessageVO.java:30`).
 Every provider fills it with `System.currentTimeMillis()`:
   
   - `provider/apache/RocketMQAdminClientImpl.java:555`
   - `provider/alibaba/AliyunInstanceProvider.java:483`
   - `provider/tencent/TencentInstanceProvider.java:600`
   
   So the wire value is a JSON **number** of epoch milliseconds. The AI tool 
contract agrees: 
`server/src/main/resources/tool-catalog/tools/message.yaml:526` declares 
`sendTime: type: integer`, and 
`ops/ai/tool/contract/message/MessageSendOutput.java:26` is `long sendTime`.
   
   Three declarations say the opposite, and they are the ones a web or 
third-party integrator actually reads:
   
   | place | claims |
   | --- | --- |
   | `docs/api-spec.md:891` | `sendTime` \| `string` \| 发送时间 (ISO 8601) |
   | `docs/api-spec.md:912` | `"sendTime": "2026-07-08T10:30:45.123Z"` in the 
response example |
   | `web/src/api/metadata.ts:289` | `sendTime: string;` on 
`SendTopicMessageResult` |
   
   The mock data layer is written to the wrong type, so the console serves two 
different shapes for the same field depending on the data mode: 
`web/src/services/topicService.ts:241` returns `new Date().toISOString()` when 
`isMockMode()`, and the real API returns `1783506645123`. Nothing catches it - 
`tsc` is happy because the mock satisfies the declared (wrong) type, and the 
real response is never type-checked.
   
   The two existing fixtures disagree with each other, which is how the drift 
stayed invisible:
   
   - `web/src/api/metadata.test.ts:139` stubs the endpoint with `sendTime: 1` - 
a number, i.e. what the server really sends - and then asserts only 
`toMatchObject({ msgId: 'msg-1' })`, so the field is never checked;
   - `web/src/pages/instance/__tests__/TopicPage.test.tsx:188` stubs the 
service with `sendTime: '2026-01-02T00:00:00Z'` - a string, i.e. what the type 
wrongly promises.
   
   Today the console only reads `result.msgId` 
(`web/src/pages/instance/topic.tsx:1455`), so this is latent rather than 
visible: the defect is that the documented and declared contract is wrong, that 
mock mode and real mode are not interchangeable for this field, and that the 
first caller who renders or formats `sendTime` - the obvious next step for a 
"message sent" confirmation, and the reason the field exists - will be written 
against a string and handed a number. `dayjs(1783506645123)` and `new 
Date('1783506645123')` do not agree, and `String(sendTime).length` checks or 
`.slice()` formatting silently produce garbage.
   
   ### Steps to Reproduce
   
   1. On `rocketmq-studio` @ `4c697f07`, read `SendMessageVO.sendTime` and the 
three provider call sites that set it - the server sends epoch millis.
   2. Read `docs/api-spec.md` §5.8 (发送消息到 Topic) and 
`web/src/api/metadata.ts:289` - both promise an ISO-8601 string.
   3. Run the console in mock data mode and call `sendTopicMessage`: 
`topicService.ts:241` returns `new Date().toISOString()`. Switch to a real 
cluster and the same call returns a number.
   4. `cd web && npx vitest run src/api/metadata.test.ts 
src/pages/instance/__tests__/TopicPage.test.tsx` - both pass, one fixture using 
`1` and the other using `'2026-01-02T00:00:00Z'`, because no assertion pins the 
type.
   
   ### What Did You Expect to See?
   
   One contract, stated the same way everywhere: `sendTime` is epoch 
milliseconds, matching `SendMessageVO`, the three providers and the 
`message.yaml` tool schema. The mock data layer should return the same shape as 
the real API so the two modes are interchangeable, and a test should pin it.
   
   ### What Did You See Instead?
   
   The spec, its JSON example and the TypeScript type all declare an ISO-8601 
string; the mock implements that string; the server returns a number; and the 
two test fixtures encode the two contradictory answers without either failing.
   
   ### Additional Context
   
   The fix should align the declarations with the server, not the server with 
the declarations: epoch millis is what all three providers already produce and 
what the AI tool schema (`message.yaml:526`) already publishes, so changing 
`SendMessageVO` to a formatted string would break the tool contract and every 
existing consumer of `rmq.message.send`.
   
   Scope of the correction: `docs/api-spec.md` §5.8 (field table and response 
example), `web/src/api/metadata.ts`, the mock branch in 
`web/src/services/topicService.ts`, the `TopicPage.test.tsx` fixture, an 
assertion on the pass-through in `metadata.test.ts`, and a new 
`topicService.test.ts` case that fails if mock mode ever drifts from the API 
shape again.
   
   ### Are You Willing to Submit a Pull Request?
   
   - [x] Yes, I am willing to submit a pull request.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to