packages feed

pgmq-hasql-0.1.0.0: test/MetricsSpec.hs

{-# LANGUAGE OverloadedStrings #-}

-- | Tests for queue metrics operations
module MetricsSpec (tests) where

import Data.Aeson (object, (.=))
import Data.Text (Text)
import EphemeralDb (TestFixture (..), withTestFixture)
import Hasql.Pool qualified as Pool
import Pgmq.Hasql.Sessions qualified as Sessions
import Pgmq.Hasql.Statements.Types (QueueMetrics (..))
import Pgmq.Hasql.Statements.Types qualified as Types
import Pgmq.Types (MessageBody (..), QueueName, parseQueueName, queueNameToText)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (assertBool, assertEqual, testCase, (@?=))
import TestUtils (assertRight, assertSession, cleanupQueue)

-- | All metrics tests
tests :: Pool.Pool -> TestTree
tests p =
  testGroup
    "Metrics"
    [ testQueueMetrics p,
      testQueueMetricsEmpty p,
      testAllQueueMetrics p
    ]

-- | Test queueMetrics returns correct metrics
testQueueMetrics :: Pool.Pool -> TestTree
testQueueMetrics p = testCase "queueMetrics returns queue statistics" $ do
  withTestFixture p $ \TestFixture {pool, queueName = qName} -> do
    assertSession pool (Sessions.createQueue qName)
    -- Send some messages
    let msg = makeSendMessage qName
    _ <- assertSession pool (Sessions.sendMessage msg)
    _ <- assertSession pool (Sessions.sendMessage msg)
    _ <- assertSession pool (Sessions.sendMessage msg)
    -- Get metrics
    metrics <- assertSession pool (Sessions.queueMetrics qName)
    -- Verify metrics
    queueLength metrics @?= 3
    totalMessages metrics @?= 3
    queueVisibleLength metrics @?= 3
    assertEqual "Queue name should match" (queueNameToText qName) (metricsQueueName metrics)
    cleanupQueue pool qName

-- | Test queueMetrics for empty queue
testQueueMetricsEmpty :: Pool.Pool -> TestTree
testQueueMetricsEmpty p = testCase "queueMetrics works for empty queue" $ do
  withTestFixture p $ \TestFixture {pool, queueName = qName} -> do
    assertSession pool (Sessions.createQueue qName)
    -- Get metrics for empty queue
    metrics <- assertSession pool (Sessions.queueMetrics qName)
    queueLength metrics @?= 0
    totalMessages metrics @?= 0
    queueVisibleLength metrics @?= 0
    cleanupQueue pool qName

-- | Test allQueueMetrics returns all queues
testAllQueueMetrics :: Pool.Pool -> TestTree
testAllQueueMetrics p = testCase "allQueueMetrics returns metrics for all queues" $ do
  queueName1 <- assertRight $ parseQueueName "test_metrics_q1"
  queueName2 <- assertRight $ parseQueueName "test_metrics_q2"
  -- Create two queues
  assertSession p (Sessions.createQueue queueName1)
  assertSession p (Sessions.createQueue queueName2)
  -- Send a message to the first queue
  let msg = makeSendMessage queueName1
  _ <- assertSession p (Sessions.sendMessage msg)
  -- Get all metrics
  allMetrics <- assertSession p Sessions.allQueueMetrics
  -- Verify both queues are in the results
  let queueNames = map metricsQueueName allMetrics
  assertBool "Queue 1 should be in metrics" (queueNameToText queueName1 `elem` queueNames)
  assertBool "Queue 2 should be in metrics" (queueNameToText queueName2 `elem` queueNames)
  -- Verify queue 1 has the correct message count
  let q1Metrics = filter (\m -> metricsQueueName m == queueNameToText queueName1) allMetrics
  case q1Metrics of
    [m] -> queueLength m @?= 1
    _ -> assertBool "Queue 1 should have metrics" False
  -- Cleanup
  cleanupQueue p queueName1
  cleanupQueue p queueName2

-- | Helper to extract queue name from metrics (avoids ambiguity)
metricsQueueName :: QueueMetrics -> Text
metricsQueueName QueueMetrics {queueName = qn} = qn

-- | Helper to create SendMessage (avoids field ambiguity)
makeSendMessage :: QueueName -> Types.SendMessage
makeSendMessage qName =
  Types.SendMessage
    { Types.queueName = qName,
      Types.messageBody = MessageBody (object ["test" .= (1 :: Int)]),
      Types.delay = Nothing
    }