diff options
author | Gregor Kleen <gkleen@yggdrasil.li> | 2016-02-25 21:16:11 +0000 |
---|---|---|
committer | Gregor Kleen <gkleen@yggdrasil.li> | 2016-02-25 21:16:11 +0000 |
commit | 0c68925e930102686ca795970d2f1fe654acbec4 (patch) | |
tree | 695331a6740e5a4ae55a0646eea226c76a237638 /server | |
parent | b080366f035d24ec481ec6fc46e18f552508d22c (diff) | |
download | thermoprint-0c68925e930102686ca795970d2f1fe654acbec4.tar thermoprint-0c68925e930102686ca795970d2f1fe654acbec4.tar.gz thermoprint-0c68925e930102686ca795970d2f1fe654acbec4.tar.bz2 thermoprint-0c68925e930102686ca795970d2f1fe654acbec4.tar.xz thermoprint-0c68925e930102686ca795970d2f1fe654acbec4.zip |
Catch early death of server thread during testing
Diffstat (limited to 'server')
-rw-r--r-- | server/test/Thermoprint/ServerSpec.hs | 23 | ||||
-rw-r--r-- | server/thermoprint-server.cabal | 1 | ||||
-rw-r--r-- | server/thermoprint-server.nix | 23 |
3 files changed, 31 insertions, 16 deletions
diff --git a/server/test/Thermoprint/ServerSpec.hs b/server/test/Thermoprint/ServerSpec.hs index deb2b9c..028ba2d 100644 --- a/server/test/Thermoprint/ServerSpec.hs +++ b/server/test/Thermoprint/ServerSpec.hs | |||
@@ -31,6 +31,10 @@ import Database.Persist.Sqlite | |||
31 | import Control.Concurrent | 31 | import Control.Concurrent |
32 | import Control.Concurrent.STM | 32 | import Control.Concurrent.STM |
33 | import Control.Concurrent.STM.TSem | 33 | import Control.Concurrent.STM.TSem |
34 | import Control.Concurrent.Async | ||
35 | |||
36 | import Control.Exception | ||
37 | import System.IO.Error | ||
34 | 38 | ||
35 | import System.IO | 39 | import System.IO |
36 | import System.IO.Temp | 40 | import System.IO.Temp |
@@ -63,7 +67,8 @@ data TestManager = TestManager | |||
63 | 67 | ||
64 | data RunningServer = RunningServer | 68 | data RunningServer = RunningServer |
65 | { thread :: ThreadId | 69 | { thread :: ThreadId |
66 | , termination :: QSem | 70 | , termination :: MVar (Either SomeException ()) |
71 | , startup :: QSem | ||
67 | , printer :: TestPrinter | 72 | , printer :: TestPrinter |
68 | , manager :: TestManager | 73 | , manager :: TestManager |
69 | } | 74 | } |
@@ -72,7 +77,8 @@ setup :: QSem -> IO RunningServer | |||
72 | setup startup = withSystemTempFile "thermoprint.sqlite" $ \fp h -> hClose h >> do | 77 | setup startup = withSystemTempFile "thermoprint.sqlite" $ \fp h -> hClose h >> do |
73 | tPrinter <- TestPrinter <$> newEmptyTMVarIO <*> newEmptyTMVarIO | 78 | tPrinter <- TestPrinter <$> newEmptyTMVarIO <*> newEmptyTMVarIO |
74 | tManager <- TestManager <$> newEmptyTMVarIO <*> atomically (newTSem 0) | 79 | tManager <- TestManager <$> newEmptyTMVarIO <*> atomically (newTSem 0) |
75 | termSem <- newQSem 0 | 80 | term <- newEmptyMVar |
81 | startSem <- newQSem 0 | ||
76 | let | 82 | let |
77 | runSqlite :: ReaderT ConnectionPool (LoggingT IO) a -> IO a | 83 | runSqlite :: ReaderT ConnectionPool (LoggingT IO) a -> IO a |
78 | runSqlite = runStderrLoggingT . filterLogger (const (> LevelDebug)) . withSqlitePool (T.pack fp) 1 . runReaderT | 84 | runSqlite = runStderrLoggingT . filterLogger (const (> LevelDebug)) . withSqlitePool (T.pack fp) 1 . runReaderT |
@@ -84,7 +90,7 @@ setup startup = withSystemTempFile "thermoprint.sqlite" $ \fp h -> hClose h >> d | |||
84 | 90 | ||
85 | tPM :: MonadIO m => Printout -> m (Maybe PrintingError) | 91 | tPM :: MonadIO m => Printout -> m (Maybe PrintingError) |
86 | tPM printout = liftIO . atomically $ putTMVar (outputChan tPrinter) printout >> tryTakeTMVar (failSwitch tPrinter) | 92 | tPM printout = liftIO . atomically $ putTMVar (outputChan tPrinter) printout >> tryTakeTMVar (failSwitch tPrinter) |
87 | RunningServer <$> forkFinally (S.thermoprintServer False (Nat runSqlite) $ def' `S.withPrinters` printers) (const $ signalQSem termSem) <*> pure termSem <*> pure tPrinter <*> pure tManager | 93 | RunningServer <$> forkFinally (S.thermoprintServer False (Nat runSqlite) $ def' `S.withPrinters` printers) (putMVar term) <*> pure term <*> pure startSem <*> pure tPrinter <*> pure tManager |
88 | where | 94 | where |
89 | def' :: MonadIO m => S.Config m | 95 | def' :: MonadIO m => S.Config m |
90 | def' = S.def { S.warpSettings = setBeforeMainLoop (signalQSem startup) $ defaultSettings } | 96 | def' = S.def { S.warpSettings = setBeforeMainLoop (signalQSem startup) $ defaultSettings } |
@@ -94,8 +100,15 @@ withSetup = beforeAll setup' . afterAll teardown | |||
94 | where | 100 | where |
95 | setup' = do | 101 | setup' = do |
96 | startup <- newQSem 0 | 102 | startup <- newQSem 0 |
97 | setup startup <* waitQSem startup | 103 | r <- setup startup |
98 | teardown RunningServer{..} = killThread thread >> waitQSem termination | 104 | waitStartup <- async $ waitQSem startup |
105 | waitTermination <- async . readMVar $ termination r | ||
106 | wait <- waitEitherCancel waitTermination waitStartup | ||
107 | case wait of | ||
108 | Left (Left err) -> throwIO err | ||
109 | Left (Right _) -> throwIO $ userError "Server thread terminated early" | ||
110 | Right _ -> return r | ||
111 | teardown RunningServer{..} = killThread thread >> void (readMVar termination) | ||
99 | 112 | ||
100 | spec :: Spec | 113 | spec :: Spec |
101 | spec = withSetup $ do | 114 | spec = withSetup $ do |
diff --git a/server/thermoprint-server.cabal b/server/thermoprint-server.cabal index f98cac1..89f636c 100644 --- a/server/thermoprint-server.cabal +++ b/server/thermoprint-server.cabal | |||
@@ -90,6 +90,7 @@ Test-Suite tests | |||
90 | , warp >=3.1.9 && <4 | 90 | , warp >=3.1.9 && <4 |
91 | , exceptions >=0.8.0 && <1 | 91 | , exceptions >=0.8.0 && <1 |
92 | , containers >=0.5.6 && <1 | 92 | , containers >=0.5.6 && <1 |
93 | , async >=2.1.0 && <3 | ||
93 | 94 | ||
94 | executable thermoprint-server | 95 | executable thermoprint-server |
95 | main-is: Main.hs | 96 | main-is: Main.hs |
diff --git a/server/thermoprint-server.nix b/server/thermoprint-server.nix index 69ecd2f..6ff8b10 100644 --- a/server/thermoprint-server.nix +++ b/server/thermoprint-server.nix | |||
@@ -1,11 +1,11 @@ | |||
1 | { mkDerivation, base, binary, bytestring, conduit, containers | 1 | { mkDerivation, async, base, binary, bytestring, conduit |
2 | , data-default-class, deepseq, dyre, either, encoding, exceptions | 2 | , containers, data-default-class, deepseq, dyre, either, encoding |
3 | , extended-reals, filelock, hspec, mmorph, monad-control | 3 | , exceptions, extended-reals, filelock, hspec, mmorph |
4 | , monad-logger, mtl, network-uri, persistent, persistent-sqlite | 4 | , monad-control, monad-logger, mtl, network-uri, persistent |
5 | , persistent-template, QuickCheck, quickcheck-instances, resourcet | 5 | , persistent-sqlite, persistent-template, QuickCheck |
6 | , servant, servant-server, stdenv, stm, temporary, text | 6 | , quickcheck-instances, resourcet, servant, servant-server, stdenv |
7 | , thermoprint-client, thermoprint-spec, time, transformers, wai | 7 | , stm, temporary, text, thermoprint-client, thermoprint-spec, time |
8 | , wai-websockets, warp, websockets | 8 | , transformers, wai, wai-websockets, warp, websockets |
9 | }: | 9 | }: |
10 | mkDerivation { | 10 | mkDerivation { |
11 | pname = "thermoprint-server"; | 11 | pname = "thermoprint-server"; |
@@ -25,9 +25,10 @@ mkDerivation { | |||
25 | base monad-logger mtl persistent-sqlite resourcet | 25 | base monad-logger mtl persistent-sqlite resourcet |
26 | ]; | 26 | ]; |
27 | testHaskellDepends = [ | 27 | testHaskellDepends = [ |
28 | base containers exceptions hspec monad-logger mtl persistent-sqlite | 28 | async base containers exceptions hspec monad-logger mtl |
29 | QuickCheck quickcheck-instances resourcet stm temporary text | 29 | persistent-sqlite QuickCheck quickcheck-instances resourcet stm |
30 | thermoprint-client thermoprint-spec transformers warp | 30 | temporary text thermoprint-client thermoprint-spec transformers |
31 | warp | ||
31 | ]; | 32 | ]; |
32 | homepage = "http://dirty-haskell.org/tags/thermoprint.html"; | 33 | homepage = "http://dirty-haskell.org/tags/thermoprint.html"; |
33 | description = "Server for thermoprint-spec"; | 34 | description = "Server for thermoprint-spec"; |