Skip to content

Commit 7c49e03

Browse files
committed
Support Golang parseDuration syntax for --max-age and --consumer-latency
1 parent 8de0827 commit 7c49e03

File tree

4 files changed

+56
-30
lines changed

4 files changed

+56
-30
lines changed

pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
<guava.version>33.4.0-jre</guava.version>
5656
<jgroups.version>5.4.1.Final</jgroups.version>
5757
<jgroups-kubernetes.version>2.0.2.Final</jgroups-kubernetes.version>
58+
<threeten-extra.version>1.8.0</threeten-extra.version>
5859
<junit.jupiter.version>5.11.4</junit.jupiter.version>
5960
<assertj.version>3.27.3</assertj.version>
6061
<spotless.check.skip>true</spotless.check.skip>
@@ -161,6 +162,12 @@
161162
<version>${jgroups-kubernetes.version}</version>
162163
</dependency>
163164

165+
<dependency>
166+
<groupId>org.threeten</groupId>
167+
<artifactId>threeten-extra</artifactId>
168+
<version>${threeten-extra.version}</version>
169+
</dependency>
170+
164171
<dependency>
165172
<groupId>org.junit.jupiter</groupId>
166173
<artifactId>junit-jupiter-engine</artifactId>

src/main/java/com/rabbitmq/stream/perf/Converters.java

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,14 @@
3535
import java.util.stream.IntStream;
3636
import javax.net.ssl.SNIHostName;
3737
import javax.net.ssl.SNIServerName;
38+
import org.threeten.extra.AmountFormats;
3839
import picocli.CommandLine;
3940

4041
final class Converters {
4142

43+
private static final CommandLine.ITypeConverter<Duration> DURATION_TYPE_CONVERTER =
44+
new DurationTypeConverter();
45+
4246
private Converters() {}
4347

4448
static void typeConversionException(String message) {
@@ -290,34 +294,48 @@ static class DurationTypeConverter implements CommandLine.ITypeConverter<Duratio
290294

291295
@Override
292296
public Duration convert(String value) {
297+
Duration duration = null;
293298
try {
294-
Duration duration = Duration.parse(value);
295-
if (duration.isNegative() || duration.isZero()) {
299+
duration = AmountFormats.parseUnitBasedDuration(value);
300+
} catch (DateTimeParseException e) {
301+
302+
}
303+
if (duration == null) {
304+
try {
305+
duration = Duration.parse(value);
306+
} catch (DateTimeParseException e) {
296307
throw new CommandLine.TypeConversionException(
297-
"'" + value + "' is not valid, it must be positive");
308+
"'" + value + "' is not valid, valid example values: PT15M, PT10H");
298309
}
299-
return duration;
300-
} catch (DateTimeParseException e) {
310+
}
311+
return duration;
312+
}
313+
}
314+
315+
static class PositiveDurationTypeConverter implements CommandLine.ITypeConverter<Duration> {
316+
317+
@Override
318+
public Duration convert(String value) throws Exception {
319+
Duration duration = DURATION_TYPE_CONVERTER.convert(value);
320+
if (duration.isNegative() || duration.isZero()) {
301321
throw new CommandLine.TypeConversionException(
302-
"'" + value + "' is not valid, valid example values: PT15M, PT10H");
322+
"'" + value + "' is not valid, it must be positive");
303323
}
324+
return duration;
304325
}
305326
}
306327

