btlqql opened a new pull request, #4718:
URL: https://github.com/apache/rocketmq-dashboard/pull/4718

   <!-- Base branch: `rocketmq-studio`, the RocketMQ Studio trunk. -->
   
   ### Brief Description
   
   `DLQService.validateTimeRange` rejects a reversed window (`endTime < 
startTime`) but accepts a
   zero-length one (`endTime == startTime`), and the two DLQ export paths are 
the ones that never
   re-check it further:
   
   ```java
   // DLQService.java (before) - equality is not rejected
   if (endTime < startTime) {
       throw new BusinessException(400, "endTime must not be earlier than 
startTime");
   }
   ```
   
   | action | zero-length window before this change |
   |---|---|
   | `GET /api/dlq/{groupName}/messages` | 400 - `RocketMQDLQProvider.java:346` 
re-checks `begin >= end` |
   | `POST /api/dlq/resend` | 400 - `RocketMQDLQProvider.java:183` re-checks 
`begin >= end` |
   | `GET /api/dlq/export` | **200** - `RocketMQDLQProvider.exportMessages` 
never checks the window |
   | `GET /api/dlq/export-excel` | **200** - `RocketMQDLQProvider.exportExcel` 
never checks the window |
   
   `RocketMQDLQProvider.scanDeadLetters` searches `minOffset` and `maxOffset` 
from the same timestamp
   when `begin == end`, so the export does not fail: it silently writes the 
single message sitting on
   that instant (or nothing at all) into a file that looks like a legitimate 
snapshot of a DLQ that has
   no dead letters. An operator exporting a range whose start and end collapsed 
to the same millisecond
   gets a successful download instead of the 400 the other two DLQ actions 
return for the same input.
   
   `DLQService.validateTimeRange` is the documented boundary for this 
validation (it is the only guard
   the export paths have, and the both-or-neither / positive / reversed checks 
already live there), so
   the zero-length case is rejected there, with the same message the topic and 
key message-query paths
   use. Reversed windows keep their existing message, and a one-millisecond 
window is still accepted -
   the new guard rejects only the window that cannot describe a range.
   
   ### Related issue
   
   Searched on 2026-09-21 for `is:pr+is:open+DLQService.java`, 
`is:pr+is:open+DLQServiceTest.java`,
   `zero-length time window`, `empty time window DLQ` and `startTime must be 
before endTime`: no open
   issue or PR covers this. The closest match is the closed #1802 (`DLQ resend 
should reject invalid
   time ranges before scanning`), which is the change that introduced the 
current `endTime < startTime`
   guard in this method - it covered reversed and non-positive windows and left 
the zero-length window
   accepted.
   
   ### How Did You Test This Change?
   
   New tests in `DLQServiceTest`: 
`everyActionShouldRejectAnEmptyTimeWindowTest` (resend, message list
   and both exports), plus 
`everyActionShouldStillAcceptAOneMillisecondTimeWindowTest` as a guard that
   only the window that cannot describe a range is rejected.
   
   Before the fix (red) - all four actions delegated the zero-length window to 
the provider:
   
   ```
   $ cd server && mvn -B -ntp test -Dtest=DLQServiceTest
   [ERROR] Tests run: 19, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 
2.273 s <<< FAILURE! -- in 
org.apache.rocketmq.studio.instance.dlq.DLQServiceTest
   [ERROR] 
org.apache.rocketmq.studio.instance.dlq.DLQServiceTest.everyActionShouldRejectAnEmptyTimeWindowTest
 -- Time elapsed: 0.024 s <<< FAILURE!
   [ERROR]   DLQServiceTest.everyActionShouldRejectAnEmptyTimeWindowTest:234
   Expecting code to raise a throwable.
   ```
   
   After the fix (green):
   
   ```
   $ cd server && mvn -B -ntp test 
-Dtest='DLQServiceTest,DLQControllerTest,DLQMessageExcelRowTest'
   [INFO] Tests run: 24, Failures: 0, Errors: 0, Skipped: 0 -- in 
org.apache.rocketmq.studio.instance.dlq.DLQControllerTest
   [INFO] Tests run: 19, Failures: 0, Errors: 0, Skipped: 0 -- in 
org.apache.rocketmq.studio.instance.dlq.DLQServiceTest
   [INFO] Tests run: 43, Failures: 0, Errors: 0, Skipped: 0
   [INFO] BUILD SUCCESS
   ```
   
   `mvn test` runs checkstyle in the `validate` phase: `You have 0 Checkstyle 
violations.`
   
   Note on the full suite: on a clean `rocketmq-studio` checkout `mvn -B -ntp 
test` already reports
   `Tests run: 3051, Failures: 6, Errors: 25, Skipped: 4`. The 11 red classes 
are the MySQL 8 backed
   Spring integration tests (`AuthServiceBootstrapIntegrationTest`,
   `AuthServiceConcurrencyIntegrationTest`, 
`AuthServiceSessionOverviewIntegrationTest`,
   `HealthProbeIntegrationTest`, `QueryHistoryServiceIntegrationTest`,
   `NativeAlertEvaluationTransactionTest`, 
`NotificationOutboxMapperIntegrationTest`,
   `RmqAlertStateMapperIntegrationTest`, `StudioApplicationTest`) plus the 
external-CLI ones
   (`CliAgentProviderTest`, `ClaudeCodeAgentProviderTest`). None of them are 
touched by this change.
   
   ### Checklist
   
   - [x] One coherent change; unrelated modifications are not bundled in
   - [x] Commit subject follows Conventional Commits (`fix:`)
   - [x] Tests added or updated for non-trivial changes, test methods named 
`...Test`
   - [x] New UI text has both Chinese and English entries under `web/src/i18n/` 
(no UI text in this change)
   - [x] Architecture constraints stay green (`mvn test` runs the ArchUnit 
checks)
   - [x] New source files carry the ASF license header (no new files)
   - [x] Documentation touched where behaviour changed (the export endpoints 
are not documented in `docs/api-spec.md`, so there is no contract text to 
update)
   


-- 
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