packages feed

instrument-0.6.1.0: test/src/Instrument/Tests/Utils.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}

module Instrument.Tests.Utils
  ( tests,
  )
where

-------------------------------------------------------------------------------
import Control.Concurrent
import Control.Monad
import qualified Data.ByteString as B
import Data.IORef
import qualified Data.Map as M
import Data.SafeCopy
import Data.Serialize
-------------------------------------------------------------------------------
import Instrument.Types
import Instrument.Utils
import Path
import qualified Path.IO as PIO
import System.Timeout
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck

-------------------------------------------------------------------------------

tests :: TestTree
tests =
  testGroup
    "Instrument.Utils"
    [ encodeDecodeTests,
      withResource spawnWorker killWorker $ testCase "indefinitely retries" . indefinitely_retry
    ]

-------------------------------------------------------------------------------
encodeDecodeTests :: TestTree
encodeDecodeTests =
  testGroup
    "encodeCompress/decodeCompress"
    [ testProperty "encode/decode compress roundtrip" encode_decode_roundtrip,
      testCase "Stats decode" $
        testDecode $(mkRelFile "test/data/Instrument/Types/Stats.gz") stats,
      testCase "Payload decode" $
        testDecode $(mkRelFile "test/data/Instrument/Types/Payload.gz") payload,
      testCase "SubmissionPacket decode" $
        testDecode $(mkRelFile "test/data/Instrument/Types/SubmissionPacket.gz") submissionPacket,
      testCase "Aggregated decode" $
        testDecode $(mkRelFile "test/data/Instrument/Types/Aggregated.gz") aggregated
    ]
  where
    stats = Stats 1 2 3 4 5 6 7 8 9 (M.singleton 10 11)
    payload = Samples [1.2, 2.3, 4.5]
    submissionPacket = SP 3.4 "metric" payload (M.singleton hostDimension "example.org")
    aggregated = Aggregated 3.4 "metric" (AggStats stats) mempty
    testDecode :: forall a b. (Serialize a, SafeCopy a, Eq a, Show a) => Path b File -> a -> Assertion
    testDecode fp v = do
      exists <- PIO.doesFileExist fp
      unless exists $ do
        PIO.ensureDir (parent fp)
        B.writeFile (toFilePath fp) (encodeCompress v)
      res <- decodeCompress <$> B.readFile (toFilePath fp)
      (res :: Either String a) @?= Right v

-------------------------------------------------------------------------------
encode_decode_roundtrip :: String -> Property
encode_decode_roundtrip a = roundtrip a === Right a
  where
    roundtrip = decodeCompress . encodeCompress

-------------------------------------------------------------------------------
indefinitely_retry :: IO (MVar (), t1, t) -> IO ()
indefinitely_retry setup = do
  (called, _signal, _) <- setup
  wasCalled <- timeout (milliseconds 100) $ takeMVar called
  assertEqual "retries until success" (Just ()) wasCalled
  where

-------------------------------------------------------------------------------
spawnWorker :: IO (MVar (), IO (), ThreadId)
spawnWorker = do
  (called, signal) <- nopeNopeYep
  tid <- forkIO $ indefinitely "Test Worker" 0 signal
  return (called, signal, tid)

-------------------------------------------------------------------------------
killWorker :: (t1, t, ThreadId) -> IO ()
killWorker (_, _, tid) = killThread tid

-------------------------------------------------------------------------------
nopeNopeYep :: IO (MVar (), IO ())
nopeNopeYep = do
  counter <- newIORef (1 :: Int)
  mv <- newEmptyMVar
  return $ (mv, go counter mv)
  where
    go counter mv = do
      count <- readIORef counter
      modifyIORef' counter (+ 1)
      when (count > 2) $ void $ tryPutMVar mv ()