From c1bcc63e631c18deaf492c63e634e6cb759d3650 Mon Sep 17 00:00:00 2001 From: oh-yes-0-fps Date: Wed, 25 Sep 2024 21:40:19 -0400 Subject: [PATCH] added some more unit tests to java --- .../java/edu/wpi/first/wpilibj/Tracer.java | 18 ++- .../edu/wpi/first/wpilibj/TracerTest.java | 107 +++++++++++++++++- 2 files changed, 117 insertions(+), 8 deletions(-) diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Tracer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Tracer.java index facaac83465..8ccf2e48066 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Tracer.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Tracer.java @@ -87,7 +87,7 @@ private static final class TracerState { * If the cycle is poisened, it will warn the user * and not publish any data. */ - boolean m_cyclePoisened = false; + boolean m_cyclePoisoned = false; /** If the tracer is disabled, it will not publish any data or do any string manipulation. */ boolean m_disabled = false; @@ -150,8 +150,8 @@ private String popTraceStack() { if (m_disabled) { return ""; } - if (m_traceStack.isEmpty() || m_traceStackHistory.isEmpty() || m_cyclePoisened) { - m_cyclePoisened = true; + if (m_traceStack.isEmpty() || m_traceStackHistory.isEmpty() || m_cyclePoisoned) { + m_cyclePoisoned = true; return ""; } m_traceStack.remove(m_traceStack.size() - 1); @@ -167,7 +167,7 @@ private double totalGCTime() { } private void endCycle() { - if (m_disabled != m_disableNextCycle || m_cyclePoisened) { + if (m_disabled != m_disableNextCycle || m_cyclePoisoned) { // Gives publishers empty times, // reporting no data is better than bad data for (var publisher : m_publishers.entrySet()) { @@ -345,6 +345,16 @@ public static R traceFunc(String name, Supplier supplier) { return ret; } + /** + * This function is only to be used in tests + * and is package private to prevent misuse. + */ + static void resetForTest() { + threadLocalState.remove(); + singleThreadedMode.set(false); + anyTracesStarted.set(false); + } + // A REIMPLEMENTATION OF THE OLD TRACER TO NOT BREAK OLD CODE private static final long kMinPrintPeriod = 1000000; // microseconds diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/TracerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/TracerTest.java index 52c69e7f09d..d3f5b08f647 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/TracerTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/TracerTest.java @@ -5,6 +5,7 @@ package edu.wpi.first.wpilibj; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import edu.wpi.first.hal.HAL; import edu.wpi.first.networktables.DoubleEntry; @@ -20,6 +21,7 @@ class TracerTest { void setup() { HAL.initialize(500, 0); SimHooks.pauseTiming(); + Tracer.resetForTest(); } @AfterEach @@ -33,21 +35,118 @@ void traceFuncTest() { final String threadName = Thread.currentThread().getName(); Tracer.disableGcLoggingForCurrentThread(); - Tracer.startTrace("Test1"); - Tracer.traceFunc("Test2", () -> SimHooks.stepTiming(0.4)); + Tracer.startTrace("FuncTest1"); + Tracer.traceFunc("FuncTest2", () -> SimHooks.stepTiming(0.4)); SimHooks.stepTiming(0.1); Tracer.endTrace(); DoubleEntry test1Entry = NetworkTableInstance.getDefault() - .getDoubleTopic("/Tracer/" + threadName + "/Test1") + .getDoubleTopic("/Tracer/" + threadName + "/FuncTest1") .getEntry(0.0); DoubleEntry test2Entry = NetworkTableInstance.getDefault() - .getDoubleTopic("/Tracer/" + threadName + "/Test1/Test2") + .getDoubleTopic("/Tracer/" + threadName + "/FuncTest1/FuncTest2") .getEntry(0.0); assertEquals(500.0, test1Entry.get(), 1.0); assertEquals(400.0, test2Entry.get(), 1.0); } + + @Test + @ResourceLock("timing") + void traceThreadTest() { + final String threadName = Thread.currentThread().getName(); + + Tracer.disableGcLoggingForCurrentThread(); + + // run a trace in the main thread, assert that the tracer ran + { + Tracer.startTrace("ThreadTest1"); + SimHooks.stepTiming(0.1); + Tracer.endTrace(); + + DoubleEntry test1Entry = + NetworkTableInstance.getDefault() + .getDoubleTopic("/Tracer/" + threadName + "/ThreadTest1") + .getEntry(0.0); + assertEquals(100.0, test1Entry.get(), 1.0); + } + + // run a trace in a new thread, assert that the tracer ran + // and that the output position and value are correct + { + final String newThreadName = "TestThread"; + try { + Thread thread = new Thread( + () -> { + Tracer.disableGcLoggingForCurrentThread(); + Tracer.startTrace("ThreadTest1"); + SimHooks.stepTiming(0.4); + Tracer.endTrace(); + }, + newThreadName + ); + thread.start(); + thread.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + DoubleEntry test2Entry = + NetworkTableInstance.getDefault() + .getDoubleTopic("/Tracer/" + newThreadName + "/ThreadTest1") + .getEntry(0.0); + assertEquals(400.0, test2Entry.get(), 1.0); + } + } + + @Test + @ResourceLock("timing") + void traceSingleThreadTest() { + final String newThreadName = "TestThread"; + + // start a trace in the main thread, assert that the tracer ran + // and that the thread name is not in the trace path + { + Tracer.enableSingleThreadedMode(); + Tracer.disableGcLoggingForCurrentThread(); + + Tracer.startTrace("SingleThreadTest1"); + SimHooks.stepTiming(0.1); + Tracer.endTrace(); + + DoubleEntry test1Entry = NetworkTableInstance.getDefault() + .getDoubleTopic("/Tracer/SingleThreadTest1") + .getEntry(0.0); + assertEquals(100.0, test1Entry.get(), 1.0); + } + + // start a trace in a new thread after enabling single threaded mode, + // this should disable the tracer on the new thread, assert that the tracer did not run + { + try { + Thread thread = new Thread( + () -> { + Tracer.disableGcLoggingForCurrentThread(); + Tracer.startTrace("SingleThreadTest1"); + SimHooks.stepTiming(0.4); + Tracer.endTrace(); + }, + newThreadName + ); + thread.start(); + thread.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + boolean test2EntryExists = + NetworkTableInstance.getDefault() + .getDoubleTopic("/Tracer/" + newThreadName + "/SingleThreadTest1") + .exists(); + + assertTrue(!test2EntryExists); + } + } }