gemmellr commented on code in PR #4710: URL: https://github.com/apache/activemq-artemis/pull/4710#discussion_r1452215672
########## artemis-server/src/test/java/org/apache/activemq/artemis/core/config/WildcardConfigurationTest.java: ########## @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.core.config; + +import org.junit.Assert; +import org.junit.Test; + +public class WildcardConfigurationTest extends Assert { Review Comment: I'd expect to see more general unit testing of the new methods, e.g the new bits around equality and returning the input directly when calling for conversion if they are the exact same or equal WildcardConfiguration. Every one of the calls in the added test uses different/non-equal WildcardConfiguration objects and also mutates something in the input string. ########## docs/user-manual/versions.adoc: ########## @@ -31,6 +31,13 @@ These settings are now no longer required. + Configure `defaultMqttSessionExpiryInterval` instead. +* Due to https://issues.apache.org/jira/browse/ARTEMIS-4532[ARTEMIS-4532] the names of addresses and queues related to MQTT topics and subscriptions respectively may change. This will only impact you: ++ + . If the broker is configured to use a xref:wildcard-syntax.adoc[wildcard syntax] which doesn't match the xref:mqtt.adoc#wildcard-syntax[MQTT wildcard syntax]. + . If you are using characters from the broker's wildcard syntax in your MQTT topic names or topic filters. Review Comment: It could be clearer from the text both items in the list need apply, just to drive it home ########## tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/spec/controlpackets/PublishTests.java: ########## @@ -311,15 +312,15 @@ public void testRetainFlagFalse() throws Exception { // send retained message producer.publish(TOPIC, RETAINED_PAYLOAD.getBytes(), 2, true); - Wait.assertTrue(() -> server.locateQueue(MQTTUtil.convertMqttTopicFilterToCore(MQTTUtil.MQTT_RETAIN_ADDRESS_PREFIX, TOPIC, MQTTUtil.MQTT_WILDCARD)).getMessageCount() == 1, 1000, 100); + Wait.assertTrue(() -> getRetainedMessageQueue(TOPIC).getMessageCount() == 1, 1000, 100); // send an unretained message; should *not* remove the existing retained message producer.publish(TOPIC, UNRETAINED_PAYLOAD.getBytes(), 2, false); producer.disconnect(); producer.close(); - Wait.assertFalse(() -> server.locateQueue(MQTTUtil.convertMqttTopicFilterToCore(MQTTUtil.MQTT_RETAIN_ADDRESS_PREFIX, TOPIC, MQTTUtil.MQTT_WILDCARD)).getMessageCount() > 1, 1000, 100); + Wait.assertFalse(() -> getRetainedMessageQueue(TOPIC).getMessageCount() > 1, 1000, 100); Review Comment: Is there a reason why the assert should not just be checking for a count of 2 ? ########## tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/spec/controlpackets/PublishTests.java: ########## @@ -269,15 +270,15 @@ public void testRetainFlagWithEmptyMessage() throws Exception { // send first retained message producer.publish(TOPIC, "retain1".getBytes(), 2, true); - Wait.assertTrue(() -> server.locateQueue(MQTTUtil.convertMqttTopicFilterToCore(MQTTUtil.MQTT_RETAIN_ADDRESS_PREFIX, TOPIC, MQTTUtil.MQTT_WILDCARD)).getMessageCount() == 1, 2000, 100); + Wait.assertTrue(() -> getRetainedMessageQueue(TOPIC).getMessageCount() == 1, 2000, 100); Review Comment: Lots of tests asserting the queue count is 1 now, but would be better if they also verified it was 0 to begin with. ########## artemis-server/src/main/java/org/apache/activemq/artemis/core/config/WildcardConfiguration.java: ########## @@ -119,19 +138,94 @@ public String getSingleWordString() { return singleWordString; } - public void setSingleWord(char singleWord) { + public WildcardConfiguration setSingleWord(char singleWord) { this.singleWord = singleWord; this.singleWordString = String.valueOf(singleWord); + return this; } - public String convert(String filter, WildcardConfiguration to) { - if (this.equals(to)) { - return filter; + /** + * Convert the input from this WildcardConfiguration into the specified WildcardConfiguration. + * + * If the input already contains characters defined in the target WildcardConfiguration then those characters will + * be escaped and preserved as such in the returned String. That said, wildcard characters which are the same + * between the two configurations will not be escaped + * + * If the input already contains escaped characters defined in this WildcardConfiguration then those characters will + * be unescaped after conversion and restored in the returned String. + * + * @param input the String to convert + * @param target the WildcardConfiguration to convert the input into + * @return the converted String + */ + public String convert(final String input, final WildcardConfiguration target) { + if (this.equals(target)) { + return input; } else { - return filter - .replace(getDelimiter(), to.getDelimiter()) - .replace(getSingleWord(), to.getSingleWord()) - .replace(getAnyWords(), to.getAnyWords()); + boolean escaped = isEscaped(input); + StringBuilder result; + if (!escaped) { + result = new StringBuilder(target.escape(input, this)); + } else { + result = new StringBuilder(input); + } + replaceChar(result, getDelimiter(), target.getDelimiter()); + replaceChar(result, getSingleWord(), target.getSingleWord()); + replaceChar(result, getAnyWords(), target.getAnyWords()); + if (escaped) { + return unescape(result.toString()); + } else { + return result.toString(); + } + } + } + + private String escape(final String input, WildcardConfiguration from) { + String result = input.replace(escapeString, escapeString + escapeString); + if (delimiter != from.getDelimiter()) { + result = result.replace(getDelimiterString(), escapeString + getDelimiterString()); + } + if (singleWord != from.getSingleWord()) { + result = result.replace(getSingleWordString(), escapeString + getSingleWordString()); + } + if (anyWords != from.getAnyWords()) { + result = result.replace(getAnyWordsString(), escapeString + getAnyWordsString()); + } + return result; + } + + private String unescape(final String input) { + return input + .replace(escapeString + escapeString, escapeString) + .replace(ESCAPE + getDelimiterString(), getDelimiterString()) + .replace(ESCAPE + getSingleWordString(), getSingleWordString()) + .replace(ESCAPE + getAnyWordsString(), getAnyWordsString()); + } + + private boolean isEscaped(final String input) { + for (int i = 0; i < input.length() - 1; i++) { + if (input.charAt(i) == ESCAPE && (input.charAt(i + 1) == getDelimiter() || input.charAt(i + 1) == getSingleWord() || input.charAt(i + 1) == getAnyWords())) { + return true; + } + } Review Comment: To be sure, this would throw IOOBE if the final character is the escape since it assumes there is another character, is that ok (doesnt seem like it should really come up often)? ########## docs/user-manual/versions.adoc: ########## @@ -31,6 +31,13 @@ These settings are now no longer required. + Configure `defaultMqttSessionExpiryInterval` instead. +* Due to https://issues.apache.org/jira/browse/ARTEMIS-4532[ARTEMIS-4532] the names of addresses and queues related to MQTT topics and subscriptions respectively may change. This will only impact you: ++ + . If the broker is configured to use a xref:wildcard-syntax.adoc[wildcard syntax] which doesn't match the xref:mqtt.adoc#wildcard-syntax[MQTT wildcard syntax]. + . If you are using characters from the broker's wildcard syntax in your MQTT topic names or topic filters. ++ +In this case the characters from the broker's wildcard syntax that do not match the characters in the MQTT wildcard syntax will be escaped with a backslash (i.e. `\`). Review Comment: Suggestion for what a user might need to do to adapt? E.g rename an existing queues to what they 'should be' now? ########## tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/spec/controlpackets/PublishTests.java: ########## @@ -653,6 +654,10 @@ public void messageArrived(String topic, MqttMessage message) throws Exception { consumer.close(); } + private Queue getRetainedMessageQueue(String TOPIC) { + return server.locateQueue(MQTTUtil.convertMqttTopicFilterToCore(MQTTUtil.MQTT_RETAIN_ADDRESS_PREFIX, TOPIC, server.getConfiguration().getWildcardConfiguration())); + } Review Comment: Both here and elsewhere, there appear to be so many tests using the _MQTTUtil.convertMqttTopicFilterToCore_ method to calculate queue names, as does the _MQTTSubscriptionManager.getQueueNameForTopic_ method which appears to be the location targeted most by the change in this PR. That seems to leave most of these tests open to compensating bugs in whatever that method happens to return. It does seem to be changed fairly regularly. I think it would be good to see some direct unit testing of what this queue naming method does to confirm it is actually meeting expectations. Also, perhaps convert the TOPIC parameter name here to lowercase? Its a little odd to use TOPIC for it, and potentially confusing when that name is already widely used elsewhere in the class. ########## artemis-server/src/test/java/org/apache/activemq/artemis/core/config/WildcardConfigurationTest.java: ########## @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.core.config; + +import org.junit.Assert; +import org.junit.Test; + +public class WildcardConfigurationTest extends Assert { + + public static final WildcardConfiguration MQTT_WILDCARD = new WildcardConfiguration().setDelimiter('/').setAnyWords('#').setSingleWord('+'); + public static final WildcardConfiguration DEFAULT_WILDCARD = new WildcardConfiguration(); Review Comment: Can these be private? Worth an assert that the default configuration object is as expected? -- 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]
