packages feed

natskell-0.0.0.1: test/Unit/WorkerPoolSpec.hs

module WorkerPoolSpec (spec) where

import           Control.Concurrent.STM
    ( atomically
    , check
    , modifyTVar'
    , newEmptyTMVarIO
    , newTQueueIO
    , newTVarIO
    , putTMVar
    , readTMVar
    , readTQueue
    , readTVar
    , readTVarIO
    , writeTQueue
    , writeTVar
    )
import           Control.Monad          (replicateM_, void, when)
import           Lib.WorkerPool         (startWorkerPool)
import           System.Timeout         (timeout)
import           Test.Hspec

spec :: Spec
spec = describe "WorkerPool" $ do
  it "limits concurrent jobs to the worker count" $ do
    queue <- newTQueueIO
    gate <- newTQueueIO
    stopVar <- newEmptyTMVarIO
    runningVar <- newTVarIO 0
    maxRunningVar <- newTVarIO 0

    let job = do
          atomically $ do
            running <- readTVar runningVar
            let running' = running + 1
            writeTVar runningVar running'
            maxRunning <- readTVar maxRunningVar
            when (running' > maxRunning) $
              writeTVar maxRunningVar running'
          atomically $ readTQueue gate
          atomically $ modifyTVar' runningVar (subtract 1)

    startWorkerPool 2 queue (void (readTMVar stopVar)) (const (pure ()))
    replicateM_ 4 (atomically $ writeTQueue queue job)

    started <- timeout 2000000 (atomically $ do
      maxRunning <- readTVar maxRunningVar
      check (maxRunning >= 2))
    started `shouldBe` Just ()

    replicateM_ 4 (atomically $ writeTQueue gate ())
    done <- timeout 2000000 (atomically $ do
      running <- readTVar runningVar
      check (running == 0))
    done `shouldBe` Just ()

    atomically $ putTMVar stopVar ()
    maxRunning <- readTVarIO maxRunningVar
    maxRunning `shouldBe` 2