rdkafka-hs-1.1.0.0: test-integration/Kafka/Integration/ReadCommittedTest.hs
-- | Watermark queries honour the consumer's @isolation.level@ (improvement
-- request IR-2, AC-4): on a @read_committed@ consumer the high watermark is the
-- last stable offset, which stops before an open transaction.
module Kafka.Integration.ReadCommittedTest
( tests,
)
where
import Control.Exception (finally)
import Data.Map qualified as Map
import Data.Text (Text)
import GHC.Clock (getMonotonicTime)
import Kafka.Consumer
import Kafka.Metadata (WatermarkOffsets (..), partitionWatermarkOffsets)
import Kafka.Producer qualified as P
import Kafka.TestEnv
import Kafka.Transaction (beginTransaction, commitTransaction, initTransactions)
import Test.Tasty (TestTree)
import Test.Tasty.HUnit (assertBool, assertFailure, testCase, (@?=))
tests :: TestEnv -> TestTree
tests env =
testCase "read_committed watermark stops before an open transaction" $
withTopic env "read-committed" 1 $ \topic _ -> do
producer <-
P.newProducer
(producerProps env <> P.extraProps (Map.fromList [("transactional.id", prefixedName env "read-committed-tx")]))
>>= either (assertFailure . ("newProducer: " <>) . show) pure
flip finally (P.closeProducer producer) $ do
initTransactions producer (Timeout 10000) >>= (@?= Nothing)
beginTransaction producer >>= (@?= Nothing)
P.produceMessage producer (P.ProducerRecord topic (P.SpecifiedPartition 0) Nothing (Just "pending") mempty)
>>= (@?= Nothing)
P.flushProducer producer
readCommitted <- observer topic "read_committed"
readUncommitted <- observer topic "read_uncommitted"
flip finally (destroyConsumer readCommitted >> destroyConsumer readUncommitted) $ do
openRc <- high readCommitted topic
openRu <- high readUncommitted topic
assertBool
("while the transaction is open, read_committed high " <> show openRc <> " must be below read_uncommitted high " <> show openRu)
(openRc < openRu)
commitTransaction producer (Timeout 10000) >>= assertBool "commitTransaction failed" . null
deadline <- (+ 10) <$> getMonotonicTime
let converge = do
rc <- high readCommitted topic
ru <- high readUncommitted topic
now <- getMonotonicTime
if rc == ru
then assertBool ("read_committed high " <> show rc <> " did not advance past " <> show openRc) (rc > openRc)
else
if now > deadline
then assertFailure ("after commit, read_committed high " <> show rc <> " never reached " <> show ru)
else converge
converge
where
observer topic (level :: Text) = do
consumer <-
newAssignedConsumer
( consumerProps env
<> groupId (makeGroupId env ("read-committed-" <> level))
<> noAutoCommit
<> extraProps (Map.fromList [("isolation.level", level)])
)
>>= either (assertFailure . ("newAssignedConsumer: " <>) . show) pure
assign consumer [TopicPartition topic (PartitionId 0) PartitionOffsetBeginning] >>= (@?= Nothing)
pure consumer
high consumer topic =
partitionWatermarkOffsets consumer (Timeout 5000) topic (PartitionId 0)
>>= either (assertFailure . ("partitionWatermarkOffsets: " <>) . show) (pure . woHighWatermark)