307-
static class MicroSecondsToDurationTypeConverter implements CommandLine.ITypeConverter<Duration> {
328+
static class GreaterThanOrEqualToZeroDurationTypeConverter
329+
implements CommandLine.ITypeConverter<Duration> {
308330

309331
@Override
310-
public Duration convert(String value) {
311-
try {
312-
Duration duration = Duration.ofNanos(Long.parseLong(value) * 1_000);
313-
if (duration.isNegative()) {
314-
throw new CommandLine.TypeConversionException(
315-
"'" + value + "' is not valid, it must be greater than or equal to 0");
316-
}
317-
return duration;
318-
} catch (NumberFormatException e) {
319-
throw new CommandLine.TypeConversionException("'" + value + "' is not a valid number");
332+
public Duration convert(String value) throws Exception {
333+
Duration duration = DURATION_TYPE_CONVERTER.convert(value);
334+
if (duration.isNegative()) {
335+
throw new CommandLine.TypeConversionException(
336+
"'" + value + "' is not valid, it must be greater than or equal to 0");
320337
}
338+
return duration;
321339
}
322340
}
323341

src/main/java/com/rabbitmq/stream/perf/StreamPerfTest.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,10 @@ public class StreamPerfTest implements Callable<Integer> {
235235
@CommandLine.Option(
236236
names = {"--max-age", "-ma"},
237237
description =
238-
"max age of segments using the ISO 8601 duration format, "
239-
+ "e.g. PT10M30S for 10 minutes 30 seconds, P5DT8H for 5 days 8 hours.",
240-
converter = Converters.DurationTypeConverter.class)
238+
"max age of segments using Golang parseDuration syntax or the ISO 8601 duration format, "
239+
+ "e.g. 10m30s for 10 minutes 30 seconds (d, w, y not supported) or "
240+
+ "PT10M30S for 10 minutes 30 seconds, P5DT8H for 5 days 8 hours.",
241+
converter = Converters.PositiveDurationTypeConverter.class)
241242
private Duration maxAge;
242243

243244
@CommandLine.Option(
@@ -558,8 +559,10 @@ static class InstanceSyncOptions {
558559

559560
@CommandLine.Option(
560561
names = {"--consumer-latency", "-L"},
561-
description = "consumer latency in microseconds",
562-
converter = Converters.MicroSecondsToDurationTypeConverter.class,
562+
description =
563+
"consumer latency using Golang parseDuration syntax, "
564+
+ "e.g. 5 ms (d, w, y are not supported)",
565+
converter = Converters.GreaterThanOrEqualToZeroDurationTypeConverter.class,
563566
defaultValue = "0")
564567
private Duration consumerLatency;
565568

src/test/java/com/rabbitmq/stream/perf/ConvertersTest.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -208,20 +208,18 @@ void sniServerNamesConverter() {
208208
}
209209

210210
@ParameterizedTest
211-
@CsvSource({"5000,5", "0,0", "1000,1"})
212-
void microSecondsToDurationTypeConverterOk(String value, long expectedInMs) {
213-
Converters.MicroSecondsToDurationTypeConverter converter =
214-
new Converters.MicroSecondsToDurationTypeConverter();
211+
@CsvSource({"50ms,50", "0,0", "1s,1000", "10m30s,630000", "PT1M30S,90000"})
212+
void durationTypeConverterOk(String value, long expectedInMs) {
213+
Converters.DurationTypeConverter converter = new Converters.DurationTypeConverter();
215214
Duration duration = converter.convert(value);
216215
assertThat(duration).isNotNull();
217216
assertThat(duration).isEqualTo(Duration.ofMillis(expectedInMs));
218217
}
219218

220219
@ParameterizedTest
221-
@ValueSource(strings = {"-1000000", "abc", "1.5"})
222-
void microSecondsToDurationTypeConverterKo(String value) {
223-
Converters.MicroSecondsToDurationTypeConverter converter =
224-
new Converters.MicroSecondsToDurationTypeConverter();
220+
@ValueSource(strings = {"1", "abc", "1.5"})
221+
void durationTypeConverterKo(String value) {
222+
Converters.DurationTypeConverter converter = new Converters.DurationTypeConverter();
225223
assertThatThrownBy(() -> converter.convert(value))
226224
.isInstanceOf(CommandLine.TypeConversionException.class)
227225
.hasMessageContaining("valid");

0 commit comments

Comments
 (0)