iloveeyjafjalla opened a new issue, #11410:
URL: https://github.com/apache/rocketmq/issues/11410

   ### Before Creating the Bug Report
   
   - [x] I found a bug, not just asking a question, which should be created in 
[GitHub Discussions](https://github.com/apache/rocketmq/discussions).
   - [x] I have searched the [GitHub 
Issues](https://github.com/apache/rocketmq/issues) and [GitHub 
Discussions](https://github.com/apache/rocketmq/discussions) of this repository 
and believe that this is not a duplicate.
   - [x] I have confirmed that this bug belongs to the current repository, not 
other repositories of RocketMQ.
   
   ### Runtime platform environment
   
   OS: any (the `mqadmin` command line tool)
   
   ### RocketMQ version
   
   branch: develop
   Git commit id: a7edeecfb
   
   ### JDK Version
   
   Compiler: Temurin 1.8.0_504 (target 1.8, same as CI)
   
   ### Describe the Bug
   
   I cross-checked every commons-cli `Option` a subcommand declares against the 
keys the same command reads (`hasOption`/`getOptionValue`) across the 73 
`SubCommand` classes of the `tools` module. Apart from the static-topic 
`-mf/--mapFile` mismatch that is already reported in #11381, three commands 
still declare an option set that does not match what their `execute()` needs:
   
   **(1) `mqadmin consumer`: `-i` is read but never declared, so the 
single-client mode cannot be used.**
   
   `ConsumerSubCommand.buildCommandlineOptions` only registers 
`-g/--consumerGroup` and `-s/--jstack` 
(`tools/src/main/java/org/apache/rocketmq/tools/command/consumer/ConsumerSubCommand.java:53-64`),
 while `execute()` branches on the option:
   
   ```java
   if (!commandLine.hasOption('i')) {
       ... // every client of the group
   } else {
       String clientId = commandLine.getOptionValue('i').trim();   // :125
       ...
   }
   ```
   
   Because `DefaultParser` rejects an option that is not registered, `mqadmin 
consumer -g <group> -i <clientId>` aborts with `Unrecognized option: -i` and 
`System.exit(1)` (`srvutil/.../ServerUtil.java:54-58`); the `else` branch is 
therefore unreachable dead code and the per-client query the command was 
written to support cannot be run at all.
   
   **(2) `mqadmin resetMasterFlushOffset`: `-b` and `-o` are declared optional 
but read unconditionally.**
   
   ```java
   Option opt = new Option("b", "brokerAddr", true, "which broker to reset");
   opt.setRequired(false);                     // :41-42
   opt = new Option("o", "offset", true, "the offset to reset at");
   opt.setRequired(false);                     // :45-46
   ...
   String brokerAddr = commandLine.getOptionValue('b').trim();            // :60
   long masterFlushOffset = 
Long.parseLong(commandLine.getOptionValue('o').trim());   // :61
   ```
   
   With either option omitted the parse succeeds and the command fails with a 
`NullPointerException` from the `.trim()` (there is no fallback for either 
value): `mqadmin resetMasterFlushOffset` crashes on `-b`, `mqadmin 
resetMasterFlushOffset -b 127.0.0.1:10911` crashes on `-o`, and `-o` with a 
non-numeric value gives a `NumberFormatException`. The exception is wrapped 
into a `SubCommandException` and printed as a stack trace by `MQAdminStartup` 
(`tools/.../command/MQAdminStartup.java:194-196`), so the user gets no usage 
information at all.
   
   **(3) `mqadmin decodeMessageId`: `-i` is declared optional but read 
unconditionally.**
   
   `DecodeMessageIdCommond.buildCommandlineOptions` marks `-i/--messageId` 
`setRequired(false)` 
(`tools/.../command/message/DecodeMessageIdCommond.java:41-42`) and `execute()` 
immediately does `commandLine.getOptionValue('i').trim()` (`:50`, outside the 
`try`), so running the command without `-i` throws a `NullPointerException` 
instead of reporting the missing argument.
   
   ### Steps to Reproduce
   
   1. `mqadmin consumer -g myGroup -i 172.17.0.1@1234` → `Unrecognized option: 
-i` plus the help text, exit code 1, although `execute()` implements exactly 
this query.
   2. `mqadmin resetMasterFlushOffset` (or with only `-b`, or with only `-o`) → 
`SubCommandException: ResetMasterFlushOffsetSubCommand command failed` caused 
by `java.lang.NullPointerException`.
   3. `mqadmin decodeMessageId` → `java.lang.NullPointerException` from 
`DecodeMessageIdCommond.execute`.
   
   At the unit level each case is reproduced by parsing the command's own 
option set with a plain `DefaultParser` (the pattern the module's existing 
tests use): the invocation either parses or it does not, and the 
missing-argument behavior is what the user sees before `execute()` runs.
   
   ### What Did You Expect to See?
   
   - `consumer -i <clientId>` is accepted and performs the single-client query, 
like the sibling `consumerStatus` command whose `-i/--clientId` option is 
declared.
   - `resetMasterFlushOffset` without `-b`/`-o` and `decodeMessageId` without 
`-i` are rejected by the parser with the standard `Missing required option: -x` 
message and the command's help, the way every other `mqadmin` command whose 
arguments are mandatory behaves — instead of reaching `execute()` and dying 
with a `NullPointerException` stack trace.
   
   ### What Did You See Instead?
   
   Either an option the command actually reads is rejected as unknown, or a 
mandatory argument that is missing produces a raw `NullPointerException` / 
`NumberFormatException` with no usage hint. Both make the tool's own contract 
unreadable: `mqadmin help <command>` cannot even tell which arguments are 
mandatory, because they are declared optional.
   
   ### Additional Context
   
   Minimal fix: declare the missing option and mark the mandatory ones required 
—
   
   - `ConsumerSubCommand`: add `new Option("i", "clientId", true, "The 
consumer's client id")` (optional, as in `ConsumerStatusSubCommand`);
   - `ResetMasterFlushOffsetSubCommand`: `-b/--brokerAddr` and `-o/--offset` 
become required;
   - `DecodeMessageIdCommond`: `-i/--messageId` becomes required.
   
   Each command keeps its documented usage working (the flags are only made 
mandatory where `execute()` has no alternative path). I will open a PR with the 
changes plus tests that parse each command's own `Options` (asserting the 
missing-argument rejection and that the normal invocation still parses).
   


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