packages feed

nakadi-client-0.6.0.0: tests/Network/Nakadi/Tests/Common.hs

{-# LANGUAGE DeriveAnyClass        #-}
{-# LANGUAGE DeriveGeneric         #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards       #-}
{-# LANGUAGE StandaloneDeriving    #-}

module Network.Nakadi.Tests.Common where

import           ClassyPrelude

import           Control.Exception.Safe         ( MonadThrow
                                                , throwM
                                                )
import           Control.Lens
import           Control.Monad.Logger
import           Data.Aeson
import           Data.List.Split                ( chunksOf )
import qualified Data.Text                     as Text
import           Data.UUID                      ( UUID )
import           Network.Nakadi
import qualified Network.Nakadi.Lenses         as L
import           System.Random
import           UnliftIO.Concurrent

data TerminateConsumption = TerminateConsumption deriving (Eq, Show, Typeable)

instance Exception TerminateConsumption

type App = LoggingT (ReaderT () IO)

runApp :: App a -> IO a
runApp = flip runReaderT () . runStdoutLoggingT

data Foo = Foo { fortune :: Text } deriving (Show, Eq, Generic)

deriving instance FromJSON Foo
deriving instance ToJSON Foo

data WrongFoo = WrongFoo { fortune :: Int } deriving (Show, Eq, Generic)

deriving instance FromJSON WrongFoo
deriving instance ToJSON WrongFoo

myEventTypeName :: EventTypeName
myEventTypeName = "test.FOO"

myEventTypeSchema :: EventTypeSchema
myEventTypeSchema = EventTypeSchema
  { _version    = Just "0.1"
  , _createdAt  = Nothing
  , _schemaType = SchemaTypeJson
  , _schema = "{ \"properties\": {\"fortune\": {\"type\": \"string\"} }, \"required\": [\"fortune\"] }"
  }

myEventType :: EventType
myEventType = EventType
  { _name                 = myEventTypeName
  , _owningApplication    = Just "test-suite"
  , _category             = Just EventTypeCategoryData
  , _enrichmentStrategies = Just [EnrichmentStrategyMetadata]
  , _partitionStrategy    = Just "hash"
  , _compatibilityMode    = Just CompatibilityModeForward
  , _partitionKeyFields   = Just ["fortune"]
  , _schema               = myEventTypeSchema
  , _defaultStatistic     = Just EventTypeStatistics
    { _messagesPerMinute = 1000
    , _messageSize       = 200
    , _readParallelism   = 8
    , _writeParallelism  = 8
    }
  , _options              = Nothing
  }

ignoreExnNotFound :: MonadThrow m => a -> NakadiException -> m a
ignoreExnNotFound a (EventTypeNotFound _) = return a
ignoreExnNotFound _ exn                   = throwM exn

extractCursor :: Partition -> Cursor
extractCursor Partition {..} = Cursor {_partition = _partition, _offset = _newestAvailableOffset}

myDataChangeEvent :: EventId -> UTCTime -> DataChangeEvent Foo
myDataChangeEvent eid now = DataChangeEvent
  { _payload  = Foo "Hello!"
  , _metadata = EventMetadata
    { _eid        = eid
    , _occurredAt = Timestamp now
    , _parentEids = Nothing
    , _partition  = Nothing
    }
  , _dataType = "test.FOO"
  , _dataOp   = DataOpUpdate
  }


genMyDataChangeEvent :: MonadIO m => m (DataChangeEvent Foo)
genMyDataChangeEvent = do
  eid <- genRandomUUID
  now <- liftIO getCurrentTime
  pure DataChangeEvent
    { _payload  = Foo "Hello!"
    , _metadata = EventMetadata
      { _eid        = EventId eid
      , _occurredAt = Timestamp now
      , _parentEids = Nothing
      , _partition  = Nothing
      }
    , _dataType = "test.FOO"
    , _dataOp   = DataOpUpdate
    }

genMyDataChangeEventIdx :: MonadIO m => Int -> m (DataChangeEvent Foo)
genMyDataChangeEventIdx idx = do
  eid <- genRandomUUID
  now <- liftIO getCurrentTime
  pure DataChangeEvent
    { _payload  = Foo ("Hello " ++ Text.pack (show idx))
    , _metadata = EventMetadata
      { _eid        = EventId eid
      , _occurredAt = Timestamp now
      , _parentEids = Nothing
      , _partition  = Nothing
      }
    , _dataType = "test.FOO"
    , _dataOp   = DataOpUpdate
    }

genRandomUUID :: MonadIO m => m UUID
genRandomUUID = liftIO randomIO

recreateEvent :: (MonadUnliftIO m, MonadNakadi b m) => EventType -> m ()
recreateEvent eventType = do
  let eventTypeName = eventType ^. L.name
  subscriptionIds <- subscriptionsList Nothing (Just [eventTypeName]) <&> map (view L.id)
  mapM_ subscriptionDelete subscriptionIds
  eventTypeDelete eventTypeName `catch` ignoreExnNotFound ()
  eventTypeCreate eventType

delayedPublish :: (MonadNakadi b m, MonadIO m, ToJSON a) => Maybe FlowId -> [a] -> m ()
delayedPublish maybeFlowId events = do
  liftIO $ threadDelay (10 ^ 6)
  let flowId = fromMaybe (FlowId "shalom") maybeFlowId
  config <- nakadiAsk <&> setFlowId flowId
  -- Publish events in batches.
  runNakadiT config $ forM_ (chunksOf 100 events) (eventsPublish myEventTypeName)