aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2016-02-25 21:16:11 +0000
committerGregor Kleen <gkleen@yggdrasil.li>2016-02-25 21:16:11 +0000
commit0c68925e930102686ca795970d2f1fe654acbec4 (patch)
tree695331a6740e5a4ae55a0646eea226c76a237638
parentb080366f035d24ec481ec6fc46e18f552508d22c (diff)
downloadthermoprint-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
-rw-r--r--server/test/Thermoprint/ServerSpec.hs23
-rw-r--r--server/thermoprint-server.cabal1
-rw-r--r--server/thermoprint-server.nix23
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
31import Control.Concurrent 31import Control.Concurrent
32import Control.Concurrent.STM 32import Control.Concurrent.STM
33import Control.Concurrent.STM.TSem 33import Control.Concurrent.STM.TSem
34import Control.Concurrent.Async
35
36import Control.Exception
37import System.IO.Error
34 38
35import System.IO 39import System.IO
36import System.IO.Temp 40import System.IO.Temp
@@ -63,7 +67,8 @@ data TestManager = TestManager
63 67
64data RunningServer = RunningServer 68data 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
72setup startup = withSystemTempFile "thermoprint.sqlite" $ \fp h -> hClose h >> do 77setup 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
100spec :: Spec 113spec :: Spec
101spec = withSetup $ do 114spec = 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
94executable thermoprint-server 95executable 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}:
10mkDerivation { 10mkDerivation {
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";