packages feed

nakadi-client-0.5.1.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 = Nothing
  , _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])
    <&> catMaybes . 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)