diff --git a/pom.xml b/pom.xml index a43b6904f7..cf166ffeda 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ net.openhft third-party-bom - 3.27ea5 + 3.27ea7 pom import @@ -85,6 +85,7 @@ org.jetbrains annotations + compile diff --git a/src/main/java/net/openhft/chronicle/core/Bootstrap.java b/src/main/java/net/openhft/chronicle/core/Bootstrap.java index 6d05f9bea4..5e003e395d 100644 --- a/src/main/java/net/openhft/chronicle/core/Bootstrap.java +++ b/src/main/java/net/openhft/chronicle/core/Bootstrap.java @@ -9,6 +9,7 @@ * Contains the pieces which must be loaded first */ public class Bootstrap { + @Deprecated(/* make private in 2026 */) public Bootstrap() { } static { diff --git a/src/main/java/net/openhft/chronicle/core/ChronicleInit.java b/src/main/java/net/openhft/chronicle/core/ChronicleInit.java index 82126375c2..2729230a59 100644 --- a/src/main/java/net/openhft/chronicle/core/ChronicleInit.java +++ b/src/main/java/net/openhft/chronicle/core/ChronicleInit.java @@ -29,10 +29,6 @@ public final class ChronicleInit { public static final String CHRONICLE_INIT_CLASS = "chronicle.init.runnable"; public static final String CHRONICLE_POSTINIT_CLASS = "chronicle.postinit.runnable"; - private ChronicleInit() { - // Suppresses default constructor, ensuring non-instantiability. - } - static { // Jvm#getProperty() does not make sense here - not initialized yet String initRunnableClass = System.getProperty(CHRONICLE_INIT_CLASS); @@ -58,6 +54,10 @@ private ChronicleInit() { } } + private ChronicleInit() { + // Suppresses default constructor, ensuring non-instantiability. + } + private static void runQuietly(Runnable runnable) { try { runnable.run(); @@ -66,14 +66,6 @@ private static void runQuietly(Runnable runnable) { } } - /** - * May be run multiple times, supposed to be idempotent - */ - @SuppressWarnings("EmptyMethod") - static void init() { - // No-op unless class is replaced - } - /** * Should be only run once by Jvm.class static block */ diff --git a/src/main/java/net/openhft/chronicle/core/Jvm.java b/src/main/java/net/openhft/chronicle/core/Jvm.java index b204392b0e..eddd5597ee 100644 --- a/src/main/java/net/openhft/chronicle/core/Jvm.java +++ b/src/main/java/net/openhft/chronicle/core/Jvm.java @@ -17,7 +17,7 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sun.misc.Signal; // NOSONAR +import sun.misc.Signal; import sun.misc.Unsafe; import sun.nio.ch.Interruptible; @@ -32,6 +32,8 @@ import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.spi.AbstractInterruptibleChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Paths; import java.util.*; import java.util.Map.Entry; @@ -98,8 +100,8 @@ public final class Jvm { ); private static final MethodHandle onSpinWaitMH; private static final ChainedSignalHandler signalHandlerGlobal; - private static boolean RESOURCE_TRACING; private static final boolean PROC_EXISTS = new File(PROC).exists(); + private static boolean RESOURCE_TRACING; @SuppressWarnings("unused") private static volatile Thread s_blackHole; @@ -144,7 +146,7 @@ public final class Jvm { if (DISABLE_DEBUG) logger.info("-Ddisable.debug.info turned of debug logging"); if (logger.isInfoEnabled() && notJUnitTest) - logger.info(String.format("Chronicle core loaded from %s", Jvm.class.getProtectionDomain().getCodeSource().getLocation())); + logger.info("Chronicle core loaded from {}", Jvm.class.getProtectionDomain().getCodeSource().getLocation()); if (RESOURCE_TRACING && !Jvm.getBoolean("disable.resource.warning")) logger.warn("Resource tracing is turned on. If you are performance testing or running in PROD you probably don't want this"); REPORT_UNOPTIMISED = Jvm.getBoolean("report.unoptimised"); @@ -152,6 +154,10 @@ public final class Jvm { ChronicleInit.postInit(); } + // Suppresses default constructor, ensuring non-instantiability. + private Jvm() { + } + private static MethodHandle getOnSpinWait() { MethodType voidType = MethodType.methodType(void.class); MethodHandles.Lookup lookup = MethodHandles.lookup(); @@ -170,10 +176,6 @@ private static MethodHandle getOnSpinWait() { return null; } - // Suppresses default constructor, ensuring non-instantiability. - private Jvm() { - } - public static void reportUnoptimised() { if (!REPORT_UNOPTIMISED) return; @@ -207,7 +209,6 @@ else if (new File("../" + SYSTEM_PROPERTIES).exists()) public static void init() { // force static initialisation - ChronicleInit.init(); } private static void loadSystemProperties(final String name, final boolean wasSet) { @@ -217,7 +218,7 @@ private static void loadSystemProperties(final String name, final boolean wasSet if (is0 == null) { File file = new File(name); if (file.exists()) - is0 = new FileInputStream(file); + is0 = Files.newInputStream(file.toPath()); } try (InputStream is = is0) { if (is == null) { @@ -282,6 +283,7 @@ public static boolean isJava9Plus() { /** * @return if the major Java version is 12 or higher */ + @Deprecated(/* to be removed in 2027, only used in tests */) public static boolean isJava12Plus() { return Bootstrap.isJava12Plus(); } @@ -396,6 +398,7 @@ public static boolean isDebug() { * @return if the JVM is running in flight recorder mode */ @SuppressWarnings("SameReturnValue") + @Deprecated(/* to be removed in 2027 */) public static boolean isFlightRecorder() { return IS_FLIGHT_RECORDER; } @@ -568,6 +571,7 @@ public static V getValue(@NotNull Object target, @NotNull final String field * @param lock to log * @return the lock.toString plus a stack trace. */ + @Deprecated(/* to be removed in 2027 */) public static String lockWithStack(@NotNull final ReentrantLock lock) { final Thread t = getValue(lock, "sync/exclusiveOwnerThread"); if (t == null) { @@ -602,6 +606,7 @@ public static long fieldOffset(final Class clazz, final String fieldName) { * @return the accumulated amount of memory in bytes used by direct ByteBuffers * or 0 if the value cannot be determined */ + @Deprecated(/* to be removed in 2027, only used in tests */) public static long usedDirectMemory() { return ReserveMemoryHolder.reservedMemory.get(); } @@ -611,6 +616,7 @@ public static long usedDirectMemory() { * * @return the accumulated amount of memory used in bytes by UnsafeMemory.allocate() */ + @Deprecated(/* to be removed in 2027, only used in tests */) public static long usedNativeMemory() { return UnsafeMemory.INSTANCE.nativeMemoryUsed(); } @@ -749,6 +755,7 @@ public static void setThreadLocalExceptionHandlers(@Nullable final ExceptionHand ((ThreadLocalisedExceptionHandler) DEBUG).threadLocalHandler(debug); } + @Deprecated(/* to be removed in 2027 */) public static void setThreadLocalExceptionHandlers(@Nullable final ExceptionHandler error, @Nullable final ExceptionHandler warn, @Nullable final ExceptionHandler debug, @@ -860,6 +867,7 @@ public static void safepoint() { } } + @Deprecated(/* to be removed in 2027, only used in tests */) public static boolean areOptionalSafepointsEnabled() { return SAFEPOINT_ENABLED; } @@ -873,6 +881,7 @@ public static boolean areOptionalSafepointsEnabled() { * @return if there is a class name that ends with the provided {@code endsWith} string * when examining the current stack trace of depth at most up to the provided {@code maxDepth} */ + @Deprecated(/* to be removed in 2027 */) public static boolean stackTraceEndsWith(final String endsWith, final int maxDepth) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); for (int i = maxDepth + 2; i < stackTrace.length; i++) @@ -908,6 +917,7 @@ public static boolean isMacArm() { * @see ClassMetrics */ @NotNull + @Deprecated(/* to be removed in 2027, only used in tests */) public static ClassMetrics classMetrics(final Class clazz) throws IllegalArgumentException { return CLASS_METRICS_MAP.computeIfAbsent(clazz, Jvm::getClassMetrics); } @@ -958,6 +968,7 @@ private static void validateClassMetrics(final Class c, * if the user's home director cannot be determined */ @NotNull + @Deprecated(/* to be removed in 2027 */) public static String userHome() { return System.getProperty("user.home", "."); } @@ -1220,6 +1231,7 @@ public void interrupt(Thread target) { ci.interrupt(); } + @SuppressWarnings({"EmptyMethod", "unused"}) public void postInterrupt() { // added in Java 23+ } @@ -1335,21 +1347,25 @@ public static boolean isProcessAlive(long pid) { @SuppressWarnings("deprecation") private static boolean isProcessAlive0(final long pid, final String command) { + Process process = null; try { - InputStreamReader isReader = new InputStreamReader( - getRuntime().exec(command).getInputStream()); - - final BufferedReader bReader = new BufferedReader(isReader); - String strLine; - while ((strLine = bReader.readLine()) != null) { - if (strLine.contains(" " + pid + " ") || strLine.startsWith(pid + " ")) { - return true; + process = getRuntime().exec(command); + try (BufferedReader bReader = new BufferedReader( + new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { + String strLine; + while ((strLine = bReader.readLine()) != null) { + if (strLine.contains(" " + pid + " ") || strLine.startsWith(pid + " ")) { + return true; + } } } - return false; } catch (Exception ex) { return true; + } finally { + if (process != null) { + process.destroy(); + } } } @@ -1523,6 +1539,17 @@ public static String getPackageName(Class clazz) { return PackageNameUtil.getPackageName(clazz); } + private static boolean isJUnitTest0() { + for (StackTraceElement[] stackTrace : Thread.getAllStackTraces().values()) { + for (StackTraceElement element : stackTrace) { + if (element.getClassName().contains(".junit")) { + return true; + } + } + } + return false; + } + public interface SignalHandler { /** * Handle a Signal @@ -1569,7 +1596,7 @@ private Safepoint() { public static void force() { // trick only works from Java 9+ //noinspection StatementWithEmptyBody - for (int i = 0; i < one; i++) ; + for (int i = 0; i < one; i++); } } @@ -1632,21 +1659,9 @@ public void handle(final Signal signal) { } } - private static boolean isJUnitTest0() { - for (StackTraceElement[] stackTrace : Thread.getAllStackTraces().values()) { - for (StackTraceElement element : stackTrace) { - if (element.getClassName().contains(".junit")) { - return true; - } - } - } - return false; - } - static class ReserveMemoryHolder { - private ReserveMemoryHolder() { - } static final Supplier reservedMemory; + static { Supplier reservedMemoryGetter; try { @@ -1666,6 +1681,9 @@ private ReserveMemoryHolder() { } reservedMemory = reservedMemoryGetter; } + + private ReserveMemoryHolder() { + } } static class MaxMemoryHolder { diff --git a/src/main/java/net/openhft/chronicle/core/LicenceCheck.java b/src/main/java/net/openhft/chronicle/core/LicenceCheck.java index f5c3cd9bc6..6c3276f94d 100644 --- a/src/main/java/net/openhft/chronicle/core/LicenceCheck.java +++ b/src/main/java/net/openhft/chronicle/core/LicenceCheck.java @@ -11,6 +11,7 @@ import java.time.temporal.ChronoUnit; import java.util.function.BiConsumer; +import static java.nio.charset.StandardCharsets.UTF_8; import static net.openhft.chronicle.core.Jvm.startup; import static net.openhft.chronicle.core.Jvm.warn; @@ -72,7 +73,7 @@ static void licenceExpiry(String product, Class caller, BiConsumer 0; ) { - sw.write(chars, 0, len); + try { + @NotNull StringWriter sw = new StringWriter(); + char @NotNull [] chars = new char[1024]; + try (@NotNull Reader r = new InputStreamReader(process.getInputStream(), UTF_8)) { + for (int len; (len = r.read(chars)) > 0; ) { + sw.write(chars, 0, len); + } } + return sw.toString(); + } finally { + process.destroy(); } - return sw.toString(); } /** @@ -641,6 +660,7 @@ private static String run(String... cmds) throws IOException { * * @return the user's current working directory */ + @Deprecated(/* to be removed in 2027, only used in tests */) public static String userDir() { return USER_DIR; } @@ -757,11 +777,12 @@ private static String getHostName0() { @SuppressWarnings({"deprecation", "RedundantSuppression"}) static String execHostname() throws IOException { + Process process = Runtime.getRuntime().exec("hostname"); // NOSONAR try (BufferedReader br = new BufferedReader( - new InputStreamReader( - Runtime.getRuntime().exec("hostname") // NOSONAR - .getInputStream()))) { + new InputStreamReader(process.getInputStream(), UTF_8))) { return br.readLine(); + } finally { + process.destroy(); } } diff --git a/src/main/java/net/openhft/chronicle/core/StackTrace.java b/src/main/java/net/openhft/chronicle/core/StackTrace.java index 364bed87f5..301877f314 100644 --- a/src/main/java/net/openhft/chronicle/core/StackTrace.java +++ b/src/main/java/net/openhft/chronicle/core/StackTrace.java @@ -171,7 +171,7 @@ public Less(String message) { } /** - * @param message the detail message for this stack trace. + * @param message the detail message for this stack trace. * @param stackTrace the stack trace elements for this stack trace. */ @SuppressWarnings("this-escape") diff --git a/src/main/java/net/openhft/chronicle/core/UnsafeMemory.java b/src/main/java/net/openhft/chronicle/core/UnsafeMemory.java index c55a2dffed..9d3481b29d 100644 --- a/src/main/java/net/openhft/chronicle/core/UnsafeMemory.java +++ b/src/main/java/net/openhft/chronicle/core/UnsafeMemory.java @@ -60,6 +60,7 @@ public class UnsafeMemory implements Memory { // during a large copy static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L; // NOSONAR + @Deprecated(/* to be removed in 2027, only used in tests */) public static final boolean IS_LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; // Create a local copy of type long (instead of int) to optimize performance @@ -148,6 +149,7 @@ private static long retryReadVolatileLong(long address, long value) { * @param offset the offset at which to insert the value. * @param value the integer value to insert. */ + @Deprecated(/* to be removed in 2027 */) public static void putInt(byte[] bytes, int offset, int value) { assert SKIP_ASSERTIONS || bytes != null; assert SKIP_ASSERTIONS || offset + Integer.BYTES <= bytes.length; @@ -159,6 +161,7 @@ public static void putInt(byte[] bytes, int offset, int value) { *

* Can be used to prevent reordering of instructions by the compiler or processor. */ + @Deprecated(/* to be removed in 2027 */) public static void unsafeStoreFence() { UNSAFE.storeFence(); } @@ -211,6 +214,7 @@ public static byte unsafeGetByte(long address) { * @param address memory address where the value is to be put. * @param value the long value to put. */ + @Deprecated(/* to be removed in 2027, only used in tests */) public static void unsafePutLong(long address, long value) { assert SKIP_ASSERTIONS || address != 0; UNSAFE.putLong(address, value); @@ -258,6 +262,7 @@ public static void unsafePutLong(byte[] bytes, int offset, long value) { * @param offset in the provided bytes where the value is written * @param value to put */ + @Deprecated(/* to be removed in 2027 */) public static void unsafePutInt(byte[] bytes, int offset, int value) { assert SKIP_ASSERTIONS || bytes != null; assert SKIP_ASSERTIONS || offset + Integer.BYTES <= bytes.length; @@ -271,6 +276,7 @@ public static void unsafePutInt(byte[] bytes, int offset, int value) { * @param offset in the provided bytes where the value is written * @param value to put */ + @Deprecated(/* to be removed in 2027 */) public static void unsafePutByte(byte[] bytes, int offset, byte value) { assert SKIP_ASSERTIONS || bytes != null; assert SKIP_ASSERTIONS || offset + Byte.BYTES <= bytes.length; diff --git a/src/main/java/net/openhft/chronicle/core/annotation/ForceInline.java b/src/main/java/net/openhft/chronicle/core/annotation/ForceInline.java index c64307463c..190f96f720 100644 --- a/src/main/java/net/openhft/chronicle/core/annotation/ForceInline.java +++ b/src/main/java/net/openhft/chronicle/core/annotation/ForceInline.java @@ -28,5 +28,6 @@ */ @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) @Retention(RetentionPolicy.RUNTIME) +@Deprecated(/* to be removed in 2027 */) public @interface ForceInline { } diff --git a/src/main/java/net/openhft/chronicle/core/annotation/HotMethod.java b/src/main/java/net/openhft/chronicle/core/annotation/HotMethod.java index 675446327d..bf3ddb3635 100644 --- a/src/main/java/net/openhft/chronicle/core/annotation/HotMethod.java +++ b/src/main/java/net/openhft/chronicle/core/annotation/HotMethod.java @@ -25,11 +25,10 @@ * *

This annotation has no runtime impact but aids Chronicle benchmarking * tools.

- * - * @see ForceInline */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) +@Deprecated(/* to be removed in 2027 */) public @interface HotMethod { @NotNull String value() default ""; } diff --git a/src/main/java/net/openhft/chronicle/core/cooler/CoolerTester.java b/src/main/java/net/openhft/chronicle/core/cooler/CoolerTester.java index 7cb4f9ec77..f5c396b872 100644 --- a/src/main/java/net/openhft/chronicle/core/cooler/CoolerTester.java +++ b/src/main/java/net/openhft/chronicle/core/cooler/CoolerTester.java @@ -20,6 +20,7 @@ */ public class CoolerTester { + private static final Object BLACK_HOLE_SENTINEL = new Object(); /** * Holds the results of the tests to avoid being optimised away and making the test meaningless. */ @@ -55,6 +56,7 @@ public class CoolerTester { * @param tested the task to be executed during the tests * @param disturbers the array of CpuCoolers to be tested */ + // TODO Move to Chronicle-Test-Framework in 2026 public CoolerTester(Callable tested, CpuCooler... disturbers) { Collections.addAll(this.disturbers, disturbers); this.testNames.add(""); @@ -102,6 +104,9 @@ private static void innerLoop2(Callable tested, Histogram histogram) throws E UNSAFE.fullFence(); long start0 = System.nanoTime(); blackhole = tested.call(); + if (blackhole == BLACK_HOLE_SENTINEL) { + throw new AssertionError("Blackhole sentinel reached"); + } // UNSAFE.fullFence(); long time0 = System.nanoTime() - start0; histogram.sample(time0); diff --git a/src/main/java/net/openhft/chronicle/core/cooler/CpuCoolers.java b/src/main/java/net/openhft/chronicle/core/cooler/CpuCoolers.java index 708d937c92..8cbabf5802 100644 --- a/src/main/java/net/openhft/chronicle/core/cooler/CpuCoolers.java +++ b/src/main/java/net/openhft/chronicle/core/cooler/CpuCoolers.java @@ -17,6 +17,7 @@ * different way. The exact way in which the CPU is disturbed is defined by the `disturb()` method * of each enum constant. */ +// TODO Move to Chronicle-Test-Framework in 2026 public enum CpuCoolers implements CpuCooler { /** * Causes the CPU to wait without doing work for a very short period of time. @@ -137,6 +138,9 @@ public void disturb() { } }, SERIALIZATION { + @SuppressWarnings("unused") + private volatile Object lastRead; + @Override public void disturb() { ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -144,7 +148,7 @@ public void disturb() { oos.writeObject(System.getProperties()); oos.close(); XMLDecoder ois = new XMLDecoder(new ByteArrayInputStream(out.toByteArray())); - blackhole = ois.readObject(); + lastRead = ois.readObject(); } }, MEMORY_COPY { @@ -167,7 +171,6 @@ public void disturb() { PAUSE10.disturb(); } }; - static volatile Object blackhole; public static void busyWait(double nanos) { long start = System.nanoTime(); diff --git a/src/main/java/net/openhft/chronicle/core/internal/ClassUtil.java b/src/main/java/net/openhft/chronicle/core/internal/ClassUtil.java index b95f79af60..b076dee952 100644 --- a/src/main/java/net/openhft/chronicle/core/internal/ClassUtil.java +++ b/src/main/java/net/openhft/chronicle/core/internal/ClassUtil.java @@ -14,27 +14,6 @@ import java.lang.reflect.*; public final class ClassUtil { - static class SetAccessibleHolder { - static final MethodHandle setAccessible0_Method = getSetAccessible0Method(); - - private static MethodHandle getSetAccessible0Method() { - if (!Bootstrap.isJava9Plus()) { - return null; - } - final MethodType signature = MethodType.methodType(boolean.class, boolean.class); - try { - // Access privateLookupIn() reflectively to support compilation with JDK 8 - Method privateLookupIn = MethodHandles.class.getDeclaredMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class); - MethodHandles.Lookup lookup = (MethodHandles.Lookup) privateLookupIn.invoke(null, AccessibleObject.class, MethodHandles.lookup()); - return lookup.findVirtual(AccessibleObject.class, "setAccessible0", signature); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | - IllegalArgumentException e) { - Logger logger = LoggerFactory.getLogger(ClassUtil.class); - logger.error("Chronicle products may require command line arguments to be provided for Java 11 and above. See https://chronicle.software/chronicle-support-java-17"); - return null; - } - } - } private ClassUtil() { } @@ -78,7 +57,7 @@ public static Field getField0(@NotNull final Class clazz, */ @SuppressWarnings("java:S3011") // Justification: centralised, audited accessibility control for Chronicle internals. public static void setAccessible(@NotNull final AccessibleObject accessibleObject) { - if (Bootstrap.isJava9Plus()) + if (Bootstrap.isJava9Plus()) { try { if (SetAccessibleHolder.setAccessible0_Method == null) return; @@ -87,8 +66,9 @@ public static void setAccessible(@NotNull final AccessibleObject accessibleObjec } catch (Throwable throwable) { throw new AssertionError(throwable); } - else + } else { accessibleObject.setAccessible(true); + } } public static Method getMethod0(@NotNull final Class clazz, @@ -117,4 +97,26 @@ public static Method getMethod0(@NotNull final Class clazz, return null; } } + + static class SetAccessibleHolder { + static final MethodHandle setAccessible0_Method = getSetAccessible0Method(); + + private static MethodHandle getSetAccessible0Method() { + if (!Bootstrap.isJava9Plus()) { + return null; + } + final MethodType signature = MethodType.methodType(boolean.class, boolean.class); + try { + // Access privateLookupIn() reflectively to support compilation with JDK 8 + Method privateLookupIn = MethodHandles.class.getDeclaredMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class); + MethodHandles.Lookup lookup = (MethodHandles.Lookup) privateLookupIn.invoke(null, AccessibleObject.class, MethodHandles.lookup()); + return lookup.findVirtual(AccessibleObject.class, "setAccessible0", signature); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | + IllegalArgumentException e) { + Logger logger = LoggerFactory.getLogger(ClassUtil.class); + logger.error("Chronicle products may require command line arguments to be provided for Java 11 and above. See https://chronicle.software/chronicle-support-java-17"); + return null; + } + } + } } diff --git a/src/main/java/net/openhft/chronicle/core/internal/CloseableUtils.java b/src/main/java/net/openhft/chronicle/core/internal/CloseableUtils.java index 403d866895..eae67286a7 100644 --- a/src/main/java/net/openhft/chronicle/core/internal/CloseableUtils.java +++ b/src/main/java/net/openhft/chronicle/core/internal/CloseableUtils.java @@ -89,14 +89,19 @@ public static void gcAndWaitForCloseablesToClose() { final BlockingQueue q = new LinkedBlockingQueue<>(); // Anonymous inner class overriding the finalize() method to track finalization. - new Object() { - @SuppressWarnings({"deprecation", "removal", "java:S1113"}) - @Override - protected void finalize() throws Throwable { - super.finalize(); - q.add("finalized"); + { + Object finalizerProbe = new Object() { + @SuppressWarnings({"deprecation", "removal", "java:S1113"}) + @Override + protected void finalize() throws Throwable { + super.finalize(); + q.add("finalized"); + } + }; + if (finalizerProbe == null) { + throw new AssertionError("Finalizer probe unexpectedly null"); } - }; + } try { // Zing JVM is not always satisfied with a single GC call: diff --git a/src/main/java/net/openhft/chronicle/core/internal/CpuClass.java b/src/main/java/net/openhft/chronicle/core/internal/CpuClass.java index 2d1487f87a..e61932f9b6 100644 --- a/src/main/java/net/openhft/chronicle/core/internal/CpuClass.java +++ b/src/main/java/net/openhft/chronicle/core/internal/CpuClass.java @@ -10,6 +10,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -38,7 +39,7 @@ public final class CpuClass { try { final Path path = Paths.get("/proc/cpuinfo"); if (Files.isReadable(path)) { - model = Files.lines(path) + model = Files.lines(path, StandardCharsets.UTF_8) .filter(line -> line.startsWith("model name")) .map(removingTag()) .findFirst().orElse(model); @@ -47,7 +48,8 @@ public final class CpuClass { Process process = new ProcessBuilder(cmd.split(" ")) .redirectErrorStream(true) .start(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { model = reader.lines() .map(String::trim) .filter(s -> !"Name".equals(s) && !s.isEmpty()) @@ -56,9 +58,9 @@ public final class CpuClass { try { int ret = process.waitFor(); if (ret != 0) - logger.warn(PROCESS + cmd + " returned " + ret); + logger.warn(PROCESS + "{} returned {}", cmd, ret); } catch (InterruptedException e) { - logger.warn(PROCESS + cmd + " waitFor threw ", e); + logger.warn(PROCESS + "{} waitFor threw ", cmd, e); // Restore the interrupt state... Thread.currentThread().interrupt(); } @@ -70,7 +72,8 @@ public final class CpuClass { Process process = new ProcessBuilder(cmd.split(" ")) .redirectErrorStream(true) .start(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { model = reader.lines() .map(String::trim) .filter(s -> s.startsWith("machdep.cpu.brand_string")) @@ -80,9 +83,9 @@ public final class CpuClass { try { int ret = process.waitFor(); if (ret != 0) - logger.warn(PROCESS + cmd + " returned " + ret); + logger.warn(PROCESS + "{} returned {}", cmd, ret); } catch (InterruptedException e) { - logger.warn(PROCESS + cmd + " waitFor threw ", e); + logger.warn(PROCESS + "{} waitFor threw ", cmd, e); // Restore the interrupt state... Thread.currentThread().interrupt(); } diff --git a/src/main/java/net/openhft/chronicle/core/internal/analytics/ReflectionUtil.java b/src/main/java/net/openhft/chronicle/core/internal/analytics/ReflectionUtil.java index 7de4f69a82..e221c09b8a 100644 --- a/src/main/java/net/openhft/chronicle/core/internal/analytics/ReflectionUtil.java +++ b/src/main/java/net/openhft/chronicle/core/internal/analytics/ReflectionUtil.java @@ -95,6 +95,7 @@ public static Object invokeOrThrow(@NotNull final Method method, * Create a proxy implementing {@code interf} that forwards calls to {@code delegate}. */ @NotNull + @Deprecated(/* to be removed in 2027, only used in tests */) public static T reflectiveProxy(@NotNull final Class interf, @NotNull final Object delegate) throws IllegalArgumentException { requireNonNull(interf); requireNonNull(delegate); @@ -110,6 +111,7 @@ public static T reflectiveProxy(@NotNull final Class interf, @NotNull fin * Create a forwarding proxy with the option to return the proxy itself for fluent APIs. */ @NotNull + @Deprecated(/* to be removed in 2027, only used in tests */) public static T reflectiveProxy(@NotNull final Class interf, @NotNull final Object delegate, final boolean returnProxy) throws IllegalArgumentException { diff --git a/src/main/java/net/openhft/chronicle/core/internal/util/DirectBufferUtil.java b/src/main/java/net/openhft/chronicle/core/internal/util/DirectBufferUtil.java index 0ac3c51e2d..672f24a24d 100644 --- a/src/main/java/net/openhft/chronicle/core/internal/util/DirectBufferUtil.java +++ b/src/main/java/net/openhft/chronicle/core/internal/util/DirectBufferUtil.java @@ -36,6 +36,7 @@ public static Class directBufferClass() { * @param buffer to clean * @throws NullPointerException if the provided {@code buffer } is {@code null} */ + @Deprecated(/* to be removed in 2027, only used in tests */) public static void cleanIfInstanceOfDirectBuffer(final ByteBuffer buffer) { requireNonNull(buffer); if (buffer instanceof DirectBuffer) { @@ -52,8 +53,11 @@ public static void cleanIfInstanceOfDirectBuffer(final ByteBuffer buffer) { * @throws ClassCastException if the provided {@code buffer } is not an instance of sun.nio.ch.DirectBuffer */ public static long addressOrThrow(final ByteBuffer buffer) { + requireNonNull(buffer); + if (!(buffer instanceof DirectBuffer)) { + throw new ClassCastException("Buffer is not a DirectBuffer: " + buffer.getClass().getName()); + } try { - requireNonNull(buffer); return ((DirectBuffer) buffer).address(); } catch (IllegalAccessError e) { throw new ClassCastException(e.toString()); diff --git a/src/main/java/net/openhft/chronicle/core/internal/util/RangeUtil.java b/src/main/java/net/openhft/chronicle/core/internal/util/RangeUtil.java index 0a90bc2a42..c618e7e7df 100644 --- a/src/main/java/net/openhft/chronicle/core/internal/util/RangeUtil.java +++ b/src/main/java/net/openhft/chronicle/core/internal/util/RangeUtil.java @@ -8,12 +8,13 @@ *

* Shared by assertion and invariant helpers to keep error wording consistent. */ +@Deprecated(/* to be removed in 2027 */) public final class RangeUtil { private RangeUtil() {} public static final String IS_POSITIVE = " is positive."; - public static final String IS_NEGATIVE = " is negative."; + public static final String IS_NEGATIVE = " is negative."; public static final String IS_ZERO = " is zero."; public static final String IS_EQUAL_TO = " is equal to."; public static final String IS_NOT_POSITIVE = " is not positive."; diff --git a/src/main/java/net/openhft/chronicle/core/io/AbstractCloseable.java b/src/main/java/net/openhft/chronicle/core/io/AbstractCloseable.java index bf32ab4394..64377a868e 100644 --- a/src/main/java/net/openhft/chronicle/core/io/AbstractCloseable.java +++ b/src/main/java/net/openhft/chronicle/core/io/AbstractCloseable.java @@ -99,6 +99,7 @@ public static void disableCloseableTracing() { * * @throws AssertionError If the finalizer does not complete within the specified timeout. */ + @Deprecated(/* to be removed in 2027 */) public static void gcAndWaitForCloseablesToClose() { CloseableUtils.gcAndWaitForCloseablesToClose(); } @@ -421,7 +422,7 @@ public void unmonitor() { * The Finalizer inner class is used to ensure that resources are properly closed * when the garbage collector decides to reclaim the memory for the enclosing AbstractCloseable instance. */ - @SuppressWarnings("RedundantSuppression") + @SuppressWarnings({"RedundantSuppression", "unused"}) class Finalizer { /** * Called by the garbage collector when the enclosing AbstractCloseable instance is diff --git a/src/main/java/net/openhft/chronicle/core/io/AbstractCloseableReferenceCounted.java b/src/main/java/net/openhft/chronicle/core/io/AbstractCloseableReferenceCounted.java index b43679b07f..4fc7a7cc16 100644 --- a/src/main/java/net/openhft/chronicle/core/io/AbstractCloseableReferenceCounted.java +++ b/src/main/java/net/openhft/chronicle/core/io/AbstractCloseableReferenceCounted.java @@ -174,6 +174,7 @@ private void throwClosing() throws ClosedIllegalStateException { * * @throws ClosedIllegalStateException If the resource has been released or closed. */ + @Deprecated(/* to be removed in 2027 */) protected void throwExceptionIfClosedInSetter() throws ClosedIllegalStateException, ThreadingIllegalStateException { throwExceptionIfClosed0(); throwExceptionIfReleased(); diff --git a/src/main/java/net/openhft/chronicle/core/io/AbstractReferenceCounted.java b/src/main/java/net/openhft/chronicle/core/io/AbstractReferenceCounted.java index 2734d5543f..0fc0f4a3b9 100644 --- a/src/main/java/net/openhft/chronicle/core/io/AbstractReferenceCounted.java +++ b/src/main/java/net/openhft/chronicle/core/io/AbstractReferenceCounted.java @@ -8,8 +8,6 @@ import net.openhft.chronicle.core.internal.ReferenceCountedUtils; import org.jetbrains.annotations.NotNull; -import java.util.Set; - import static net.openhft.chronicle.core.io.BackgroundResourceReleaser.BG_RELEASER; /** @@ -27,11 +25,11 @@ */ public abstract class AbstractReferenceCounted implements ReferenceCountedTracer, ReferenceOwner, SingleThreadedChecked, Monitorable { // Constants + @Deprecated(/* to be removed in 2026 */) protected static final long WARN_NS = (long) (Jvm.getDouble("reference.warn.secs", 0.003) * 1e9); protected static final int WARN_COUNT = Jvm.getInteger("reference.warn.count", Integer.MAX_VALUE); // Fields - static volatile Set referenceCountedSet; protected final transient MonitorReferenceCounted referenceCounted; private final int referenceId; private transient volatile Thread usedByThread; diff --git a/src/main/java/net/openhft/chronicle/core/io/ClosedState.java b/src/main/java/net/openhft/chronicle/core/io/ClosedState.java index 72306385c9..0800e1eb8e 100644 --- a/src/main/java/net/openhft/chronicle/core/io/ClosedState.java +++ b/src/main/java/net/openhft/chronicle/core/io/ClosedState.java @@ -7,6 +7,7 @@ * typically implemented with a lambda or method reference. */ @FunctionalInterface +@Deprecated(/* to be removed in 2027 */) public interface ClosedState { /** diff --git a/src/main/java/net/openhft/chronicle/core/io/IOTools.java b/src/main/java/net/openhft/chronicle/core/io/IOTools.java index caa81aa939..94a4c66f46 100644 --- a/src/main/java/net/openhft/chronicle/core/io/IOTools.java +++ b/src/main/java/net/openhft/chronicle/core/io/IOTools.java @@ -245,7 +245,7 @@ public static void deleteDirWithFilesOrWait(long timeoutMs, @NotNull File dir) { * @throws IOException If an I/O error occurs */ public static void writeFile(@NotNull String filename, byte @NotNull [] bytes) throws IOException { - try (@NotNull OutputStream out0 = new FileOutputStream(filename)) { + try (@NotNull OutputStream out0 = Files.newOutputStream(Paths.get(filename))) { OutputStream out = out0; if (filename.endsWith(".gz")) out = new GZIPOutputStream(out); @@ -381,6 +381,7 @@ public static String tempName(@NotNull String filename) { * @param dir The path of the directory to create * @throws IOException If an I/O error occurs */ + @Deprecated(/* to be removed in 2027 */) public static void createDirectories(Path dir) throws IOException { if (dir == null || dir.getNameCount() == 0 || Files.isDirectory(dir)) return; @@ -460,6 +461,7 @@ public static void unmonitor(final Object t) { * * @param bb The ByteBuffer to clean */ + // TODO ensure used in Bytes public static void clean(ByteBuffer bb) { CleanerServiceLocator.cleanerService().clean(bb); } diff --git a/src/main/java/net/openhft/chronicle/core/io/LimitedInputStream.java b/src/main/java/net/openhft/chronicle/core/io/LimitedInputStream.java index 0ce82068de..4b0d4feef7 100644 --- a/src/main/java/net/openhft/chronicle/core/io/LimitedInputStream.java +++ b/src/main/java/net/openhft/chronicle/core/io/LimitedInputStream.java @@ -23,6 +23,7 @@ *

The class is package-private on purpose; use it through public APIs such as * {@link Wget} instead of referencing it directly.

*/ +@Deprecated(/* to be removed in 2026, only used in tests */) final class LimitedInputStream extends FilterInputStream { /** Remaining budget in bytes. */ diff --git a/src/main/java/net/openhft/chronicle/core/io/TracingReferenceCounted.java b/src/main/java/net/openhft/chronicle/core/io/TracingReferenceCounted.java index 007381be28..8201e8776b 100644 --- a/src/main/java/net/openhft/chronicle/core/io/TracingReferenceCounted.java +++ b/src/main/java/net/openhft/chronicle/core/io/TracingReferenceCounted.java @@ -161,7 +161,7 @@ public void releaseLast(ReferenceOwner id) throws IllegalStateException { } catch (Exception e) { e0 = e; } - if (references.size() > 0) { + if (!references.isEmpty()) { IllegalStateException ise = new IllegalStateException(type.getName() + " still reserved " + referencesAsString(), createdHere); synchronized (references) { references.values().forEach(ise::addSuppressed); diff --git a/src/main/java/net/openhft/chronicle/core/io/Wget.java b/src/main/java/net/openhft/chronicle/core/io/Wget.java index 93ce5712b0..eeff328137 100644 --- a/src/main/java/net/openhft/chronicle/core/io/Wget.java +++ b/src/main/java/net/openhft/chronicle/core/io/Wget.java @@ -22,65 +22,23 @@ */ public final class Wget { - /** Opens a (potentially mocked) connection for the given URL. */ - @FunctionalInterface - public interface ConnectionProvider { InputStream open(URL url) throws IOException; } - - /** Decides which charset to use when decoding the response body. */ - @FunctionalInterface - public interface CharsetDetector { Charset detect(InputStream response, String contentTypeHeader); } - - public static final class Builder { - private static final ConnectionProvider DEFAULT_PROVIDER = URL::openStream; - - private ConnectionProvider connectionProvider = DEFAULT_PROVIDER; - private CharsetDetector charsetDetector = (in, ct) -> StandardCharsets.UTF_8; - private int connectTimeoutMs = 10_000; - private int readTimeoutMs = 10_000; - private long maxResponseBytes = 10L << 20; // 10 MiB - - public Builder connectionProvider(final ConnectionProvider p) { this.connectionProvider = Objects.requireNonNull(p); return this; } - public Builder charsetDetector (final CharsetDetector d) { this.charsetDetector = Objects.requireNonNull(d); return this; } - public Builder connectTimeoutMs (final int v) { this.connectTimeoutMs = v; return this; } - public Builder readTimeoutMs (final int v) { this.readTimeoutMs = v; return this; } - public Builder maxResponseBytes (final long v) { if (v < 0) throw new IllegalArgumentException("maxResponseBytes must be >= 0"); this.maxResponseBytes = v; return this; } - - /** Creates a {@link Wget} with defaults or caller-supplied overrides. */ - public Wget build() { - ConnectionProvider cp = this.connectionProvider; - if (cp == DEFAULT_PROVIDER) { // wrap default provider to apply time-outs - final int ct = connectTimeoutMs; - final int rt = readTimeoutMs; - cp = url -> { - URLConnection conn = url.openConnection(); - conn.setConnectTimeout(ct); - conn.setReadTimeout(rt); - if (conn instanceof HttpURLConnection) - ((HttpURLConnection) conn).setInstanceFollowRedirects(false); - return conn.getInputStream(); - }; - } - return new Wget(cp, charsetDetector, maxResponseBytes); - } - } - + private static final int MAX_URL_LENGTH = 2_048; private final ConnectionProvider connectionProvider; - private final CharsetDetector charsetDetector; - private final long maxResponseBytes; + private final CharsetDetector charsetDetector; + private final long maxResponseBytes; private Wget(final ConnectionProvider cp, final CharsetDetector cd, final long maxBytes) { this.connectionProvider = cp; - this.charsetDetector = cd; - this.maxResponseBytes = maxBytes; + this.charsetDetector = cd; + this.maxResponseBytes = maxBytes; } - private static final int MAX_URL_LENGTH = 2_048; - /** * Shortcut that uses the default configuration. */ + @Deprecated(/* to be removed in 2027, only used in tests */) public static void url(final String url, final StringBuilder sb) throws IOException { if (url.length() > MAX_URL_LENGTH) throw new IllegalArgumentException("URL too long (" + url.length() + ")"); @@ -95,15 +53,94 @@ public void fetch(final String url, final Appendable out) throws IOException { if (!"http".equals(scheme) && !"https".equals(scheme)) throw new MalformedURLException("Only http/https allowed, not " + scheme); - try (InputStream raw = connectionProvider.open(u); + try (InputStream raw = connectionProvider.open(u); InputStream limited = new LimitedInputStream(raw, maxResponseBytes)) { Charset cs = charsetDetector.detect(raw, null); if (cs == null) cs = StandardCharsets.UTF_8; - Reader reader = new BufferedReader(new InputStreamReader(limited, cs)); - for (int ch; (ch = reader.read()) != -1; ) - out.append((char) ch); + try (Reader reader = new BufferedReader(new InputStreamReader(limited, cs))) { + for (int ch; (ch = reader.read()) != -1; ) + out.append((char) ch); + } + } + } + + /** + * Opens a (potentially mocked) connection for the given URL. + */ + @FunctionalInterface + public interface ConnectionProvider { + InputStream open(URL url) throws IOException; + } + + /** + * Decides which charset to use when decoding the response body. + */ + @FunctionalInterface + public interface CharsetDetector { + Charset detect(InputStream response, String contentTypeHeader); + } + + public static final class Builder { + private static final ConnectionProvider DEFAULT_PROVIDER = URL::openStream; + + private ConnectionProvider connectionProvider = DEFAULT_PROVIDER; + private CharsetDetector charsetDetector = (in, ct) -> StandardCharsets.UTF_8; + private int connectTimeoutMs = 10_000; + private int readTimeoutMs = 10_000; + private long maxResponseBytes = 10L << 20; // 10 MiB + + @Deprecated(/* to be removed in 2027, only used in tests */) + public Builder connectionProvider(final ConnectionProvider provider) { + this.connectionProvider = Objects.requireNonNull(provider); + return this; + } + + @Deprecated(/* to be removed in 2027, only used in tests */) + public Builder charsetDetector(final CharsetDetector detector) { + this.charsetDetector = Objects.requireNonNull(detector); + return this; + } + + @Deprecated(/* to be removed in 2027, only used in tests */) + public Builder connectTimeoutMs(final int timeoutMs) { + this.connectTimeoutMs = timeoutMs; + return this; + } + + @Deprecated(/* to be removed in 2027, only used in tests */) + public Builder readTimeoutMs(final int timeoutMs) { + this.readTimeoutMs = timeoutMs; + return this; + } + + @Deprecated(/* to be removed in 2027, only used in tests */) + public Builder maxResponseBytes(final long maxResponseBytes) { + if (maxResponseBytes < 0) + throw new IllegalArgumentException("maxResponseBytes must be >= 0"); + this.maxResponseBytes = maxResponseBytes; + return this; + } + + /** + * Creates a {@link Wget} with defaults or caller-supplied overrides. + */ + public Wget build() { + ConnectionProvider cp = this.connectionProvider; + if (cp == DEFAULT_PROVIDER) { // wrap default provider to apply time-outs + final int ct = connectTimeoutMs; + final int rt = readTimeoutMs; + cp = url -> { + URLConnection conn = url.openConnection(); + conn.setConnectTimeout(ct); + conn.setReadTimeout(rt); + if (conn instanceof HttpURLConnection) + ((HttpURLConnection) conn).setInstanceFollowRedirects(false); + return conn.getInputStream(); + }; + } + return new Wget(cp, charsetDetector, maxResponseBytes); } } } diff --git a/src/main/java/net/openhft/chronicle/core/onoes/ChainedExceptionHandler.java b/src/main/java/net/openhft/chronicle/core/onoes/ChainedExceptionHandler.java index 8527233845..05cd90c0ae 100644 --- a/src/main/java/net/openhft/chronicle/core/onoes/ChainedExceptionHandler.java +++ b/src/main/java/net/openhft/chronicle/core/onoes/ChainedExceptionHandler.java @@ -66,7 +66,7 @@ public void on(@NotNull Class clazz, @Nullable String message, @Nullable Thro try { eh.on(clazz, message, thrown); } catch (Throwable t) { - LoggerFactory.getLogger(eh.getClass()).error("Unable to call with message " + message, t); + LoggerFactory.getLogger(eh.getClass()).error("Unable to call with message {}", message, t); } } } @@ -85,7 +85,7 @@ public void on(@NotNull Logger logger, @Nullable String message, Throwable throw try { eh.on(logger, message, thrown); } catch (Throwable t) { - LoggerFactory.getLogger(eh.getClass()).error("Unable to call with message " + message, t); + LoggerFactory.getLogger(eh.getClass()).error("Unable to call with message {}", message, t); } } diff --git a/src/main/java/net/openhft/chronicle/core/onoes/ExceptionKey.java b/src/main/java/net/openhft/chronicle/core/onoes/ExceptionKey.java index a44e356a2c..e2bd3ab0d4 100644 --- a/src/main/java/net/openhft/chronicle/core/onoes/ExceptionKey.java +++ b/src/main/java/net/openhft/chronicle/core/onoes/ExceptionKey.java @@ -80,7 +80,7 @@ public Class clazz() { * @return The message. */ public String message() { - return message; + return message == null || message.isEmpty() ? throwable.toString() : message; } /** diff --git a/src/main/java/net/openhft/chronicle/core/onoes/ThreadLocalisedExceptionHandler.java b/src/main/java/net/openhft/chronicle/core/onoes/ThreadLocalisedExceptionHandler.java index 169cb18169..ad2981c2f8 100644 --- a/src/main/java/net/openhft/chronicle/core/onoes/ThreadLocalisedExceptionHandler.java +++ b/src/main/java/net/openhft/chronicle/core/onoes/ThreadLocalisedExceptionHandler.java @@ -119,6 +119,7 @@ public ThreadLocalisedExceptionHandler defaultHandler(ExceptionHandler defaultHa * * @return the thread-local handler or {@code null} */ + @Deprecated(/* to be removed in 2027 */) public ExceptionHandler threadLocalHandler() { return handlerTL.get(); } diff --git a/src/main/java/net/openhft/chronicle/core/pom/PomProperties.java b/src/main/java/net/openhft/chronicle/core/pom/PomProperties.java index 908a8b4adb..b30fab978a 100644 --- a/src/main/java/net/openhft/chronicle/core/pom/PomProperties.java +++ b/src/main/java/net/openhft/chronicle/core/pom/PomProperties.java @@ -42,6 +42,7 @@ private PomProperties() { * @return a new instance of Properties for the provided parameters. */ @NotNull + @Deprecated(/* to be removed in 2027, only used in tests */) public static Properties create(@NotNull final String groupId, @NotNull final String artifactId) { return InternalPomProperties.create(groupId, artifactId); } diff --git a/src/main/java/net/openhft/chronicle/core/pool/ClassLookup.java b/src/main/java/net/openhft/chronicle/core/pool/ClassLookup.java index 56a127a7b2..6fdbd89bdc 100644 --- a/src/main/java/net/openhft/chronicle/core/pool/ClassLookup.java +++ b/src/main/java/net/openhft/chronicle/core/pool/ClassLookup.java @@ -109,6 +109,7 @@ default ClassLookup wrap(@NotNull ClassLoader classLoader) { * @throws NullPointerException if the provided {@code name} is {@code null}. * @see #addAlias(Class, String) for how aliases are added to the pool. */ + @Deprecated(/* to be removed in 2027, only used in tests */) default CharSequence applyAlias(CharSequence name) { try { return nameFor(forName(name)); diff --git a/src/main/java/net/openhft/chronicle/core/pool/DynamicEnumClass.java b/src/main/java/net/openhft/chronicle/core/pool/DynamicEnumClass.java index 7b9ee944a9..b345de44fd 100644 --- a/src/main/java/net/openhft/chronicle/core/pool/DynamicEnumClass.java +++ b/src/main/java/net/openhft/chronicle/core/pool/DynamicEnumClass.java @@ -32,13 +32,13 @@ * @param the type of enum instances this class will manage. It must extend {@link CoreDynamicEnum}. * Example usage: *
{@code
- *            EnumCache c =
- *                EnumCache.of(
- *                    YesNo.class);
- *            YesNo maybe =
- *                c.valueOf("Maybe");
- *            }
- *            
+ * EnumCache c = + * EnumCache.of( + * YesNo.class); + * YesNo maybe = + * c.valueOf("Maybe"); + * } + * */ public class DynamicEnumClass> extends EnumCache { @@ -48,9 +48,9 @@ public class DynamicEnumClass> extends EnumCache private final List eList = new ArrayList<>(); // Fields to reflectively set properties on new instances. private final Field nameField; + private final Field ordinalField; // An array of enum values private E[] values = null; - private final Field ordinalField; // The function used to create new enum instances private final Function create = this::create; diff --git a/src/main/java/net/openhft/chronicle/core/pool/EnumCache.java b/src/main/java/net/openhft/chronicle/core/pool/EnumCache.java index 93e18b8a14..4e6088cac3 100644 --- a/src/main/java/net/openhft/chronicle/core/pool/EnumCache.java +++ b/src/main/java/net/openhft/chronicle/core/pool/EnumCache.java @@ -96,6 +96,7 @@ public Class type() { * @param index the ordinal index of the enum instance to retrieve. * @return the enum instance at the given index. */ + @Deprecated(/* to be removed in 2027 */) public abstract E forIndex(int index); /** diff --git a/src/main/java/net/openhft/chronicle/core/pool/ParsingCache.java b/src/main/java/net/openhft/chronicle/core/pool/ParsingCache.java index 17581a7600..73a23aa65a 100644 --- a/src/main/java/net/openhft/chronicle/core/pool/ParsingCache.java +++ b/src/main/java/net/openhft/chronicle/core/pool/ParsingCache.java @@ -33,6 +33,7 @@ * * @param The type of object the cache stores. Typically, these are objects created from strings. */ +@Deprecated(/* to be removed in 2027, only used in tests */) public class ParsingCache { protected final ParsedData[] interner; protected final int mask; diff --git a/src/main/java/net/openhft/chronicle/core/pool/StringBuilderPool.java b/src/main/java/net/openhft/chronicle/core/pool/StringBuilderPool.java index c5e7aff816..6943118bda 100644 --- a/src/main/java/net/openhft/chronicle/core/pool/StringBuilderPool.java +++ b/src/main/java/net/openhft/chronicle/core/pool/StringBuilderPool.java @@ -7,8 +7,6 @@ import net.openhft.chronicle.core.scoped.ScopedResourcePool; import net.openhft.chronicle.core.scoped.ScopedThreadLocal; -import static java.lang.ThreadLocal.withInitial; - /** * This class provides a pool of StringBuilder objects for efficient string building operations. * Each thread gets its own StringBuilder instance via a ThreadLocal, @@ -18,13 +16,6 @@ public final class StringBuilderPool { private static final int DEFAULT_STRING_BUILDER_POOL_SIZE_PER_THREAD = Jvm.getInteger("chronicle.stringBuilderPool.instancesPerThread", 4); - /** - * Thread-local variable that holds a StringBuilder for each thread. - * The initial capacity for each StringBuilder is 128. - */ - private final ThreadLocal sbtl = withInitial( - () -> new StringBuilder(128)); - /** * Returns a scoped-thread-local pool of StringBuilders. * diff --git a/src/main/java/net/openhft/chronicle/core/pool/StringInterner.java b/src/main/java/net/openhft/chronicle/core/pool/StringInterner.java index 57159c6bbe..b82bde321d 100644 --- a/src/main/java/net/openhft/chronicle/core/pool/StringInterner.java +++ b/src/main/java/net/openhft/chronicle/core/pool/StringInterner.java @@ -63,6 +63,7 @@ public StringInterner(int capacity) throws IllegalArgumentException { /** * @return the size of interner[] */ + @Deprecated(/* to be removed in 2027, only used in tests */) public int capacity() { return interner.length; } @@ -103,6 +104,7 @@ public String intern(@Nullable CharSequence cs) { * @param onChanged callback invoked when a new value is stored * @return the slot index or {@code -1} if the text is too long */ + @Deprecated(/* to be removed in 2027, only used in tests */) public int index(@Nullable CharSequence cs, @Nullable Changed onChanged) { if (cs == null) return -1; @@ -136,6 +138,7 @@ public int index(@Nullable CharSequence cs, @Nullable Changed onChanged) { * @return the interned string, or {@code null} if no value is stored at that index */ @Nullable + @Deprecated(/* to be removed in 2027, only used in tests */) public String get(int index) { return interner[index]; } diff --git a/src/main/java/net/openhft/chronicle/core/threads/CleaningThread.java b/src/main/java/net/openhft/chronicle/core/threads/CleaningThread.java index caeebbca2a..0956200dbe 100644 --- a/src/main/java/net/openhft/chronicle/core/threads/CleaningThread.java +++ b/src/main/java/net/openhft/chronicle/core/threads/CleaningThread.java @@ -30,10 +30,6 @@ public class CleaningThread extends Thread { private static final Field TABLE; private static final Field VALUE; - private final boolean inEventLoop; - @SuppressWarnings("unused") - private final StackTrace createdHere = isResourceTracing() ? new StackTrace("Created here") : null; - // Static block to initialize reflection fields. static { THREAD_LOCALS = Jvm.getField(Thread.class, "threadLocals"); @@ -41,6 +37,9 @@ public class CleaningThread extends Thread { VALUE = Jvm.getField(TABLE.getType().getComponentType(), "value"); } + private final boolean inEventLoop; + private final StackTrace createdHere = isResourceTracing() ? new StackTrace("Created here") : null; + /** * Constructs a new CleaningThread with the specified target Runnable. * @@ -203,4 +202,11 @@ public void run() { public boolean inEventLoop() { return inEventLoop; } + + /** + * @return where the Thread was created, if available + */ + public StackTrace createdHere() { + return createdHere; + } } diff --git a/src/main/java/net/openhft/chronicle/core/threads/InterruptedRuntimeException.java b/src/main/java/net/openhft/chronicle/core/threads/InterruptedRuntimeException.java index 5d6e8b3584..ef54b61d71 100644 --- a/src/main/java/net/openhft/chronicle/core/threads/InterruptedRuntimeException.java +++ b/src/main/java/net/openhft/chronicle/core/threads/InterruptedRuntimeException.java @@ -32,6 +32,7 @@ public class InterruptedRuntimeException extends IllegalStateException { /** * Constructs an {@code InterruptedRuntimeException} with no detail message or cause. */ + @Deprecated(/* to be removed in 2027, only used in tests */) public InterruptedRuntimeException() { } diff --git a/src/main/java/net/openhft/chronicle/core/threads/ThreadDump.java b/src/main/java/net/openhft/chronicle/core/threads/ThreadDump.java index 90f437b587..223fc5555b 100644 --- a/src/main/java/net/openhft/chronicle/core/threads/ThreadDump.java +++ b/src/main/java/net/openhft/chronicle/core/threads/ThreadDump.java @@ -132,7 +132,7 @@ public void assertNoNewThreads(int delay, @NotNull TimeUnit delayUnit) { } throw assertionError; } - Jvm.pause(delayMillis + (1L << (i/2))); + Jvm.pause(delayMillis + (1L << (i / 2))); } } @@ -153,9 +153,7 @@ private boolean isExtra(String name) { return false; if (startsWith(name, "RMI ", "VM JFR ", "JFR ", "JMX ", "ForkJoinPool.commonPool-worker-", "JVMCI")) return false; - if (name.startsWith("HttpClient-") && name.endsWith("-SelectorManager")) - return false; - return true; + return !name.startsWith("HttpClient-") || !name.endsWith("-SelectorManager"); } private void addThreadErrorDetails(AssertionError assertionError, Thread thread) { diff --git a/src/main/java/net/openhft/chronicle/core/threads/ThreadLocalHelper.java b/src/main/java/net/openhft/chronicle/core/threads/ThreadLocalHelper.java index 21ca8b023d..2dc1fce0fe 100644 --- a/src/main/java/net/openhft/chronicle/core/threads/ThreadLocalHelper.java +++ b/src/main/java/net/openhft/chronicle/core/threads/ThreadLocalHelper.java @@ -63,6 +63,7 @@ public static T getTL(@NotNull ThreadLocal> threadLocal, @N * @return Existing or newly created value */ @NotNull + @Deprecated(/* to be removed in 2027, only used in tests */) public static T getSTL(@NotNull ThreadLocal threadLocal, @NotNull Supplier supplier) { @Nullable T ret = threadLocal.get(); if (ret == null) { diff --git a/src/main/java/net/openhft/chronicle/core/time/SetTimeProvider.java b/src/main/java/net/openhft/chronicle/core/time/SetTimeProvider.java index a69bf8cf59..9aee0f6764 100644 --- a/src/main/java/net/openhft/chronicle/core/time/SetTimeProvider.java +++ b/src/main/java/net/openhft/chronicle/core/time/SetTimeProvider.java @@ -60,6 +60,7 @@ public SetTimeProvider(Instant instant) { * * @return a new provider initialised to the current time */ + @Deprecated(/* to be removed in 2027 */) public SetTimeProvider now() { return new SetTimeProvider(SystemTimeProvider.CLOCK.currentTimeNanos()); } @@ -125,6 +126,7 @@ public long currentTimeMillis() { * @param micros new time in microseconds, not less than the current value * @throws IllegalArgumentException if the time would go backwards */ + @Deprecated(/* to be removed in 2027, only used in tests */) public void currentTimeMicros(long micros) throws IllegalArgumentException { currentTimeNanos(TimeUnit.MICROSECONDS.toNanos(micros)); } @@ -167,6 +169,7 @@ public long currentTimeNanos() { * @param unit target unit, not {@code null} * @return the current time in that unit */ + @Deprecated(/* to be removed in 2027, only used in tests */) public long currentTime(TimeUnit unit) { return unit.convert(currentTimeNanos(), TimeUnit.NANOSECONDS); } diff --git a/src/main/java/net/openhft/chronicle/core/util/ClassMetrics.java b/src/main/java/net/openhft/chronicle/core/util/ClassMetrics.java index 368e0a876c..49ac996b27 100644 --- a/src/main/java/net/openhft/chronicle/core/util/ClassMetrics.java +++ b/src/main/java/net/openhft/chronicle/core/util/ClassMetrics.java @@ -9,6 +9,7 @@ * ClassMetrics is a utility class that holds offset and length metrics of a class. * It provides methods to access these metrics and overrides equals, hashCode, and toString methods. */ +@Deprecated(/* to be removed in 2027, only used in tests */) public class ClassMetrics { private final int offset; private final int length; diff --git a/src/main/java/net/openhft/chronicle/core/util/CompilerUtils.java b/src/main/java/net/openhft/chronicle/core/util/CompilerUtils.java index b0e0840f91..094e54fb0c 100644 --- a/src/main/java/net/openhft/chronicle/core/util/CompilerUtils.java +++ b/src/main/java/net/openhft/chronicle/core/util/CompilerUtils.java @@ -19,6 +19,7 @@ * Note that this class is intended for use cases where there is a need to load classes into the JVM * programmatically during runtime. */ +@Deprecated(/* to be removed in 2027, only used in tests */) public final class CompilerUtils { private static final Method DEFINE_CLASS_METHOD; diff --git a/src/main/java/net/openhft/chronicle/core/util/GenericReflection.java b/src/main/java/net/openhft/chronicle/core/util/GenericReflection.java index eb5229d4a1..20e2097207 100644 --- a/src/main/java/net/openhft/chronicle/core/util/GenericReflection.java +++ b/src/main/java/net/openhft/chronicle/core/util/GenericReflection.java @@ -142,6 +142,8 @@ public static Class erase(Type type) { } if (type instanceof ParameterizedType) return erase(((ParameterizedType) type).getRawType()); - return (Class) type; + if (type instanceof Class) + return (Class) type; + throw new UnsupportedOperationException("Unsupported type: " + type); } } diff --git a/src/main/java/net/openhft/chronicle/core/util/Histogram.java b/src/main/java/net/openhft/chronicle/core/util/Histogram.java index f08670e059..4d7db989e8 100644 --- a/src/main/java/net/openhft/chronicle/core/util/Histogram.java +++ b/src/main/java/net/openhft/chronicle/core/util/Histogram.java @@ -223,6 +223,7 @@ public double min() { * * @return the median value */ + @Deprecated(/* to be removed in 2027 */) public double typical() { return percentile(0.5); } diff --git a/src/main/java/net/openhft/chronicle/core/util/Ints.java b/src/main/java/net/openhft/chronicle/core/util/Ints.java index 840b190d5b..bf61fb6971 100644 --- a/src/main/java/net/openhft/chronicle/core/util/Ints.java +++ b/src/main/java/net/openhft/chronicle/core/util/Ints.java @@ -68,6 +68,7 @@ public static int requireNonNegative(final int value) { * @throws AssertionError if the check fails and assertions are enabled both via the {@code -ea} JVM command * line option and by setting {@link AssertUtil#SKIP_ASSERTIONS} to {@code false}. */ + @Deprecated(/* to be removed in 2027, only used in tests */) public static boolean assertIfEnabled(final IntPredicate requirement, final int value) { assert AssertUtil.SKIP_ASSERTIONS || requirement.test(value) @@ -97,6 +98,7 @@ public static String failDescription(final IntPredicate requirement, * * @return a predicate that can test if a value is non-negative (i.e. value >= 0) */ + @Deprecated(/* to be removed in 2027, only used in tests */) public static IntPredicate nonNegative() { return IntCondition.NON_NEGATIVE; } diff --git a/src/main/java/net/openhft/chronicle/core/util/ObjectUtils.java b/src/main/java/net/openhft/chronicle/core/util/ObjectUtils.java index 80737426ab..39cf89cd11 100644 --- a/src/main/java/net/openhft/chronicle/core/util/ObjectUtils.java +++ b/src/main/java/net/openhft/chronicle/core/util/ObjectUtils.java @@ -50,10 +50,6 @@ @SuppressWarnings("unchecked") public final class ObjectUtils { - // Suppresses default constructor, ensuring non-instantiability. - private ObjectUtils() { - } - static final Map, Class> PRIM_MAP = ofUnmodifiable( entry(boolean.class, Boolean.class), entry(byte.class, Byte.class), @@ -75,9 +71,25 @@ private ObjectUtils() { entry(float.class, 0.0f), entry(double.class, 0.0d) ); - + static final ClassLocal> PARSER_CL = ClassLocal.withInitial(new ConversionFunction()); + static final ClassLocal>> CASE_IGNORE_LOOKUP = ClassLocal.withInitial(ObjectUtils::caseIgnoreLookup); + static final ClassValue READ_RESOLVE = ClassLocal.withInitial(c -> { + try { + Method m = c.getDeclaredMethod("readResolve"); + ClassUtil.setAccessible(m); + return m; + } catch (NoSuchMethodException expected) { + return null; + } catch (Exception e) { + throw new AssertionError(e); + } + }); private static final Map, Function> conversionMap = new HashMap<>(); private static final Map, UnaryOperator> numberConversionMap = new HashMap<>(); + private static final Map, Immutability> IMMUTABILITY_MAP = new ConcurrentHashMap<>(); + // these should only ever be changed on startup. + private static volatile ClassLocal> interfaceToDefaultClass = ClassLocal.withInitial(ObjectUtils::lookForImplEnum); + private static volatile ClassLocal> supplierClassLocal = ClassLocal.withInitial(ObjectUtils::supplierForClass); static { conversionMap.put(Double.class, Double::valueOf); @@ -98,25 +110,9 @@ private ObjectUtils() { numberConversionMap.put(BigDecimal.class, n -> n instanceof Long ? BigDecimal.valueOf(n.longValue()) : BigDecimal.valueOf(n.doubleValue())); numberConversionMap.put(BigInteger.class, o -> new BigInteger(o.toString())); } - - static final ClassLocal> PARSER_CL = ClassLocal.withInitial(new ConversionFunction()); - static final ClassLocal>> CASE_IGNORE_LOOKUP = ClassLocal.withInitial(ObjectUtils::caseIgnoreLookup); - static final ClassValue READ_RESOLVE = ClassLocal.withInitial(c -> { - try { - Method m = c.getDeclaredMethod("readResolve"); - ClassUtil.setAccessible(m); - return m; - } catch (NoSuchMethodException expected) { - return null; - } catch (Exception e) { - throw new AssertionError(e); - } - }); - private static final Map, Immutability> IMMUTABILITY_MAP = new ConcurrentHashMap<>(); - - // these should only ever be changed on startup. - private static volatile ClassLocal> interfaceToDefaultClass = ClassLocal.withInitial(ObjectUtils::lookForImplEnum); - private static volatile ClassLocal> supplierClassLocal = ClassLocal.withInitial(ObjectUtils::supplierForClass); + // Suppresses default constructor, ensuring non-instantiability. + private ObjectUtils() { + } /** * Rethrows the given Throwable as a RuntimeException. @@ -438,14 +434,15 @@ static E convertChar(@NotNull Object o) { private static E convertCharSequence(Class eClass, CharSequence o) { @Nullable CharSequence cs = o; if (Character.class.equals(eClass)) { - if (cs.length() > 0) + if (cs.length() > 0) { try { return (E) (Character) cs.charAt(0); } catch (IndexOutOfBoundsException e) { throw new AssertionError(e); } - else + } else { return null; + } } @NotNull String s = cs.toString(); if (eClass == String.class) @@ -744,7 +741,7 @@ public static Boolean toBoolean(@Nullable String s) { public static Class[] getAllInterfaces(Object o) { Set> results = new HashSet<>(); getAllInterfaces(o, results::add); - return results.toArray(new Class[results.size()]); + return results.toArray(new Class[0]); } /** @@ -853,6 +850,20 @@ public static Class implementationToUse(Class tClass) { return tClass; } + /** + * Standard mechanism to determine objects as not null. Same method contract as {@link Objects#requireNonNull(Object)} + * + * @param o reference to check for nullity + * @throws NullPointerException If o is {@code null } + */ + @SuppressWarnings("UnusedReturnValue") + public static T requireNonNull(T o) { + // see https://stackoverflow.com/questions/43115645/in-java-lambdas-why-is-getclass-called-on-a-captured-variable + // Maybe calling Objects.requireNonNull is just as optimisable/intrinisfiable but I didn't do the research + o.getClass(); + return o; + } + public enum Immutability { YES, NO, MAYBE } @@ -909,22 +920,8 @@ static class ThrowsCCE implements ThrowingFunction { } @Override - public @NotNull Object apply(String in) throws Exception { + public @NotNull Object apply(String in) { throw cce; } } - - /** - * Standard mechanism to determine objects as not null. Same method contract as {@link Objects#requireNonNull(Object)} - * - * @param o reference to check for nullity - * @throws NullPointerException If o is {@code null } - */ - @SuppressWarnings("UnusedReturnValue") - public static T requireNonNull(T o) { - // see https://stackoverflow.com/questions/43115645/in-java-lambdas-why-is-getclass-called-on-a-captured-variable - // Maybe calling Objects.requireNonNull is just as optimisable/intrinisfiable but I didn't do the research - o.getClass(); - return o; - } } diff --git a/src/main/java/net/openhft/chronicle/core/util/RecordingHistogram.java b/src/main/java/net/openhft/chronicle/core/util/RecordingHistogram.java index b8fb41434f..b3513b1205 100644 --- a/src/main/java/net/openhft/chronicle/core/util/RecordingHistogram.java +++ b/src/main/java/net/openhft/chronicle/core/util/RecordingHistogram.java @@ -22,7 +22,6 @@ public class RecordingHistogram extends Histogram { private final Top10 top10 = new Top10(); private long start; - private int sampleCount; /** * Constructs a new RecordingHistogram with specified parameters. @@ -83,7 +82,6 @@ protected long currentTimeNanos() { @Override public void reset() { super.reset(); - sampleCount = 0; top10.reset(); } diff --git a/src/main/java/net/openhft/chronicle/core/util/SerializableUpdaterWithArg.java b/src/main/java/net/openhft/chronicle/core/util/SerializableUpdaterWithArg.java index b87bb61b5f..3bb443f7a8 100644 --- a/src/main/java/net/openhft/chronicle/core/util/SerializableUpdaterWithArg.java +++ b/src/main/java/net/openhft/chronicle/core/util/SerializableUpdaterWithArg.java @@ -9,6 +9,7 @@ * This interface expect to take an object for alteration and it must be serializable. */ @FunctionalInterface +@Deprecated(/* to be removed in 2027 */) public interface SerializableUpdaterWithArg extends Serializable { void accept(U updated, A argument); } diff --git a/src/main/java/net/openhft/chronicle/core/util/StringUtils.java b/src/main/java/net/openhft/chronicle/core/util/StringUtils.java index 32a185781b..6c5af5e0c0 100644 --- a/src/main/java/net/openhft/chronicle/core/util/StringUtils.java +++ b/src/main/java/net/openhft/chronicle/core/util/StringUtils.java @@ -14,9 +14,9 @@ import java.lang.reflect.Array; import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; import static java.lang.Character.toLowerCase; +import static java.nio.charset.StandardCharsets.ISO_8859_1; /** * A utility class that provides a collection of static methods for advanced string manipulation. @@ -35,10 +35,6 @@ */ public final class StringUtils { - // Suppresses default constructor, ensuring non-instantiability. - private StringUtils() { - } - private static final String VALUE_FIELD_NAME = "value"; private static final String COUNT_FIELD_NAME = "count"; private static final String CODER_FIELD_NAME = "coder"; @@ -92,6 +88,10 @@ private StringUtils() { } } + // Suppresses default constructor, ensuring non-instantiability. + private StringUtils() { + } + @NotNull private static UnsafeMemory getMemory() { return UnsafeMemory.INSTANCE; @@ -143,6 +143,7 @@ public static void setLength(@NotNull StringBuilder sb, int length) { * @param sb the {@link StringBuilder} to be modified. * @param cs the {@link CharSequence} whose content will be set in the {@link StringBuilder}. */ + @Deprecated(/* to be removed in 2027, only used in tests */) public static void set(@NotNull StringBuilder sb, CharSequence cs) { sb.setLength(0); sb.append(cs); @@ -244,7 +245,7 @@ private static boolean isEqualJava9(@NotNull StringBuilder s, @NotNull CharSeque /** * Compares two {@link CharSequence}s1 for equality ignoring case considerations. * - * @param s1 the first {@link CharSequence} to be compared. + * @param s1 the first {@link CharSequence} to be compared. * @param s2 the second {@link CharSequence} to be compared. * @return {@code true} if the {@link CharSequence}s1 are equal irrespective of case, {@code false} otherwise. */ @@ -317,7 +318,7 @@ public static char[] extractChars(@NotNull String s) { @Java9 public static byte[] extractBytes(@NotNull String s) { if (!HAS_ONE_BYTE_PER_CHAR) - return s.getBytes(StandardCharsets.ISO_8859_1); + return s.getBytes(ISO_8859_1); ensureJava9Plus(); return getMemory().getObject(s, S_VALUE_OFFSET); @@ -333,8 +334,7 @@ public static String newString(char @NotNull [] chars) { if (Bootstrap.isJava9Plus()) { return new String(chars); } - //noinspection RedundantStringConstructorCall - @NotNull String str = new String(); + @NotNull String str = new String(new char[0]); try { S_VALUE.set(str, chars); if (S_COUNT_OFFSET > -1) @@ -353,12 +353,12 @@ private static void ensureJava9Plus() { @Java9 @NotNull + @Deprecated(/* to be removed in 2027, only used in tests */) public static String newStringFromBytes(byte @NotNull [] bytes) { if (!HAS_ONE_BYTE_PER_CHAR) - return new String(bytes, StandardCharsets.ISO_8859_1); + return new String(bytes, ISO_8859_1); ensureJava9Plus(); - //noinspection RedundantStringConstructorCall - @NotNull String str = new String(); + @NotNull String str = new String(new byte[0], ISO_8859_1); try { S_VALUE.set(str, bytes); return str; @@ -432,12 +432,12 @@ public static double parseDouble(@NotNull CharSequence in) { private static final class SbFields { - private Field sbValue; private long sbValOffset; private Field sbCount; private long sbCountOffset; public SbFields() throws ClassNotFoundException, NoSuchFieldException { + Field sbValue; try { sbValue = Class.forName("java.lang.AbstractStringBuilder").getDeclaredField(VALUE_FIELD_NAME); ClassUtil.setAccessible(sbValue); @@ -479,6 +479,7 @@ private static boolean compareRest(@NotNull CharSequence in, * @return the converted string in title case with underscores, or null if the input is null. */ @Nullable + @Deprecated(/* to be removed in 2027, only used in tests */) public static String toTitleCase(@Nullable String name) { if (name == null || name.isEmpty()) return name; @@ -616,6 +617,7 @@ static NumberFormatException forRadix(int radix, boolean less) { " greater than Character.MAX_RADIX"); } + @Deprecated(/* to be removed in 2027, only used in tests */) public static long parseLong(CharSequence s, int radix) throws NumberFormatException { if (s == null) { diff --git a/src/main/java/net/openhft/chronicle/core/values/MaxBytes.java b/src/main/java/net/openhft/chronicle/core/values/MaxBytes.java index 4c854641d9..15ab7403e8 100644 --- a/src/main/java/net/openhft/chronicle/core/values/MaxBytes.java +++ b/src/main/java/net/openhft/chronicle/core/values/MaxBytes.java @@ -26,6 +26,7 @@ @Target(PARAMETER) @Retention(RUNTIME) @Documented +@Deprecated(/* to be removed in 2027, only used in tests */) public @interface MaxBytes { /** diff --git a/src/test/java/net/openhft/chronicle/core/ARMMemoryAddIntAndMessagesTest.java b/src/test/java/net/openhft/chronicle/core/ARMMemoryAddIntAndMessagesTest.java index 9d39142ef1..a04da5ccd5 100644 --- a/src/test/java/net/openhft/chronicle/core/ARMMemoryAddIntAndMessagesTest.java +++ b/src/test/java/net/openhft/chronicle/core/ARMMemoryAddIntAndMessagesTest.java @@ -15,12 +15,19 @@ class ARMMemoryAddIntAndMessagesTest { private long alloc(int bytes) { allocated = UnsafeMemory.UNSAFE.allocateMemory(bytes); - for (int i = 0; i < bytes; i++) UnsafeMemory.UNSAFE.putByte(allocated + i, (byte) 0); + for (int i = 0; i < bytes; i++) { + UnsafeMemory.UNSAFE.putByte(allocated + i, (byte) 0); + } return allocated; } @AfterEach - void tearDown() { if (allocated != 0) UnsafeMemory.UNSAFE.freeMemory(allocated); allocated = 0; } + void tearDown() { + if (allocated != 0) { + UnsafeMemory.UNSAFE.freeMemory(allocated); + } + allocated = 0; + } @Test void addIntAlignedAndMisaligned() { diff --git a/src/test/java/net/openhft/chronicle/core/ChronicleInitTest.java b/src/test/java/net/openhft/chronicle/core/ChronicleInitTest.java index 25e90545b4..a2ffc5c9c7 100644 --- a/src/test/java/net/openhft/chronicle/core/ChronicleInitTest.java +++ b/src/test/java/net/openhft/chronicle/core/ChronicleInitTest.java @@ -10,8 +10,10 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; +import java.io.UnsupportedEncodingException; import java.util.ServiceLoader; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.jupiter.api.Assertions.*; public class ChronicleInitTest extends CoreTestCommon { @@ -19,29 +21,58 @@ public class ChronicleInitTest extends CoreTestCommon { private final ByteArrayOutputStream errContent = new ByteArrayOutputStream(); private final PrintStream originalErr = System.err; - @BeforeEach - public void setUpStream() { - System.setErr(new PrintStream(errContent)); + private static JavaProcessBuilder builder(String... extraJvmArgs) { + return JavaProcessBuilder.create(ChronicleInitTest.class) + .withJvmArguments(extraJvmArgs); } - @AfterEach - public void restoreStream() { - System.setErr(originalErr); + private static JavaProcessBuilder builderWithTracingDisabled(String... extraJvmArgs) { + String[] args = new String[extraJvmArgs.length + 1]; + args[0] = "-Djvm.resource.tracing=false"; + System.arraycopy(extraJvmArgs, 0, args, 1, extraJvmArgs.length); + return JavaProcessBuilder.create(ChronicleInitTest.class) + .withJvmArguments(args); } public static void main(String[] args) { // Service loader implementation - assertEquals("dolor", Jvm.getProperty("lorem.ipsum")); - + if (!"dolor".equals(Jvm.getProperty("lorem.ipsum"))) { + System.out.println("Service loader implementation did not run"); + System.exit(10); + } // Normally enabled via system.properties file - assertFalse(Jvm.isResourceTracing()); - assertTrue(Jvm.areOptionalSafepointsEnabled()); - assertEquals("false", Jvm.getProperty("jvm.safepoint.enabled")); + if (Jvm.isResourceTracing()) { + System.out.println("Resource tracing is enabled"); + System.exit(11); + } + if (!Jvm.areOptionalSafepointsEnabled()) { + System.out.println("Optional safepoints are not enabled"); + System.exit(12); + } + if (!"false".equals(Jvm.getProperty("jvm.resource.tracing"))) { + System.out.println("Resource tracing was " + Jvm.getProperty("jvm.resource.tracing")); + System.exit(13); + } + } + + @BeforeEach + public void setUpStream() { + try { + System.setErr(new PrintStream(errContent, true, UTF_8.name())); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException("ISO-8859-1 should always be supported", e); + } + } + + @AfterEach + public void restoreStream() { + System.setErr(originalErr); } @Test public void initShouldNotThrowException() { - assertDoesNotThrow(ChronicleInit::init, "Calling init should not throw an exception"); + assertDoesNotThrow(() -> Class.forName(ChronicleInit.class.getName()), + "Loading ChronicleInit should not throw an exception"); } @Test @@ -57,11 +88,12 @@ public void shouldLoadServiceProviders() { @Test public void testPositive() throws Exception { - Process process = JavaProcessBuilder.create(ChronicleInitTest.class) - .withJvmArguments("-Dchronicle.init.runnable=" + ResourceTracingInit.class.getName()).start(); + Process process = builderWithTracingDisabled("-Dchronicle.init.runnable=" + ResourceTracingInit.class.getName()).start(); try { assertEquals(0, process.waitFor()); + String stdout = JavaProcessBuilder.getProcessStdOut(process); + assertTrue(stdout.contains("disabling resource tracking"), "Init runnable should execute"); } finally { JavaProcessBuilder.printProcessOutput("ChronicleInitTest", process); } @@ -69,11 +101,49 @@ public void testPositive() throws Exception { @Test public void testPostInitNegative() throws Exception { - Process process = JavaProcessBuilder.create(ChronicleInitTest.class) - .withJvmArguments("-Dchronicle.postinit.runnable=" + ResourceTracingInit.class.getName()).start(); + Process process = builder("-Dchronicle.postinit.runnable=" + ResourceTracingInit.class.getName()).start(); + + try { + assertEquals(11, process.waitFor()); + } finally { + JavaProcessBuilder.printProcessOutput("ChronicleInitTest", process); + } + } + + @Test + public void testExitCode10WhenServiceLoaderPropertyOverridden() throws Exception { + Process process = builder("-Dchronicle.postinit.runnable=" + PostInitOverridesLoremIpsum.class.getName()).start(); + + try { + assertEquals(10, process.waitFor()); + } finally { + JavaProcessBuilder.printProcessOutput("ChronicleInitTest", process); + } + } + + @Test + public void testExitCode12WhenOptionalSafepointsDisabled() throws Exception { + Process process = builder( + "-Djvm.resource.tracing=false", + "-Djvm.safepoint.enabled=false", + "-Dlorem.ipsum=dolor").start(); + + try { + assertEquals(12, process.waitFor()); + } finally { + JavaProcessBuilder.printProcessOutput("ChronicleInitTest", process); + } + } + + @Test + public void testExitCode13WhenResourceTracingPropertyDiffersFromFlag() throws Exception { + Process process = builder( + "-Djvm.resource.tracing=false", + "-Dchronicle.postinit.runnable=" + PostInitEnablesResourceTracingProperty.class.getName(), + "-Dlorem.ipsum=dolor").start(); try { - assertEquals(1, process.waitFor()); + assertEquals(13, process.waitFor()); } finally { JavaProcessBuilder.printProcessOutput("ChronicleInitTest", process); } @@ -81,7 +151,7 @@ public void testPostInitNegative() throws Exception { @Test public void testNoInit() throws Exception { - Process process = JavaProcessBuilder.create(ChronicleInitTest.class).start(); + Process process = builder().start(); try { assertNotEquals(0, process.waitFor()); @@ -92,8 +162,7 @@ public void testNoInit() throws Exception { @Test public void testBadClass() throws Exception { - Process process = JavaProcessBuilder.create(ChronicleInitTest.class) - .withJvmArguments("-Dchronicle.init.class=" + ChronicleInitTest.class.getName()).start(); + Process process = builder("-Dchronicle.init.class=" + ChronicleInitTest.class.getName()).start(); try { assertNotEquals(0, process.waitFor()); @@ -102,6 +171,17 @@ public void testBadClass() throws Exception { } } + @Test + public void testCommandLineOverride() throws Exception { + Process process = builderWithTracingDisabled().start(); + + try { + assertEquals(0, process.waitFor()); + } finally { + JavaProcessBuilder.printProcessOutput("ChronicleInitTest", process); + } + } + public static class ResourceTracingInit implements Runnable { @Override public void run() { @@ -110,6 +190,13 @@ public void run() { } } + public static class PostInitOverridesLoremIpsum implements Runnable { + @Override + public void run() { + System.setProperty("lorem.ipsum", "sit"); + } + } + public static class ServiceLoaderInit implements ChronicleInitRunnable { @Override public void run() { @@ -121,4 +208,11 @@ public void postInit() { System.setProperty("jvm.safepoint.enabled", "false"); } } + + public static class PostInitEnablesResourceTracingProperty implements Runnable { + @Override + public void run() { + System.setProperty("jvm.resource.tracing", "true"); + } + } } diff --git a/src/test/java/net/openhft/chronicle/core/CleaningRandomAccessFileTest.java b/src/test/java/net/openhft/chronicle/core/CleaningRandomAccessFileTest.java index 1dd3d94b72..9ec78e261e 100644 --- a/src/test/java/net/openhft/chronicle/core/CleaningRandomAccessFileTest.java +++ b/src/test/java/net/openhft/chronicle/core/CleaningRandomAccessFileTest.java @@ -25,7 +25,9 @@ private static int getFDs() { @Test public void resourceLeak() throws IOException { File tempDir = IOTools.createTempFile("resourceLeak"); - tempDir.mkdir(); + if (!tempDir.mkdir() && !tempDir.isDirectory()) { + throw new IOException("Unable to create temp directory " + tempDir); + } int repeat = Jvm.isArm() ? 6 : 50; for (int j = 0; j < repeat; j++) { int files = getFDs(); diff --git a/src/test/java/net/openhft/chronicle/core/JvmTest.java b/src/test/java/net/openhft/chronicle/core/JvmTest.java index 576de9f187..5927d0e5e4 100644 --- a/src/test/java/net/openhft/chronicle/core/JvmTest.java +++ b/src/test/java/net/openhft/chronicle/core/JvmTest.java @@ -82,21 +82,6 @@ public void resetExceptionHandlersSetHandlersBackToTheirDefaults() throws Illega assertSame(Jvm.getField(Jvm.class, "DEFAULT_DEBUG_EXCEPTION_HANDLER").get(null), Jvm.debug().defaultHandler()); } - static final class ReportUnoptimised { - - private ReportUnoptimised() { - } - - static { - Jvm.reportUnoptimised(); - } - - @SuppressWarnings("EmptyMethod") - static void reportOnce() { - // Do nothing as reports are made in the static initializer - } - } - @Test public void reportThis() { final Map map = recordExceptions(); @@ -223,48 +208,8 @@ public void isProcessAliveTest() { @Test public void testGetMethod() { Assert.assertNotNull(Jvm.getMethod(ClassIWDM.class, "hello", CharSequence.class)); - boolean fail = false; - try { - Jvm.getMethod(ClassIWDM.class, "helloDefault", CharSequence.class); - fail = true; - } catch (Throwable ignored) { - } - assertFalse(fail); - } - - static class ClassA { - long l; - int i; - short s; - byte b; - boolean flag; - } - - static class ClassB extends ClassA { - String text; - } - - static class ClassC extends ClassB { - String hi; - } - - private static class ClassD extends ClassC { - byte x; - } - - interface InterfaceWithDefaultMethod { - @SuppressWarnings("EmptyMethod") - void hello(CharSequence ignored); - - default void helloDefault(CharSequence cs) { - hello(cs); - } - } - - static class ClassIWDM implements InterfaceWithDefaultMethod { - @Override - public void hello(CharSequence ignored) { - } + assertThrows(Throwable.class, + () -> Jvm.getMethod(ClassIWDM.class, "helloDefault", CharSequence.class)); } @Test @@ -291,8 +236,8 @@ public void findAnnotationOnMethod() throws NoSuchMethodException { assertEquals("Hello", raz.value()); // This case still fails - final RealAnno raz2 = findAnnotation(Baz.class.getMethod("directAnno"), RealAnno.class); - assertEquals("G'Day", raz2.value()); + final RealAnno raz2 = findAnnotation(Baz.class.getMethod("directAnno"), RealAnno.class); + assertEquals("G'Day", raz2.value()); } @Test @@ -310,6 +255,7 @@ public void isLambdaClass() { assertTrue(Jvm.isLambdaClass(r.getClass())); + // needs to look like a lambda class so don't change the name class My$$Lambda$Class { } @@ -349,7 +295,7 @@ public void testGetProcessId() { @Test public void testTrimStackTrace() { StringBuilder sb = new StringBuilder(); - StackTraceElement[] stes = new StackTraceElement[] { + StackTraceElement[] stes = new StackTraceElement[]{ new StackTraceElement("Class1", "method1", "Class1.java", 1), new StackTraceElement("Class2", "method2", "Class2.java", 2) }; @@ -423,8 +369,13 @@ public void getPackageName() { assertEquals("net.openhft.chronicle.core", Jvm.getPackageName(Jvm.class)); } - private static class SomeClass { - private int somePrivateField; + interface InterfaceWithDefaultMethod { + @SuppressWarnings("EmptyMethod") + void hello(CharSequence ignored); + + default void helloDefault(CharSequence cs) { + hello(cs); + } } @Target(value = {ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.METHOD}) @@ -433,19 +384,13 @@ private static class SomeClass { String value(); } + @Target(value = {ElementType.FIELD, ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @RealAnno("Hello") @interface AnnoAlias { } - static class DTO { - @AnnoAlias - long inheritedAnno; - - @RealAnno("G'Day") - double directAnno; - } @AnnoAlias @SuppressWarnings("EmptyMethod") @@ -462,6 +407,59 @@ interface Bar extends Foo { } + static final class ReportUnoptimised { + + static { + Jvm.reportUnoptimised(); + } + + private ReportUnoptimised() { + } + + @SuppressWarnings("EmptyMethod") + static void reportOnce() { + // Do nothing as reports are made in the static initializer + } + } + + static class ClassA { + long l; + int i; + short s; + byte b; + boolean flag; + } + + static class ClassB extends ClassA { + String text; + } + + static class ClassC extends ClassB { + String hi; + } + + private static class ClassD extends ClassC { + byte x; + } + + static class ClassIWDM implements InterfaceWithDefaultMethod { + @Override + public void hello(CharSequence ignored) { + } + } + + private static class SomeClass { + private int somePrivateField; + } + + static class DTO { + @AnnoAlias + long inheritedAnno; + + @RealAnno("G'Day") + double directAnno; + } + static class Baz implements Bar { @Override public void inheritedAnno() { diff --git a/src/test/java/net/openhft/chronicle/core/MathsTest.java b/src/test/java/net/openhft/chronicle/core/MathsTest.java index 5ab0c10db7..6885e9d8fc 100644 --- a/src/test/java/net/openhft/chronicle/core/MathsTest.java +++ b/src/test/java/net/openhft/chronicle/core/MathsTest.java @@ -29,6 +29,7 @@ public class MathsTest extends CoreTestCommon { private static final double err = 5.1e-9; private static final int COUNT = Jvm.isArm() ? 500_000 : 3_000_000; + private static final Random TEST_RANDOM = new Random(1); private ThreadDump threadDump; @Test @@ -157,11 +158,6 @@ public void nanTest() { .forEach(d -> assertTrue(Double.isNaN(d))); } - @FunctionalInterface - public interface Rounder { - double round(double d); - } - @Test public void digits() { assertEquals(1, Maths.digits(0)); @@ -308,15 +304,15 @@ public void testIntLog2() throws IllegalArgumentException { @SuppressWarnings("deprecation") @Test public void testRounding() { - @NotNull Random rand = new Random(1); + @NotNull Random rand = TEST_RANDOM; for (int i = 0; i < 1000; i++) { double d = Math.pow(1e18, rand.nextDouble()) / 1e6; @NotNull BigDecimal bd = new BigDecimal(d); - assertEquals(bd.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(), Maths.round2(d), 5e-2); - assertEquals(bd.setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue(), Maths.round4(d), 5e-4); - assertEquals(bd.setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue(), Maths.round6(d), 5e-6); + assertEquals(bd.setScale(2, RoundingMode.HALF_UP).doubleValue(), Maths.round2(d), 5e-2); + assertEquals(bd.setScale(4, RoundingMode.HALF_UP).doubleValue(), Maths.round4(d), 5e-4); + assertEquals(bd.setScale(6, RoundingMode.HALF_UP).doubleValue(), Maths.round6(d), 5e-6); if (d < 1e8) - assertEquals(bd.setScale(8, BigDecimal.ROUND_HALF_UP).doubleValue(), Maths.round8(d), 5e-8); + assertEquals(bd.setScale(8, RoundingMode.HALF_UP).doubleValue(), Maths.round8(d), 5e-8); } } @@ -352,7 +348,7 @@ public void testDivideRoundUp() { @Test(expected = ArithmeticException.class) public void divideRoundUpZeroDivisorThrows() { - Maths.divideRoundUp(1, 0); + assertEquals(0, Maths.divideRoundUp(1, 0)); } @Test @@ -410,7 +406,7 @@ public void testHash64ForString() { String a1 = "Test"; long ah1 = Maths.hash64(a1); - String a2 = new StringBuilder().append("T").append("e") + "st"; + String a2 = "T" + "e" + "st"; long ah2 = Maths.hash64(a2); assertEquals(ah1, ah2); @@ -523,18 +519,16 @@ public void testHashMethods() { Object o2 = "test2"; Object o3 = "test3"; Object o4 = "test4"; - Object o5 = "test5"; - int hash1 = Maths.hash(o1); int hash2 = Maths.hash(o1, o2); int hash3 = Maths.hash(o1, o2, o3); int hash4 = Maths.hash(o1, o2, o3, o4); - int hash5 = Maths.hash(o1, o2, o3, o4, o5); assertNotEquals(hash1, hash2); assertNotEquals(hash2, hash3); assertNotEquals(hash3, hash4); - assertNotEquals(hash4, hash5); + Object o5 = "test5"; + assertNotEquals(hash4, Maths.hash(o1, o2, o3, o4, o5)); } @Test @@ -667,4 +661,9 @@ public void testEdgeCasesLong() { // Test when min is greater than n and is the next power of two assertEquals(128L, Maths.nextPower2(65L, 128L)); } + + @FunctionalInterface + public interface Rounder { + double round(double d); + } } diff --git a/src/test/java/net/openhft/chronicle/core/MockerFacadeTest.java b/src/test/java/net/openhft/chronicle/core/MockerFacadeTest.java index 8d5bb831e7..acb01d5522 100644 --- a/src/test/java/net/openhft/chronicle/core/MockerFacadeTest.java +++ b/src/test/java/net/openhft/chronicle/core/MockerFacadeTest.java @@ -11,14 +11,11 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.*; public class MockerFacadeTest { - interface Sample { - void run(String value); - } - @Test public void loggingToStringWriterDelegates() { StringWriter writer = new StringWriter(); @@ -32,11 +29,16 @@ public void loggingToStringWriterDelegates() { @Test public void loggingToPrintStreamDelegates() { ByteArrayOutputStream backing = new ByteArrayOutputStream(); - PrintStream stream = new PrintStream(backing, true); + PrintStream stream; + try { + stream = new PrintStream(backing, true, UTF_8.name()); + } catch (java.io.UnsupportedEncodingException e) { + throw new IllegalStateException("ISO-8859-1 should always be supported", e); + } Sample sample = Mocker.logging(Sample.class, "ps-", stream); sample.run("data"); - String logged = backing.toString(); + String logged = new String(backing.toByteArray(), UTF_8); assertTrue(logged.contains("ps-run")); assertTrue(logged.contains("data")); } @@ -56,4 +58,8 @@ public void ignoredProxySupportsCalls() { sample.run("whatever"); assertNotNull(sample); } + + interface Sample { + void run(String value); + } } diff --git a/src/test/java/net/openhft/chronicle/core/OSPageCacheTest.java b/src/test/java/net/openhft/chronicle/core/OSPageCacheTest.java index eb7426e358..51af356a57 100644 --- a/src/test/java/net/openhft/chronicle/core/OSPageCacheTest.java +++ b/src/test/java/net/openhft/chronicle/core/OSPageCacheTest.java @@ -7,7 +7,8 @@ import java.lang.reflect.Field; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; class OSPageCacheTest { @@ -22,6 +23,7 @@ void pageSizeAndMapAlignmentCache() throws Exception { assertTrue(second > 0); long align1 = OS.mapAlignment(); + assertTrue(align1 > 0); Field ma = OS.class.getDeclaredField("mapAlignment"); ma.setAccessible(true); ma.setInt(null, 0); diff --git a/src/test/java/net/openhft/chronicle/core/OSTest.java b/src/test/java/net/openhft/chronicle/core/OSTest.java index f1de3bebd4..6ebb376ef4 100644 --- a/src/test/java/net/openhft/chronicle/core/OSTest.java +++ b/src/test/java/net/openhft/chronicle/core/OSTest.java @@ -12,7 +12,6 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; -import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.nio.ByteOrder; import java.nio.MappedByteBuffer; @@ -249,8 +248,8 @@ public void mapAlign() { assertEquals(0, OS.mapAlign(0, customPageSize)); // Perfectly aligned already assertEquals(customPageSize, OS.mapAlign(1, customPageSize)); // Not aligned, should round up to higher closest assertEquals(customPageSize, OS.mapAlign(customPageSize, customPageSize)); // Perfectly aligned already - assertEquals(2 * customPageSize, OS.mapAlign(customPageSize + 1, customPageSize)); // Not aligned, should round up to higher closest - assertEquals(2 * customPageSize, OS.mapAlign(2 * customPageSize - 1, customPageSize)); // Not aligned, should round up to higher closest + assertEquals(2L * customPageSize, OS.mapAlign(customPageSize + 1, customPageSize)); // Not aligned, should round up to higher closest + assertEquals(2L * customPageSize, OS.mapAlign(2L * customPageSize - 1, customPageSize)); // Not aligned, should round up to higher closest // Testing with page alignment equal to 1 (should not change the offset) assertEquals(42, OS.mapAlign(42, 1)); // Alignment of 1, no change @@ -287,8 +286,8 @@ public void pageAlign() { assertEquals(0, OS.pageAlign(0, customPageSize)); // Perfectly aligned already assertEquals(customPageSize, OS.pageAlign(1, customPageSize)); // Not aligned, should round up to higher closest assertEquals(customPageSize, OS.pageAlign(customPageSize, customPageSize)); // Perfectly aligned already - assertEquals(2 * customPageSize, OS.pageAlign(customPageSize + 1, customPageSize)); // Not aligned, should round up to higher closest - assertEquals(2 * customPageSize, OS.pageAlign(2 * customPageSize - 1, customPageSize)); // Not aligned, should round up to higher closest + assertEquals(2L * customPageSize, OS.pageAlign(customPageSize + 1, customPageSize)); // Not aligned, should round up to higher closest + assertEquals(2L * customPageSize, OS.pageAlign(2L * customPageSize - 1, customPageSize)); // Not aligned, should round up to higher closest } @Test @@ -352,7 +351,7 @@ public void testGetHostName0() { } } - assertEquals(expectedHostName, OS.HostnameHolder.HOST_NAME); + assertEquals(OS.HostnameHolder.HOST_NAME, expectedHostName); } @Test(expected = IllegalArgumentException.class) diff --git a/src/test/java/net/openhft/chronicle/core/RandomAccessFileCleanupMain.java b/src/test/java/net/openhft/chronicle/core/RandomAccessFileCleanupMain.java index cae1d31698..3ea2a8eba8 100644 --- a/src/test/java/net/openhft/chronicle/core/RandomAccessFileCleanupMain.java +++ b/src/test/java/net/openhft/chronicle/core/RandomAccessFileCleanupMain.java @@ -16,7 +16,9 @@ public class RandomAccessFileCleanupMain { public static void main(String[] args) throws IOException { File tempDir = IOTools.createTempFile("RandomAccessFileCleanupMain"); - tempDir.mkdir(); + if (!tempDir.mkdir() && !tempDir.isDirectory()) { + throw new IOException("Unable to create temp directory " + tempDir); + } for (int j = 0; j < 100; j++) { int files = new File("/proc/self/fd").list().length; System.out.println("File descriptors " + files); diff --git a/src/test/java/net/openhft/chronicle/core/StackTraceTest.java b/src/test/java/net/openhft/chronicle/core/StackTraceTest.java index 1ff101faf2..c2e22314ae 100644 --- a/src/test/java/net/openhft/chronicle/core/StackTraceTest.java +++ b/src/test/java/net/openhft/chronicle/core/StackTraceTest.java @@ -98,30 +98,27 @@ public void forThread() throws InterruptedException { if (Jvm.isJava20Plus()) { // The exact string might differ in Java 20+ if the thread is displayed differently assertTrue(String.format("%s must match regular expression expecting timestamp to nanosecond precision", st.getMessage()), - st.getMessage().matches("Thread\\[\\#\\d+,background,5,main\\] on main at " + TIMESTAMP_REGEX)); + st.getMessage().matches("Thread\\[\\#\\d+,background,5,main\\] on main at " + TIMESTAMP_REGEX)); // Allow either our wrapper or the underlying sleep to appear at the top on newer JDKs String f0 = st.getStackTrace()[0].toString().split("\\(")[0].replaceAll("^app//", "").replaceFirst("^[^/]+/", ""); String f1 = st.getStackTrace().length > 1 ? st.getStackTrace()[1].toString().split("\\(")[0].replaceAll("^app//", "").replaceFirst("^[^/]+/", "") : ""; boolean ok = "net.openhft.chronicle.core.Jvm.pause".equals(f0) || - "net.openhft.chronicle.core.Jvm.pause".equals(f1) || - "java.lang.Thread.sleep".equals(f0) || - "java.lang.Thread.sleep".equals(f1); + "net.openhft.chronicle.core.Jvm.pause".equals(f1) || + "java.lang.Thread.sleep".equals(f0) || + "java.lang.Thread.sleep".equals(f1); assertTrue("Expected top frames to include Jvm.pause or Thread.sleep but were: " + Arrays.asList(f0, f1), ok); } else { assertTrue(st.getMessage() + " must match regular expression expecting timestamp to nanosecond precision", - // matching against example: "Thread[background,5,main] on main at 2024-01-02T03:04:05.006007008Z", - st.getMessage().matches("Thread\\[background,5,main\\] on main at " + TIMESTAMP_REGEX) - // "Thread[background,5,main] on main at 2024-01-02T03:04:05.006007008Z", - ); + st.getMessage().matches("Thread\\[background,5,main\\] on main at " + TIMESTAMP_REGEX)); // Allow either our wrapper or the underlying sleep to appear at the top String f0 = st.getStackTrace()[0].toString().split("\\(")[0].replaceAll("^app//", "").replaceFirst("^[^/]+/", ""); String f1 = st.getStackTrace().length > 1 ? st.getStackTrace()[1].toString().split("\\(")[0].replaceAll("^app//", "").replaceFirst("^[^/]+/", "") : ""; boolean ok = "net.openhft.chronicle.core.Jvm.pause".equals(f0) || - "net.openhft.chronicle.core.Jvm.pause".equals(f1) || - "java.lang.Thread.sleep".equals(f0) || - "java.lang.Thread.sleep".equals(f1); + "net.openhft.chronicle.core.Jvm.pause".equals(f1) || + "java.lang.Thread.sleep".equals(f0) || + "java.lang.Thread.sleep".equals(f1); assertTrue("Expected top frames to include Jvm.pause or Thread.sleep but were: " + Arrays.asList(f0, f1), ok); } } diff --git a/src/test/java/net/openhft/chronicle/core/UnsafeMemory2Test.java b/src/test/java/net/openhft/chronicle/core/UnsafeMemory2Test.java index c45c7165f4..f309e9a3c7 100644 --- a/src/test/java/net/openhft/chronicle/core/UnsafeMemory2Test.java +++ b/src/test/java/net/openhft/chronicle/core/UnsafeMemory2Test.java @@ -21,6 +21,7 @@ @RunWith(Parameterized.class) public class UnsafeMemory2Test extends CoreTestCommon { private static final int INT_VAL = 0x12345678; + private static final Random TEST_RANDOM = new Random(1); private final UnsafeMemory memory; public UnsafeMemory2Test(UnsafeMemory memory) { @@ -88,7 +89,7 @@ public void is7BitBytes2() { byte[] bytes = new byte[256]; for (int i = 0; i < 256; i++) bytes[i] = (byte) i; - Random rand = new Random(); + Random rand = TEST_RANDOM; for (int i = 0; i < 1000; i++) { int a = rand.nextInt(256); int b = rand.nextInt(256); @@ -119,7 +120,7 @@ public void is7BitChars2() { char[] chars = new char[512]; for (int i = 0; i < 512; i++) chars[i] = (char) i; - Random rand = new Random(); + Random rand = TEST_RANDOM; for (int i = 0; i < 1000; i++) { int a = rand.nextInt(512); int b = rand.nextInt(512); @@ -151,7 +152,7 @@ public void is7BitAddr2() { for (int i = 0; i < 256; i++) memory.writeByte(addr + i, (byte) i); - Random rand = new Random(); + Random rand = TEST_RANDOM; for (int i = 0; i < 1000; i++) { int a = rand.nextInt(256); int b = rand.nextInt(256); @@ -325,7 +326,7 @@ public void copyMemoryEachWayByteArrayLongArray() { for (int i = 0; i < lengthInBytes; i++) assertEquals(i, bytes[i]); Arrays.fill(longs, 0); - memory.copyMemory((Object) bytes, 0, longs, memory.arrayBaseOffset(longs.getClass()), lengthInBytes); + memory.copyMemory(bytes, 0, longs, memory.arrayBaseOffset(longs.getClass()), lengthInBytes); assertArrayEquals(copy, longs); } diff --git a/src/test/java/net/openhft/chronicle/core/UnsafeMemoryTest.java b/src/test/java/net/openhft/chronicle/core/UnsafeMemoryTest.java index afa61e99cd..515be9057b 100644 --- a/src/test/java/net/openhft/chronicle/core/UnsafeMemoryTest.java +++ b/src/test/java/net/openhft/chronicle/core/UnsafeMemoryTest.java @@ -33,15 +33,10 @@ public class UnsafeMemoryTest extends CoreTestCommon { public final TestName testName = new TestName(); private final UnsafeMemory memory; - private Boolean onHeap; - private Object object; + private final Boolean onHeap; + private final Object object; private long addr; - private static class TestClass { - boolean booleanField = false; - double doubleField = 0.0; - } - @SuppressWarnings("unused") public UnsafeMemoryTest(String name, UnsafeMemory memory, Boolean onHeap) { this.memory = memory; @@ -106,7 +101,9 @@ public void testUnsafeBooleanOperations() throws NoSuchFieldException { @Test public void testUnsafeCharOperations() throws NoSuchFieldException { - class CharHolder { char value; } + class CharHolder { + char value; + } CharHolder holder = new CharHolder(); long offset = UnsafeMemory.UNSAFE.objectFieldOffset(CharHolder.class.getDeclaredField("value")); @@ -117,7 +114,9 @@ class CharHolder { char value; } @Test public void testUnsafeFloatOperations() throws NoSuchFieldException { - class FloatHolder { float value; } + class FloatHolder { + float value; + } FloatHolder holder = new FloatHolder(); long offset = UnsafeMemory.UNSAFE.objectFieldOffset(FloatHolder.class.getDeclaredField("value")); @@ -138,7 +137,9 @@ public void testUnsafeDoubleOperations() throws NoSuchFieldException { @Test public void testUnsafeObjectOperations() throws NoSuchFieldException { - class ObjectHolder { Object value; } + class ObjectHolder { + Object value; + } ObjectHolder holder = new ObjectHolder(); long offset = UnsafeMemory.UNSAFE.objectFieldOffset(ObjectHolder.class.getDeclaredField("value")); @@ -255,10 +256,6 @@ public void testTestAndSetIntObjectField() throws NoSuchFieldException { assertThrows(IllegalStateException.class, () -> memory.testAndSetInt(obj, offset, expected, 30)); } - static class TestObject { - int value; - } - @Test public void writeShort() { for (int i = 0; i <= 64; i++) { @@ -619,4 +616,13 @@ public void addLong() throws MisAlignedAssertionError { throw e; } } + + private static class TestClass { + final boolean booleanField = false; + final double doubleField = 0.0; + } + + static class TestObject { + int value; + } } diff --git a/src/test/java/net/openhft/chronicle/core/UnsafeMemoryTestMixin.java b/src/test/java/net/openhft/chronicle/core/UnsafeMemoryTestMixin.java index 22221e27e1..eb90f08cfc 100644 --- a/src/test/java/net/openhft/chronicle/core/UnsafeMemoryTestMixin.java +++ b/src/test/java/net/openhft/chronicle/core/UnsafeMemoryTestMixin.java @@ -28,6 +28,41 @@ interface UnsafeMemoryTestMixin { int MEM_SIZE = CACHE_LINE_SIZE * 2; int NO_THREADS = 5; + static int await(CyclicBarrier cyclicBarrier) { + try { + return cyclicBarrier.await(); + } catch (InterruptedException | BrokenBarrierException e) { + throw new AssertionError(e); + } + } + + static int await(CyclicBarrier cyclicBarrier, long timeOut, TimeUnit timeUnit) { + try { + return cyclicBarrier.await(timeOut, timeUnit); + } catch (InterruptedException | BrokenBarrierException | TimeoutException e) { + throw new AssertionError(e); + } + } + + static Stream arguments() { + final UnsafeMemory memory1 = new UnsafeMemory(); + final UnsafeMemory.ARMMemory memory2 = new UnsafeMemory.ARMMemory(); + Stream.Builder builder = Stream.builder(); + if (!Jvm.isArm()) { + builder.add(Arguments.of("UnsafeMemory offheap", memory1, Mode.NATIVE_ADDRESS)); + builder.add(Arguments.of("UnsafeMemory onheap", memory1, Mode.OBJECT)); + builder.add(Arguments.of("UnsafeMemory offheap (null)", memory1, Mode.NULL_OBJECT)); + } + builder.add(Arguments.of("ARMMemory offheap", memory2, Mode.NATIVE_ADDRESS)); + builder.add(Arguments.of("ARMMemory onheap", memory2, Mode.OBJECT)); + builder.add(Arguments.of("ARMMemory offheap (null)", memory2, Mode.NULL_OBJECT)); + return builder.build(); + } + + static Mode mode(Arguments args) { + return (Mode) args.get()[2]; + } + Class type(); IntPredicate alignedToType(); @@ -129,6 +164,7 @@ default Stream volatileTests() { // Busy wait for a short time. This gives the threads some time to see changes final long expireNs = System.nanoTime() + TimeUnit.MICROSECONDS.toNanos(100); while (System.nanoTime() < expireNs) { + Jvm.pause(1); } try { @@ -155,6 +191,84 @@ default Stream volatileTests() { ); } + default void test(final Variant variant, + final T testValue, + final MemoryLongObjConsumer addressWriter, + final MemoryLongFunction addressReader) { + for (int i = 0; i <= CACHE_LINE_SIZE; i++) { + addressWriter.accept(variant.memory(), variant.addr() + i, testValue); + final T t = addressReader.apply(variant.memory(), variant.addr() + i); + assertEquals(testValue, t); + } + } + + default void testObj(final Variant variant, + final T testValue, + final MemoryObjLongObjConsumer objectWriter, + final MemoryObjLongFunction objectReader) { + for (int i = 0; i <= CACHE_LINE_SIZE; i++) { + objectWriter.accept(variant.memory(), variant.object(), variant.addr() + i, testValue); + final T t = objectReader.apply(variant.memory(), variant.object(), variant.addr() + i); + assertEquals(testValue, t); + } + } + + default IntStream interestingOffsets() { + return IntStream.concat( + IntStream.of(0, 1), + IntStream.of(CACHE_LINE_SIZE_ARM, CACHE_LINE_SIZE) + .flatMap(s -> IntStream.rangeClosed(s - Long.BYTES, s))) + .filter(alignedToType()); + } + + enum Mode { + + /** + * Use a native address with direct addressing. + *

+ * e.g. memory.readInt(address); + */ + NATIVE_ADDRESS, + + /** + * Use an object with offset addressing. + *

+ * e.g. memory.readInt(object, offset); + */ + OBJECT, + + /** + * Use a null object with offset addressing + *

+ * e.g. memory.readInt(null, offset); + */ + NULL_OBJECT; + + boolean isDirectAddressing() { + return this == NATIVE_ADDRESS; + } + } + + @FunctionalInterface + interface MemoryLongObjConsumer { + void accept(UnsafeMemory um, long l, T t); + } + + @FunctionalInterface + interface MemoryLongFunction { + T apply(UnsafeMemory um, long l); + } + + @FunctionalInterface + interface MemoryObjLongObjConsumer { + void accept(UnsafeMemory um, Object o, long l, T t); + } + + @FunctionalInterface + interface MemoryObjLongFunction { + T apply(UnsafeMemory um, Object o, long l); + } + final class Reader implements Runnable { private final int no; @@ -185,6 +299,7 @@ public void run() { T actual; // Expect a change, not a specific value while ((actual = getter.get()).equals(previousValue)) { + Jvm.pause(1); } if (!expected.equals(actual)) { errors.add("Reader " + no + " expected " + expected + " but was " + actual); @@ -196,22 +311,6 @@ public void run() { } } - static int await(CyclicBarrier cyclicBarrier) { - try { - return cyclicBarrier.await(); - } catch (InterruptedException | BrokenBarrierException e) { - throw new AssertionError(e); - } - } - - static int await(CyclicBarrier cyclicBarrier, long timeOut, TimeUnit timeUnit) { - try { - return cyclicBarrier.await(timeOut, timeUnit); - } catch (InterruptedException | BrokenBarrierException | TimeoutException e) { - throw new AssertionError(e); - } - } - final class NamedOperation { private final String name; @@ -231,71 +330,6 @@ T operation() { } } - @FunctionalInterface - interface MemoryLongObjConsumer { - void accept(UnsafeMemory um, long l, T t); - } - - @FunctionalInterface - interface MemoryLongFunction { - T apply(UnsafeMemory um, long l); - } - - @FunctionalInterface - interface MemoryObjLongObjConsumer { - void accept(UnsafeMemory um, Object o, long l, T t); - } - - @FunctionalInterface - interface MemoryObjLongFunction { - T apply(UnsafeMemory um, Object o, long l); - } - - default void test(final Variant variant, - final T testValue, - final MemoryLongObjConsumer addressWriter, - final MemoryLongFunction addressReader) { - for (int i = 0; i <= CACHE_LINE_SIZE; i++) { - addressWriter.accept(variant.memory(), variant.addr() + i, testValue); - final T t = addressReader.apply(variant.memory(), variant.addr() + i); - assertEquals(testValue, t); - } - } - - default void testObj(final Variant variant, - final T testValue, - final MemoryObjLongObjConsumer objectWriter, - final MemoryObjLongFunction objectReader) { - for (int i = 0; i <= CACHE_LINE_SIZE; i++) { - objectWriter.accept(variant.memory(), variant.object(), variant.addr() + i, testValue); - final T t = objectReader.apply(variant.memory(), variant.object(), variant.addr() + i); - assertEquals(testValue, t); - } - } - - default IntStream interestingOffsets() { - return IntStream.concat( - IntStream.of(0, 1), - IntStream.of(CACHE_LINE_SIZE_ARM, CACHE_LINE_SIZE) - .flatMap(s -> IntStream.rangeClosed(s - Long.BYTES, s))) - .filter(alignedToType()); - } - - static Stream arguments() { - final UnsafeMemory memory1 = new UnsafeMemory(); - final UnsafeMemory.ARMMemory memory2 = new UnsafeMemory.ARMMemory(); - Stream.Builder builder = Stream.builder(); - if (!Jvm.isArm()) { - builder.add(Arguments.of("UnsafeMemory offheap", memory1, Mode.NATIVE_ADDRESS)); - builder.add(Arguments.of("UnsafeMemory onheap", memory1, Mode.OBJECT)); - builder.add(Arguments.of("UnsafeMemory offheap (null)", memory1, Mode.NULL_OBJECT)); - } - builder.add(Arguments.of("ARMMemory offheap", memory2, Mode.NATIVE_ADDRESS)); - builder.add(Arguments.of("ARMMemory onheap", memory2, Mode.OBJECT)); - builder.add(Arguments.of("ARMMemory offheap (null)", memory2, Mode.NULL_OBJECT)); - return builder.build(); - } - final class Variant implements AutoCloseable { private final Runnable closer; @@ -355,36 +389,4 @@ public void close() { closer.run(); } } - - static Mode mode(Arguments args) { - return (Mode) args.get()[2]; - } - - enum Mode { - - /** - * Use a native address with direct addressing. - *

- * e.g. memory.readInt(address); - */ - NATIVE_ADDRESS, - - /** - * Use an object with offset addressing. - *

- * e.g. memory.readInt(object, offset); - */ - OBJECT, - - /** - * Use a null object with offset addressing - *

- * e.g. memory.readInt(null, offset); - */ - NULL_OBJECT; - - boolean isDirectAddressing() { - return this == NATIVE_ADDRESS; - } - } } diff --git a/src/test/java/net/openhft/chronicle/core/UnsafePingPointMain.java b/src/test/java/net/openhft/chronicle/core/UnsafePingPointMain.java index 5c97a70b6c..65b703a784 100644 --- a/src/test/java/net/openhft/chronicle/core/UnsafePingPointMain.java +++ b/src/test/java/net/openhft/chronicle/core/UnsafePingPointMain.java @@ -52,9 +52,7 @@ public void run() { } private void toggle(int x, int y) { - if (!unsafe.compareAndSwapInt(null, addrA, x, y)) { - throw new AssertionError(); - } + assert unsafe.compareAndSwapInt(null, addrA, x, y); int value = unsafe.getIntVolatile(null, addrB); int count = 1000; while (value != y && count-- > 0) { diff --git a/src/test/java/net/openhft/chronicle/core/benchmarks/Randomness.java b/src/test/java/net/openhft/chronicle/core/benchmarks/Randomness.java index 4cd65d48bf..77184dd2cf 100644 --- a/src/test/java/net/openhft/chronicle/core/benchmarks/Randomness.java +++ b/src/test/java/net/openhft/chronicle/core/benchmarks/Randomness.java @@ -6,10 +6,13 @@ import net.openhft.chronicle.core.Maths; import java.security.SecureRandom; +import java.util.Random; public class Randomness { - // Long running, avg score = 6879 + private static final Random RNG = new SecureRandom(); + + // Long running, avg score = 446980825 public static void main(String[] args) { long time = 0, timeCount = 0; long scoreSum = 0; @@ -17,7 +20,7 @@ public static void main(String[] args) { long[] hashs = new long[8192]; StringBuilder sb = new StringBuilder(); byte[] init = new byte[hashs.length / 64]; - new SecureRandom().nextBytes(init); + RNG.nextBytes(init); for (int i = 0; i < hashs.length; i++) { sb.setLength(0); sb.append(t).append('-').append(i); @@ -37,10 +40,9 @@ public static void main(String[] args) { } } scoreSum += score; -// if (t % 50 == 0) -// System.out.println(t + " - Score: " + score); } System.out.println("Average score: " + scoreSum / 500); - System.out.printf("Average time %.3f us%n", time / timeCount / 1e3); + double avgTimeMicros = (double) time / (double) timeCount / 1e3; + System.out.printf("Average time %.3f us%n", avgTimeMicros); } } diff --git a/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceFallbackTest.java b/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceFallbackTest.java index 20ae2c4390..9a3543922b 100644 --- a/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceFallbackTest.java +++ b/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceFallbackTest.java @@ -10,12 +10,13 @@ import java.io.IOException; import java.net.URL; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import static org.junit.jupiter.api.Assertions.*; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; class CleanerServiceFallbackTest { @@ -28,6 +29,12 @@ private static void resetLocator() throws Exception { inst.set(null, null); } + private static void prepareBrokenServiceDescriptor(Path serviceFile) throws IOException { + Files.createDirectories(serviceFile.getParent()); + // Reference a class that does not exist so ServiceLoader triggers ServiceConfigurationError + Files.write(serviceFile, "non.existent.Cleaner\n".getBytes(UTF_8)); + } + @AfterEach void tearDown() throws Exception { resetLocator(); @@ -77,10 +84,4 @@ public java.io.InputStream getResourceAsStream(String name) { current.setContextClassLoader(previous); } } - - private static void prepareBrokenServiceDescriptor(Path serviceFile) throws IOException { - Files.createDirectories(serviceFile.getParent()); - // Reference a class that does not exist so ServiceLoader triggers ServiceConfigurationError - Files.write(serviceFile, "non.existent.Cleaner\n".getBytes(StandardCharsets.ISO_8859_1)); - } } diff --git a/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceIncludeNewerOlderTest.java b/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceIncludeNewerOlderTest.java index 6ae051ebbd..495e757713 100644 --- a/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceIncludeNewerOlderTest.java +++ b/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceIncludeNewerOlderTest.java @@ -11,9 +11,9 @@ import java.io.FileOutputStream; import java.net.URL; import java.net.URLClassLoader; -import java.nio.charset.StandardCharsets; -import static org.junit.jupiter.api.Assertions.*; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertTrue; class CleanerServiceIncludeNewerOlderTest { @@ -36,11 +36,13 @@ void includeNewerOlderGateAllowsAppropriateProviders() throws Exception { resetLocator(); File root = new File("target/tmp-services-include"); File svc = new File(root, "META-INF/services/" + ByteBufferCleanerService.class.getName()); - if (!svc.getParentFile().exists() && !svc.getParentFile().mkdirs()) throw new IllegalStateException("Cannot create services dir"); + if (!svc.getParentFile().exists() && !svc.getParentFile().mkdirs()) { + throw new IllegalStateException("Cannot create services dir"); + } try (FileOutputStream fos = new FileOutputStream(svc)) { String content = "net.openhft.chronicle.core.cleaner.testimpl2.NewerInclOlderCleaner\n" + "net.openhft.chronicle.core.cleaner.testimpl2.OlderInclNewerCleaner\n"; - fos.write(content.getBytes(StandardCharsets.ISO_8859_1)); + fos.write(content.getBytes(UTF_8)); } URLClassLoader cl = new URLClassLoader(new URL[]{root.toURI().toURL()}, CleanerServiceLocator.class.getClassLoader()); Thread t = Thread.currentThread(); diff --git a/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceLoaderErrorTest.java b/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceLoaderErrorTest.java index 94b5ad52be..8fd4226d73 100644 --- a/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceLoaderErrorTest.java +++ b/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceLoaderErrorTest.java @@ -11,9 +11,10 @@ import java.io.FileOutputStream; import java.net.URL; import java.net.URLClassLoader; -import java.nio.charset.StandardCharsets; -import static org.junit.jupiter.api.Assertions.*; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Exercises the ServiceConfigurationError path by providing a bogus provider entry. @@ -43,7 +44,7 @@ void serviceConfigurationErrorFallsBackToReflection() throws Exception { if (!parent.exists() && !parent.mkdirs()) throw new IllegalStateException("Cannot create temp services dir"); try (FileOutputStream fos = new FileOutputStream(svc)) { // bogus provider triggers ServiceConfigurationError when iterating - fos.write("does.not.ExistProvider\n".getBytes(StandardCharsets.ISO_8859_1)); + fos.write("does.not.ExistProvider\n".getBytes(UTF_8)); } // Child-first isolation: no parent to avoid inheriting other service resources from the test classpath URLClassLoader cl = new URLClassLoader(new URL[]{root.toURI().toURL()}, null); diff --git a/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceMixedTest.java b/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceMixedTest.java index 328ac81fe2..079fc60779 100644 --- a/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceMixedTest.java +++ b/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServiceMixedTest.java @@ -11,9 +11,9 @@ import java.io.FileOutputStream; import java.net.URL; import java.net.URLClassLoader; -import java.nio.charset.StandardCharsets; -import static org.junit.jupiter.api.Assertions.*; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; class CleanerServiceMixedTest { @@ -36,11 +36,13 @@ void mixedValidAndInvalidEntriesStillChooseValidProvider() throws Exception { resetLocator(); File root = new File("target/tmp-services-mixed"); File svc = new File(root, "META-INF/services/" + ByteBufferCleanerService.class.getName()); - if (!svc.getParentFile().exists() && !svc.getParentFile().mkdirs()) throw new IllegalStateException("Cannot create services dir"); + if (!svc.getParentFile().exists() && !svc.getParentFile().mkdirs()) { + throw new IllegalStateException("Cannot create services dir"); + } try (FileOutputStream fos = new FileOutputStream(svc)) { String content = "does.not.ExistProvider\n" + "net.openhft.chronicle.core.cleaner.testimpl.AllowedCleaner\n"; - fos.write(content.getBytes(StandardCharsets.ISO_8859_1)); + fos.write(content.getBytes(UTF_8)); } URLClassLoader cl = new URLClassLoader(new URL[]{root.toURI().toURL()}, CleanerServiceLocator.class.getClassLoader()); Thread t = Thread.currentThread(); diff --git a/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServicePriorityTest.java b/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServicePriorityTest.java index de97fd4e98..6bb6cb908c 100644 --- a/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServicePriorityTest.java +++ b/src/test/java/net/openhft/chronicle/core/cleaner/CleanerServicePriorityTest.java @@ -11,9 +11,9 @@ import java.io.FileOutputStream; import java.net.URL; import java.net.URLClassLoader; -import java.nio.charset.StandardCharsets; -import static org.junit.jupiter.api.Assertions.*; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; class CleanerServicePriorityTest { @@ -38,11 +38,13 @@ void lowestImpactChosenRegardlessOfDiscoveryOrder() throws Exception { File root = new File("target/tmp-services-priority"); File svc = new File(root, "META-INF/services/" + ByteBufferCleanerService.class.getName()); File parent = svc.getParentFile(); - if (!parent.exists() && !parent.mkdirs()) throw new IllegalStateException("Cannot create temp services dir"); + if (!parent.exists() && !parent.mkdirs()) { + throw new IllegalStateException("Cannot create temp services dir"); + } try (FileOutputStream fos = new FileOutputStream(svc)) { String content = "net.openhft.chronicle.core.cleaner.testimpl.AllowedCleaner\n" + "net.openhft.chronicle.core.cleaner.testimpl.SomeImpactCleaner\n"; - fos.write(content.getBytes(StandardCharsets.ISO_8859_1)); + fos.write(content.getBytes(UTF_8)); } URLClassLoader cl = new URLClassLoader(new URL[]{root.toURI().toURL()}, CleanerServiceLocator.class.getClassLoader()); Thread t = Thread.currentThread(); diff --git a/src/test/java/net/openhft/chronicle/core/cleaner/impl/jdk9/Jdk9ByteBufferCleanerServiceTest.java b/src/test/java/net/openhft/chronicle/core/cleaner/impl/jdk9/Jdk9ByteBufferCleanerServiceTest.java index 5962648995..87103aa7a3 100644 --- a/src/test/java/net/openhft/chronicle/core/cleaner/impl/jdk9/Jdk9ByteBufferCleanerServiceTest.java +++ b/src/test/java/net/openhft/chronicle/core/cleaner/impl/jdk9/Jdk9ByteBufferCleanerServiceTest.java @@ -13,7 +13,7 @@ public class Jdk9ByteBufferCleanerServiceTest extends CoreTestCommon { @Test - public void shouldCleanBuffer() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { + public void shouldCleanBuffer() { assumeTrue(Jvm.isJava9Plus()); CleanerTestUtil.test(new Jdk9ByteBufferCleanerService()::clean); diff --git a/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/AllowedCleaner.java b/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/AllowedCleaner.java index f8b2bce1b0..06e4baac29 100644 --- a/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/AllowedCleaner.java +++ b/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/AllowedCleaner.java @@ -8,7 +8,7 @@ import java.nio.ByteBuffer; -@TargetMajorVersion(majorVersion = 0, includeNewer = true, includeOlder = true) +@TargetMajorVersion(includeNewer = true, includeOlder = true) public class AllowedCleaner implements ByteBufferCleanerService { @Override public Impact impact() { diff --git a/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/DisallowedCleaner.java b/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/DisallowedCleaner.java index 016bba8112..70b2c7e2f4 100644 --- a/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/DisallowedCleaner.java +++ b/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/DisallowedCleaner.java @@ -8,7 +8,7 @@ import java.nio.ByteBuffer; -@TargetMajorVersion(majorVersion = 99, includeNewer = false, includeOlder = false) +@TargetMajorVersion(majorVersion = 99) public class DisallowedCleaner implements ByteBufferCleanerService { @Override public Impact impact() { diff --git a/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/SomeImpactCleaner.java b/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/SomeImpactCleaner.java index 9a8641615f..1393bf86eb 100644 --- a/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/SomeImpactCleaner.java +++ b/src/test/java/net/openhft/chronicle/core/cleaner/testimpl/SomeImpactCleaner.java @@ -8,7 +8,7 @@ import java.nio.ByteBuffer; -@TargetMajorVersion(majorVersion = 0, includeNewer = true, includeOlder = true) +@TargetMajorVersion(includeNewer = true, includeOlder = true) public class SomeImpactCleaner implements ByteBufferCleanerService { @Override public Impact impact() { diff --git a/src/test/java/net/openhft/chronicle/core/cooler/CoolerTesterTest.java b/src/test/java/net/openhft/chronicle/core/cooler/CoolerTesterTest.java index 97ae4e6cd1..312b5e9594 100644 --- a/src/test/java/net/openhft/chronicle/core/cooler/CoolerTesterTest.java +++ b/src/test/java/net/openhft/chronicle/core/cooler/CoolerTesterTest.java @@ -4,10 +4,11 @@ package net.openhft.chronicle.core.cooler; import org.junit.jupiter.api.Test; + import java.util.concurrent.Callable; -import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; class CoolerTesterTest { diff --git a/src/test/java/net/openhft/chronicle/core/cooler/CpuCoolersTest.java b/src/test/java/net/openhft/chronicle/core/cooler/CpuCoolersTest.java index ebea698cb8..897c42bc07 100644 --- a/src/test/java/net/openhft/chronicle/core/cooler/CpuCoolersTest.java +++ b/src/test/java/net/openhft/chronicle/core/cooler/CpuCoolersTest.java @@ -5,8 +5,8 @@ import org.junit.jupiter.api.Test; -import static org.junit.Assume.assumeFalse; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assumptions.assumeFalse; class CpuCoolersTest { diff --git a/src/test/java/net/openhft/chronicle/core/init/SystemPropertiesPrimingRunnable.java b/src/test/java/net/openhft/chronicle/core/init/SystemPropertiesPrimingRunnable.java new file mode 100644 index 0000000000..bd3139d8b6 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/core/init/SystemPropertiesPrimingRunnable.java @@ -0,0 +1,18 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +package net.openhft.chronicle.core.init; + +import net.openhft.chronicle.core.Jvm; + +import static org.junit.Assert.assertNotNull; + +public class SystemPropertiesPrimingRunnable implements Runnable { + @Override + public void run() { + String path = System.getProperty("chronicle.init.test.systemPropertiesPath"); + assertNotNull("chronicle.init.test.systemPropertiesPath must be provided", path); + System.setProperty(Jvm.SYSTEM_PROPERTIES, path); + } +} + diff --git a/src/test/java/net/openhft/chronicle/core/init/SystemPropertiesProbeMain.java b/src/test/java/net/openhft/chronicle/core/init/SystemPropertiesProbeMain.java new file mode 100644 index 0000000000..c930f260e3 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/core/init/SystemPropertiesProbeMain.java @@ -0,0 +1,23 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +package net.openhft.chronicle.core.init; + +import net.openhft.chronicle.core.Jvm; + +public final class SystemPropertiesProbeMain { + private SystemPropertiesProbeMain() { + } + + public static void main(String[] args) { + // triggers Jvm class initialisation which loads system.properties + Jvm.init(); + String value = System.getProperty("chronicle.init.test.flag"); + if (value == null) { + System.err.println("chronicle.init.test.flag missing"); + System.exit(2); + } + System.out.println(value); + } +} + diff --git a/src/test/java/net/openhft/chronicle/core/internal/ClassUtilExtraTest.java b/src/test/java/net/openhft/chronicle/core/internal/ClassUtilExtraTest.java index 918bc2edaf..85e6ab57ac 100644 --- a/src/test/java/net/openhft/chronicle/core/internal/ClassUtilExtraTest.java +++ b/src/test/java/net/openhft/chronicle/core/internal/ClassUtilExtraTest.java @@ -3,6 +3,7 @@ */ package net.openhft.chronicle.core.internal; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import org.junit.jupiter.api.Test; import java.lang.reflect.Field; @@ -12,15 +13,6 @@ class ClassUtilExtraTest { - private static class Parent { - @SuppressWarnings("unused") - private int hidden = 42; - @SuppressWarnings("unused") - private String greet() { return "hi"; } - } - - private static class Child extends Parent { } - @Test void getField0FindsPrivateFieldInHierarchy() { Field f = ClassUtil.getField0(Child.class, "hidden", true, true); @@ -45,5 +37,19 @@ void getMethod0FindsPrivateMethodInHierarchy() { assertNotNull(m); assertEquals("greet", m.getName()); } + + private static class Parent { + @UsedViaReflection + @SuppressWarnings({"unused", "FieldMayBeFinal"}) + private int hidden = 42; + + @SuppressWarnings("unused") + private String greet() { + return "hi"; + } + } + + private static class Child extends Parent { + } } diff --git a/src/test/java/net/openhft/chronicle/core/internal/ClassUtilSetAccessibleTest.java b/src/test/java/net/openhft/chronicle/core/internal/ClassUtilSetAccessibleTest.java index 73d872fb9b..f2a9a57d81 100644 --- a/src/test/java/net/openhft/chronicle/core/internal/ClassUtilSetAccessibleTest.java +++ b/src/test/java/net/openhft/chronicle/core/internal/ClassUtilSetAccessibleTest.java @@ -7,16 +7,11 @@ import java.lang.reflect.Method; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; class ClassUtilSetAccessibleTest { - // package-private class with a private method to trigger setAccessible branch - static class PkgClass { - @SuppressWarnings("unused") - private String greet() { return "ok"; } - } - @Test void getMethod0OnNonPublicClassMakesMethodUsable() throws Exception { Method m = ClassUtil.getMethod0(PkgClass.class, "greet", new Class[0], true); @@ -25,4 +20,12 @@ void getMethod0OnNonPublicClassMakesMethodUsable() throws Exception { String s = (String) m.invoke(new PkgClass()); assertEquals("ok", s); } + + // package-private class with a private method to trigger setAccessible branch + static class PkgClass { + @SuppressWarnings("unused") + private String greet() { + return "ok"; + } + } } diff --git a/src/test/java/net/openhft/chronicle/core/internal/CloseableUtilsEdgeTest.java b/src/test/java/net/openhft/chronicle/core/internal/CloseableUtilsEdgeTest.java index 59838c8eb8..e0449dd506 100644 --- a/src/test/java/net/openhft/chronicle/core/internal/CloseableUtilsEdgeTest.java +++ b/src/test/java/net/openhft/chronicle/core/internal/CloseableUtilsEdgeTest.java @@ -15,29 +15,19 @@ class CloseableUtilsEdgeTest { - static final class CountingCloseable implements AutoCloseable { - final AtomicInteger count; - CountingCloseable(AtomicInteger c) { this.count = c; } - @Override public void close() { count.incrementAndGet(); } - } - - static final class ThrowingCloseable implements AutoCloseable { - @Override public void close() throws Exception { throw new Exception("boom"); } - } - @Test void closeQuietlyHandlesNullArrayAndCollections() { assertDoesNotThrow(() -> Closeable.closeQuietly((Object[]) null)); List list = new ArrayList<>(); list.add(null); - list.add(new Object[] {null}); + list.add(new Object[]{null}); assertDoesNotThrow(() -> Closeable.closeQuietly(list)); } @Test void closeQuietlyClosesElementsAndIgnoresThrowers() { AtomicInteger c = new AtomicInteger(); - Object[] arr = new Object[] { + Object[] arr = new Object[]{ new CountingCloseable(c), new ThrowingCloseable(), new CountingCloseable(c) @@ -45,5 +35,24 @@ void closeQuietlyClosesElementsAndIgnoresThrowers() { assertDoesNotThrow(() -> Closeable.closeQuietly(arr)); assertEquals(2, c.get()); } -} + static final class CountingCloseable implements AutoCloseable { + final AtomicInteger count; + + CountingCloseable(AtomicInteger c) { + this.count = c; + } + + @Override + public void close() { + count.incrementAndGet(); + } + } + + static final class ThrowingCloseable implements AutoCloseable { + @Override + public void close() throws Exception { + throw new Exception("boom"); + } + } +} diff --git a/src/test/java/net/openhft/chronicle/core/internal/CpuClassTest.java b/src/test/java/net/openhft/chronicle/core/internal/CpuClassTest.java index 46afcc4bfb..6b242284bf 100644 --- a/src/test/java/net/openhft/chronicle/core/internal/CpuClassTest.java +++ b/src/test/java/net/openhft/chronicle/core/internal/CpuClassTest.java @@ -45,6 +45,6 @@ public void getCpuModelShouldReturnNonNullValue() { @Test public void getCpuModelShouldReturnNonEmptyValue() { - assertNotEquals("", CpuClass.getCpuModel(), "CPU model should not be an empty string"); + assertNotEquals("", "CPU model should not be an empty string", CpuClass.getCpuModel()); } } diff --git a/src/test/java/net/openhft/chronicle/core/internal/analytics/AnalyticsFacadeTest.java b/src/test/java/net/openhft/chronicle/core/internal/analytics/AnalyticsFacadeTest.java index 357e1c7fbe..718a856d0e 100644 --- a/src/test/java/net/openhft/chronicle/core/internal/analytics/AnalyticsFacadeTest.java +++ b/src/test/java/net/openhft/chronicle/core/internal/analytics/AnalyticsFacadeTest.java @@ -10,7 +10,8 @@ import java.util.concurrent.TimeUnit; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class AnalyticsFacadeTest extends CoreTestCommon { diff --git a/src/test/java/net/openhft/chronicle/core/internal/analytics/ReflectionProxyTest.java b/src/test/java/net/openhft/chronicle/core/internal/analytics/ReflectionProxyTest.java index eded5be723..7a8aecff14 100644 --- a/src/test/java/net/openhft/chronicle/core/internal/analytics/ReflectionProxyTest.java +++ b/src/test/java/net/openhft/chronicle/core/internal/analytics/ReflectionProxyTest.java @@ -5,30 +5,45 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; class ReflectionProxyTest { + @Test + void reflectiveProxyCanReturnProxyForFluent() { + Delegate delegate = new Delegate(); + Fluent proxy = ReflectionUtil.reflectiveProxy(Fluent.class, delegate, true); + Fluent chained = proxy.withA(7).withB("ok"); + assertSame(proxy, chained); + assertEquals("7:ok", proxy.build()); + } + interface Fluent { Fluent withA(Integer x); + Fluent withB(String y); + String build(); } static class Delegate { - Integer a; String b; - public Delegate withA(Integer x) { a = x; return this; } - public Delegate withB(String y) { b = y; return this; } - public String build() { return a + ":" + b; } - } + Integer a; + String b; - @Test - void reflectiveProxyCanReturnProxyForFluent() { - Delegate delegate = new Delegate(); - Fluent proxy = ReflectionUtil.reflectiveProxy(Fluent.class, delegate, true); - Fluent chained = proxy.withA(7).withB("ok"); - assertSame(proxy, chained); - assertEquals("7:ok", proxy.build()); + public Delegate withA(Integer x) { + a = x; + return this; + } + + public Delegate withB(String y) { + b = y; + return this; + } + + public String build() { + return a + ":" + b; + } } // Only exercise the fluent (returnProxy=true) path which is the intended usage. diff --git a/src/test/java/net/openhft/chronicle/core/internal/analytics/StandardMapsTest.java b/src/test/java/net/openhft/chronicle/core/internal/analytics/StandardMapsTest.java index 4b767d1eb1..83bb41a209 100644 --- a/src/test/java/net/openhft/chronicle/core/internal/analytics/StandardMapsTest.java +++ b/src/test/java/net/openhft/chronicle/core/internal/analytics/StandardMapsTest.java @@ -11,8 +11,6 @@ import java.util.stream.Stream; import static org.junit.Assert.*; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; public class StandardMapsTest extends CoreTestCommon { diff --git a/src/test/java/net/openhft/chronicle/core/internal/announcer/InternalAnnouncerConcurrencyTest.java b/src/test/java/net/openhft/chronicle/core/internal/announcer/InternalAnnouncerConcurrencyTest.java index 02d536b439..0103a12a91 100644 --- a/src/test/java/net/openhft/chronicle/core/internal/announcer/InternalAnnouncerConcurrencyTest.java +++ b/src/test/java/net/openhft/chronicle/core/internal/announcer/InternalAnnouncerConcurrencyTest.java @@ -31,7 +31,7 @@ void concurrentAnnounceDoesNotRaceOrThrow() throws InterruptedException { CountDownLatch done = new CountDownLatch(n); for (int i = 0; i < n; i++) { final int idx = i; - pool.submit(() -> { + pool.execute(() -> { try { start.await(); assertDoesNotThrow(() -> Announcer.announce("net.openhft", "artifact-" + (idx % 3), Collections.emptyMap())); diff --git a/src/test/java/net/openhft/chronicle/core/internal/pom/InternalPomPropertiesPresenceTest.java b/src/test/java/net/openhft/chronicle/core/internal/pom/InternalPomPropertiesPresenceTest.java index ba23e55a6f..7870dd1529 100644 --- a/src/test/java/net/openhft/chronicle/core/internal/pom/InternalPomPropertiesPresenceTest.java +++ b/src/test/java/net/openhft/chronicle/core/internal/pom/InternalPomPropertiesPresenceTest.java @@ -8,12 +8,12 @@ import java.net.URL; import java.net.URLClassLoader; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; class InternalPomPropertiesPresenceTest { @Test - void versionLoadedFromResourceAndThenCached() throws Exception { + void versionLoadedFromResourceAndThenCached() { String v1 = InternalPomProperties.version("test.group", "test-artifact"); assertEquals("1.2.3", v1); // Now hide resources via an empty TCCL and read again; cache should serve same value diff --git a/src/test/java/net/openhft/chronicle/core/internal/util/DirectBufferUtilTest.java b/src/test/java/net/openhft/chronicle/core/internal/util/DirectBufferUtilTest.java index 7b78f63b1e..7427512610 100644 --- a/src/test/java/net/openhft/chronicle/core/internal/util/DirectBufferUtilTest.java +++ b/src/test/java/net/openhft/chronicle/core/internal/util/DirectBufferUtilTest.java @@ -9,9 +9,9 @@ import java.nio.ByteBuffer; -import static org.junit.Assume.assumeTrue; import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assumptions.assumeFalse; +import static org.junit.jupiter.api.Assumptions.assumeTrue; class DirectBufferUtilTest { diff --git a/src/test/java/net/openhft/chronicle/core/io/AbstractCloseableReferenceCountedTest.java b/src/test/java/net/openhft/chronicle/core/io/AbstractCloseableReferenceCountedTest.java index e25700375e..c6a7976f6a 100644 --- a/src/test/java/net/openhft/chronicle/core/io/AbstractCloseableReferenceCountedTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/AbstractCloseableReferenceCountedTest.java @@ -39,11 +39,7 @@ public void reserve() throws IllegalStateException, IllegalArgumentException { rc.reserve(b); assertEquals(3, rc.refCount()); - try { - rc.reserve(a); - fail(); - } catch (IllegalStateException ignored) { - } + assertThrows(IllegalStateException.class, () -> rc.reserve(a)); assertEquals(3, rc.refCount()); rc.release(b); @@ -71,11 +67,7 @@ public void reserveWhenClosed() throws IllegalStateException, IllegalArgumentExc assertEquals(1, rc.refCount()); ReferenceOwner b = ReferenceOwner.temporary("b"); - try { - rc.reserve(b); - fail(); - } catch (IllegalStateException ignored) { - } + assertThrows(IllegalStateException.class, () -> rc.reserve(b)); assertEquals(1, rc.refCount()); assertFalse(rc.tryReserve(b)); @@ -85,12 +77,7 @@ public void reserveWhenClosed() throws IllegalStateException, IllegalArgumentExc assertEquals(0, rc.refCount()); assertEquals(1, rc.performRelease); - try { - rc.throwExceptionIfReleased(); - fail(); - } catch (IllegalStateException ignored) { - - } + assertThrows(IllegalStateException.class, rc::throwExceptionIfReleased); } @Override diff --git a/src/test/java/net/openhft/chronicle/core/io/AbstractCloseableTest.java b/src/test/java/net/openhft/chronicle/core/io/AbstractCloseableTest.java index 195eaaf6b0..9294853606 100644 --- a/src/test/java/net/openhft/chronicle/core/io/AbstractCloseableTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/AbstractCloseableTest.java @@ -44,7 +44,7 @@ public void throwExceptionIfClosed() throws IllegalStateException { public void warnAndCloseIfNotClosed() { Jvm.setResourceTracing(true); - Map map = Jvm.recordExceptions(); + final Map map = Jvm.recordExceptions(); MyCloseable mc = new MyCloseable(); // not recorded for now. diff --git a/src/test/java/net/openhft/chronicle/core/io/AbstractReferenceCountedTest.java b/src/test/java/net/openhft/chronicle/core/io/AbstractReferenceCountedTest.java index 3a6a5b7985..bf6c2e9c25 100644 --- a/src/test/java/net/openhft/chronicle/core/io/AbstractReferenceCountedTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/AbstractReferenceCountedTest.java @@ -7,7 +7,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; public class AbstractReferenceCountedTest extends ReferenceCountedTracerContractTest { @@ -26,11 +26,7 @@ public void reserve() throws IllegalStateException, IllegalArgumentException { rc.reserve(b); assertEquals(3, rc.refCount()); - try { - rc.reserve(a); - fail(); - } catch (IllegalStateException ignored) { - } + assertThrows(IllegalStateException.class, () -> rc.reserve(a)); assertEquals(3, rc.refCount()); rc.release(b); diff --git a/src/test/java/net/openhft/chronicle/core/io/BackgroundResourceReleaserMain.java b/src/test/java/net/openhft/chronicle/core/io/BackgroundResourceReleaserMain.java index afd3c3abe7..b8dcf8adbd 100644 --- a/src/test/java/net/openhft/chronicle/core/io/BackgroundResourceReleaserMain.java +++ b/src/test/java/net/openhft/chronicle/core/io/BackgroundResourceReleaserMain.java @@ -25,6 +25,8 @@ public static void main(String[] args) throws Throwable { case "foreground": new BackgroundResourceReleaserMain().runResourcesCleanedUpInForeground(); break; + default: + throw new IllegalArgumentException("Unknown mode: " + args[0]); } } catch (Throwable th) { th.printStackTrace(); diff --git a/src/test/java/net/openhft/chronicle/core/io/BackgroundResourceReleaserTest.java b/src/test/java/net/openhft/chronicle/core/io/BackgroundResourceReleaserTest.java index 9fc8902820..c9a2324953 100644 --- a/src/test/java/net/openhft/chronicle/core/io/BackgroundResourceReleaserTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/BackgroundResourceReleaserTest.java @@ -9,7 +9,8 @@ import net.openhft.chronicle.testframework.process.JavaProcessBuilder; import org.junit.Test; -import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Supplier; @@ -20,6 +21,12 @@ public class BackgroundResourceReleaserTest extends CoreTestCommon { private final AtomicLong closed = new AtomicLong(); private final AtomicLong released = new AtomicLong(); + private static void assertBetween(long min, long actual, long max) { + if (min <= actual && actual <= max) + return; + throw new AssertionError("Not in range " + min + " <= " + actual + " <= " + max); + } + @Test public void testResourcesCleanedUp() throws IllegalStateException { int count = 20; @@ -50,8 +57,8 @@ public void testResourcesCleanedUp() throws IllegalStateException { BackgroundResourceReleaser.releasePendingResources(); long time = System.currentTimeMillis() - start0; if (BackgroundResourceReleaser.BG_RELEASER) { - int factor = count * (Jvm.isAzulZulu() || OS.isMacOSX() ? 80 : OS.isWindows() ? 20 : 18); - assertBetween(count * 9, time, factor); + long factor = (long) count * (Jvm.isAzulZulu() || OS.isMacOSX() ? 80L : OS.isWindows() ? 20L : 18L); + assertBetween(count * 9L, time, factor); } assertEquals(count, closed.get()); assertEquals(count, released.get()); @@ -110,6 +117,35 @@ public void isOnBackgroundResourceReleaserThreadIsFalseWhenNotOnThread() { assertFalse(recorder.wasClosedInBackgroundResourceReleaserThread()); } + @Test + public void releasePendingResourcesFlushesQueuedWork() { + AtomicInteger closedCount = new AtomicInteger(); + int total = 32; + for (int i = 0; i < total; i++) { + CountingCloseable closeable = new CountingCloseable(closedCount); + BackgroundResourceReleaser.release(closeable); + } + BackgroundResourceReleaser.releasePendingResources(); + assertEquals(total, closedCount.get()); + } + + @Test + public void releasePendingResourcesReassertsInterrupt() throws InterruptedException { + AtomicBoolean interrupted = new AtomicBoolean(); + AtomicInteger closed = new AtomicInteger(); + Thread t = new Thread(() -> { + CountingCloseable closeable = new CountingCloseable(closed); + BackgroundResourceReleaser.release(closeable); + Thread.currentThread().interrupt(); + BackgroundResourceReleaser.releasePendingResources(); + interrupted.set(Thread.currentThread().isInterrupted()); + }); + t.start(); + t.join(); + assertEquals(1, closed.get()); + assertTrue(interrupted.get()); + } + private void assertValueBecomes(boolean expectedValue, Supplier supplier) { long endTime = System.currentTimeMillis() + 5_000; while (supplier.get() == null) { @@ -145,12 +181,6 @@ Boolean wasClosedInBackgroundResourceReleaserThread() { } } - private static void assertBetween(long min, long actual, long max) { - if (min <= actual && actual <= max) - return; - throw new AssertionError("Not in range " + min + " <= " + actual + " <= " + max); - } - static class WaitingCloseable extends AbstractCloseable { @Override protected boolean shouldWaitForClosed() { @@ -163,6 +193,25 @@ protected void performClose() { } } + static class CountingCloseable extends AbstractCloseable { + + private final AtomicInteger counter; + + CountingCloseable(AtomicInteger counter) { + this.counter = counter; + } + + @Override + protected boolean shouldPerformCloseInBackground() { + return true; + } + + @Override + protected void performClose() { + counter.incrementAndGet(); + } + } + class BGCloseable extends AbstractCloseable { @Override protected boolean shouldPerformCloseInBackground() { diff --git a/src/test/java/net/openhft/chronicle/core/io/CleaningRandomAccessFileTest.java b/src/test/java/net/openhft/chronicle/core/io/CleaningRandomAccessFileTest.java index ffc42172c6..703fee97b7 100644 --- a/src/test/java/net/openhft/chronicle/core/io/CleaningRandomAccessFileTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/CleaningRandomAccessFileTest.java @@ -20,6 +20,13 @@ public class CleaningRandomAccessFileTest extends CoreTestCommon { + private static int getFDs() { + if (!OS.isLinux()) + return -1; + //noinspection DataFlowIssue + return new File("/proc/self/fd").list().length; + } + @Test public void testOpenAndClose() throws IOException { File tempFile = File.createTempFile("test", "raf"); @@ -58,8 +65,9 @@ public void testFinalizeAndCleanup() throws IOException { @Test public void resourceLeak() throws IOException { File tempDir = IOTools.createTempFile("resourceLeak"); - //noinspection ResultOfMethodCallIgnored - tempDir.mkdir(); + if (!tempDir.mkdir() && !tempDir.isDirectory()) { + throw new IOException("Unable to create temp directory " + tempDir); + } int repeat = Jvm.isArm() ? 6 : OS.isWindows() ? 25 : 50; for (int j = 0; j < repeat; j++) { int files = getFDs(); @@ -88,11 +96,4 @@ public void resourceLeak() throws IOException { } IOTools.deleteDirWithFiles(tempDir); } - - private static int getFDs() { - if (!OS.isLinux()) - return -1; - //noinspection DataFlowIssue - return new File("/proc/self/fd").list().length; - } } diff --git a/src/test/java/net/openhft/chronicle/core/io/IOBenchmarkMain.java b/src/test/java/net/openhft/chronicle/core/io/IOBenchmarkMain.java index e2fe45cbe0..c3be30882c 100644 --- a/src/test/java/net/openhft/chronicle/core/io/IOBenchmarkMain.java +++ b/src/test/java/net/openhft/chronicle/core/io/IOBenchmarkMain.java @@ -3,9 +3,10 @@ */ package net.openhft.chronicle.core.io; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; +import java.nio.file.Files; + +import static java.nio.charset.StandardCharsets.UTF_8; public enum IOBenchmarkMain { ; // none @@ -13,22 +14,26 @@ public enum IOBenchmarkMain { public static void main(String[] args) throws IOException { String path = args.length > 0 ? args[0] : "."; File dir = new File(path, "deleteme"); - if (!dir.exists()) - dir.mkdir(); + if (!dir.exists() && !dir.mkdir()) + throw new IOException("Unable to create benchmark directory " + dir); int count = 0; long start = System.nanoTime(); do { - try (FileWriter fw = new FileWriter(new File(dir, "file" + count))) { + File file = new File(dir, "file" + count); + try (Writer fw = new OutputStreamWriter(Files.newOutputStream(file.toPath()), UTF_8)) { fw.write("Hello World"); count++; } } while (start + 3e9 > System.nanoTime()); for (int i = 0; i < count; i++) { - new File(dir, "file" + i).delete(); + File f = new File(dir, "file" + i); + if (!f.delete() && f.exists()) + throw new IOException("Failed to delete benchmark file " + f); } long time = System.nanoTime() - start; System.out.printf("IO Throughput %,d IO/s%n", (long) (count * 2 * 1e9 / time)); - dir.delete(); + if (!dir.delete() && dir.exists()) + throw new IOException("Failed to delete benchmark directory " + dir); } } diff --git a/src/test/java/net/openhft/chronicle/core/io/IORuntimeExceptionTest.java b/src/test/java/net/openhft/chronicle/core/io/IORuntimeExceptionTest.java index 915fa55199..2cd6d4a334 100644 --- a/src/test/java/net/openhft/chronicle/core/io/IORuntimeExceptionTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/IORuntimeExceptionTest.java @@ -43,7 +43,7 @@ void testNewIORuntimeException() { IORuntimeException runtimeClosedException = IORuntimeException.newIORuntimeException(closedException); IORuntimeException runtimeOtherException = IORuntimeException.newIORuntimeException(otherException); - assertTrue(runtimeClosedException instanceof ClosedIORuntimeException); + assertInstanceOf(ClosedIORuntimeException.class, runtimeClosedException); assertEquals(closedException, runtimeClosedException.getCause()); assertFalse(runtimeOtherException instanceof ClosedIORuntimeException); diff --git a/src/test/java/net/openhft/chronicle/core/io/IOToolsCreateDirectoriesTest.java b/src/test/java/net/openhft/chronicle/core/io/IOToolsCreateDirectoriesTest.java index 9f81cf762f..68a9352b39 100644 --- a/src/test/java/net/openhft/chronicle/core/io/IOToolsCreateDirectoriesTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/IOToolsCreateDirectoriesTest.java @@ -17,6 +17,18 @@ public class IOToolsCreateDirectoriesTest { + private static void delete(File file) throws IOException { + if (!file.exists()) + return; + File[] children = file.listFiles(); + if (children != null) { + for (File child : children) + delete(child); + } + if (!file.delete() && file.exists()) + throw new IOException("Failed to delete " + file); + } + @Test public void createDirectoriesBuildsNestedStructure() throws IOException { Path base = Files.createTempDirectory(Paths.get(OS.getTarget()), "iotools-dir-test"); @@ -43,15 +55,4 @@ public void createDirectoriesFailsWhenFileWithSameNameExists() throws IOExceptio delete(base.toFile()); } } - - private static void delete(File file) { - if (!file.exists()) - return; - File[] children = file.listFiles(); - if (children != null) { - for (File child : children) - delete(child); - } - file.delete(); - } } diff --git a/src/test/java/net/openhft/chronicle/core/io/IOToolsTempDirectoryTest.java b/src/test/java/net/openhft/chronicle/core/io/IOToolsTempDirectoryTest.java index a4864e8224..2b4df3c6b1 100644 --- a/src/test/java/net/openhft/chronicle/core/io/IOToolsTempDirectoryTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/IOToolsTempDirectoryTest.java @@ -8,13 +8,30 @@ import java.io.File; import java.io.IOException; -import java.nio.file.*; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Comparator; import static org.junit.Assert.*; public class IOToolsTempDirectoryTest { + private static void deleteRecursively(Path path) throws IOException { + if (path == null || !Files.exists(path)) + return; + Files.walk(path) + .sorted(Comparator.reverseOrder()) + .forEach(p -> { + try { + Files.deleteIfExists(p); + } catch (IOException e) { + throw new UncheckedIOException("Unable to delete " + p, e); + } + }); + } + @Test public void createTempDirectoryCreatesUniqueFolders() throws IOException { Path dir1 = IOTools.createTempDirectory("temp-test"); @@ -48,17 +65,4 @@ public void createTempFileUsesTempDirectory() throws IOException { Files.deleteIfExists(file.toPath()); } } - - private static void deleteRecursively(Path path) throws IOException { - if (path == null || !Files.exists(path)) - return; - Files.walk(path) - .sorted(Comparator.reverseOrder()) - .forEach(p -> { - try { - Files.deleteIfExists(p); - } catch (IOException ignored) { - } - }); - } } diff --git a/src/test/java/net/openhft/chronicle/core/io/IOToolsTest.java b/src/test/java/net/openhft/chronicle/core/io/IOToolsTest.java index 2f4c66bdd7..6b3bac8fb7 100644 --- a/src/test/java/net/openhft/chronicle/core/io/IOToolsTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/IOToolsTest.java @@ -11,23 +11,19 @@ import org.junit.Assume; import org.junit.Test; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; +import java.io.*; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.atomic.LongAccumulator; import java.util.stream.IntStream; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.*; public class IOToolsTest extends CoreTestCommon { @@ -46,11 +42,12 @@ public void testWriteFile() throws IOException { String testFilename = "testFile.tmp"; String testData = "Test Data"; - IOTools.writeFile(testFilename, testData.getBytes()); + byte[] encoded = testData.getBytes(UTF_8); + IOTools.writeFile(testFilename, encoded); Path path = Paths.get(testFilename); assertTrue(Files.exists(path)); - assertArrayEquals(testData.getBytes(), Files.readAllBytes(path)); + assertArrayEquals(encoded, Files.readAllBytes(path)); BackgroundResourceReleaser.releasePendingResources(); Files.deleteIfExists(path); @@ -117,11 +114,12 @@ public void testDeleteDirWithFiles() throws IOException { @Test public void testReadAsBytes() throws IOException { String testData = "Test Data"; - ByteArrayInputStream bais = new ByteArrayInputStream(testData.getBytes()); + byte[] encoded = testData.getBytes(UTF_8); + ByteArrayInputStream bais = new ByteArrayInputStream(encoded); byte[] bytes = IOTools.readAsBytes(bais); - assertArrayEquals(testData.getBytes(), bytes); + assertArrayEquals(encoded, bytes); } @Test @@ -150,7 +148,7 @@ public void readFileManyTimesByFile() throws IOException { String file = OS.getTarget() + "/readFileManyTimes.txt"; try (FileOutputStream fos = new FileOutputStream(file)) { - fos.write("Delete me\n".getBytes(StandardCharsets.UTF_8)); + fos.write("Delete me\n".getBytes(UTF_8)); } IntStream.range(0, iterations) @@ -228,9 +226,11 @@ public void cannotTurnAfileIntoADirectory() throws IOException { String path = OS.getTarget(); Path file = Paths.get(path, "test-file" + Time.uniqueId()); - file.toFile().delete(); - file.toFile().deleteOnExit(); - assertTrue(file.toFile().createNewFile()); + File asFile = file.toFile(); + if (asFile.exists() && !asFile.delete()) + throw new IOException("Cannot delete pre-existing file " + asFile); + asFile.deleteOnExit(); + assertTrue(asFile.createNewFile()); try { IOTools.createDirectories(Paths.get(file.toString(), "subdir" + Time.uniqueId())); } catch (IOException ioe) { @@ -287,7 +287,6 @@ public void connectionClosed() throws IOException { final byte[] bytes = new byte[512]; try { for (int i = 0; i < 100; i++) { -// System.out.println(i); os.write(bytes); } fail(); @@ -328,7 +327,6 @@ public void connectionClosed2() throws IOException { ss.close(); try { for (int i = 0; i < 100; i++) { -// System.out.println(i); bytes.clear(); sc.write(bytes); } @@ -360,11 +358,10 @@ public void connectionClosed3() throws IOException { } catch (IOException e) { e.printStackTrace(); } - }, "close~thread"); + }, "close~thread"); t.start(); try { for (int i = 0; i < 10000; i++) { -// System.out.println(i); bytes.clear(); final int write = sc.write(bytes); assertTrue(write > 0); @@ -406,7 +403,6 @@ public void connectionClosed4() throws IOException { t.start(); try { for (int i = 0; i < 10000; i++) { -// System.out.println(i); bytes.clear(); final int write = sc.write(bytes); assertTrue(write > 0); diff --git a/src/test/java/net/openhft/chronicle/core/io/LimitedInputStreamTest.java b/src/test/java/net/openhft/chronicle/core/io/LimitedInputStreamTest.java index 2df0abe481..8479bcbd02 100644 --- a/src/test/java/net/openhft/chronicle/core/io/LimitedInputStreamTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/LimitedInputStreamTest.java @@ -33,69 +33,74 @@ private static ByteArrayInputStream bytes(int length) { @Test void constructor_rejectsNegativeLimit() { - assertThrows(IllegalArgumentException.class, - () -> new LimitedInputStream(bytes(1), -1)); + assertThrows(IllegalArgumentException.class, () -> { + try (LimitedInputStream in = new LimitedInputStream(bytes(1), -1)) { + assertEquals(-1, in.read()); + } + }); } @Test void read_singleBytes_consumesBudgetExactly() throws IOException { - LimitedInputStream in = new LimitedInputStream(bytes(3), 3); - - assertEquals(0, in.read()); - assertEquals(1, in.read()); - assertEquals(2, in.read()); - assertEquals(-1, in.read()); // true EOF once budget is zero + try (LimitedInputStream in = new LimitedInputStream(bytes(3), 3)) { + assertEquals(0, in.read()); + assertEquals(1, in.read()); + assertEquals(2, in.read()); + assertEquals(-1, in.read()); // true EOF once budget is zero + } } @Test void read_singleByte_throwsWhenBudgetExhaustedAndDataRemains() throws IOException { - LimitedInputStream in = new LimitedInputStream(bytes(2), 1); - - assertEquals(0, in.read()); // budget used up + try (LimitedInputStream in = new LimitedInputStream(bytes(2), 1)) { + assertEquals(0, in.read()); // budget used up - IOException ex = assertThrows(IOException.class, in::read); - assertEquals("Size limit exceeded", ex.getMessage()); + IOException ex = assertThrows(IOException.class, in::read); + assertEquals("Size limit exceeded", ex.getMessage()); + } } @Test void read_bulkWithinLimit_returnsRequestedBytes() throws IOException { - LimitedInputStream in = new LimitedInputStream(bytes(10), 10); - - byte[] buf = new byte[10]; - int n = in.read(buf, 0, buf.length); - - assertEquals(10, n); - for (int i = 0; i < 10; i++) - assertEquals(i, buf[i]); - assertEquals(-1, in.read()); // budget exhausted, underlying EOF + try (LimitedInputStream in = new LimitedInputStream(bytes(10), 10)) { + byte[] buf = new byte[10]; + int n = in.read(buf, 0, buf.length); + + assertEquals(10, n); + for (int i = 0; i < 10; i++) + assertEquals(i, buf[i]); + assertEquals(-1, in.read()); // budget exhausted, underlying EOF + } } @Test void read_bulkCrossesLimit_allowedPartReadThenThrows() throws IOException { - LimitedInputStream in = new LimitedInputStream(bytes(5), 3); - byte[] buf = new byte[5]; + try (LimitedInputStream in = new LimitedInputStream(bytes(5), 3)) { + byte[] buf = new byte[5]; - int n = in.read(buf, 0, 5); // only 3 permitted - assertEquals(3, n); + int n = in.read(buf, 0, 5); // only 3 permitted + assertEquals(3, n); - IOException ex = assertThrows(IOException.class, - () -> in.read(buf, 0, 1)); - assertEquals("Size limit exceeded", ex.getMessage()); + IOException ex = assertThrows(IOException.class, + () -> in.read(buf, 0, 1)); + assertEquals("Size limit exceeded", ex.getMessage()); + } } @Test void read_zeroLengthBuffer_doesNothingAndReturnsZero() throws IOException { - LimitedInputStream in = new LimitedInputStream(bytes(1), 1); - byte[] zero = new byte[0]; + try (LimitedInputStream in = new LimitedInputStream(bytes(1), 1)) { + byte[] zero = new byte[0]; - assertEquals(0, in.read(zero, 0, 0)); - assertEquals(0, in.read()); // budget unchanged + assertEquals(0, in.read(zero, 0, 0)); + assertEquals(0, in.read()); // budget unchanged + } } @Test void read_budgetZeroAndUnderlyingEOF_returnsMinusOne() throws IOException { - LimitedInputStream in = new LimitedInputStream(bytes(0), 0); - - assertEquals(-1, in.read()); + try (LimitedInputStream in = new LimitedInputStream(bytes(0), 0)) { + assertEquals(-1, in.read()); + } } } diff --git a/src/test/java/net/openhft/chronicle/core/io/ManagedCloseableTest.java b/src/test/java/net/openhft/chronicle/core/io/ManagedCloseableTest.java index 1b8d855109..a6ca383762 100644 --- a/src/test/java/net/openhft/chronicle/core/io/ManagedCloseableTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/ManagedCloseableTest.java @@ -9,14 +9,16 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.*; -import static org.junit.jupiter.api.Assertions.*; class ManagedCloseableTest { @BeforeEach void mockitoNotSupportedOnJava21() { Assumptions.assumeTrue(Jvm.majorVersion() <= 17); } + @Test void testWarnAndCloseIfNotClosed() { ManagedCloseable closeable = spy(ManagedCloseable.class); diff --git a/src/test/java/net/openhft/chronicle/core/io/ReferenceCountedContractTest.java b/src/test/java/net/openhft/chronicle/core/io/ReferenceCountedContractTest.java index a5bdd19e7c..d6465c6351 100644 --- a/src/test/java/net/openhft/chronicle/core/io/ReferenceCountedContractTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/ReferenceCountedContractTest.java @@ -299,7 +299,6 @@ public void shouldBeAbleToAddAndRemoveListeners() { ReferenceCounted rc = createReferenceCounted(); ReferenceOwner a = ReferenceOwner.temporary("a"); - ReferenceOwner b = ReferenceOwner.temporary("b"); CounterReferenceChangeListener listener1 = new CounterReferenceChangeListener(); CounterReferenceChangeListener listener2 = new CounterReferenceChangeListener(); @@ -309,6 +308,8 @@ public void shouldBeAbleToAddAndRemoveListeners() { assertEquals(1, listener1.referenceAddedCount); assertEquals(0, listener2.referenceAddedCount); rc.addReferenceChangeListener(listener2); + + ReferenceOwner b = ReferenceOwner.temporary("b"); rc.reserve(b); assertEquals(2, listener1.referenceAddedCount); assertEquals(1, listener2.referenceAddedCount); @@ -323,6 +324,14 @@ public void shouldBeAbleToAddAndRemoveListeners() { rc.releaseLast(); } + private void getQuietly(Future future) { + try { + future.get(); + } catch (ExecutionException | InterruptedException e) { + Jvm.error().on(ReferenceCountedContractTest.class, "Exception thrown by acquirer", e); + } + } + static class CounterReferenceChangeListener implements ReferenceChangeListener { int referenceAddedCount = 0; int referenceRemovedCount = 0; @@ -344,14 +353,6 @@ public void onReferenceTransferred(ReferenceCounted referenceCounted, ReferenceO } } - private void getQuietly(Future future) { - try { - future.get(); - } catch (ExecutionException | InterruptedException e) { - Jvm.error().on(ReferenceCountedContractTest.class, "Exception thrown by acquirer", e); - } - } - private static class ResourceGetter implements Runnable { private final int id; diff --git a/src/test/java/net/openhft/chronicle/core/io/ReferenceCountedWarningsTest.java b/src/test/java/net/openhft/chronicle/core/io/ReferenceCountedWarningsTest.java index 30ddeb56ec..74c5ead62b 100644 --- a/src/test/java/net/openhft/chronicle/core/io/ReferenceCountedWarningsTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/ReferenceCountedWarningsTest.java @@ -37,9 +37,9 @@ public void onReferenceTransferred(ReferenceCounted referenceCounted, ReferenceO xfers.incrementAndGet(); } }); - ReferenceOwner A = ReferenceOwner.INIT; - ReferenceOwner B = ReferenceOwner.INIT; // for API symmetry; a second owner type is not required for counting - assertDoesNotThrow(() -> ref.reserveTransfer(A, B)); + ReferenceOwner ownerA = ReferenceOwner.INIT; + ReferenceOwner ownerB = ReferenceOwner.INIT; // for API symmetry; a second owner type is not required + assertDoesNotThrow(() -> ref.reserveTransfer(ownerA, ownerB)); assertEquals(1, xfers.get()); // cleanup ref.warnAndReleaseIfNotReleased(); diff --git a/src/test/java/net/openhft/chronicle/core/io/ReferenceCountingFuzzTest.java b/src/test/java/net/openhft/chronicle/core/io/ReferenceCountingFuzzTest.java index 6e5a58fead..ca17aae92b 100644 --- a/src/test/java/net/openhft/chronicle/core/io/ReferenceCountingFuzzTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/ReferenceCountingFuzzTest.java @@ -6,7 +6,7 @@ import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -25,7 +25,7 @@ class ReferenceCountingFuzzTest { void randomisedReserveReleaseSequence(org.junit.jupiter.api.RepetitionInfo repetitionInfo) throws ClosedIllegalStateException { TestReference ref = new TestReference(false); boolean[] hasOwner = new boolean[OWNERS.length]; - Random random = new Random(repetitionInfo.getCurrentRepetition()); + ThreadLocalRandom random = ThreadLocalRandom.current(); for (int step = 0; step < 200; step++) { int idx = random.nextInt(OWNERS.length); diff --git a/src/test/java/net/openhft/chronicle/core/io/ReferenceTracingIntegrationTest.java b/src/test/java/net/openhft/chronicle/core/io/ReferenceTracingIntegrationTest.java new file mode 100644 index 0000000000..bc6d12b434 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/core/io/ReferenceTracingIntegrationTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +package net.openhft.chronicle.core.io; + +import net.openhft.chronicle.core.StackTrace; +import net.openhft.chronicle.core.internal.ReferenceCountedUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class ReferenceTracingIntegrationTest { + + @Before + public void enableTracing() { + ReferenceCountedUtils.enableReferenceTracing(); + } + + @After + public void disableTracing() { + ReferenceCountedUtils.disableReferenceTracing(); + } + + @Test + public void leaksAreReportedWithSuppressedStackTrace() { + final SampleReference ref = new SampleReference(); + + AssertionError error = assertThrows(AssertionError.class, ReferenceCountedUtils::assertReferencesReleased); + assertEquals("Reference counted not released", error.getMessage()); + assertEquals(1, error.getSuppressed().length); + String detail = error.getSuppressed()[0].toString(); + assertTrue("stack trace should mention SampleReference", detail.contains(SampleReference.class.getSimpleName())); + + ref.warnAndReleaseIfNotReleased(); + ReferenceCountedUtils.assertReferencesReleased(); + } + + @Test + public void createdHereCapturesAllocationSite() { + SampleReference ref = new SampleReference(); + StackTrace stackTrace = ref.createdHere(); + assertNotNull("createdHere should be recorded", stackTrace); + assertTrue(stackTrace.toString().contains("SampleReference")); + + ref.releaseLast(ReferenceOwner.INIT); + ReferenceCountedUtils.assertReferencesReleased(); + } + + private static final class SampleReference extends AbstractReferenceCounted { + private boolean released; + + @Override + protected void performRelease() { + released = true; + } + + boolean released() { + return released; + } + } +} diff --git a/src/test/java/net/openhft/chronicle/core/io/VanillaReferenceCountedEdgeTest.java b/src/test/java/net/openhft/chronicle/core/io/VanillaReferenceCountedEdgeTest.java index bc5dce834b..c793051f12 100644 --- a/src/test/java/net/openhft/chronicle/core/io/VanillaReferenceCountedEdgeTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/VanillaReferenceCountedEdgeTest.java @@ -54,11 +54,21 @@ void listenersAreCalledOnAddRemove() { VanillaReferenceCounted ref = newRef(new AtomicInteger()); ReferenceChangeListener listener = new ReferenceChangeListener() { @Override - public void onReferenceAdded(ReferenceCounted referenceCounted, ReferenceOwner referenceOwner) { added.incrementAndGet(); } + public void onReferenceAdded(ReferenceCounted referenceCounted, ReferenceOwner referenceOwner) { + added.incrementAndGet(); + } + @Override - public void onReferenceRemoved(ReferenceCounted referenceCounted, ReferenceOwner referenceOwner) { removed.incrementAndGet(); } + public void onReferenceRemoved(ReferenceCounted referenceCounted, ReferenceOwner referenceOwner) { + removed.incrementAndGet(); + } + @Override - public void onReferenceTransferred(ReferenceCounted referenceCounted, ReferenceOwner from, ReferenceOwner to) { /* ignore */ } + public void onReferenceTransferred(ReferenceCounted referenceCounted, + ReferenceOwner from, + ReferenceOwner to) { + // ignore + } }; ref.addReferenceChangeListener(listener); ref.reserve(ReferenceOwner.INIT); diff --git a/src/test/java/net/openhft/chronicle/core/io/WgetTest.java b/src/test/java/net/openhft/chronicle/core/io/WgetTest.java index dd711a3f97..5d5d118c05 100644 --- a/src/test/java/net/openhft/chronicle/core/io/WgetTest.java +++ b/src/test/java/net/openhft/chronicle/core/io/WgetTest.java @@ -6,22 +6,33 @@ import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.nio.charset.StandardCharsets; - -import static org.junit.jupiter.api.Assertions.*; - -import java.io.*; +import java.io.InputStream; import java.net.URL; import java.net.URLConnection; -import java.util.concurrent.*; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import static org.junit.jupiter.api.Assertions.*; + /** * Tests for the Wget class, which provides a simple way to fetch content from URLs. */ class WgetTest { + private static java.nio.charset.Charset nullDetector(InputStream in, String contentType) { + return null; + } + + private static java.nio.charset.Charset throwingDetector(InputStream in, String contentType) { + throw new RuntimeException("boom"); + } + @Test void fetch_appends_response_body() throws IOException { String expected = "hello world"; @@ -78,7 +89,7 @@ public int read() { } @Test - void IOException_from_connection_provider_bubbles_up() { + void ioExceptionFromConnectionProviderBubblesUp() { Wget wget = new Wget.Builder() .connectionProvider(u -> { throw new IOException("boom"); @@ -118,7 +129,7 @@ public Appendable append(CharSequence csq, int s, int e) { } }; Wget wget = new Wget.Builder() - .connectionProvider(u -> new ByteArrayInputStream("x".getBytes())) + .connectionProvider(u -> new ByteArrayInputStream("x".getBytes(StandardCharsets.UTF_8))) .build(); assertThrows(IOException.class, () -> wget.fetch("http://x", broken)); } @@ -133,7 +144,7 @@ void static_url_method_rejects_oversized_url() { @Test void fetch_is_thread_safe_when_instance_is_shared() throws Exception { Wget wget = new Wget.Builder() - .connectionProvider(u -> new ByteArrayInputStream("ok".getBytes())) + .connectionProvider(u -> new ByteArrayInputStream("ok".getBytes(StandardCharsets.UTF_8))) .build(); ExecutorService pool = Executors.newFixedThreadPool(4); AtomicInteger successes = new AtomicInteger(); @@ -143,15 +154,21 @@ void fetch_is_thread_safe_when_instance_is_shared() throws Exception { if ("ok".contentEquals(sb)) successes.incrementAndGet(); return null; }; - for (int i = 0; i < 20; i++) pool.submit(task); + java.util.List> futures = new java.util.ArrayList<>(); + for (int i = 0; i < 20; i++) { + futures.add(pool.submit(task)); + } pool.shutdown(); assertTrue(pool.awaitTermination(2, TimeUnit.SECONDS)); + for (java.util.concurrent.Future future : futures) { + future.get(); + } assertEquals(20, successes.get()); } @Test void limited_stream_behaves_like_eof_after_budget() throws IOException { - byte[] data = "abc".getBytes(); + byte[] data = "abc".getBytes(StandardCharsets.UTF_8); LimitedInputStream lim = new LimitedInputStream(new ByteArrayInputStream(data), 3); ByteArrayOutputStream copy = new ByteArrayOutputStream(); for (int b; (b = lim.read()) != -1; ) copy.write(b); @@ -170,7 +187,7 @@ void zero_budget_allows_empty_body_but_blocks_data() throws IOException { assertEquals("", sb.toString()); Wget tooMuch = new Wget.Builder() - .connectionProvider(u -> new ByteArrayInputStream("x".getBytes())) + .connectionProvider(u -> new ByteArrayInputStream("x".getBytes(StandardCharsets.UTF_8))) .maxResponseBytes(0) .build(); assertThrows(IOException.class, () -> tooMuch.fetch("http://x", new StringBuilder())); @@ -195,20 +212,12 @@ void limited_stream_byte_array_path_respects_limit() throws IOException { @Test void charset_detector_exception_bubbles_up() { Wget wget = new Wget.Builder() - .connectionProvider(u -> new ByteArrayInputStream("x".getBytes())) + .connectionProvider(u -> new ByteArrayInputStream("x".getBytes(StandardCharsets.UTF_8))) .charsetDetector(WgetTest::throwingDetector) .build(); assertThrows(RuntimeException.class, () -> wget.fetch("http://x", new StringBuilder())); } - private static java.nio.charset.Charset nullDetector(InputStream in, String contentType) { - return null; - } - - private static java.nio.charset.Charset throwingDetector(InputStream in, String contentType) { - throw new RuntimeException("boom"); - } - @Test void default_provider_sets_timeouts() throws Exception { AtomicInteger seenConnect = new AtomicInteger(-1); diff --git a/src/test/java/net/openhft/chronicle/core/jitter/LongPingPongMain.java b/src/test/java/net/openhft/chronicle/core/jitter/LongPingPongMain.java deleted file mode 100644 index 5040b20e56..0000000000 --- a/src/test/java/net/openhft/chronicle/core/jitter/LongPingPongMain.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 - */ -package net.openhft.chronicle.core.jitter; - -import net.openhft.chronicle.core.util.Histogram; - -public class LongPingPongMain { - static volatile long pingTime = 0; - static volatile long pingCount = 0; - static volatile long pongCount = 0; - private static volatile boolean running = true; - - public static void main(String[] args) { - Histogram h = new Histogram(32, 7); - Thread pong = new Thread(() -> { - while (running) { - - } - }); - } -} diff --git a/src/test/java/net/openhft/chronicle/core/onoes/ChainedExceptionHandlerTest.java b/src/test/java/net/openhft/chronicle/core/onoes/ChainedExceptionHandlerTest.java index ce678cc314..e49038b40d 100644 --- a/src/test/java/net/openhft/chronicle/core/onoes/ChainedExceptionHandlerTest.java +++ b/src/test/java/net/openhft/chronicle/core/onoes/ChainedExceptionHandlerTest.java @@ -6,10 +6,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InOrder; -import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.*; -import static org.junit.jupiter.api.Assertions.*; class ChainedExceptionHandlerTest { @@ -52,7 +51,9 @@ void onWithClassShouldCallEachHandler() { @Test void onShouldCatchExceptionsFromHandlers() { - ExceptionHandler faultyHandler = (clazz, msg, thr) -> { throw new RuntimeException("Handler error"); }; + ExceptionHandler faultyHandler = (clazz, msg, thr) -> { + throw new RuntimeException("Handler error"); + }; ChainedExceptionHandler chained = new ChainedExceptionHandler(faultyHandler); // This call should not throw an exception diff --git a/src/test/java/net/openhft/chronicle/core/onoes/ExceptionHandlerFallbackTest.java b/src/test/java/net/openhft/chronicle/core/onoes/ExceptionHandlerFallbackTest.java index 5beadb5deb..dd1b62608f 100644 --- a/src/test/java/net/openhft/chronicle/core/onoes/ExceptionHandlerFallbackTest.java +++ b/src/test/java/net/openhft/chronicle/core/onoes/ExceptionHandlerFallbackTest.java @@ -10,7 +10,7 @@ import java.lang.reflect.Field; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Test for {@link Slf4jExceptionHandler} to ensure that it falls back to the default diff --git a/src/test/java/net/openhft/chronicle/core/pom/PomPropertiesTest.java b/src/test/java/net/openhft/chronicle/core/pom/PomPropertiesTest.java index f9999fb9d8..203b871fa9 100644 --- a/src/test/java/net/openhft/chronicle/core/pom/PomPropertiesTest.java +++ b/src/test/java/net/openhft/chronicle/core/pom/PomPropertiesTest.java @@ -21,7 +21,7 @@ void testCreateWithNullGroupId() { assertThrows(NullPointerException.class, () -> { try { - PomProperties.create(null, "chronicle-queue").toString(); + PomProperties.create(null, "chronicle-queue"); } catch (IllegalArgumentException iae) { throw new NullPointerException(); } @@ -33,7 +33,7 @@ void testCreateWithNullArtifactId() { assertThrows(NullPointerException.class, () -> { try { - PomProperties.create("net.openhft", null).toString(); + PomProperties.create("net.openhft", null); } catch (IllegalArgumentException iae) { throw new NullPointerException(); } diff --git a/src/test/java/net/openhft/chronicle/core/pool/ClassAliasPoolTest.java b/src/test/java/net/openhft/chronicle/core/pool/ClassAliasPoolTest.java index 62c2a387fd..12e8f3a275 100644 --- a/src/test/java/net/openhft/chronicle/core/pool/ClassAliasPoolTest.java +++ b/src/test/java/net/openhft/chronicle/core/pool/ClassAliasPoolTest.java @@ -84,6 +84,27 @@ public void forName() { assertEquals(ClassAliasPoolTest.class, CLASS_ALIASES.forName(sb)); } + @Test + public void addAliasViaStaticCompatibilityMethod() throws Exception { + boolean methodInvoked = false; + for (java.lang.reflect.Method method : ClassAliasPool.class.getDeclaredMethods()) { + if (java.lang.reflect.Modifier.isStatic(method.getModifiers()) + && void.class.equals(method.getReturnType()) + && method.isVarArgs() + && method.getParameterCount() == 1 + && method.getParameterTypes()[0] == Class[].class) { + method.invoke(null, (Object) new Class[]{ClassAliasPoolTest.class, StringInternerTest.class}); + methodInvoked = true; + break; + } + } + if (!methodInvoked) { + throw new AssertionError("Static compatibility method not found"); + } + assertEquals(ClassAliasPoolTest.class, CLASS_ALIASES.forName(ClassAliasPoolTest.class.getSimpleName())); + assertEquals(StringInternerTest.class, CLASS_ALIASES.forName(StringInternerTest.class.getSimpleName())); + } + @Test public void testClean() throws IllegalArgumentException { assertEquals("String", CLASS_ALIASES.nameFor(String.class)); diff --git a/src/test/java/net/openhft/chronicle/core/pool/ClassLookupTest.java b/src/test/java/net/openhft/chronicle/core/pool/ClassLookupTest.java index 7faabec6c1..14cd044c42 100644 --- a/src/test/java/net/openhft/chronicle/core/pool/ClassLookupTest.java +++ b/src/test/java/net/openhft/chronicle/core/pool/ClassLookupTest.java @@ -4,12 +4,14 @@ package net.openhft.chronicle.core.pool; import net.openhft.chronicle.core.util.ClassNotFoundRuntimeException; -import org.junit.jupiter.api.*; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; class ClassLookupTest { - private ClassLookup classLookup = ClassAliasPool.CLASS_ALIASES; + private final ClassLookup classLookup = ClassAliasPool.CLASS_ALIASES; @Test void testClassLookupByName() { @@ -34,7 +36,8 @@ void testImmutabilityOfWrappedInstance() { @Test void testLookupOfLambdaClass() { - Runnable lambda = () -> {}; + Runnable lambda = () -> { + }; assertThrows(IllegalArgumentException.class, () -> classLookup.nameFor(lambda.getClass())); } } diff --git a/src/test/java/net/openhft/chronicle/core/pool/ParsingCacheTest.java b/src/test/java/net/openhft/chronicle/core/pool/ParsingCacheTest.java index 62c04c0e7d..5cb84f9927 100644 --- a/src/test/java/net/openhft/chronicle/core/pool/ParsingCacheTest.java +++ b/src/test/java/net/openhft/chronicle/core/pool/ParsingCacheTest.java @@ -14,7 +14,7 @@ public class ParsingCacheTest extends CoreTestCommon { @Test - public void intern() throws Exception { + public void intern() { @NotNull ParsingCache pc = new ParsingCache<>(128, BigDecimal::new); @Nullable BigDecimal bd1 = pc.intern("1.234"); @Nullable BigDecimal bd2 = pc.intern("12.234"); diff --git a/src/test/java/net/openhft/chronicle/core/pool/StringInternerTest.java b/src/test/java/net/openhft/chronicle/core/pool/StringInternerTest.java index 3818cd35ce..f513670254 100644 --- a/src/test/java/net/openhft/chronicle/core/pool/StringInternerTest.java +++ b/src/test/java/net/openhft/chronicle/core/pool/StringInternerTest.java @@ -5,12 +5,13 @@ import net.openhft.chronicle.core.CoreTestCommon; import org.jetbrains.annotations.NotNull; -import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; public class StringInternerTest extends CoreTestCommon { + private String[] uppercase; + @Test public void testIntern() throws IllegalArgumentException { @NotNull StringInterner si = new StringInterner(128); @@ -28,12 +29,10 @@ public void testInternIndex() throws IllegalArgumentException { } } - private String[] uppercase; - /** - * an example of the StringInterner used in conjunction with the uppercase[] to cache another value + * Demonstrates using the StringInterner together with an uppercase cache. * - * @throws IllegalArgumentException + * @throws IllegalArgumentException if the interner cannot allocate entries */ @Test public void testToUppercaseInternIndex() throws IllegalArgumentException { @@ -42,7 +41,7 @@ public void testToUppercaseInternIndex() throws IllegalArgumentException { uppercase = new String[si.capacity()]; for (int i = 0; i < 100; i++) { String lowerCaseString = randomLowercaseString(); - System.out.println(lowerCaseString.toString()); + System.out.println(lowerCaseString); int index = si.index(lowerCaseString, this::changed); if (index != -1) assertEquals(lowerCaseString.toUpperCase(), uppercase[index]); diff --git a/src/test/java/net/openhft/chronicle/core/scoped/ScopedThreadLocalLifecycleTest.java b/src/test/java/net/openhft/chronicle/core/scoped/ScopedThreadLocalLifecycleTest.java index bb82f1b142..5705b1f744 100644 --- a/src/test/java/net/openhft/chronicle/core/scoped/ScopedThreadLocalLifecycleTest.java +++ b/src/test/java/net/openhft/chronicle/core/scoped/ScopedThreadLocalLifecycleTest.java @@ -19,6 +19,14 @@ class ScopedThreadLocalLifecycleTest { + private static void forceGc(WeakReference ref) { + for (int i = 0; i < 50 && ref.get() != null; i++) { + System.gc(); + Jvm.pause(50); + } + assertNull(ref.get(), "Reference should be cleared after GC"); + } + @Test void zeroCapacityIsRejected() { IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> @@ -95,27 +103,13 @@ void threadConfinementViolationIsSurfaced() throws Exception { Future future = executor.submit(resource.get()::touch); ExecutionException exception = assertThrows(ExecutionException.class, () -> future.get(5, TimeUnit.SECONDS)); - assertTrue(exception.getCause() instanceof IllegalStateException); + assertInstanceOf(IllegalStateException.class, exception.getCause()); } finally { executor.shutdownNow(); executor.awaitTermination(5, TimeUnit.SECONDS); } } - private static void acquireAndClose(ScopedThreadLocal pool) { - try (ScopedResource ignored = pool.get()) { - // scope closes immediately - } - } - - private static void forceGc(WeakReference ref) { - for (int i = 0; i < 50 && ref.get() != null; i++) { - System.gc(); - Jvm.pause(50); - } - assertNull(ref.get(), "Reference should be cleared after GC"); - } - private static final class CloseableProbe implements Closeable { private final int id; private final AtomicInteger closedCount; diff --git a/src/test/java/net/openhft/chronicle/core/shutdown/PriorityHookTest.java b/src/test/java/net/openhft/chronicle/core/shutdown/PriorityHookTest.java index 326d12db14..50358e2103 100644 --- a/src/test/java/net/openhft/chronicle/core/shutdown/PriorityHookTest.java +++ b/src/test/java/net/openhft/chronicle/core/shutdown/PriorityHookTest.java @@ -3,14 +3,22 @@ */ package net.openhft.chronicle.core.shutdown; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; import org.mockito.InOrder; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; class PriorityHookTest { + @AfterEach + void clearHook() { + PriorityHook.clear(); + } + @Test void testAddHook() { Runnable hook1 = mock(Runnable.class); diff --git a/src/test/java/net/openhft/chronicle/core/threads/CleaningThreadLocalIntegrationTest.java b/src/test/java/net/openhft/chronicle/core/threads/CleaningThreadLocalIntegrationTest.java index 9707ffcca8..54047afd1b 100644 --- a/src/test/java/net/openhft/chronicle/core/threads/CleaningThreadLocalIntegrationTest.java +++ b/src/test/java/net/openhft/chronicle/core/threads/CleaningThreadLocalIntegrationTest.java @@ -21,12 +21,30 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.UnaryOperator; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; class CleaningThreadLocalIntegrationTest { + private static void createOrphans(CleaningThreadLocal ctl, int count) throws InterruptedException { + Thread[] threads = new Thread[count]; + for (int i = 0; i < count; i++) { + threads[i] = new Thread(ctl::get, "ctl-orphan-" + i); + } + for (Thread t : threads) t.start(); + for (Thread t : threads) t.join(); + } + + private static int trackedEntryCount(CleaningThreadLocal ctl) { + try { + Field field = CleaningThreadLocal.class.getDeclaredField("nonCleaningThreadValues"); + field.setAccessible(true); + Map map = (Map) field.get(ctl); + return map == null ? 0 : map.size(); + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + @Test void cleanupNonCleaningThreadsHandlesConcurrentCallers() throws Exception { int ctls = 4; @@ -50,7 +68,7 @@ void cleanupNonCleaningThreadsHandlesConcurrentCallers() throws Exception { CountDownLatch start = new CountDownLatch(1); AtomicReference failure = new AtomicReference<>(); for (int i = 0; i < cleaners; i++) { - executor.submit(() -> { + executor.execute(() -> { try { start.await(); for (int j = 0; j < 32; j++) { @@ -113,26 +131,6 @@ void cleanupTriggersBackgroundReferenceRelease() throws Exception { assertEquals(orphans, releases.get(), "all reference-counted values should be released once"); } - private static void createOrphans(CleaningThreadLocal ctl, int count) throws InterruptedException { - Thread[] threads = new Thread[count]; - for (int i = 0; i < count; i++) { - threads[i] = new Thread(ctl::get, "ctl-orphan-" + i); - } - for (Thread t : threads) t.start(); - for (Thread t : threads) t.join(); - } - - private static int trackedEntryCount(CleaningThreadLocal ctl) { - try { - Field field = CleaningThreadLocal.class.getDeclaredField("nonCleaningThreadValues"); - field.setAccessible(true); - Map map = (Map) field.get(ctl); - return map == null ? 0 : map.size(); - } catch (ReflectiveOperationException e) { - throw new AssertionError(e); - } - } - private static final class TrackedResource { private final AtomicBoolean cleaned = new AtomicBoolean(); diff --git a/src/test/java/net/openhft/chronicle/core/threads/DelegatingEventLoopTest.java b/src/test/java/net/openhft/chronicle/core/threads/DelegatingEventLoopTest.java index d899f26a31..bfedde00e4 100644 --- a/src/test/java/net/openhft/chronicle/core/threads/DelegatingEventLoopTest.java +++ b/src/test/java/net/openhft/chronicle/core/threads/DelegatingEventLoopTest.java @@ -3,10 +3,12 @@ */ package net.openhft.chronicle.core.threads; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.*; -import static org.junit.jupiter.api.Assertions.*; class DelegatingEventLoopTest { @@ -56,7 +58,8 @@ void isClosedShouldDelegateToInner() { @Test void isStoppedShouldDelegateToInner() { - delegatingEventLoop.isStopped(); + when(innerEventLoop.isStopped()).thenReturn(true); + assertTrue(delegatingEventLoop.isStopped()); verify(innerEventLoop).isStopped(); } diff --git a/src/test/java/net/openhft/chronicle/core/threads/EventHandlerTest.java b/src/test/java/net/openhft/chronicle/core/threads/EventHandlerTest.java index e7f7174158..11049a50e5 100644 --- a/src/test/java/net/openhft/chronicle/core/threads/EventHandlerTest.java +++ b/src/test/java/net/openhft/chronicle/core/threads/EventHandlerTest.java @@ -4,13 +4,14 @@ package net.openhft.chronicle.core.threads; import net.openhft.chronicle.core.Jvm; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import java.io.Closeable; import java.io.IOException; -import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; class EventHandlerTest { @@ -19,6 +20,7 @@ class EventHandlerTest { void mockitoNotSupportedOnJava21() { Assumptions.assumeTrue(Jvm.majorVersion() <= 17); } + @Test void eventLoopShouldBeCalledWithCorrectEventLoop() { EventLoop mockEventLoop = mock(EventLoop.class); @@ -51,7 +53,7 @@ void loopFinishedShouldBeCalled() { void priorityShouldReturnMediumByDefault() { EventHandler handler = mock(EventHandler.class, CALLS_REAL_METHODS); - assertEquals(HandlerPriority.MEDIUM, handler.priority()); + Assertions.assertEquals(HandlerPriority.MEDIUM, handler.priority()); } @Test diff --git a/src/test/java/net/openhft/chronicle/core/threads/EventLoopTest.java b/src/test/java/net/openhft/chronicle/core/threads/EventLoopTest.java index a23c62fa40..e70e53de6b 100644 --- a/src/test/java/net/openhft/chronicle/core/threads/EventLoopTest.java +++ b/src/test/java/net/openhft/chronicle/core/threads/EventLoopTest.java @@ -3,9 +3,12 @@ */ package net.openhft.chronicle.core.threads; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.*; -import static org.junit.jupiter.api.Assertions.*; class EventLoopTest { diff --git a/src/test/java/net/openhft/chronicle/core/threads/InvalidEventHandlerExceptionTest.java b/src/test/java/net/openhft/chronicle/core/threads/InvalidEventHandlerExceptionTest.java index 3eca34eb05..1e36063af6 100644 --- a/src/test/java/net/openhft/chronicle/core/threads/InvalidEventHandlerExceptionTest.java +++ b/src/test/java/net/openhft/chronicle/core/threads/InvalidEventHandlerExceptionTest.java @@ -12,12 +12,15 @@ import java.io.PrintStream; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.*; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class InvalidEventHandlerExceptionTest extends CoreTestCommon { + private InvalidEventHandlerException e; + @Test public void testStandardConstructors() { String message = "Error occurred"; @@ -48,7 +51,6 @@ public void testReusableInstance() { reusableInstance.setStackTrace(new StackTraceElement[]{}); assertEquals(0, reusableInstance.getStackTrace().length); } - private InvalidEventHandlerException e; @Before public void setup() { @@ -76,7 +78,7 @@ public void write(int b) { sb.append((char) b); } }; - PrintStream ps = new PrintStream(os)) { + PrintStream ps = new PrintStream(os, true, UTF_8.name())) { e.printStackTrace(ps); } final String stackTrace = sb.toString(); diff --git a/src/test/java/net/openhft/chronicle/core/threads/ThreadDumpTest.java b/src/test/java/net/openhft/chronicle/core/threads/ThreadDumpTest.java index 2999606367..a7b2702da3 100644 --- a/src/test/java/net/openhft/chronicle/core/threads/ThreadDumpTest.java +++ b/src/test/java/net/openhft/chronicle/core/threads/ThreadDumpTest.java @@ -4,10 +4,11 @@ package net.openhft.chronicle.core.threads; import net.openhft.chronicle.core.Jvm; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assume.assumeFalse; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertThrows; class ThreadDumpTest { @@ -24,7 +25,8 @@ void testIgnoreThread() { threadDump.ignore(ignoredThreadName); // Simulate an ignored thread - Thread ignoredThread = new Thread(() -> {}, ignoredThreadName); + Thread ignoredThread = new Thread(() -> { + }, ignoredThreadName); ignoredThread.start(); threadDump.assertNoNewThreads(); @@ -40,7 +42,7 @@ void testAssertNoNewThreads() { @Test void testAssertNewThreads() { - assumeFalse(Jvm.isArm()); + Assumptions.assumeFalse(Jvm.isArm()); Thread newThread = new Thread(() -> { Jvm.pause(10000); }); diff --git a/src/test/java/net/openhft/chronicle/core/threads/ThreadLocalHelperTest.java b/src/test/java/net/openhft/chronicle/core/threads/ThreadLocalHelperTest.java index e07e498a30..0be4de9906 100644 --- a/src/test/java/net/openhft/chronicle/core/threads/ThreadLocalHelperTest.java +++ b/src/test/java/net/openhft/chronicle/core/threads/ThreadLocalHelperTest.java @@ -4,10 +4,11 @@ package net.openhft.chronicle.core.threads; import org.junit.jupiter.api.Test; + import java.lang.ref.WeakReference; import java.util.concurrent.atomic.AtomicInteger; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; class ThreadLocalHelperTest { diff --git a/src/test/java/net/openhft/chronicle/core/threads/TimerTest.java b/src/test/java/net/openhft/chronicle/core/threads/TimerTest.java index 4f2ac7689e..f42214261a 100644 --- a/src/test/java/net/openhft/chronicle/core/threads/TimerTest.java +++ b/src/test/java/net/openhft/chronicle/core/threads/TimerTest.java @@ -6,46 +6,15 @@ import net.openhft.chronicle.core.time.TimeProvider; import org.junit.Test; -import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; public class TimerTest { - private static final class FakeLoop implements EventLoop { - final List handlers = new ArrayList<>(); - @Override public String name() { return "fake"; } - @Override public void addHandler(EventHandler handler) { handlers.add(handler); } - @Override public void start() { } - @Override public void unpause() { } - @Override public void stop() { } - @Override public boolean isAlive() { return true; } - @Override public boolean isStopped() { return false; } - private boolean closed; - @Override public void close() { closed = true; handlers.clear(); } - @Override public boolean isClosed() { return closed; } - - void tickOnce() { - for (Iterator it = handlers.iterator(); it.hasNext();) { - EventHandler h = it.next(); - try { - h.action(); - } catch (InvalidEventHandlerException e) { - it.remove(); - } - } - } - } - - private static final class FakeTime implements TimeProvider { - long now; - @Override public long currentTimeMillis() { return now; } - } - @Test public void fixedRateFiresAfterInitialDelayAndPeriod() { FakeLoop loop = new FakeLoop(); @@ -53,7 +22,10 @@ public void fixedRateFiresAfterInitialDelayAndPeriod() { Timer timer = new Timer(loop, time); AtomicInteger calls = new AtomicInteger(); - VanillaEventHandler vh = () -> { calls.incrementAndGet(); return false; }; + VanillaEventHandler vh = () -> { + calls.incrementAndGet(); + return false; + }; timer.scheduleAtFixedRate(vh, 10, 5); @@ -78,7 +50,7 @@ public void fixedRateFiresAfterInitialDelayAndPeriod() { } @Test - public void scheduleOnceRemovesItselfAfterRun() throws IOException { + public void scheduleOnceRemovesItselfAfterRun() { FakeLoop loop = new FakeLoop(); FakeTime time = new FakeTime(); CancellableTimer ct = new CancellableTimer(loop, time); @@ -97,4 +69,72 @@ public void scheduleOnceRemovesItselfAfterRun() throws IOException { assertEquals(1, ran.get()); assertEquals(0, loop.handlers.size()); } + + private static final class FakeLoop implements EventLoop { + final List handlers = new ArrayList<>(); + private boolean closed; + + @Override + public String name() { + return "fake"; + } + + @Override + public void addHandler(EventHandler handler) { + handlers.add(handler); + } + + @Override + public void start() { + } + + @Override + public void unpause() { + } + + @Override + public void stop() { + } + + @Override + public boolean isAlive() { + return true; + } + + @Override + public boolean isStopped() { + return false; + } + + @Override + public void close() { + closed = true; + handlers.clear(); + } + + @Override + public boolean isClosed() { + return closed; + } + + void tickOnce() { + for (Iterator it = handlers.iterator(); it.hasNext(); ) { + EventHandler h = it.next(); + try { + h.action(); + } catch (InvalidEventHandlerException e) { + it.remove(); + } + } + } + } + + private static final class FakeTime implements TimeProvider { + long now; + + @Override + public long currentTimeMillis() { + return now; + } + } } diff --git a/src/test/java/net/openhft/chronicle/core/time/PosixTimeProviderTest.java b/src/test/java/net/openhft/chronicle/core/time/PosixTimeProviderTest.java index ed39d6ae33..17e6f99eb6 100644 --- a/src/test/java/net/openhft/chronicle/core/time/PosixTimeProviderTest.java +++ b/src/test/java/net/openhft/chronicle/core/time/PosixTimeProviderTest.java @@ -78,16 +78,16 @@ private void currentTimeMicros0() { try { if (!OS.isWindows()) - assertBetween(-5 * error, minDiff, 5 * error); - assertBetween(990, maxDiff, 1000 + 30 * error); + assertBetween(-5L * error, minDiff, 5L * error); + assertBetween(990L, maxDiff, 1000L + 30L * error); break; } catch (AssertionError e) { // do nothing } } if (!OS.isWindows()) - assertBetween(-5 * error, minDiff, 5 * error); - assertBetween(990, maxDiff, 1000 + 30 * error); + assertBetween(-5L * error, minDiff, 5L * error); + assertBetween(990L, maxDiff, 1000L + 30L * error); } @Test diff --git a/src/test/java/net/openhft/chronicle/core/time/SetTimeProviderTest.java b/src/test/java/net/openhft/chronicle/core/time/SetTimeProviderTest.java index 6ddb32c1a6..2cf53b80a3 100644 --- a/src/test/java/net/openhft/chronicle/core/time/SetTimeProviderTest.java +++ b/src/test/java/net/openhft/chronicle/core/time/SetTimeProviderTest.java @@ -7,9 +7,15 @@ import org.junit.Test; import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class SetTimeProviderTest extends CoreTestCommon { @@ -103,4 +109,59 @@ public void autoIncrement() { assertEquals(1534769584077L, tp.currentTimeMillis()); } + + @Test(expected = DateTimeParseException.class) + public void invalidTimestampFormatThrows() { + new SetTimeProvider("2018/08/20 12:53:04"); // missing T separator -> should fail + } + + @Test + public void autoIncrementIsMonotonicAcrossThreads() throws InterruptedException { + SetTimeProvider tp = new SetTimeProvider(0).autoIncrement(1, TimeUnit.MICROSECONDS); + int threads = 4; + int readsPerThread = 50; + long[] values = new long[threads * readsPerThread]; + CountDownLatch start = new CountDownLatch(1); + CountDownLatch done = new CountDownLatch(threads); + ExecutorService pool = Executors.newFixedThreadPool(threads); + for (int t = 0; t < threads; t++) { + final int threadIndex = t; + pool.execute(() -> { + try { + start.await(); + for (int i = 0; i < readsPerThread; i++) { + values[threadIndex * readsPerThread + i] = tp.currentTimeNanos(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + done.countDown(); + } + }); + } + start.countDown(); + done.await(); + pool.shutdown(); + long[] copy = Arrays.copyOf(values, values.length); + Arrays.sort(copy); + for (int i = 1; i < copy.length; i++) { + assertTrue("time not strictly increasing", copy[i] > copy[i - 1]); + } + } + + @Test + public void advanceAllowsNegativeOffsets() { + SetTimeProvider tp = new SetTimeProvider(2_000_000); + tp.advanceMillis(-1).advanceMicros(-500).advanceNanos(250); + long expected = 2_000_000 - 1_000_000 - 500_000 + 250; + assertEquals(expected, tp.currentTimeNanos()); + } + + @Test + public void currentTimeConversionUsesExactUnits() { + SetTimeProvider tp = new SetTimeProvider(123_456_789_123L); + assertEquals(123_456_789L, tp.currentTimeMicros()); + assertEquals(123_456L, tp.currentTimeMillis()); + assertEquals(123L, tp.currentTime(TimeUnit.SECONDS)); + } } diff --git a/src/test/java/net/openhft/chronicle/core/time/SystemTimeProviderTest.java b/src/test/java/net/openhft/chronicle/core/time/SystemTimeProviderTest.java index 8b011560d5..099678e6f8 100644 --- a/src/test/java/net/openhft/chronicle/core/time/SystemTimeProviderTest.java +++ b/src/test/java/net/openhft/chronicle/core/time/SystemTimeProviderTest.java @@ -11,11 +11,17 @@ import org.jetbrains.annotations.NotNull; import org.junit.Test; -import java.security.SecureRandom; +import java.util.concurrent.ThreadLocalRandom; import static org.junit.Assert.assertTrue; public class SystemTimeProviderTest extends CoreTestCommon { + static void assertBetween(long min, long actual, long max) { + if (min <= actual && actual <= max) + return; + throw new AssertionError("Not in range " + min + " <= " + actual + " <= " + max); + } + @Test public void currentTimeMicros() throws IllegalStateException { // doCurrentTimeMicros() is very flaky so that is why we retry this operation @@ -26,17 +32,12 @@ public void currentTimeMicros() throws IllegalStateException { break; } catch (Throwable t) { System.out.println("Trying to deflake flaky test: " + i); - Jvm.pause(500 + new SecureRandom().nextInt(500)); + int jitter = ThreadLocalRandom.current().nextInt(500); + Jvm.pause(500 + jitter); } } } - static void assertBetween(long min, long actual, long max) { - if (min <= actual && actual <= max) - return; - throw new AssertionError("Not in range " + min + " <= " + actual + " <= " + max); - } - private void doCurrentTimeMicros() throws IllegalStateException { @NotNull TimeProvider tp = SystemTimeProvider.INSTANCE; long minDiff = 0; @@ -76,15 +77,15 @@ private void doCurrentTimeMicros() throws IllegalStateException { } while (System.currentTimeMillis() < start + 500); try { - assertBetween(-5 * error, minDiff, 5 * error); - assertBetween(990, maxDiff, 1000 + 30 * error); + assertBetween(-5L * error, minDiff, 5L * error); + assertBetween(990L, maxDiff, 1000L + 30L * error); break; } catch (AssertionError e) { continue; } } - assertBetween(-5 * error, minDiff, 5 * error); - assertBetween(990, maxDiff, 1000 + 30 * error); + assertBetween(-5L * error, minDiff, 5L * error); + assertBetween(990L, maxDiff, 1000L + 30L * error); } @Test diff --git a/src/test/java/net/openhft/chronicle/core/time/UniqueMicroTimeProviderTest.java b/src/test/java/net/openhft/chronicle/core/time/UniqueMicroTimeProviderTest.java index 1c9a605803..ebc677a69f 100644 --- a/src/test/java/net/openhft/chronicle/core/time/UniqueMicroTimeProviderTest.java +++ b/src/test/java/net/openhft/chronicle/core/time/UniqueMicroTimeProviderTest.java @@ -45,7 +45,7 @@ public void shouldProvideUniqueTimeAcrossThreadsMillis() throws InterruptedExcep for (int j = 0; j < iterationsPerThread; j++) { // there could be a race condition for the next two methods, but it shouldn't matter for this test - setTimeProvider.advanceMicros(j * 100); + setTimeProvider.advanceMicros(j * 100L); long currentTimeMillis = timeProvider.currentTimeMillis(); threadTimeSet.add(currentTimeMillis); @@ -62,8 +62,9 @@ public void shouldProvideUniqueTimeAcrossThreadsMillis() throws InterruptedExcep latch.await(); executor.shutdown(); + long expectedMillisCount = (long) numberOfThreads * iterationsPerThread; assertEquals("All timestamps across all threads and iterations should be unique", - numberOfThreads * iterationsPerThread, allGeneratedTimestamps.size()); + expectedMillisCount, allGeneratedTimestamps.size()); } @Test @@ -100,8 +101,9 @@ public void shouldProvideUniqueTimeAcrossThreadsMicros() throws InterruptedExcep latch.await(); executor.shutdown(); + long expectedMicrosCount = (long) numberOfThreads * iterationsPerThread * factor; assertEquals("All timestamps across all threads and iterations should be unique", - numberOfThreads * iterationsPerThread * factor, allGeneratedTimestamps.size()); + expectedMicrosCount, allGeneratedTimestamps.size()); } @Test @@ -138,8 +140,9 @@ public void shouldProvideUniqueTimeAcrossThreadsNanos() throws InterruptedExcept latch.await(); executor.shutdown(); + long expectedNanosCount = (long) numberOfThreads * iterationsPerThread * factor; assertEquals("All timestamps across all threads and iterations should be unique", - numberOfThreads * iterationsPerThread * factor, allGeneratedTimestamps.size()); + expectedNanosCount, allGeneratedTimestamps.size()); } @Test diff --git a/src/test/java/net/openhft/chronicle/core/util/AbstractInvocationHandlerTest.java b/src/test/java/net/openhft/chronicle/core/util/AbstractInvocationHandlerTest.java index 0f1efce451..96d91e7a4c 100644 --- a/src/test/java/net/openhft/chronicle/core/util/AbstractInvocationHandlerTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/AbstractInvocationHandlerTest.java @@ -7,14 +7,15 @@ import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.core.io.Closeable; import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; -import org.junit.jupiter.api.BeforeEach; -import java.lang.reflect.Method; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.*; @@ -31,13 +32,10 @@ protected Object doInvoke(Object proxy, Method method, Object[] args) { public class AbstractInvocationHandlerTest extends CoreTestCommon { - private AbstractInvocationHandler handler; - private Method exampleMethod; - @BeforeEach public void setUp() throws NoSuchMethodException { - handler = new ConcreteInvocationHandler(); - exampleMethod = String.class.getMethod("length"); + AbstractInvocationHandler handler = new ConcreteInvocationHandler(); + Method exampleMethod = String.class.getMethod("length"); } @Test diff --git a/src/test/java/net/openhft/chronicle/core/util/ClassNotFoundRuntimeExceptionTest.java b/src/test/java/net/openhft/chronicle/core/util/ClassNotFoundRuntimeExceptionTest.java index 128b0aa378..44411ac9bf 100644 --- a/src/test/java/net/openhft/chronicle/core/util/ClassNotFoundRuntimeExceptionTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/ClassNotFoundRuntimeExceptionTest.java @@ -24,7 +24,7 @@ void testGetCause() { Throwable throwableCause = exception.getCause(); - assertTrue(throwableCause instanceof ClassNotFoundException); + assertInstanceOf(ClassNotFoundException.class, throwableCause); assertEquals(cause, throwableCause); } } diff --git a/src/test/java/net/openhft/chronicle/core/util/CompilerUtilsTest.java b/src/test/java/net/openhft/chronicle/core/util/CompilerUtilsTest.java index 74943fc80c..64e4606172 100644 --- a/src/test/java/net/openhft/chronicle/core/util/CompilerUtilsTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/CompilerUtilsTest.java @@ -5,15 +5,15 @@ import org.junit.jupiter.api.Test; -import static org.mockito.Mockito.*; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; class CompilerUtilsTest { @Test void defineClassShouldThrowAssertionErrorForIllegalAccessException() { ClassLoader classLoader = mock(ClassLoader.class); String className = "com.example.MyClass"; - byte[] bytes = new byte[] { /* class file bytes */ }; + byte[] bytes = new byte[]{ /* class file bytes */}; // Simulate IllegalAccessException assertThrows(AssertionError.class, () -> CompilerUtils.defineClass(classLoader, className, bytes)); @@ -23,7 +23,7 @@ void defineClassShouldThrowAssertionErrorForIllegalAccessException() { void defineClassShouldThrowAssertionErrorForInvocationTargetException() { ClassLoader classLoader = mock(ClassLoader.class); String className = "com.example.MyClass"; - byte[] bytes = new byte[] { /* class file bytes */ }; + byte[] bytes = new byte[]{ /* class file bytes */}; // Simulate InvocationTargetException assertThrows(AssertionError.class, () -> CompilerUtils.defineClass(classLoader, className, bytes)); diff --git a/src/test/java/net/openhft/chronicle/core/util/GenericReflectionTest.java b/src/test/java/net/openhft/chronicle/core/util/GenericReflectionTest.java index 85fc485dec..effef96948 100644 --- a/src/test/java/net/openhft/chronicle/core/util/GenericReflectionTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/GenericReflectionTest.java @@ -126,20 +126,20 @@ interface OverlyNestedExtendsGenericMethod extends NestedExtendsGenericMethod private interface MassivelyNestedExtendsGenericMethod extends OverlyNestedExtendsGenericMethod, OverridesGenericMethod { } - class ReturnsInteger implements Returns { + static class ReturnsInteger implements Returns { @Override public Integer ret() { return null; } } - class Returns2 { + static class Returns2 { public A ret() { return null; } } - class Returns2Double extends Returns2 { + static class Returns2Double extends Returns2 { @Override public Double ret() { return 1.0; diff --git a/src/test/java/net/openhft/chronicle/core/util/IntConditionTest.java b/src/test/java/net/openhft/chronicle/core/util/IntConditionTest.java index e5f7c8b171..2d95073feb 100644 --- a/src/test/java/net/openhft/chronicle/core/util/IntConditionTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/IntConditionTest.java @@ -85,9 +85,10 @@ public void evenPowerOfTwo() { ); } - private void test(IntCondition predicate, - IntCondition negatedPredicate, - Map.Entry... expected) { + @SafeVarargs + private final void test(IntCondition predicate, + IntCondition negatedPredicate, + Map.Entry... expected) { assertEquals(predicate.negate(), negatedPredicate); @@ -98,8 +99,9 @@ private void test(IntCondition predicate, }); } - private void test(IntCondition predicate, - Map.Entry... expected) { + @SafeVarargs + private final void test(IntCondition predicate, + Map.Entry... expected) { Arrays.stream(expected) .forEach(e -> { diff --git a/src/test/java/net/openhft/chronicle/core/util/InvocationTargetRuntimeExceptionTest.java b/src/test/java/net/openhft/chronicle/core/util/InvocationTargetRuntimeExceptionTest.java index fd908c4c94..33d29872e7 100644 --- a/src/test/java/net/openhft/chronicle/core/util/InvocationTargetRuntimeExceptionTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/InvocationTargetRuntimeExceptionTest.java @@ -3,7 +3,6 @@ */ package net.openhft.chronicle.core.util; -import org.junit.Ignore; import org.junit.Test; import java.lang.reflect.InvocationTargetException; @@ -33,7 +32,6 @@ public void testConstructorWithNonInvocationTargetException() { } @Test - @Ignore public void testConstructorWithNullCause() { InvocationTargetRuntimeException exception = new InvocationTargetRuntimeException(null); diff --git a/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsAdditionalTest.java b/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsAdditionalTest.java index 97fcdbbeb8..d23ceac426 100644 --- a/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsAdditionalTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsAdditionalTest.java @@ -13,13 +13,6 @@ public class ObjectUtilsAdditionalTest { - // --- Helpers used by conversion tests --- - public static final class WithCtor { - final String v; public WithCtor(String v) { this.v = v; } - } - public static final class WithValueOf { final String v; private WithValueOf(String v){this.v=v;} public static WithValueOf valueOf(String s){return new WithValueOf(s);} } - public static final class WithParse { final String v; private WithParse(String v){this.v=v;} public static WithParse parse(CharSequence s){return new WithParse(s.toString());} } - @Test public void booleanParsingAcceptsYesTrueAndNoFalse() { assertTrue(ObjectUtils.isTrue("t")); @@ -64,7 +57,7 @@ public void convertListToObjectArray() { @Test public void requireNonNullThrowsOnNull() { - assertThrows(NullPointerException.class, () -> ObjectUtils.requireNonNull(null)); + assertThrows(NullPointerException.class, () -> ObjectUtils.requireNonNull(null)); assertEquals("abc", ObjectUtils.requireNonNull("abc")); } @@ -73,5 +66,37 @@ public void convertNumberToBigDecimalFromNumberPath() { BigDecimal bd = (BigDecimal) ObjectUtils.convertToNumber(BigDecimal.class, 5L); assertEquals(BigDecimal.valueOf(5L), bd); } -} + // --- Helpers used by conversion tests --- + public static final class WithCtor { + final String v; + + public WithCtor(String v) { + this.v = v; + } + } + + public static final class WithValueOf { + final String v; + + private WithValueOf(String v) { + this.v = v; + } + + public static WithValueOf valueOf(String s) { + return new WithValueOf(s); + } + } + + public static final class WithParse { + final String v; + + private WithParse(String v) { + this.v = v; + } + + public static WithParse parse(CharSequence s) { + return new WithParse(s.toString()); + } + } +} diff --git a/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsConvertToTest.java b/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsConvertToTest.java index c074d788bc..dc23ad742c 100644 --- a/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsConvertToTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsConvertToTest.java @@ -51,11 +51,9 @@ static class DEnum implements CoreDynamicEnum { static final DEnum TWO = new DEnum("Two", 2); private final String name; - private final int ordinal; DEnum(String name, int ordinal) { this.name = name; - this.ordinal = ordinal; } @Override diff --git a/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsTest.java b/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsTest.java index 16148dc8b0..1f0d594f77 100644 --- a/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/ObjectUtilsTest.java @@ -21,7 +21,7 @@ public class ObjectUtilsTest extends CoreTestCommon { @SuppressWarnings("rawtypes") @Test public void testImmutable() { - for (@NotNull Class c: new Class[]{ + for (@NotNull Class c : new Class[]{ String.class, Integer.class, Date.class, @@ -30,7 +30,7 @@ public void testImmutable() { }) { assertEquals(c.getName(), ObjectUtils.Immutability.MAYBE, ObjectUtils.isImmutable(c)); } - for (@NotNull Class c: new Class[]{ + for (@NotNull Class c : new Class[]{ // StringBuilder.class, // StringBuilder implements Comparable in Java 11 ArrayList.class, HashMap.class, @@ -61,45 +61,6 @@ public void canConvertTo() { assertFalse(ObjectUtils.canConvertText(ClassWithSetter.class)); } - static class ClassWithString { - private final String s; - - ClassWithString(String s) { - this.s = s; - } - } - - static class ClassWithValueOf { - private final String s; - - ClassWithValueOf(String s) { - this.s = s; - } - - public static ClassWithValueOf valueOf(String s) { - return new ClassWithValueOf(s); - } - } - - static class ClassWithParse { - private final String s; - - ClassWithParse(String s) { - this.s = s; - } - - public static ClassWithParse parse(CharSequence s) { - return new ClassWithParse(s.toString()); - } - } - static class ClassWithSetter { - private String s; - - public void setS(String s) { - this.s = s; - } - } - @Test public void testConvert() throws IllegalStateException, IllegalArgumentException { assertEquals('1', (char) ObjectUtils.convertTo(char.class, 1)); @@ -246,7 +207,7 @@ public void sizeOfUnsupportedTypeTest() { @Test public void convertToNumberTest() { - assertEquals(Integer.valueOf(1), ObjectUtils.convertToNumber(Integer.class, "1")); + assertEquals(1, ObjectUtils.convertToNumber(Integer.class, "1")); } @Test @@ -290,14 +251,6 @@ public void implementationToUseNonInterfaceTest() { Class impl = ObjectUtils.implementationToUse(RegularClass.class); assertEquals(RegularClass.class, impl); } - // Define MyEnum or use an existing enum for testing - enum MyEnum { - MY_VALUE - } - - class ImplementingClass implements IgnoresEverything {} - private class AbstractTestClass {} - private class RegularClass {} @Test public void testDefaultValueForPrimitives() { @@ -338,4 +291,49 @@ public void testDefaultValueForUnsupportedType() { public void testDefaultValueWithNullClass() { assertNull(ObjectUtils.defaultValue(null)); } + + enum MyEnum { + MY_VALUE + } + + static class ClassWithString { + + ClassWithString(String s) { + } + } + + static class ClassWithValueOf { + + ClassWithValueOf(String s) { + } + + public static ClassWithValueOf valueOf(String s) { + return new ClassWithValueOf(s); + } + } + + static class ClassWithParse { + + ClassWithParse(String s) { + } + + public static ClassWithParse parse(CharSequence s) { + return new ClassWithParse(s.toString()); + } + } + + static class ClassWithSetter { + + public void setS(String s) { + } + } + + static class ImplementingClass implements IgnoresEverything { + } + + private static class AbstractTestClass { + } + + private static class RegularClass { + } } diff --git a/src/test/java/net/openhft/chronicle/core/util/RecordingHistogramTest.java b/src/test/java/net/openhft/chronicle/core/util/RecordingHistogramTest.java index 03273bf0fe..8e202b9cbb 100644 --- a/src/test/java/net/openhft/chronicle/core/util/RecordingHistogramTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/RecordingHistogramTest.java @@ -10,7 +10,6 @@ import org.junit.Test; import static org.junit.Assert.*; -import static org.junit.Assert.assertNotEquals; public class RecordingHistogramTest extends CoreTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/core/util/SimpleCleanerTest.java b/src/test/java/net/openhft/chronicle/core/util/SimpleCleanerTest.java index dcec3224c4..8230d23910 100644 --- a/src/test/java/net/openhft/chronicle/core/util/SimpleCleanerTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/SimpleCleanerTest.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.*; class SimpleCleanerTest { diff --git a/src/test/java/net/openhft/chronicle/core/util/StringUtilsTest.java b/src/test/java/net/openhft/chronicle/core/util/StringUtilsTest.java index 2dd421e589..62ea1ace11 100644 --- a/src/test/java/net/openhft/chronicle/core/util/StringUtilsTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/StringUtilsTest.java @@ -7,14 +7,34 @@ import net.openhft.chronicle.core.Maths; import org.junit.Test; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.function.BiFunction; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.*; public class StringUtilsTest extends CoreTestCommon { + private static void validate(BiFunction method) { + assertEquals(100, (long) method.apply("100", 10)); + assertEquals(-100, (long) method.apply("-100", 10)); + + // Lone char + NumberFormatException firstCharEx = assertThrows(NumberFormatException.class, () -> method.apply("+", 10)); + assertEquals("For input string: \"+\"", firstCharEx.getMessage()); + + // Null + NumberFormatException nullEx = assertThrows(NumberFormatException.class, () -> method.apply(null, 0)); + assertEquals("null", nullEx.getMessage()); + + // Max radix + NumberFormatException maxRadixEx = assertThrows(NumberFormatException.class, () -> method.apply("100", 37)); + assertEquals("radix 37 greater than Character.MAX_RADIX", maxRadixEx.getMessage()); + + // Min radix + NumberFormatException minRadixEx = assertThrows(NumberFormatException.class, () -> method.apply("100", 0)); + assertEquals("radix 0 less than Character.MIN_RADIX", minRadixEx.getMessage()); + } + @Test public void testIsEqualWithStringBuilderAndCharSequence() { StringBuilder sb = new StringBuilder("test"); @@ -83,7 +103,7 @@ public void testToStringMethod() { @Test public void testExtractBytesString() { String str = "test"; - byte[] expectedBytes = str.getBytes(StandardCharsets.ISO_8859_1); + byte[] expectedBytes = str.getBytes(UTF_8); assertArrayEquals(expectedBytes, StringUtils.extractBytes(str)); } @@ -95,7 +115,7 @@ public void testNewStringFromChars() { @Test public void testNewStringFromBytes() { - byte[] bytes = "test".getBytes(StandardCharsets.ISO_8859_1); + byte[] bytes = "test".getBytes(UTF_8); assertEquals("test", StringUtils.newStringFromBytes(bytes)); } @@ -148,10 +168,7 @@ public void shouldGetCharsOfString() { @Test public void shouldExtractBytesFromString() { - assertTrue( - Arrays.equals( - "foobar".getBytes(StandardCharsets.US_ASCII), - StringUtils.extractBytes("foobar"))); + assertArrayEquals("foobar".getBytes(UTF_8), StringUtils.extractBytes("foobar")); } @Test @@ -170,7 +187,7 @@ public void shouldCreateNewStringFromChars() { @Test public void shouldCreateNewStringFromBytes() { final byte[] bytes = {'A', 'B', 'C'}; - String expected = new String(bytes,StandardCharsets.ISO_8859_1); + String expected = new String(bytes, UTF_8); String actual = StringUtils.newStringFromBytes(bytes); assertEquals(expected, actual); } @@ -212,27 +229,6 @@ public void testParseLong() { validate(StringUtils::parseLong); } - private static void validate(BiFunction method) { - assertEquals(100, (long) method.apply("100", 10)); - assertEquals(-100, (long) method.apply("-100", 10)); - - // Lone char - NumberFormatException firstCharEx = assertThrows(NumberFormatException.class, () -> method.apply("+", 10)); - assertEquals("For input string: \"+\"", firstCharEx.getMessage()); - - // Null - NumberFormatException nullEx = assertThrows(NumberFormatException.class, () -> method.apply(null, 0)); - assertEquals("null", nullEx.getMessage()); - - // Max radix - NumberFormatException maxRadixEx = assertThrows(NumberFormatException.class, () -> method.apply("100", 37)); - assertEquals("radix 37 greater than Character.MAX_RADIX", maxRadixEx.getMessage()); - - // Min radix - NumberFormatException minRadixEx = assertThrows(NumberFormatException.class, () -> method.apply("100", 0)); - assertEquals("radix 0 less than Character.MIN_RADIX", minRadixEx.getMessage()); - } - @Test public void reverse() { StringBuilder stringBuilder = new StringBuilder("test"); diff --git a/src/test/java/net/openhft/chronicle/core/util/ThrowingFunctionTest.java b/src/test/java/net/openhft/chronicle/core/util/ThrowingFunctionTest.java index 85caaa0b74..47ee4d7165 100644 --- a/src/test/java/net/openhft/chronicle/core/util/ThrowingFunctionTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/ThrowingFunctionTest.java @@ -8,17 +8,22 @@ import org.junit.Test; import java.io.BufferedReader; -import java.io.FileReader; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.function.Function; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.fail; public class ThrowingFunctionTest extends CoreTestCommon { @Test - public void asFunction() throws Exception { + public void asFunction() { @NotNull Function sc = ThrowingFunction.asFunction(s -> { - try (@NotNull BufferedReader br = new BufferedReader(new FileReader(s))) { + try (@NotNull BufferedReader br = new BufferedReader( + new InputStreamReader(Files.newInputStream(Paths.get(s)), UTF_8))) { return br.readLine(); } }); diff --git a/src/test/java/net/openhft/chronicle/core/util/UnresolvedTypeTest.java b/src/test/java/net/openhft/chronicle/core/util/UnresolvedTypeTest.java index 06525ff3b5..2993b68f3f 100644 --- a/src/test/java/net/openhft/chronicle/core/util/UnresolvedTypeTest.java +++ b/src/test/java/net/openhft/chronicle/core/util/UnresolvedTypeTest.java @@ -23,7 +23,7 @@ void factoryMethodShouldCreateUnresolvedType() { String expectedTypeName = "MyType"; Type type = UnresolvedType.of(expectedTypeName); - assertTrue(type instanceof UnresolvedType); + assertInstanceOf(UnresolvedType.class, type); assertEquals(expectedTypeName, type.getTypeName()); }