0 | module Evince.Async.Shared
3 | import Data.Linear.Ref1
10 | import Evince.Reporter
12 | import Evince.Runner
13 | import Evince.Synchronized
14 | import Evince.Async.Synchronized
20 | AbortRef = Data.IORef.IORef Bool
24 | lockedReporter : Reporter (Async e []) -> Lock (Async e []) -> Reporter (Async e [])
25 | lockedReporter base lock = MkReporter (\ev => lock.withLock (base.onEvent ev))
38 | Reporter (Async e [])
39 | -> Lock (Async e [])
42 | -> List (SpecTree (Async e []) ())
43 | -> Async e [] EvalResult
44 | evalAsyncForest base lock cfg abortRef trees =
46 | Z => evalForest (lockedReporter base lock) cfg abortRef [] trees 0
48 | queue <- newref trees
49 | results <- newref emptyResult
50 | cancelled <- newref False
51 | interrupted <- newref False
52 | registry <- newref (the (List (Nat, Fiber [] ())) [])
53 | let idxs = workerIds (min (S k) (length trees))
54 | fibs <- traverse (\i => start (worker queue results cancelled registry interrupted i)) idxs
55 | writeref registry (zip idxs fibs)
57 | unclaimed <- readref queue
58 | cut <- readref interrupted
59 | when (cut || not (null unclaimed)) (lock.withLock (base.onEvent SuiteAborted))
62 | workerIds : Nat -> List Nat
64 | workerIds (S m) = [0 .. m]
66 | toSummary : TestReport -> Summary
67 | toSummary rep = case rep.outcome of
68 | Passed d => MkSummary 1 0 0 d
69 | Failed _ d => MkSummary 0 1 0 d
70 | Skipped _ => MkSummary 0 0 1 0
74 | partialResult : List Event -> EvalResult
76 | let reps = mapMaybe (\case TestDone rep _ => Just rep;
_ => Nothing) evs
77 | in (foldMap toSummary reps, Lin <>< reps)
79 | deposit : Ref World EvalResult -> EvalResult -> Async e [] ()
80 | deposit results r = runIO $
casupdate1 results (\acc => (mergeResults acc r, ()))
82 | runGroup : Ref World EvalResult -> Ref World Bool -> SpecTree (Async e []) () -> Async e [] ()
83 | runGroup results interrupted t = do
84 | buf <- liftIO (newIORef (the (SnocList Event) [<]))
85 | done <- liftIO (newIORef False)
86 | let buffered = MkReporter (\ev => liftIO (modifyIORef buf (:< ev)))
87 | flush : Async e [] (List Event)
89 | evs <- liftIO (readIORef buf)
91 | lock.withLock (traverse_ base.onEvent l)
94 | (do r <- evalTree buffered cfg abortRef [] t 0
98 | uncancelable $
\_ => do
101 | liftIO (writeIORef done True))
105 | (do d <- liftIO (readIORef done)
107 | writeref interrupted True
109 | deposit results (partialResult evs))
111 | claim : Ref World (List (SpecTree (Async e []) ())) -> Async e [] (Maybe (SpecTree (Async e []) ()))
112 | claim queue = runIO $
casupdate1 queue $
\case
113 | [] => ([], Nothing)
114 | (t :: ts) => (ts, Just t)
117 | Ref World (List (SpecTree (Async e []) ()))
118 | -> Ref World EvalResult
120 | -> Ref World (List (Nat, Fiber [] ()))
124 | worker queue results cancelled registry interrupted me = loop
127 | cancelSiblings : Async e [] ()
128 | cancelSiblings = do
129 | won <- runIO (caswrite1 cancelled False True)
131 | fibs <- readref registry
132 | traverse_ (\(i, f) => when (i /= me) (cancel f)) fibs
134 | loop : Async e [] ()
136 | stop <- liftIO (readIORef abortRef)
137 | if stop then cancelSiblings else do
138 | Just t <- claim queue
139 | | Nothing => pure ()
140 | runGroup results interrupted t
141 | st <- liftIO (readIORef abortRef)
142 | if st then cancelSiblings else loop
151 | -> (Async e [] () -> IO ())
153 | -> Spec (Async e []) () ()
155 | runResultVia runLoop cfg spec = do
156 | out <- newIORef (the (Maybe EvalResult) Nothing)
158 | base <- makeReporter cfg
159 | lock <- liftIO newLock
160 | result <- runForestWith (lockedReporter base lock)
161 | (\ref, ts => evalAsyncForest base lock cfg ref ts)
162 | cfg (getSpecTrees spec)
163 | liftIO (writeIORef out (Just result))
164 | Just r <- readIORef out
165 | | Nothing => die "evince: the event loop ended before the suite completed"
171 | runSpecVia : {e : Type} -> (Async e [] () -> IO ()) -> RunConfig -> Spec (Async e []) () () -> IO ()
172 | runSpecVia runLoop cfg spec = do
173 | (summary, reports) <- runResultVia runLoop cfg spec
174 | writeFailures (failedPaths reports)
175 | when (summary.failed > 0) exitFailure
179 | summaryVia : {e : Type} -> (Async e [] () -> IO ()) -> RunConfig -> Spec (Async e []) () () -> IO Summary
180 | summaryVia runLoop cfg spec = fst <$> runResultVia runLoop cfg spec
185 | runSpecArgsVia : {e : Type} -> (Async e [] () -> IO ()) -> Spec (Async e []) () () -> IO ()
186 | runSpecArgsVia runLoop spec = do
188 | cfg <- handleArgs (drop 1 args)
189 | runSpecVia runLoop cfg spec
193 | runSpecFailFastVia : {e : Type} -> (Async e [] () -> IO ()) -> Spec (Async e []) () () -> IO ()
194 | runSpecFailFastVia runLoop = runSpecVia runLoop ({ failFast := True } defaultConfig)
198 | runSpecTimedVia : {e : Type} -> (Async e [] () -> IO ()) -> Spec (Async e []) () () -> IO ()
199 | runSpecTimedVia runLoop = runSpecVia runLoop ({ showTiming := True } defaultConfig)