From 698614e3cc71c38f2979e5e165172aeb911bc8be Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 17 Dec 2024 10:57:01 +0100 Subject: [PATCH] [MNG-8436] Fix wrong transfer rates displayed in console (#1985) ``` Downloaded from central: https://repo.maven.apache.org/maven2/org/graalvm/compiler/compiler/24.1.1/compiler-24.1.1.pom (1.7 kB at 9223372036854775807 GB/s) ``` --- https://issues.apache.org/jira/browse/MNG-8436 --- .../AbstractMavenTransferListener.java | 7 ++- .../maven/cling/transfer/FileSizeFormat.java | 19 +++--- .../cling/transfer/FileSizeFormatTest.java | 61 +++++++++++++++++-- 3 files changed, 70 insertions(+), 17 deletions(-) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/transfer/AbstractMavenTransferListener.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/transfer/AbstractMavenTransferListener.java index fa4341b8f1..a3985ec0cb 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/transfer/AbstractMavenTransferListener.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/transfer/AbstractMavenTransferListener.java @@ -20,6 +20,7 @@ package org.apache.maven.cling.transfer; import java.io.PrintWriter; import java.time.Duration; +import java.util.concurrent.TimeUnit; import org.apache.maven.api.MonotonicClock; import org.apache.maven.api.services.MessageBuilder; @@ -83,8 +84,10 @@ public abstract class AbstractMavenTransferListener extends AbstractTransferList message.style(STYLE).append(" (").append(format.format(contentLength)); Duration duration = Duration.between(resource.getStartTime(), MonotonicClock.now()); - if ((duration.getSeconds() | duration.getNano()) > 0) { // duration.isPositive() - double bytesPerSecond = contentLength / (double) duration.toSeconds(); + long nanos = duration.toNanos(); + if (nanos > 0) { + double seconds = nanos / (double) TimeUnit.SECONDS.toNanos(1); // Convert to fractional seconds + double bytesPerSecond = contentLength / seconds; message.append(" at "); format.formatRate(message, bytesPerSecond); } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/transfer/FileSizeFormat.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/transfer/FileSizeFormat.java index d29eb01540..803b39635d 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/transfer/FileSizeFormat.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/transfer/FileSizeFormat.java @@ -153,19 +153,16 @@ public class FileSizeFormat { } public void formatRate(MessageBuilder builder, double rate) { + // Handle invalid rates gracefully (including negative values) + if (Double.isNaN(rate) || Double.isInfinite(rate) || rate < 0) { + builder.append("? B/s"); + return; + } + ScaleUnit unit = ScaleUnit.getScaleUnit(Math.round(rate)); double scaledRate = rate / unit.bytes(); - if (unit == ScaleUnit.BYTE || scaledRate < 0.05d || scaledRate >= 10.0d) { - builder.append(Long.toString(Math.round(scaledRate))); - } else { - builder.append(Double.toString(Math.round(scaledRate * 10d) / 10d)); - } - if (unit == ScaleUnit.BYTE) { - builder.append(" B"); - } else { - builder.append(" ").append(unit.symbol()); - } - builder.append("/s"); + builder.append(String.format("%.1f", scaledRate)); + builder.append(" ").append(unit.symbol()).append("/s"); } private void format(MessageBuilder builder, long size, ScaleUnit unit, boolean omitSymbol) { diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/transfer/FileSizeFormatTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/transfer/FileSizeFormatTest.java index 9a969f0359..aec45fd4ca 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/transfer/FileSizeFormatTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/transfer/FileSizeFormatTest.java @@ -296,7 +296,7 @@ class FileSizeFormatTest { // Test bytes per second MessageBuilder builder = new DefaultMessageBuilder(); format.formatRate(builder, 5.0); - assertEquals("5 B/s", builder.build()); + assertEquals("5.0 B/s", builder.build()); // Test kilobytes per second builder = new DefaultMessageBuilder(); @@ -319,19 +319,33 @@ class FileSizeFormatTest { FileSizeFormat format = new FileSizeFormat(); // Test value less than 0.05 + // Test exact unit thresholds MessageBuilder builder = new DefaultMessageBuilder(); format.formatRate(builder, 45.0); // 45 B/s - assertEquals("45 B/s", builder.build()); + assertEquals("45.0 B/s", builder.build()); // Test value greater than or equal to 10 builder = new DefaultMessageBuilder(); format.formatRate(builder, 15000.0); // 15 kB/s - assertEquals("15 kB/s", builder.build()); + assertEquals("15.0 kB/s", builder.build()); // Test value between 0.05 and 10 builder = new DefaultMessageBuilder(); format.formatRate(builder, 5500.0); // 5.5 kB/s assertEquals("5.5 kB/s", builder.build()); + + // Test exact unit thresholds + builder = new DefaultMessageBuilder(); + format.formatRate(builder, 1000.0); // 1 kB/s + assertEquals("1.0 kB/s", builder.build()); + + builder = new DefaultMessageBuilder(); + format.formatRate(builder, 1000000.0); // 1 MB/s + assertEquals("1.0 MB/s", builder.build()); + + builder = new DefaultMessageBuilder(); + format.formatRate(builder, 1000000000.0); // 1 GB/s + assertEquals("1.0 GB/s", builder.build()); } @Test @@ -341,7 +355,7 @@ class FileSizeFormatTest { // Test zero rate MessageBuilder builder = new DefaultMessageBuilder(); format.formatRate(builder, 0.0); - assertEquals("0 B/s", builder.build()); + assertEquals("0.0 B/s", builder.build()); // Test rate at exactly 1000 (1 kB/s) builder = new DefaultMessageBuilder(); @@ -353,4 +367,43 @@ class FileSizeFormatTest { format.formatRate(builder, 1000000.0); assertEquals("1.0 MB/s", builder.build()); } + + @Test + void testFormatRateLargeValues() { + FileSizeFormat format = new FileSizeFormat(); + + // Test large but valid rates + MessageBuilder builder = new DefaultMessageBuilder(); + format.formatRate(builder, 5e12); // 5 TB/s + assertEquals("5000.0 GB/s", builder.build()); + + // Test very large rate + builder = new DefaultMessageBuilder(); + format.formatRate(builder, 1e15); // 1 PB/s + assertEquals("1000000.0 GB/s", builder.build()); + } + + @Test + void testFormatRateInvalidValues() { + FileSizeFormat format = new FileSizeFormat(); + + // Test negative rate + MessageBuilder builder = new DefaultMessageBuilder(); + format.formatRate(builder, -1.0); + assertEquals("? B/s", builder.build()); + + // Test NaN + builder = new DefaultMessageBuilder(); + format.formatRate(builder, Double.NaN); + assertEquals("? B/s", builder.build()); + + // Test Infinity + builder = new DefaultMessageBuilder(); + format.formatRate(builder, Double.POSITIVE_INFINITY); + assertEquals("? B/s", builder.build()); + + builder = new DefaultMessageBuilder(); + format.formatRate(builder, Double.NEGATIVE_INFINITY); + assertEquals("? B/s", builder.build()); + } }