2016-06-08 20:12:07 +02:00
|
|
|
{-# LANGUAGE LambdaCase #-}
|
|
|
|
{-# LANGUAGE OverloadedLists #-}
|
Begin safe low-level Haskell layer (#7)
* grpc_server_request_call
* basic slice functionality
* rename function to emphasize side effects
* add docs
* ByteBuffer function bindings
* replace unsafeCoerce with more specific function, add docs, tests.
* add newtypes for Tag and Reserved void pointers
* manually fix request_registered_call binding
* use nocode keyword to fix Ptr () problems
* decouple copying Slice from freeing slice
* Add time ops
* remove nocode decls
* Start Op module, fix c2hs preprocessing order
* metadata manipulation operations
* metadata free function, test
* helper functions for constructing ops of each type
* bindings for op creation functions
* finish up Op creation functions, implement Op destruction, add docs.
* tweak documentation
* rework Op creation functions to work with an array of ops, for ease of use with grpc_call_start_batch
* forgot to change return types
* wrap hook lines, fix types to op creation functions
* implement part of the payload test
* hideous, but working, end to end test
* bindings for connectivity state checks, split test into two threads
* various cleanup
* rename Core to Unsafe for emphasis, clean up tests more
* begin safe low-level facilities
* begin completion queue and server stuff
* Finish server start/stop, cq start/stop, add tests
* facilities for safely executing op batches
* reorganize LowLevel modules, begin explicit export list
* client functionality, stub payload test, various refactors
* tweak cabal file, add test
* add more documentation
* doc tweaks
* begin refactor to improve CompletionQueue safety
* export only thread-safe CQ functions, add registered call creation and other CQ utilities
* begin refactor to use GRPCIO monad, fix missing push semaphore, fix mem leak in server calls
* switch to explicit Either where needed
* add crashing tests, continue fleshing out serverHandleNormalCall
* fix haddock error, finish first draft of request handling function
* reduce GHC warnings
* non-registered client request helpers
* initial request/response test working
* don't pass tags around; generate where needed
* server call bracket functions
* correct order of semaphore acquisition and shutdown check
* simple debug flag logging, simplify Call type
* fix various registered method issues (but still not working)
* cleanup
* delete old code
* remove old todo
* use MetadataMap synonym pervasively
* more comments
* update TODOs
* tweak safety caveat
* docs tweaks
* improve haddocks
* add casts to eliminate clang warnings, remove unused function
* update options to eliminate cabal warnings
* remove outdated todo
* remove unneeded exports from CompletionQueue
* rename to GRPCIOCallError, re-add create/shutdown exports (needed for Server module)
* newtypes for hosts and method names
* more newtypes
* more debug logging
* Fix flag name collision
* instrument uses of free
* more debug
* switch to STM for completion queue stuff
* reduce warnings
* more debugging, create/destroy call tests
* refactor, fix failure cleanup for server call creation. More tests passing.
* formatting tweaks
2016-05-24 22:34:50 +02:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2016-06-08 20:12:07 +02:00
|
|
|
{-# LANGUAGE RecordWildCards #-}
|
Begin safe low-level Haskell layer (#7)
* grpc_server_request_call
* basic slice functionality
* rename function to emphasize side effects
* add docs
* ByteBuffer function bindings
* replace unsafeCoerce with more specific function, add docs, tests.
* add newtypes for Tag and Reserved void pointers
* manually fix request_registered_call binding
* use nocode keyword to fix Ptr () problems
* decouple copying Slice from freeing slice
* Add time ops
* remove nocode decls
* Start Op module, fix c2hs preprocessing order
* metadata manipulation operations
* metadata free function, test
* helper functions for constructing ops of each type
* bindings for op creation functions
* finish up Op creation functions, implement Op destruction, add docs.
* tweak documentation
* rework Op creation functions to work with an array of ops, for ease of use with grpc_call_start_batch
* forgot to change return types
* wrap hook lines, fix types to op creation functions
* implement part of the payload test
* hideous, but working, end to end test
* bindings for connectivity state checks, split test into two threads
* various cleanup
* rename Core to Unsafe for emphasis, clean up tests more
* begin safe low-level facilities
* begin completion queue and server stuff
* Finish server start/stop, cq start/stop, add tests
* facilities for safely executing op batches
* reorganize LowLevel modules, begin explicit export list
* client functionality, stub payload test, various refactors
* tweak cabal file, add test
* add more documentation
* doc tweaks
* begin refactor to improve CompletionQueue safety
* export only thread-safe CQ functions, add registered call creation and other CQ utilities
* begin refactor to use GRPCIO monad, fix missing push semaphore, fix mem leak in server calls
* switch to explicit Either where needed
* add crashing tests, continue fleshing out serverHandleNormalCall
* fix haddock error, finish first draft of request handling function
* reduce GHC warnings
* non-registered client request helpers
* initial request/response test working
* don't pass tags around; generate where needed
* server call bracket functions
* correct order of semaphore acquisition and shutdown check
* simple debug flag logging, simplify Call type
* fix various registered method issues (but still not working)
* cleanup
* delete old code
* remove old todo
* use MetadataMap synonym pervasively
* more comments
* update TODOs
* tweak safety caveat
* docs tweaks
* improve haddocks
* add casts to eliminate clang warnings, remove unused function
* update options to eliminate cabal warnings
* remove outdated todo
* remove unneeded exports from CompletionQueue
* rename to GRPCIOCallError, re-add create/shutdown exports (needed for Server module)
* newtypes for hosts and method names
* more newtypes
* more debug logging
* Fix flag name collision
* instrument uses of free
* more debug
* switch to STM for completion queue stuff
* reduce warnings
* more debugging, create/destroy call tests
* refactor, fix failure cleanup for server call creation. More tests passing.
* formatting tweaks
2016-05-24 22:34:50 +02:00
|
|
|
|
2016-06-13 22:51:53 +02:00
|
|
|
module LowLevelTests where
|
Begin safe low-level Haskell layer (#7)
* grpc_server_request_call
* basic slice functionality
* rename function to emphasize side effects
* add docs
* ByteBuffer function bindings
* replace unsafeCoerce with more specific function, add docs, tests.
* add newtypes for Tag and Reserved void pointers
* manually fix request_registered_call binding
* use nocode keyword to fix Ptr () problems
* decouple copying Slice from freeing slice
* Add time ops
* remove nocode decls
* Start Op module, fix c2hs preprocessing order
* metadata manipulation operations
* metadata free function, test
* helper functions for constructing ops of each type
* bindings for op creation functions
* finish up Op creation functions, implement Op destruction, add docs.
* tweak documentation
* rework Op creation functions to work with an array of ops, for ease of use with grpc_call_start_batch
* forgot to change return types
* wrap hook lines, fix types to op creation functions
* implement part of the payload test
* hideous, but working, end to end test
* bindings for connectivity state checks, split test into two threads
* various cleanup
* rename Core to Unsafe for emphasis, clean up tests more
* begin safe low-level facilities
* begin completion queue and server stuff
* Finish server start/stop, cq start/stop, add tests
* facilities for safely executing op batches
* reorganize LowLevel modules, begin explicit export list
* client functionality, stub payload test, various refactors
* tweak cabal file, add test
* add more documentation
* doc tweaks
* begin refactor to improve CompletionQueue safety
* export only thread-safe CQ functions, add registered call creation and other CQ utilities
* begin refactor to use GRPCIO monad, fix missing push semaphore, fix mem leak in server calls
* switch to explicit Either where needed
* add crashing tests, continue fleshing out serverHandleNormalCall
* fix haddock error, finish first draft of request handling function
* reduce GHC warnings
* non-registered client request helpers
* initial request/response test working
* don't pass tags around; generate where needed
* server call bracket functions
* correct order of semaphore acquisition and shutdown check
* simple debug flag logging, simplify Call type
* fix various registered method issues (but still not working)
* cleanup
* delete old code
* remove old todo
* use MetadataMap synonym pervasively
* more comments
* update TODOs
* tweak safety caveat
* docs tweaks
* improve haddocks
* add casts to eliminate clang warnings, remove unused function
* update options to eliminate cabal warnings
* remove outdated todo
* remove unneeded exports from CompletionQueue
* rename to GRPCIOCallError, re-add create/shutdown exports (needed for Server module)
* newtypes for hosts and method names
* more newtypes
* more debug logging
* Fix flag name collision
* instrument uses of free
* more debug
* switch to STM for completion queue stuff
* reduce warnings
* more debugging, create/destroy call tests
* refactor, fix failure cleanup for server call creation. More tests passing.
* formatting tweaks
2016-05-24 22:34:50 +02:00
|
|
|
|
2016-06-08 18:50:57 +02:00
|
|
|
import Control.Concurrent (threadDelay)
|
2016-05-24 23:34:23 +02:00
|
|
|
import Control.Concurrent.Async
|
2016-05-26 00:41:37 +02:00
|
|
|
import Control.Monad
|
2016-06-22 22:07:38 +02:00
|
|
|
import Data.ByteString (ByteString,
|
|
|
|
isPrefixOf,
|
|
|
|
isSuffixOf)
|
2016-06-08 18:50:57 +02:00
|
|
|
import qualified Data.Map as M
|
2016-05-24 23:39:53 +02:00
|
|
|
import Network.GRPC.LowLevel
|
2016-06-22 19:41:14 +02:00
|
|
|
import qualified Network.GRPC.LowLevel.Call.Unregistered as U
|
2016-06-08 21:38:01 +02:00
|
|
|
import qualified Network.GRPC.LowLevel.Client.Unregistered as U
|
|
|
|
import qualified Network.GRPC.LowLevel.Server.Unregistered as U
|
2016-05-24 23:39:53 +02:00
|
|
|
import Test.Tasty
|
2016-06-08 18:50:57 +02:00
|
|
|
import Test.Tasty.HUnit as HU (Assertion,
|
2016-06-13 16:25:32 +02:00
|
|
|
assertBool,
|
2016-06-08 18:50:57 +02:00
|
|
|
assertEqual,
|
|
|
|
assertFailure,
|
|
|
|
testCase,
|
|
|
|
(@?=))
|
Begin safe low-level Haskell layer (#7)
* grpc_server_request_call
* basic slice functionality
* rename function to emphasize side effects
* add docs
* ByteBuffer function bindings
* replace unsafeCoerce with more specific function, add docs, tests.
* add newtypes for Tag and Reserved void pointers
* manually fix request_registered_call binding
* use nocode keyword to fix Ptr () problems
* decouple copying Slice from freeing slice
* Add time ops
* remove nocode decls
* Start Op module, fix c2hs preprocessing order
* metadata manipulation operations
* metadata free function, test
* helper functions for constructing ops of each type
* bindings for op creation functions
* finish up Op creation functions, implement Op destruction, add docs.
* tweak documentation
* rework Op creation functions to work with an array of ops, for ease of use with grpc_call_start_batch
* forgot to change return types
* wrap hook lines, fix types to op creation functions
* implement part of the payload test
* hideous, but working, end to end test
* bindings for connectivity state checks, split test into two threads
* various cleanup
* rename Core to Unsafe for emphasis, clean up tests more
* begin safe low-level facilities
* begin completion queue and server stuff
* Finish server start/stop, cq start/stop, add tests
* facilities for safely executing op batches
* reorganize LowLevel modules, begin explicit export list
* client functionality, stub payload test, various refactors
* tweak cabal file, add test
* add more documentation
* doc tweaks
* begin refactor to improve CompletionQueue safety
* export only thread-safe CQ functions, add registered call creation and other CQ utilities
* begin refactor to use GRPCIO monad, fix missing push semaphore, fix mem leak in server calls
* switch to explicit Either where needed
* add crashing tests, continue fleshing out serverHandleNormalCall
* fix haddock error, finish first draft of request handling function
* reduce GHC warnings
* non-registered client request helpers
* initial request/response test working
* don't pass tags around; generate where needed
* server call bracket functions
* correct order of semaphore acquisition and shutdown check
* simple debug flag logging, simplify Call type
* fix various registered method issues (but still not working)
* cleanup
* delete old code
* remove old todo
* use MetadataMap synonym pervasively
* more comments
* update TODOs
* tweak safety caveat
* docs tweaks
* improve haddocks
* add casts to eliminate clang warnings, remove unused function
* update options to eliminate cabal warnings
* remove outdated todo
* remove unneeded exports from CompletionQueue
* rename to GRPCIOCallError, re-add create/shutdown exports (needed for Server module)
* newtypes for hosts and method names
* more newtypes
* more debug logging
* Fix flag name collision
* instrument uses of free
* more debug
* switch to STM for completion queue stuff
* reduce warnings
* more debugging, create/destroy call tests
* refactor, fix failure cleanup for server call creation. More tests passing.
* formatting tweaks
2016-05-24 22:34:50 +02:00
|
|
|
|
|
|
|
lowLevelTests :: TestTree
|
|
|
|
lowLevelTests = testGroup "Unit tests of low-level Haskell library"
|
2016-06-08 20:12:07 +02:00
|
|
|
[ testGRPCBracket
|
|
|
|
, testCompletionQueueCreateDestroy
|
|
|
|
, testClientCreateDestroy
|
2016-06-08 17:48:28 +02:00
|
|
|
, testClientCall
|
2016-06-08 20:12:07 +02:00
|
|
|
, testClientTimeoutNoServer
|
2016-06-08 17:48:28 +02:00
|
|
|
, testServerCreateDestroy
|
2016-06-16 17:23:54 +02:00
|
|
|
, testMixRegisteredUnregistered
|
2016-06-08 20:12:07 +02:00
|
|
|
, testPayload
|
|
|
|
, testPayloadUnregistered
|
2016-06-13 22:51:53 +02:00
|
|
|
, testServerCancel
|
2016-06-13 16:25:32 +02:00
|
|
|
, testGoaway
|
|
|
|
, testSlowServer
|
2016-06-16 21:45:55 +02:00
|
|
|
, testServerCallExpirationCheck
|
2016-06-22 22:07:38 +02:00
|
|
|
, testCustomUserAgent
|
|
|
|
, testClientCompression
|
|
|
|
, testClientServerCompression
|
2016-06-08 20:12:07 +02:00
|
|
|
]
|
Begin safe low-level Haskell layer (#7)
* grpc_server_request_call
* basic slice functionality
* rename function to emphasize side effects
* add docs
* ByteBuffer function bindings
* replace unsafeCoerce with more specific function, add docs, tests.
* add newtypes for Tag and Reserved void pointers
* manually fix request_registered_call binding
* use nocode keyword to fix Ptr () problems
* decouple copying Slice from freeing slice
* Add time ops
* remove nocode decls
* Start Op module, fix c2hs preprocessing order
* metadata manipulation operations
* metadata free function, test
* helper functions for constructing ops of each type
* bindings for op creation functions
* finish up Op creation functions, implement Op destruction, add docs.
* tweak documentation
* rework Op creation functions to work with an array of ops, for ease of use with grpc_call_start_batch
* forgot to change return types
* wrap hook lines, fix types to op creation functions
* implement part of the payload test
* hideous, but working, end to end test
* bindings for connectivity state checks, split test into two threads
* various cleanup
* rename Core to Unsafe for emphasis, clean up tests more
* begin safe low-level facilities
* begin completion queue and server stuff
* Finish server start/stop, cq start/stop, add tests
* facilities for safely executing op batches
* reorganize LowLevel modules, begin explicit export list
* client functionality, stub payload test, various refactors
* tweak cabal file, add test
* add more documentation
* doc tweaks
* begin refactor to improve CompletionQueue safety
* export only thread-safe CQ functions, add registered call creation and other CQ utilities
* begin refactor to use GRPCIO monad, fix missing push semaphore, fix mem leak in server calls
* switch to explicit Either where needed
* add crashing tests, continue fleshing out serverHandleNormalCall
* fix haddock error, finish first draft of request handling function
* reduce GHC warnings
* non-registered client request helpers
* initial request/response test working
* don't pass tags around; generate where needed
* server call bracket functions
* correct order of semaphore acquisition and shutdown check
* simple debug flag logging, simplify Call type
* fix various registered method issues (but still not working)
* cleanup
* delete old code
* remove old todo
* use MetadataMap synonym pervasively
* more comments
* update TODOs
* tweak safety caveat
* docs tweaks
* improve haddocks
* add casts to eliminate clang warnings, remove unused function
* update options to eliminate cabal warnings
* remove outdated todo
* remove unneeded exports from CompletionQueue
* rename to GRPCIOCallError, re-add create/shutdown exports (needed for Server module)
* newtypes for hosts and method names
* more newtypes
* more debug logging
* Fix flag name collision
* instrument uses of free
* more debug
* switch to STM for completion queue stuff
* reduce warnings
* more debugging, create/destroy call tests
* refactor, fix failure cleanup for server call creation. More tests passing.
* formatting tweaks
2016-05-24 22:34:50 +02:00
|
|
|
|
|
|
|
testGRPCBracket :: TestTree
|
2016-06-08 20:12:07 +02:00
|
|
|
testGRPCBracket =
|
|
|
|
testCase "Start/stop GRPC" $ withGRPC nop
|
Begin safe low-level Haskell layer (#7)
* grpc_server_request_call
* basic slice functionality
* rename function to emphasize side effects
* add docs
* ByteBuffer function bindings
* replace unsafeCoerce with more specific function, add docs, tests.
* add newtypes for Tag and Reserved void pointers
* manually fix request_registered_call binding
* use nocode keyword to fix Ptr () problems
* decouple copying Slice from freeing slice
* Add time ops
* remove nocode decls
* Start Op module, fix c2hs preprocessing order
* metadata manipulation operations
* metadata free function, test
* helper functions for constructing ops of each type
* bindings for op creation functions
* finish up Op creation functions, implement Op destruction, add docs.
* tweak documentation
* rework Op creation functions to work with an array of ops, for ease of use with grpc_call_start_batch
* forgot to change return types
* wrap hook lines, fix types to op creation functions
* implement part of the payload test
* hideous, but working, end to end test
* bindings for connectivity state checks, split test into two threads
* various cleanup
* rename Core to Unsafe for emphasis, clean up tests more
* begin safe low-level facilities
* begin completion queue and server stuff
* Finish server start/stop, cq start/stop, add tests
* facilities for safely executing op batches
* reorganize LowLevel modules, begin explicit export list
* client functionality, stub payload test, various refactors
* tweak cabal file, add test
* add more documentation
* doc tweaks
* begin refactor to improve CompletionQueue safety
* export only thread-safe CQ functions, add registered call creation and other CQ utilities
* begin refactor to use GRPCIO monad, fix missing push semaphore, fix mem leak in server calls
* switch to explicit Either where needed
* add crashing tests, continue fleshing out serverHandleNormalCall
* fix haddock error, finish first draft of request handling function
* reduce GHC warnings
* non-registered client request helpers
* initial request/response test working
* don't pass tags around; generate where needed
* server call bracket functions
* correct order of semaphore acquisition and shutdown check
* simple debug flag logging, simplify Call type
* fix various registered method issues (but still not working)
* cleanup
* delete old code
* remove old todo
* use MetadataMap synonym pervasively
* more comments
* update TODOs
* tweak safety caveat
* docs tweaks
* improve haddocks
* add casts to eliminate clang warnings, remove unused function
* update options to eliminate cabal warnings
* remove outdated todo
* remove unneeded exports from CompletionQueue
* rename to GRPCIOCallError, re-add create/shutdown exports (needed for Server module)
* newtypes for hosts and method names
* more newtypes
* more debug logging
* Fix flag name collision
* instrument uses of free
* more debug
* switch to STM for completion queue stuff
* reduce warnings
* more debugging, create/destroy call tests
* refactor, fix failure cleanup for server call creation. More tests passing.
* formatting tweaks
2016-05-24 22:34:50 +02:00
|
|
|
|
|
|
|
testCompletionQueueCreateDestroy :: TestTree
|
|
|
|
testCompletionQueueCreateDestroy =
|
2016-06-08 20:12:07 +02:00
|
|
|
testCase "Create/destroy CQ" $ withGRPC $ \g ->
|
|
|
|
withCompletionQueue g nop
|
Begin safe low-level Haskell layer (#7)
* grpc_server_request_call
* basic slice functionality
* rename function to emphasize side effects
* add docs
* ByteBuffer function bindings
* replace unsafeCoerce with more specific function, add docs, tests.
* add newtypes for Tag and Reserved void pointers
* manually fix request_registered_call binding
* use nocode keyword to fix Ptr () problems
* decouple copying Slice from freeing slice
* Add time ops
* remove nocode decls
* Start Op module, fix c2hs preprocessing order
* metadata manipulation operations
* metadata free function, test
* helper functions for constructing ops of each type
* bindings for op creation functions
* finish up Op creation functions, implement Op destruction, add docs.
* tweak documentation
* rework Op creation functions to work with an array of ops, for ease of use with grpc_call_start_batch
* forgot to change return types
* wrap hook lines, fix types to op creation functions
* implement part of the payload test
* hideous, but working, end to end test
* bindings for connectivity state checks, split test into two threads
* various cleanup
* rename Core to Unsafe for emphasis, clean up tests more
* begin safe low-level facilities
* begin completion queue and server stuff
* Finish server start/stop, cq start/stop, add tests
* facilities for safely executing op batches
* reorganize LowLevel modules, begin explicit export list
* client functionality, stub payload test, various refactors
* tweak cabal file, add test
* add more documentation
* doc tweaks
* begin refactor to improve CompletionQueue safety
* export only thread-safe CQ functions, add registered call creation and other CQ utilities
* begin refactor to use GRPCIO monad, fix missing push semaphore, fix mem leak in server calls
* switch to explicit Either where needed
* add crashing tests, continue fleshing out serverHandleNormalCall
* fix haddock error, finish first draft of request handling function
* reduce GHC warnings
* non-registered client request helpers
* initial request/response test working
* don't pass tags around; generate where needed
* server call bracket functions
* correct order of semaphore acquisition and shutdown check
* simple debug flag logging, simplify Call type
* fix various registered method issues (but still not working)
* cleanup
* delete old code
* remove old todo
* use MetadataMap synonym pervasively
* more comments
* update TODOs
* tweak safety caveat
* docs tweaks
* improve haddocks
* add casts to eliminate clang warnings, remove unused function
* update options to eliminate cabal warnings
* remove outdated todo
* remove unneeded exports from CompletionQueue
* rename to GRPCIOCallError, re-add create/shutdown exports (needed for Server module)
* newtypes for hosts and method names
* more newtypes
* more debug logging
* Fix flag name collision
* instrument uses of free
* more debug
* switch to STM for completion queue stuff
* reduce warnings
* more debugging, create/destroy call tests
* refactor, fix failure cleanup for server call creation. More tests passing.
* formatting tweaks
2016-05-24 22:34:50 +02:00
|
|
|
|
|
|
|
testClientCreateDestroy :: TestTree
|
|
|
|
testClientCreateDestroy =
|
2016-06-08 20:12:07 +02:00
|
|
|
clientOnlyTest "start/stop" nop
|
Begin safe low-level Haskell layer (#7)
* grpc_server_request_call
* basic slice functionality
* rename function to emphasize side effects
* add docs
* ByteBuffer function bindings
* replace unsafeCoerce with more specific function, add docs, tests.
* add newtypes for Tag and Reserved void pointers
* manually fix request_registered_call binding
* use nocode keyword to fix Ptr () problems
* decouple copying Slice from freeing slice
* Add time ops
* remove nocode decls
* Start Op module, fix c2hs preprocessing order
* metadata manipulation operations
* metadata free function, test
* helper functions for constructing ops of each type
* bindings for op creation functions
* finish up Op creation functions, implement Op destruction, add docs.
* tweak documentation
* rework Op creation functions to work with an array of ops, for ease of use with grpc_call_start_batch
* forgot to change return types
* wrap hook lines, fix types to op creation functions
* implement part of the payload test
* hideous, but working, end to end test
* bindings for connectivity state checks, split test into two threads
* various cleanup
* rename Core to Unsafe for emphasis, clean up tests more
* begin safe low-level facilities
* begin completion queue and server stuff
* Finish server start/stop, cq start/stop, add tests
* facilities for safely executing op batches
* reorganize LowLevel modules, begin explicit export list
* client functionality, stub payload test, various refactors
* tweak cabal file, add test
* add more documentation
* doc tweaks
* begin refactor to improve CompletionQueue safety
* export only thread-safe CQ functions, add registered call creation and other CQ utilities
* begin refactor to use GRPCIO monad, fix missing push semaphore, fix mem leak in server calls
* switch to explicit Either where needed
* add crashing tests, continue fleshing out serverHandleNormalCall
* fix haddock error, finish first draft of request handling function
* reduce GHC warnings
* non-registered client request helpers
* initial request/response test working
* don't pass tags around; generate where needed
* server call bracket functions
* correct order of semaphore acquisition and shutdown check
* simple debug flag logging, simplify Call type
* fix various registered method issues (but still not working)
* cleanup
* delete old code
* remove old todo
* use MetadataMap synonym pervasively
* more comments
* update TODOs
* tweak safety caveat
* docs tweaks
* improve haddocks
* add casts to eliminate clang warnings, remove unused function
* update options to eliminate cabal warnings
* remove outdated todo
* remove unneeded exports from CompletionQueue
* rename to GRPCIOCallError, re-add create/shutdown exports (needed for Server module)
* newtypes for hosts and method names
* more newtypes
* more debug logging
* Fix flag name collision
* instrument uses of free
* more debug
* switch to STM for completion queue stuff
* reduce warnings
* more debugging, create/destroy call tests
* refactor, fix failure cleanup for server call creation. More tests passing.
* formatting tweaks
2016-05-24 22:34:50 +02:00
|
|
|
|
2016-06-08 17:48:28 +02:00
|
|
|
testClientCall :: TestTree
|
|
|
|
testClientCall =
|
2016-06-08 20:12:07 +02:00
|
|
|
clientOnlyTest "create/destroy call" $ \c -> do
|
2016-06-08 21:38:01 +02:00
|
|
|
r <- U.withClientCall c "/foo" 10 $ const $ return $ Right ()
|
2016-06-08 20:12:07 +02:00
|
|
|
r @?= Right ()
|
|
|
|
|
|
|
|
testClientTimeoutNoServer :: TestTree
|
|
|
|
testClientTimeoutNoServer =
|
|
|
|
clientOnlyTest "request timeout when server DNE" $ \c -> do
|
|
|
|
rm <- clientRegisterMethod c "/foo" Normal
|
2016-06-08 21:38:01 +02:00
|
|
|
r <- clientRequest c rm 1 "Hello" mempty
|
2016-06-22 19:41:14 +02:00
|
|
|
r @?= Left GRPCIOTimeout
|
2016-06-08 20:12:07 +02:00
|
|
|
|
2016-06-08 17:48:28 +02:00
|
|
|
testServerCreateDestroy :: TestTree
|
|
|
|
testServerCreateDestroy =
|
|
|
|
serverOnlyTest "start/stop" [] nop
|
|
|
|
|
2016-06-16 17:23:54 +02:00
|
|
|
testMixRegisteredUnregistered :: TestTree
|
|
|
|
testMixRegisteredUnregistered =
|
|
|
|
csTest "server uses unregistered calls to handle unknown endpoints"
|
|
|
|
client
|
|
|
|
server
|
|
|
|
[("/foo", Normal)]
|
|
|
|
where
|
|
|
|
client c = do
|
|
|
|
rm1 <- clientRegisterMethod c "/foo" Normal
|
|
|
|
rm2 <- clientRegisterMethod c "/bar" Normal
|
|
|
|
clientRequest c rm1 1 "Hello" mempty >>= do
|
|
|
|
checkReqRslt $ \NormalRequestResult{..} -> do
|
|
|
|
rspBody @?= "reply test"
|
|
|
|
initMD @?= Just dummyMeta
|
|
|
|
trailMD @?= dummyMeta
|
|
|
|
clientRequest c rm2 1 "bad endpoint" mempty >>= do
|
|
|
|
checkReqRslt $ \NormalRequestResult{..} -> do
|
|
|
|
rspBody @?= ""
|
|
|
|
return ()
|
|
|
|
server s = do
|
|
|
|
concurrently regThread unregThread
|
|
|
|
return ()
|
|
|
|
where regThread = do
|
|
|
|
let rm = head (registeredMethods s)
|
2016-06-22 19:41:14 +02:00
|
|
|
r <- serverHandleNormalCall s rm dummyMeta $ \_ body _ -> do
|
2016-06-16 17:23:54 +02:00
|
|
|
body @?= "Hello"
|
|
|
|
return ("reply test", dummyMeta, StatusOk, StatusDetails "")
|
|
|
|
return ()
|
|
|
|
unregThread = do
|
2016-06-22 19:41:14 +02:00
|
|
|
r1 <- U.serverHandleNormalCall s mempty $ \call _ -> do
|
|
|
|
U.callMethod call @?= "/bar"
|
2016-06-16 17:23:54 +02:00
|
|
|
return ("", mempty, StatusOk,
|
|
|
|
StatusDetails "Wrong endpoint")
|
|
|
|
return ()
|
2016-06-08 20:12:07 +02:00
|
|
|
|
|
|
|
-- TODO: There seems to be a race here (and in other client/server pairs, of
|
|
|
|
-- course) about what gets reported when there is a failure. E.g., if one of the
|
|
|
|
-- Assertions fails in the request processing block for the server, we /may/ get
|
|
|
|
-- that error reported accurately as a call cancellation on the client, rather
|
|
|
|
-- than a useful error about the failure on the server. Maybe we'll need to
|
|
|
|
-- tweak EH behavior / async use.
|
|
|
|
testPayload :: TestTree
|
|
|
|
testPayload =
|
|
|
|
csTest "registered normal request/response" client server [("/foo", Normal)]
|
|
|
|
where
|
|
|
|
clientMD = [("foo_key", "foo_val"), ("bar_key", "bar_val")]
|
|
|
|
client c = do
|
|
|
|
rm <- clientRegisterMethod c "/foo" Normal
|
2016-06-08 21:38:01 +02:00
|
|
|
clientRequest c rm 10 "Hello!" clientMD >>= do
|
2016-06-08 20:12:07 +02:00
|
|
|
checkReqRslt $ \NormalRequestResult{..} -> do
|
2016-06-16 17:23:54 +02:00
|
|
|
rspCode @?= StatusOk
|
2016-06-08 20:12:07 +02:00
|
|
|
rspBody @?= "reply test"
|
|
|
|
details @?= "details string"
|
|
|
|
initMD @?= Just dummyMeta
|
|
|
|
trailMD @?= dummyMeta
|
|
|
|
server s = do
|
|
|
|
length (registeredMethods s) @?= 1
|
|
|
|
let rm = head (registeredMethods s)
|
2016-06-22 19:41:14 +02:00
|
|
|
r <- serverHandleNormalCall s rm dummyMeta $ \_ reqBody reqMD -> do
|
2016-06-08 20:12:07 +02:00
|
|
|
reqBody @?= "Hello!"
|
|
|
|
checkMD "Server metadata mismatch" clientMD reqMD
|
2016-06-16 17:23:54 +02:00
|
|
|
return ("reply test", dummyMeta, StatusOk,
|
|
|
|
StatusDetails "details string")
|
2016-06-13 22:51:53 +02:00
|
|
|
r @?= Right ()
|
|
|
|
|
|
|
|
testServerCancel :: TestTree
|
|
|
|
testServerCancel =
|
|
|
|
csTest "server cancel call" client server [("/foo", Normal)]
|
|
|
|
where
|
|
|
|
client c = do
|
|
|
|
rm <- clientRegisterMethod c "/foo" Normal
|
|
|
|
res <- clientRequest c rm 10 "" mempty
|
2016-06-16 17:23:54 +02:00
|
|
|
res @?= Left (GRPCIOBadStatusCode StatusCancelled
|
2016-06-13 22:51:53 +02:00
|
|
|
(StatusDetails
|
|
|
|
"Received RST_STREAM err=8"))
|
|
|
|
server s = do
|
|
|
|
let rm = head (registeredMethods s)
|
2016-06-22 19:41:14 +02:00
|
|
|
r <- serverHandleNormalCall s rm mempty $ \c _ _ -> do
|
2016-06-16 17:23:54 +02:00
|
|
|
serverCallCancel c StatusCancelled ""
|
2016-06-22 19:41:14 +02:00
|
|
|
return (mempty, mempty, StatusCancelled, "")
|
2016-06-08 20:12:07 +02:00
|
|
|
r @?= Right ()
|
|
|
|
|
|
|
|
testPayloadUnregistered :: TestTree
|
|
|
|
testPayloadUnregistered =
|
|
|
|
csTest "unregistered normal request/response" client server []
|
|
|
|
where
|
|
|
|
client c = do
|
2016-06-08 21:38:01 +02:00
|
|
|
U.clientRequest c "/foo" 10 "Hello!" mempty >>= do
|
2016-06-08 20:12:07 +02:00
|
|
|
checkReqRslt $ \NormalRequestResult{..} -> do
|
2016-06-16 17:23:54 +02:00
|
|
|
rspCode @?= StatusOk
|
2016-06-08 20:12:07 +02:00
|
|
|
rspBody @?= "reply test"
|
|
|
|
details @?= "details string"
|
|
|
|
server s = do
|
2016-06-22 19:41:14 +02:00
|
|
|
r <- U.serverHandleNormalCall s mempty $ \U.ServerCall{..} body -> do
|
2016-06-08 20:12:07 +02:00
|
|
|
body @?= "Hello!"
|
2016-06-22 19:41:14 +02:00
|
|
|
callMethod @?= "/foo"
|
2016-06-16 17:23:54 +02:00
|
|
|
return ("reply test", mempty, StatusOk, "details string")
|
2016-06-08 20:12:07 +02:00
|
|
|
r @?= Right ()
|
2016-05-24 23:34:23 +02:00
|
|
|
|
2016-06-13 16:25:32 +02:00
|
|
|
testGoaway :: TestTree
|
|
|
|
testGoaway =
|
|
|
|
csTest "Client handles server shutdown gracefully"
|
|
|
|
client
|
|
|
|
server
|
|
|
|
[("/foo", Normal)]
|
|
|
|
where
|
|
|
|
client c = do
|
|
|
|
rm <- clientRegisterMethod c "/foo" Normal
|
|
|
|
clientRequest c rm 10 "" mempty
|
|
|
|
clientRequest c rm 10 "" mempty
|
|
|
|
lastResult <- clientRequest c rm 1 "" mempty
|
|
|
|
assertBool "Client handles server shutdown gracefully" $
|
|
|
|
lastResult == unavailableStatus
|
|
|
|
||
|
2016-06-15 19:30:17 +02:00
|
|
|
lastResult == deadlineExceededStatus
|
2016-06-22 19:41:14 +02:00
|
|
|
||
|
|
|
|
lastResult == Left GRPCIOTimeout
|
2016-06-13 16:25:32 +02:00
|
|
|
server s = do
|
|
|
|
let rm = head (registeredMethods s)
|
2016-06-22 19:41:14 +02:00
|
|
|
serverHandleNormalCall s rm mempty dummyHandler
|
|
|
|
serverHandleNormalCall s rm mempty dummyHandler
|
2016-06-13 16:25:32 +02:00
|
|
|
return ()
|
|
|
|
|
|
|
|
testSlowServer :: TestTree
|
|
|
|
testSlowServer =
|
|
|
|
csTest "Client handles slow server response" client server [("/foo", Normal)]
|
|
|
|
where
|
|
|
|
client c = do
|
|
|
|
rm <- clientRegisterMethod c "/foo" Normal
|
|
|
|
result <- clientRequest c rm 1 "" mempty
|
2016-06-15 19:30:17 +02:00
|
|
|
result @?= deadlineExceededStatus
|
2016-06-13 16:25:32 +02:00
|
|
|
server s = do
|
|
|
|
let rm = head (registeredMethods s)
|
2016-06-22 19:41:14 +02:00
|
|
|
serverHandleNormalCall s rm mempty $ \_ _ _ -> do
|
2016-06-13 16:25:32 +02:00
|
|
|
threadDelay (2*10^(6 :: Int))
|
2016-06-22 22:07:38 +02:00
|
|
|
return dummyResp
|
2016-06-13 16:25:32 +02:00
|
|
|
return ()
|
|
|
|
|
2016-06-16 21:45:55 +02:00
|
|
|
testServerCallExpirationCheck :: TestTree
|
|
|
|
testServerCallExpirationCheck =
|
|
|
|
csTest "Check for call expiration" client server [("/foo", Normal)]
|
|
|
|
where
|
|
|
|
client c = do
|
|
|
|
rm <- clientRegisterMethod c "/foo" Normal
|
|
|
|
result <- clientRequest c rm 3 "" mempty
|
|
|
|
return ()
|
|
|
|
server s = do
|
|
|
|
let rm = head (registeredMethods s)
|
2016-06-22 19:41:14 +02:00
|
|
|
serverHandleNormalCall s rm mempty $ \c _ _ -> do
|
2016-06-16 21:45:55 +02:00
|
|
|
exp1 <- serverCallIsExpired c
|
|
|
|
assertBool "Call isn't expired when handler starts" $ not exp1
|
|
|
|
threadDelaySecs 1
|
|
|
|
exp2 <- serverCallIsExpired c
|
|
|
|
assertBool "Call isn't expired after 1 second" $ not exp2
|
|
|
|
threadDelaySecs 3
|
|
|
|
exp3 <- serverCallIsExpired c
|
|
|
|
assertBool "Call is expired after 4 seconds" exp3
|
2016-06-22 22:07:38 +02:00
|
|
|
return dummyResp
|
|
|
|
return ()
|
|
|
|
|
|
|
|
testCustomUserAgent :: TestTree
|
|
|
|
testCustomUserAgent =
|
|
|
|
csTest' "Server sees custom user agent prefix/suffix" client server
|
|
|
|
where
|
|
|
|
clientArgs = [UserAgentPrefix "prefix!", UserAgentSuffix "suffix!"]
|
|
|
|
client =
|
|
|
|
TestClient (ClientConfig "localhost" 50051 clientArgs) $
|
|
|
|
\c -> do rm <- clientRegisterMethod c "/foo" Normal
|
|
|
|
result <- clientRequest c rm 4 "" mempty
|
|
|
|
return ()
|
|
|
|
server = TestServer (stdServerConf [("/foo", Normal)]) $ \s -> do
|
|
|
|
let rm = head (registeredMethods s)
|
|
|
|
serverHandleNormalCall s rm mempty $ \_ _ meta -> do
|
|
|
|
let ua = meta M.! "user-agent"
|
|
|
|
assertBool "User agent prefix is present" $ isPrefixOf "prefix!" ua
|
|
|
|
assertBool "User agent suffix is present" $ isSuffixOf "suffix!" ua
|
|
|
|
return dummyResp
|
|
|
|
return ()
|
|
|
|
|
|
|
|
testClientCompression :: TestTree
|
|
|
|
testClientCompression =
|
|
|
|
csTest' "client-only compression: no errors" client server
|
|
|
|
where
|
|
|
|
client =
|
|
|
|
TestClient (ClientConfig
|
|
|
|
"localhost"
|
|
|
|
50051
|
|
|
|
[CompressionAlgArg GrpcCompressDeflate]) $ \c -> do
|
|
|
|
rm <- clientRegisterMethod c "/foo" Normal
|
|
|
|
result <- clientRequest c rm 1 "hello" mempty
|
|
|
|
return ()
|
|
|
|
server = TestServer (stdServerConf [("/foo", Normal)]) $ \s -> do
|
|
|
|
let rm = head (registeredMethods s)
|
|
|
|
serverHandleNormalCall s rm mempty $ \c body _ -> do
|
|
|
|
body @?= "hello"
|
|
|
|
return dummyResp
|
|
|
|
return ()
|
|
|
|
|
|
|
|
testClientServerCompression :: TestTree
|
|
|
|
testClientServerCompression =
|
|
|
|
csTest' "client/server compression: no errors" client server
|
|
|
|
where
|
|
|
|
cconf = ClientConfig "localhost"
|
|
|
|
50051
|
|
|
|
[CompressionAlgArg GrpcCompressDeflate]
|
|
|
|
client = TestClient cconf $ \c -> do
|
|
|
|
rm <- clientRegisterMethod c "/foo" Normal
|
|
|
|
clientRequest c rm 1 "hello" mempty >>= do
|
|
|
|
checkReqRslt $ \NormalRequestResult{..} -> do
|
|
|
|
rspCode @?= StatusOk
|
|
|
|
rspBody @?= "hello"
|
|
|
|
details @?= ""
|
|
|
|
initMD @?= Just dummyMeta
|
|
|
|
trailMD @?= dummyMeta
|
|
|
|
return ()
|
|
|
|
sconf = ServerConfig "localhost"
|
|
|
|
50051
|
|
|
|
[("/foo", Normal)]
|
|
|
|
[CompressionAlgArg GrpcCompressDeflate]
|
|
|
|
server = TestServer sconf $ \s -> do
|
|
|
|
let rm = head (registeredMethods s)
|
|
|
|
serverHandleNormalCall s rm dummyMeta $ \c body _ -> do
|
|
|
|
body @?= "hello"
|
|
|
|
return ("hello", dummyMeta, StatusOk, StatusDetails "")
|
2016-06-16 21:45:55 +02:00
|
|
|
return ()
|
|
|
|
|
2016-05-25 19:34:03 +02:00
|
|
|
--------------------------------------------------------------------------------
|
2016-05-25 19:49:38 +02:00
|
|
|
-- Utilities and helpers
|
|
|
|
|
|
|
|
dummyMeta :: M.Map ByteString ByteString
|
2016-06-08 20:12:07 +02:00
|
|
|
dummyMeta = [("foo","bar")]
|
2016-05-25 19:48:37 +02:00
|
|
|
|
2016-06-22 22:07:38 +02:00
|
|
|
dummyResp = ("", mempty, StatusOk, StatusDetails "")
|
|
|
|
|
2016-06-13 22:51:53 +02:00
|
|
|
dummyHandler :: ServerCall -> ByteString -> MetadataMap
|
2016-06-16 17:23:54 +02:00
|
|
|
-> IO (ByteString, MetadataMap, StatusCode, StatusDetails)
|
2016-06-22 22:07:38 +02:00
|
|
|
dummyHandler _ _ _ = return dummyResp
|
2016-06-13 16:25:32 +02:00
|
|
|
|
|
|
|
unavailableStatus :: Either GRPCIOError a
|
|
|
|
unavailableStatus =
|
2016-06-16 17:23:54 +02:00
|
|
|
Left (GRPCIOBadStatusCode StatusUnavailable (StatusDetails ""))
|
2016-06-13 16:25:32 +02:00
|
|
|
|
|
|
|
deadlineExceededStatus :: Either GRPCIOError a
|
|
|
|
deadlineExceededStatus =
|
2016-06-16 17:23:54 +02:00
|
|
|
Left (GRPCIOBadStatusCode StatusDeadlineExceeded
|
2016-06-13 16:25:32 +02:00
|
|
|
(StatusDetails "Deadline Exceeded"))
|
|
|
|
|
2016-05-25 19:48:37 +02:00
|
|
|
nop :: Monad m => a -> m ()
|
|
|
|
nop = const (return ())
|
2016-05-25 19:34:03 +02:00
|
|
|
|
2016-06-08 20:12:07 +02:00
|
|
|
serverOnlyTest :: TestName
|
|
|
|
-> [(MethodName, GRPCMethodType)]
|
|
|
|
-> (Server -> IO ())
|
|
|
|
-> TestTree
|
|
|
|
serverOnlyTest nm ms =
|
|
|
|
testCase ("Server - " ++ nm) . runTestServer . stdTestServer ms
|
|
|
|
|
|
|
|
clientOnlyTest :: TestName -> (Client -> IO ()) -> TestTree
|
|
|
|
clientOnlyTest nm =
|
|
|
|
testCase ("Client - " ++ nm) . runTestClient . stdTestClient
|
|
|
|
|
|
|
|
csTest :: TestName
|
|
|
|
-> (Client -> IO ())
|
|
|
|
-> (Server -> IO ())
|
|
|
|
-> [(MethodName, GRPCMethodType)]
|
|
|
|
-> TestTree
|
|
|
|
csTest nm c s ms = csTest' nm (stdTestClient c) (stdTestServer ms s)
|
|
|
|
|
|
|
|
csTest' :: TestName -> TestClient -> TestServer -> TestTree
|
|
|
|
csTest' nm tc ts =
|
|
|
|
testCase ("Client/Server - " ++ nm)
|
|
|
|
$ void (s `concurrently` c)
|
|
|
|
where
|
|
|
|
-- We use a small delay to give the server a head start
|
|
|
|
c = threadDelay 100000 >> runTestClient tc
|
|
|
|
s = runTestServer ts
|
|
|
|
|
|
|
|
-- | @checkMD msg expected actual@ fails when keys from @expected@ are not in
|
|
|
|
-- @actual@, or when values differ for matching keys.
|
|
|
|
checkMD :: String -> MetadataMap -> MetadataMap -> Assertion
|
|
|
|
checkMD desc expected actual = do
|
|
|
|
when (not $ M.null $ expected `diff` actual) $ do
|
|
|
|
assertEqual desc expected (actual `M.intersection` expected)
|
|
|
|
where
|
|
|
|
diff = M.differenceWith $ \a b -> if a == b then Nothing else Just b
|
|
|
|
|
|
|
|
checkReqRslt :: Show a => (b -> Assertion) -> Either a b -> Assertion
|
|
|
|
checkReqRslt = either clientFail
|
|
|
|
|
|
|
|
clientFail :: Show a => a -> Assertion
|
|
|
|
clientFail = assertFailure . ("Client error: " ++). show
|
|
|
|
|
|
|
|
data TestClient = TestClient ClientConfig (Client -> IO ())
|
|
|
|
|
|
|
|
runTestClient :: TestClient -> IO ()
|
|
|
|
runTestClient (TestClient conf c) = withGRPC $ \g -> withClient g conf c
|
|
|
|
|
|
|
|
stdTestClient :: (Client -> IO ()) -> TestClient
|
|
|
|
stdTestClient = TestClient stdClientConf
|
|
|
|
|
|
|
|
stdClientConf :: ClientConfig
|
2016-06-22 22:07:38 +02:00
|
|
|
stdClientConf = ClientConfig "localhost" 50051 []
|
2016-06-08 20:12:07 +02:00
|
|
|
|
|
|
|
data TestServer = TestServer ServerConfig (Server -> IO ())
|
|
|
|
|
|
|
|
runTestServer :: TestServer -> IO ()
|
|
|
|
runTestServer (TestServer conf s) = withGRPC $ \g -> withServer g conf s
|
|
|
|
|
|
|
|
stdTestServer :: [(MethodName, GRPCMethodType)] -> (Server -> IO ()) -> TestServer
|
|
|
|
stdTestServer = TestServer . stdServerConf
|
|
|
|
|
|
|
|
stdServerConf :: [(MethodName, GRPCMethodType)] -> ServerConfig
|
2016-06-22 22:07:38 +02:00
|
|
|
stdServerConf xs = ServerConfig "localhost" 50051 xs []
|
2016-06-16 21:45:55 +02:00
|
|
|
|
|
|
|
|
|
|
|
threadDelaySecs :: Int -> IO ()
|
|
|
|
threadDelaySecs = threadDelay . (* 10^(6::Int))
|