packages feed

nakadi-client-0.5.0.0: tests/Network/Nakadi/MonadicAPI/Test.hs

{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances  #-}

module Network.Nakadi.MonadicAPI.Test where

import           ClassyPrelude
import           Control.Lens
import           Control.Monad.Logger
import           Control.Monad.State.Strict
import           Control.Monad.Trans.Resource
import           Control.Retry
import           Network.HTTP.Client
import qualified Network.Nakadi               as Nakadi
import           Network.Nakadi.Base
import qualified Network.Nakadi.Lenses        as L
import           Network.Nakadi.Tests.Common
import           Test.Tasty
import           Test.Tasty.HUnit

httpErrorCallback :: Request -> HttpException -> RetryStatus -> Bool -> App ()
httpErrorCallback _req exn _retryStatus _isFinalFailure =
  putStrLn $ "nakadi-client triggered exception: " <> tshow exn

testMonadicAPI :: Nakadi.Config App -> TestTree
testMonadicAPI conf = testGroup "Monadic API"
  [ testCase "Simple Monadic API" (testSimpleMonadicAPI conf')
  , testCase "Simple NakadiBaseT" (testSimpleNakadiBaseT confLifted)
  , testCase "NakadiBaseT with non-trivial stack" (testNonTrivNakadiBaseT confLifted)
  , testCase "MonadNakadi instance for ReaderT" (testReaderT conf)
  ]

  where conf' = Nakadi.setHttpErrorCallback httpErrorCallback conf
        confLifted = Nakadi.newConfig Nakadi.httpBackendIO (conf^.L.requestTemplate)

testSimpleMonadicAPI :: Nakadi.Config App -> Assertion
testSimpleMonadicAPI conf = runApp . Nakadi.runNakadiT conf $ do
  -- Tests Nakadi call within NakadiT monad transformer
  _events <- Nakadi.eventTypesList
  -- But we can also call Nakadi from within monad transformers on top of NakadiT:
  void $ flip runStateT () $ do
    _events <- Nakadi.eventTypesList
    pure ()
  -- Required for consuming via subscription API is the ability to
  -- call Nakadi from within ResourceT:
  runResourceT $ do
    _partitionStrategies <- Nakadi.registryPartitionStrategies
    pure ()
  -- We can retrieve the configuration using nakadiAsk:
  _conf <- Nakadi.nakadiAsk
  pure ()

testSimpleNakadiBaseT :: Nakadi.Config (NakadiBaseT App) -> Assertion
testSimpleNakadiBaseT conf = runApp . Nakadi.runNakadiWithBase conf $ do
  _events <- Nakadi.eventTypesList
  pure ()

-- | This tests the verbose but more general method of seperating
-- runNakadiBaseT from runNakadiT, changing the monad transformer
-- stack inbetween (by adding NoLoggingT).
testNonTrivNakadiBaseT :: Nakadi.Config (NakadiBaseT App) -> Assertion
testNonTrivNakadiBaseT conf =
  runApp . Nakadi.runNakadiBaseT . runNoLoggingT . Nakadi.runNakadiT conf $ do
  _events <- Nakadi.eventTypesList
  pure ()


data Env = Env { nakadiConfiguration :: Nakadi.Config App }

instance Nakadi.HasNakadiConfig App Env where
  nakadiConfig = nakadiConfiguration

-- | This test uses the 'MonadNakadi' instance for 'ReaderT' with a
-- 'HasNakadiConfig' constraint.
testReaderT :: Nakadi.Config App -> Assertion
testReaderT conf = runApp . flip runReaderT (Env conf) $ do
  _events <- Nakadi.eventTypesList
  pure ()