Repository navigation
Conversation
Aias00
left a comment
There was a problem hiding this comment.
Review: #6923 honor requested QoS in SUBACK
Decision: APPROVE
What changed
Subscribe.sendSubAckMessage(...): previously the SUBACK always granted QoS 0 regardless of what the client requested. Now it grants each subscription the QoS the client requested (topicSub.qualityOfService().value()), which is the correct MQTT behavior.- The FAILURE-filtered subscription list is now collected into
ackSubscriptions(kept before the topic-name mapping) and passed through tosendSubAckMessage. - Removed now-unused imports (
java.util.ArrayList,io.netty.handler.codec.mqtt.MqttQoS). - Added
SubscribeTest(Mockito + ArgumentCaptor) covering: granted QoS matches requested (2/0/1), FAILURE subscriptions are excluded from SUBACK and not looked up intopicRepository, and connected-state closes the channel without writing a SUBACK.
Verification
- Granted QoS list length matches the filtered subscription count; FAILURE entries are dropped before SUBACK construction, consistent with prior behavior.
- Honoring the requested QoS (server may grant equal-or-lower; here it grants exactly requested) is within MQTT spec and strictly better than always-0.
- Tests assert
grantedQoSLevels()ordering and exclusion, validating the logic.
Notes
- None blocking. Behavior improvement, well-tested.
Approving.
dengliming
left a comment
There was a problem hiding this comment.
This test is still calling the old setConnected signature. MessageType#setConnected now requires the Channel plus the boolean flag, so this won’t compile in CI.
Suggested fix:
subscribe.setConnected(channel, true);|
CI note (PMC Aias00): the only failing check is CodeQL |
Aias00
left a comment
There was a problem hiding this comment.
Correct fix — SUBACK was hard-coding QoS 0 regardless of what the subscriber asked for.
// before
for (int i = 0; i < ackTopics.size(); i++) {
qos.add(MqttQoS.AT_MOST_ONCE.value()); // always 0
}MQTT-3.8.4 requires the SUBACK payload to carry, for each subscription in order, the QoS level the server actually granted. Reporting 0 unconditionally tells a client that requested QoS 1 or 2 that it will get at-most-once delivery, so well-behaved clients downgrade their delivery guarantees (and stop sending PUBACK/PUBREC) even though the broker would have honoured the higher level. Carrying the requested qualityOfService().value() through is the right behaviour.
Also good: the filtered ackSubscriptions list is now what drives both the repository registration and the SUBACK, so the granted levels line up with the topics actually registered instead of being derived from a parallel list.
Tests are solid: testSubAckGrantsRequestedQoS asserts [2, 0, 1] for subscriptions requested in the order QoS2/QoS0/QoS1 — which also locks in that ordering is preserved, not just the set of values.
Two non-blocking observations:
-
Failed subscriptions. MQTT-3.8.4-5 says a subscription that cannot be granted should get the failure code
0x80in the SUBACK, keeping the response positionally aligned with the request. This PR filtersFAILUREentries out of the list instead, so the SUBACK ends up shorter than the request. Clients that match by index will mis-align. Returning0x80for those entries would be spec-correct;testSubAckExcludesFailureSubscriptionscurrently documents the filtering behaviour, so changing it means updating that test. -
subscribe.setConnected(true)is used intestSubscribeWhenConnectedClosesChannel— if that setter is only intended for tests, a brief comment would help; if it's production API, it's fine as-is.
MessageType#setConnected is now keyed on the channel and Subscribe closes the channel when it is not connected, so SubscribeTest was left stale by the merged connection state guard and failed to compile. Use EmbeddedChannel so the CONNECTED attribute and outbound writes are real, and rename testSubscribeWhenConnectedClosesChannel to testSubscribeBeforeConnectClosesChannel to assert the current guard.
Aias00
left a comment
There was a problem hiding this comment.
Returning the requested QoS in SUBACK is directionally correct. Please confirm the broker actually supports every granted QoS and add coverage for false and legacy 0/1 representations so compatibility is explicit.
Aias00
left a comment
There was a problem hiding this comment.
Re-reviewed the current head. The previous test compilation issue is fixed and SUBACK now returns the requested QoS values using the current session API. The original blocker is resolved. The existing handling of rejected subscription entries remains a separate compatibility watch.
Make sure that:
./mvnw clean install -Dmaven.javadoc.skip=true.Summary
Changes:
hard-coding AT_MOST_ONCE for every topic (MQTT-3.8.4/3.9). FAILURE subscriptions remain excluded from the ack. Removed the now-unused MqttQoS and ArrayList imports.
Test Cases:
close #6848