@@ -15,7 +15,6 @@ import Control.Exception hiding (Handler)
15
15
import Control.Monad.Trans.Resource (register )
16
16
import Control.Monad.IO.Class
17
17
import Data.IORef
18
- import Data.Maybe (isJust )
19
18
import Data.Proxy
20
19
import GHC.TypeLits (Symbol , KnownSymbol , symbolVal )
21
20
import Servant
@@ -27,18 +26,42 @@ import qualified Data.Text as T
27
26
28
27
import System.IO.Unsafe (unsafePerformIO )
29
28
29
+ data TestResource x
30
+ = TestResourceNone
31
+ | TestResource x
32
+ | TestResourceFreed
33
+ | TestResourceError
34
+ deriving (Eq , Show )
35
+
30
36
-- Let's not write to the filesystem
31
- delayedTestRef :: IORef (Maybe String )
32
- delayedTestRef = unsafePerformIO $ newIORef Nothing
37
+ delayedTestRef :: IORef (TestResource String )
38
+ delayedTestRef = unsafePerformIO $ newIORef TestResourceNone
39
+
40
+ fromTestResource :: a -> (b -> a ) -> TestResource b -> a
41
+ fromTestResource _ f (TestResource x) = f x
42
+ fromTestResource x _ _ = x
43
+
44
+ initTestResource :: IO ()
45
+ initTestResource = writeIORef delayedTestRef TestResourceNone
46
+
47
+ writeTestResource :: String -> IO ()
48
+ writeTestResource x = modifyIORef delayedTestRef $ \ r -> case r of
49
+ TestResourceNone -> TestResource x
50
+ _ -> TestResourceError
51
+
52
+ freeTestResource :: IO ()
53
+ freeTestResource = modifyIORef delayedTestRef $ \ r -> case r of
54
+ TestResource _ -> TestResourceFreed
55
+ _ -> TestResourceError
33
56
34
57
delayed :: DelayedIO () -> RouteResult (Handler () ) -> Delayed () (Handler () )
35
58
delayed body srv = Delayed
36
59
{ capturesD = \ _ -> return ()
37
60
, methodD = return ()
38
61
, authD = return ()
39
62
, bodyD = do
40
- liftIO (writeIORef delayedTestRef ( Just " hia" ) >> putStrLn " garbage created" )
41
- _ <- register (writeIORef delayedTestRef Nothing >> putStrLn " garbage collected" )
63
+ liftIO (writeTestResource " hia" >> putStrLn " garbage created" )
64
+ _ <- register (freeTestResource >> putStrLn " garbage collected" )
42
65
body
43
66
, serverD = \ () () _body _req -> srv
44
67
}
@@ -59,14 +82,14 @@ simpleRun d = fmap (either ignoreE id) . try $
59
82
data Res (sym :: Symbol )
60
83
61
84
instance (KnownSymbol sym , HasServer api ctx ) => HasServer (Res sym :> api ) ctx where
62
- type ServerT (Res sym :> api ) m = IORef (Maybe String ) -> ServerT api m
85
+ type ServerT (Res sym :> api ) m = IORef (TestResource String ) -> ServerT api m
63
86
route Proxy ctx server = route (Proxy :: Proxy api ) ctx $
64
87
server `addBodyCheck` check
65
88
where
66
89
sym = symbolVal (Proxy :: Proxy sym )
67
90
check = do
68
- liftIO $ writeIORef delayedTestRef ( Just sym)
69
- _ <- register (writeIORef delayedTestRef Nothing )
91
+ liftIO $ writeTestResource sym
92
+ _ <- register freeTestResource
70
93
return delayedTestRef
71
94
72
95
type ResApi = " foobar" :> Res " foobar" :> Get '[PlainText ] T. Text
@@ -75,7 +98,7 @@ resApi :: Proxy ResApi
75
98
resApi = Proxy
76
99
77
100
resServer :: Server ResApi
78
- resServer ref = liftIO $ fmap (maybe " <empty >" T. pack) $ readIORef ref
101
+ resServer ref = liftIO $ fmap (fromTestResource " <wrong >" T. pack) $ readIORef ref
79
102
80
103
-------------------------------------------------------------------------------
81
104
-- Spec
@@ -85,25 +108,30 @@ spec :: Spec
85
108
spec = do
86
109
describe " Delayed" $ do
87
110
it " actually runs clean up actions" $ do
111
+ liftIO initTestResource
88
112
_ <- simpleRun $ delayed (return () ) (Route $ return () )
89
- cleanUpDone <- isJust <$> readIORef delayedTestRef
90
- cleanUpDone `shouldBe` False
113
+ res <- readIORef delayedTestRef
114
+ res `shouldBe` TestResourceFreed
91
115
it " even with exceptions in serverD" $ do
116
+ liftIO initTestResource
92
117
_ <- simpleRun $ delayed (return () ) (Route $ throw DivideByZero )
93
- cleanUpDone <- isJust <$> readIORef delayedTestRef
94
- cleanUpDone `shouldBe` False
118
+ res <- readIORef delayedTestRef
119
+ res `shouldBe` TestResourceFreed
95
120
it " even with routing failure in bodyD" $ do
121
+ liftIO initTestResource
96
122
_ <- simpleRun $ delayed (delayedFailFatal err500) (Route $ return () )
97
- cleanUpDone <- isJust <$> readIORef delayedTestRef
98
- cleanUpDone `shouldBe` False
123
+ res <- readIORef delayedTestRef
124
+ res `shouldBe` TestResourceFreed
99
125
it " even with exceptions in bodyD" $ do
126
+ liftIO initTestResource
100
127
_ <- simpleRun $ delayed (liftIO $ throwIO DivideByZero ) (Route $ return () )
101
- cleanUpDone <- isJust <$> readIORef delayedTestRef
102
- cleanUpDone `shouldBe` False
128
+ res <- readIORef delayedTestRef
129
+ res `shouldBe` TestResourceFreed
103
130
describe " ResApi" $
104
131
with (return $ serve resApi resServer) $ do
105
132
it " writes and cleanups resources" $ do
133
+ liftIO initTestResource
106
134
request " GET" " foobar" [] " " `shouldRespondWith` " foobar"
107
135
liftIO $ do
108
- cleanUpDone <- isJust <$> readIORef delayedTestRef
109
- cleanUpDone `shouldBe` False
136
+ res <- readIORef delayedTestRef
137
+ res `shouldBe` TestResourceFreed
0 commit comments