packages feed

glue-ekg-0.6.2: test/Glue/EkgSpec.hs

{-# LANGUAGE DeriveDataTypeable  #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Glue.EkgSpec where

import           Control.Exception.Base      hiding (throw, throwIO)
import           Control.Exception.Lifted
import qualified Data.HashMap.Strict         as M
import           Data.Int
import           Data.Text
import           Data.Typeable
import           Glue.Ekg
import           Glue.Types
import           System.Metrics
import qualified System.Metrics.Distribution as MD
import           Test.Hspec
import           Test.QuickCheck
import           Test.QuickCheck.Instances   ()

data EkgTestException = EkgTestException deriving (Eq, Show, Typeable)
instance Exception EkgTestException

data MetricsResult = CounterResult Int64
                   | GaugeResult Int64
                   | LabelResult Text
                   | DistributionResult Int64
                    deriving (Eq, Show)

checkResult :: Store -> Text -> (MetricsResult -> Expectation) -> Expectation
checkResult store name check = do
  allMetrics <- sampleAll store
  let possibleValue = M.lookup name allMetrics
  result <- case possibleValue of
                (Just (Counter counterCount)) -> return $ CounterResult counterCount
                (Just (Gauge value))          -> return $ GaugeResult value
                (Just (Label text))           -> return $ LabelResult text
                (Just (Distribution stats))   -> return $ DistributionResult $ MD.count stats
                Nothing                       -> fail "No metric."
  check result

testStats :: String ->
            (Store -> Text -> BasicService IO Int Int -> IO (BasicService IO Int Int)) ->
            (Int -> Int -> MetricsResult -> Expectation) ->
            (Int -> Int -> MetricsResult -> Expectation) ->
            Spec
testStats methodName method successCheck failureCheck =
  describe methodName $ do
    it "Successful call" $ do
      property $ \(request :: Int, result :: Int, name :: Text) -> do
        let service _ = return result :: IO Int
        store <- newStore
        wrappedService <- method store name service :: IO (BasicService IO Int Int)
        (wrappedService request) `shouldReturn` result
        checkResult store name $ successCheck request result
    it "Failing call" $ do
      property $ \(request :: Int, result :: Int, name :: Text) -> do
        let service _ = throwIO EkgTestException :: IO Int
        store <- newStore
        wrappedService <- method store name service :: IO (BasicService IO Int Int)
        (wrappedService request) `shouldThrow` (== EkgTestException)
        checkResult store name $ failureCheck request result

spec :: Spec
spec = parallel $ do
  testStats "recordDistribution" recordDistribution (\_ -> \_ -> \m -> m `shouldBe` (DistributionResult 1)) (\_ -> \_ -> \m -> m `shouldBe` (DistributionResult 1))
  testStats "recordAttempts" recordAttempts (\_ -> \_ -> \m -> m `shouldBe` (CounterResult 1)) (\_ -> \_ -> \m -> m `shouldBe` (CounterResult 1))
  testStats "recordSuccesses" recordSuccesses (\_ -> \_ -> \m -> m `shouldBe` (CounterResult 1)) (\_ -> \_ -> \m -> m `shouldBe` (CounterResult 0))
  testStats "recordFailures" recordFailures (\_ -> \_ -> \m -> m `shouldBe` (CounterResult 0)) (\_ -> \_ -> \m -> m `shouldBe` (CounterResult 1))
  testStats "recordLastRequest" recordLastRequest (\r -> \_ -> \m -> m `shouldBe` (LabelResult $ pack $ show r)) (\r -> \_ -> \m -> m `shouldBe` (LabelResult $ pack $ show r))
  testStats "recordLastResult" recordLastResult (\_ -> \r -> \m -> m `shouldBe` (LabelResult $ pack $ show r)) (\_ -> \_ -> \m -> m `shouldBe` (LabelResult ""))