packages feed

grapesy-1.0.0: test-grapesy/Test/Sanity/Any.hs

{-# LANGUAGE OverloadedLabels  #-}
{-# LANGUAGE OverloadedStrings #-}

module Test.Sanity.Any (tests) where

import Control.Exception
import Test.Tasty
import Test.Tasty.HUnit

import Network.GRPC.Client (rpc)
import Network.GRPC.Client.StreamType.IO qualified as Client
import Network.GRPC.Common
import Network.GRPC.Common.Protobuf
import Network.GRPC.Common.Protobuf.Any (Any)
import Network.GRPC.Common.Protobuf.Any qualified as Any
import Network.GRPC.Server.StreamType qualified as Server

import Test.Driver.ClientServer

import Proto.API.Ping
import Proto.API.TestAny

{-------------------------------------------------------------------------------
  Top-level
-------------------------------------------------------------------------------}

tests :: TestTree
tests = testGroup "Test.Sanity.Any" [
      testCase "Any"    testAny
    , testCase "Status" testStatus
    ]

{-------------------------------------------------------------------------------
  Using the 'Any' wrapper
-------------------------------------------------------------------------------}

testAny :: Assertion
testAny = testClientServer $ ClientServerTest {
      config = def
    , server = [Server.fromMethod @Reverse $ Server.ServerHandler handler]
    , client = simpleTestClient $ \conn -> do
        let req, expected :: Proto TestAnyMsg
            req      = withDetails [Any.pack detail1, Any.pack detail2]
            expected = withDetails [Any.pack detail2, Any.pack detail1]

        resp <- Client.nonStreaming conn (rpc @Reverse) req
        assertEqual "" expected $ resp
    }
  where
    handler :: Proto TestAnyMsg -> IO (Proto TestAnyMsg)
    handler msg = return $ msg & #details %~ reverse

    detail1 :: Proto A
    detail1 = defMessage & #a .~ 1

    detail2 :: Proto B
    detail2 = defMessage & #b .~ 1

    withDetails :: [Proto Any] -> Proto TestAnyMsg
    withDetails details =
        defMessage
          & #message .~ "foo"
          & #details .~ details

{-------------------------------------------------------------------------------
  Protobuf-specific error details (which relies on 'Any')
-------------------------------------------------------------------------------}

testStatus :: Assertion
testStatus = testClientServer $ ClientServerTest {
      config = def {
          isExpectedServerException = \e ->
            case fromException e of
              Just err'  -> grpcError err' == GrpcNotFound
              _otherwise -> False
        }
    , server = [
          Server.fromMethod @Ping $ Server.ServerHandler $ \_req ->
            throwProtobufErrorHom protobufError
        ]
    , client = simpleTestClient $ \conn -> do
        mResp :: Either GrpcException (Proto PongMessage) <-
          try $ Client.nonStreaming conn (rpc @Ping) defMessage
        case mResp of
          Right _   -> assertFailure "Expected exception"
          Left  err ->
            assertEqual "" (Right protobufError) $
              toProtobufErrorHom err
    }
  where
    protobufError :: ProtobufError (Proto A)
    protobufError = ProtobufError {
          protobufErrorCode    = GrpcNotFound
        , protobufErrorMessage = Just "Not found"
        , protobufErrorDetails = [detail1, detail2]
        }


    detail1, detail2 :: Proto A
    detail1 = defMessage & #a .~ 1
    detail2 = defMessage & #a .~ 2