packages feed

reserve-0.1.2: test/ReserveSpec.hs

{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}
module ReserveSpec (spec) where

import           Helper

import qualified Data.ByteString.Lazy.Char8 as L
import           Control.Exception
import           Control.Concurrent
import           Network.Socket
import           Network.Socket.ByteString (sendAll)
import           Data.Streaming.Network (getSocketTCP)
import           Network.HTTP.Conduit
import           Data.String.Interpolate

import           Options
import           Reserve

appWithResponse :: String -> IO ()
appWithResponse response = writeFile "app.hs" [i|
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where

import Network.Wai
import Network.HTTP.Types
import Network.Wai.Handler.Warp (run)
import qualified Data.ByteString.Lazy.Char8 as B

app :: Application
app _ = ($ responseLBS status200 [("Content-Type", "text/plain")] #{response})

main :: IO ()
main = run 3000 app
|]

literal :: String -> String
literal = show

withServer :: IO () -> IO ()
withServer action = inTempDirectory $ do
  appWithResponse (literal "hello")
  mvar <- newEmptyMVar
  bracket (runReserve mvar) killThread (const $ yield >> action)
  takeMVar mvar
  where
    runReserve mvar = forkIO $ run defaultOptions {optionsMainIs = "app.hs"} `finally` putMVar mvar ()

spec :: Spec
spec = around_ withServer $ do
  describe "run" $ do
    it "runs app" $ do
      simpleHttp "http://localhost:12000/" `shouldReturn` "hello"

    it "reloads app" $ do
      simpleHttp "http://localhost:12000/" `shouldReturn` "hello"
      appWithResponse (literal "foo")
      simpleHttp "http://localhost:12000/" `shouldReturn` "foo"

    it "can deal with large response bodies" $ do
      appWithResponse [i|(B.take 100000 $ B.cycle #{literal "foo bar baz\n"})|]
      simpleHttp "http://localhost:12000/large-response" `shouldReturn` (L.take 100000 $ L.cycle "foo bar baz\n")

    context "when client closes connection early" $ do
      it "ignores that client" $ do
        (sock, _) <- getSocketTCP "localhost" 12000
        sendAll sock "GET / HTTP/1.1\r\n\r\n"
        close sock
        simpleHttp "http://localhost:12000/" `shouldReturn` "hello"