Skip to content

Commit

Permalink
Implement recordingTracerM to avoid affecting the scheduling of execu…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
facundominguez authored and nbacquey committed May 29, 2024
1 parent dbbc3ab commit 915238e
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import Test.QuickCheck
import Test.Util.Orphans.IOLike ()
import Test.Util.QuickCheck (forAllGenRunShrinkCheck)
import Test.Util.TestBlock (TestBlock)
import Test.Util.Tracer (recordingTracerTVar)
import Test.Util.Tracer (recordingTracerM)
import Text.Printf (printf)


Expand All @@ -56,7 +56,7 @@ runGenesisTest ::
RunGenesisTestResult
runGenesisTest schedulerConfig genesisTest =
runSimStrictShutdownOrThrow $ do
(recordingTracer, getTrace) <- recordingTracerTVar
(recordingTracer, getTrace) <- recordingTracerM
let tracer = if scDebug schedulerConfig then debugTracer else recordingTracer

traceLinesWith tracer $ prettyGenesisTest prettyPeersSchedule genesisTest
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Test.Util.Tracer (
recordingTracerIORef
, recordingTracerM
, recordingTracerTVar
) where

import Control.Tracer
import Data.IORef
import Ouroboros.Consensus.Util.IOLike
import System.IO.Unsafe (unsafePerformIO)

-- | Create a 'Tracer' that stores all events in an 'IORef' that is atomically
-- updated. The second return value lets you obtain the events recorded so far
Expand All @@ -24,3 +27,26 @@ recordingTracerTVar = uncheckedNewTVarM [] >>= \ref -> return
( Tracer $ \ev -> atomically $ modifyTVar ref (ev:)
, atomically $ reverse <$> readTVar ref
)

-- | Like 'recordingTracerIORef', but lifts IO to an arbitrary applicative.
-- This is useful to record events without changing the scheduling during a
-- test.
recordingTracerM :: forall m ev. Monad m => m (Tracer m ev, m [ev])
recordingTracerM = do
(tr, get) <- liftIOtoM recordingTracerIORef
pure (natTracer liftIOtoM tr, liftIOtoM get)
where
liftIOtoM :: IO a -> m a
liftIOtoM m = do
-- The ficticious state is only used to force unsafePerformIO to run @m@
-- every time @liftIOtoM m@ is evaluated.
s <- getStateM
pure $! snd $ unsafePerformIO $ do
r <- m
pure (s, r)

-- We mark this function as NOINLINE to ensure the compiler cannot reason
-- that two calls of @getStateM@ might yield the same value.
{-# NOINLINE getStateM #-}
getStateM :: m Int
getStateM = pure 0

0 comments on commit 915238e

Please sign in to comment.