mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-05-12 16:44:45 +00:00
147 lines
5.0 KiB
Haskell
147 lines
5.0 KiB
Haskell
{-# LANGUAGE DuplicateRecordFields #-}
|
|
{-# LANGUAGE NumericUnderscores #-}
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
|
|
module SMPAgentClient where
|
|
|
|
import Control.Monad
|
|
import Control.Monad.IO.Unlift
|
|
import Crypto.Random
|
|
import Network.Socket (HostName, ServiceName)
|
|
import SMPClient (testPort, withSmpServer, withSmpServerThreadOn)
|
|
import Simplex.Messaging.Agent
|
|
import Simplex.Messaging.Agent.Env.SQLite
|
|
import Simplex.Messaging.Agent.Transmission
|
|
import Simplex.Messaging.Client (SMPClientConfig (..), smpDefaultConfig)
|
|
import Simplex.Messaging.Transport
|
|
import Test.Hspec
|
|
import UnliftIO.Concurrent
|
|
import UnliftIO.Directory
|
|
import qualified UnliftIO.Exception as E
|
|
import UnliftIO.IO
|
|
|
|
agentTestHost :: HostName
|
|
agentTestHost = "localhost"
|
|
|
|
agentTestPort :: ServiceName
|
|
agentTestPort = "5001"
|
|
|
|
agentTestPort2 :: ServiceName
|
|
agentTestPort2 = "5011"
|
|
|
|
agentTestPort3 :: ServiceName
|
|
agentTestPort3 = "5021"
|
|
|
|
testDB :: String
|
|
testDB = "smp-agent.test.protocol.db"
|
|
|
|
testDB2 :: String
|
|
testDB2 = "smp-agent2.test.protocol.db"
|
|
|
|
testDB3 :: String
|
|
testDB3 = "smp-agent3.test.protocol.db"
|
|
|
|
smpAgentTest :: ARawTransmission -> IO ARawTransmission
|
|
smpAgentTest cmd = runSmpAgentTest $ \h -> tPutRaw h cmd >> tGetRaw h
|
|
|
|
runSmpAgentTest :: (MonadUnliftIO m, MonadRandom m) => (Handle -> m a) -> m a
|
|
runSmpAgentTest test = withSmpServer . withSmpAgent $ testSMPAgentClient test
|
|
|
|
runSmpAgentServerTest :: (MonadUnliftIO m, MonadRandom m) => ((ThreadId, ThreadId) -> Handle -> m a) -> m a
|
|
runSmpAgentServerTest test =
|
|
withSmpServerThreadOn testPort $
|
|
\server -> withSmpAgentThreadOn (agentTestPort, testDB) $
|
|
\agent -> testSMPAgentClient $ test (server, agent)
|
|
|
|
smpAgentServerTest :: ((ThreadId, ThreadId) -> Handle -> IO ()) -> Expectation
|
|
smpAgentServerTest test' = runSmpAgentServerTest test' `shouldReturn` ()
|
|
|
|
runSmpAgentTestN :: forall m a. (MonadUnliftIO m, MonadRandom m) => [(ServiceName, String)] -> ([Handle] -> m a) -> m a
|
|
runSmpAgentTestN agents test = withSmpServer $ run agents []
|
|
where
|
|
run :: [(ServiceName, String)] -> [Handle] -> m a
|
|
run [] hs = test hs
|
|
run (a@(p, _) : as) hs = withSmpAgentOn a $ testSMPAgentClientOn p $ \h -> run as (h : hs)
|
|
|
|
runSmpAgentTestN_1 :: forall m a. (MonadUnliftIO m, MonadRandom m) => Int -> ([Handle] -> m a) -> m a
|
|
runSmpAgentTestN_1 nClients test = withSmpServer . withSmpAgent $ run nClients []
|
|
where
|
|
run :: Int -> [Handle] -> m a
|
|
run 0 hs = test hs
|
|
run n hs = testSMPAgentClient $ \h -> run (n - 1) (h : hs)
|
|
|
|
smpAgentTestN :: [(ServiceName, String)] -> ([Handle] -> IO ()) -> Expectation
|
|
smpAgentTestN agents test' = runSmpAgentTestN agents test' `shouldReturn` ()
|
|
|
|
smpAgentTestN_1 :: Int -> ([Handle] -> IO ()) -> Expectation
|
|
smpAgentTestN_1 n test' = runSmpAgentTestN_1 n test' `shouldReturn` ()
|
|
|
|
smpAgentTest2 :: (Handle -> Handle -> IO ()) -> Expectation
|
|
smpAgentTest2 test' =
|
|
smpAgentTestN [(agentTestPort, testDB), (agentTestPort2, testDB2)] _test
|
|
where
|
|
_test [h1, h2] = test' h1 h2
|
|
_test _ = error "expected 2 handles"
|
|
|
|
smpAgentTest2_1 :: (Handle -> Handle -> IO ()) -> Expectation
|
|
smpAgentTest2_1 test' = smpAgentTestN_1 2 _test
|
|
where
|
|
_test [h1, h2] = test' h1 h2
|
|
_test _ = error "expected 2 handles"
|
|
|
|
smpAgentTest3 :: (Handle -> Handle -> Handle -> IO ()) -> Expectation
|
|
smpAgentTest3 test' =
|
|
smpAgentTestN
|
|
[(agentTestPort, testDB), (agentTestPort2, testDB2), (agentTestPort3, testDB3)]
|
|
_test
|
|
where
|
|
_test [h1, h2, h3] = test' h1 h2 h3
|
|
_test _ = error "expected 3 handles"
|
|
|
|
smpAgentTest3_1 :: (Handle -> Handle -> Handle -> IO ()) -> Expectation
|
|
smpAgentTest3_1 test' = smpAgentTestN_1 3 _test
|
|
where
|
|
_test [h1, h2, h3] = test' h1 h2 h3
|
|
_test _ = error "expected 3 handles"
|
|
|
|
cfg :: AgentConfig
|
|
cfg =
|
|
AgentConfig
|
|
{ tcpPort = agentTestPort,
|
|
rsaKeySize = 2048 `div` 8,
|
|
connIdBytes = 12,
|
|
tbqSize = 1,
|
|
dbFile = testDB,
|
|
smpCfg =
|
|
smpDefaultConfig
|
|
{ qSize = 1,
|
|
defaultPort = testPort,
|
|
tcpTimeout = 500_000
|
|
}
|
|
}
|
|
|
|
withSmpAgentThreadOn :: (MonadUnliftIO m, MonadRandom m) => (ServiceName, String) -> (ThreadId -> m a) -> m a
|
|
withSmpAgentThreadOn (port', db') =
|
|
E.bracket
|
|
(forkIOWithUnmask ($ runSMPAgent cfg {tcpPort = port', dbFile = db'}))
|
|
(liftIO . killThread >=> const (removeFile db'))
|
|
|
|
withSmpAgentOn :: (MonadUnliftIO m, MonadRandom m) => (ServiceName, String) -> m a -> m a
|
|
withSmpAgentOn (port', db') = withSmpAgentThreadOn (port', db') . const
|
|
|
|
withSmpAgent :: (MonadUnliftIO m, MonadRandom m) => m a -> m a
|
|
withSmpAgent = withSmpAgentOn (agentTestPort, testDB)
|
|
|
|
testSMPAgentClientOn :: MonadUnliftIO m => ServiceName -> (Handle -> m a) -> m a
|
|
testSMPAgentClientOn port' client = do
|
|
threadDelay 500_000 -- TODO hack: thread delay for SMP agent to start
|
|
runTCPClient agentTestHost port' $ \h -> do
|
|
line <- liftIO $ getLn h
|
|
if line == "Welcome to SMP v0.2.0 agent"
|
|
then client h
|
|
else error "not connected"
|
|
|
|
testSMPAgentClient :: MonadUnliftIO m => (Handle -> m a) -> m a
|
|
testSMPAgentClient = testSMPAgentClientOn agentTestPort
|