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]