tests: reproduce RSLV fan-out, proxy stuck session

This commit is contained in:
shum
2026-09-09 07:30:04 +00:00
parent 23d912eb92
commit 58e4f0eaa7
3 changed files with 46 additions and 0 deletions
+20
View File
@@ -11,7 +11,10 @@
module RSLVTests (rslvTests) where
import Control.Concurrent (threadDelay)
import Control.Monad (forM_)
import Control.Monad.Trans.Except (ExceptT, runExceptT)
import Data.IORef (readIORef)
import qualified Data.Aeson as J
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy as LB
@@ -82,6 +85,23 @@ rslvTests = do
it "PFWD-wrapped RSLV success returns RNAME (record JSON frames over the proxy)" testRslvForwardedSuccess
describe "RSLV success path (RNAME response)" $ do
it "returns RNAME with NameRecord" testRslvSuccess
describe "RSLV resource use" $
xit "one connection must not fan out to many concurrent resolver requests" testRslvFanOut
testRslvFanOut :: IO ()
testRslvFanOut =
NRS.withResolverServerDelayed 3000 (NRS.resolveResp status200 "{}") $ \port reqs ->
withSmpServerConfigOn (transport @TLS) (withNames port memCfg) testPort $ const $
testSMPClient @TLS $ \(h@THandle {params} :: THandleSMP TLS 'TClient) -> do
let k = 64 :: Int
globalCap = 8 :: Int
forM_ [1 .. k] $ \i -> do
let TransmissionForAuth {tToSend} = encodeTransmissionForAuth params (CorrId (B.pack $ "fan" <> show i), NoEntity, Cmd SResolver (RSLV (domain "alice.simplex")))
[Right ()] <- tPut h (Right (Nothing, tToSend) :| [])
pure ()
threadDelay 800000
inFlight <- length . filter ((== ["resolve"]) . take 1) <$> readIORef reqs
inFlight `shouldSatisfy` (<= globalCap)
testRslvBackendNotFound :: IO ()
testRslvBackendNotFound =
+11
View File
@@ -346,6 +346,17 @@ proxyCfgShortTimeout =
nt = NetworkTimeout {backgroundTimeout = 4_000000, interactiveTimeout = 4_000000}
in cfg' {smpAgentCfg = aCfg {smpCfg = cCfg {networkConfig = (networkConfig cCfg) {tcpConnectTimeout = nt}}}}
-- Proxy whose forward (RFWD) response deadline is 1us: every forward to the relay times out
-- while the initial relay connect (tcpConnectTimeout) is unaffected, so a session is established
-- and then every forward on it fails with a response timeout.
proxyCfgForwardTimeout :: AServerConfig
proxyCfgForwardTimeout =
updateCfg proxyCfg $ \cfg' ->
let aCfg = smpAgentCfg cfg'
cCfg = smpCfg aCfg
nt = NetworkTimeout {backgroundTimeout = 1, interactiveTimeout = 1}
in cfg' {smpAgentCfg = aCfg {smpCfg = cCfg {networkConfig = (networkConfig cCfg) {tcpTimeout = nt}}}}
withSmpServerStoreMsgLogOn :: HasCallStack => (ASrvTransport, AStoreType) -> ServiceName -> (HasCallStack => ThreadId -> IO a) -> IO a
withSmpServerStoreMsgLogOn (t, msType) =
withSmpServerConfigOn t $ updateCfg (cfgMS msType) $ \cfg' -> cfg' {storeNtfsFile = Just testStoreNtfsFile, serverStatsBackupFile = Just testServerStatsBackupFile}
+15
View File
@@ -63,6 +63,8 @@ smpProxyTests = do
testProxyRecoversWithoutDisconnect
it "reconnects to relay after sender disconnects mid-connection" $ \_ ->
testProxyReconnectAfterRelayRestart
xit "must drop a stuck relay session after forward timeouts" $ \_ ->
testProxyForwardTimeoutStuckSession
describe "agent client reconnection" $ do
it "reconnects after a connect is cancelled mid-flight" $ \_ ->
testAgentClientReconnectAfterCancel
@@ -494,6 +496,19 @@ testProxyReconnectAfterRelayRestart =
race_ (threadDelay 1000000) requestRelaySession
requireProxyReconnect
testProxyForwardTimeoutStuckSession :: IO ()
testProxyForwardTimeoutStuckSession =
withSmpServerConfigOn (transport @TLS) proxyCfgForwardTimeout testPort $ \_ -> do
g <- C.newRandom
ts <- getCurrentTime
let srv = SMPServer testHost testPort testKeyHash
vr = mkVersionRange minServerSMPRelayVersion currentClientSMPRelayVersion
pc <- either (fail . show) pure =<< getProtocolClient g NRMInteractive (1, srv, Nothing) defaultSMPClientConfig {serverVRange = vr} [] Nothing ts (\_ -> pure ())
sess <- runExceptT' $ connectSMPProxiedRelay pc NRMInteractive srv (Just "correct")
sId <- atomically $ SMP.EntityId <$> C.randomBytes 24 g
rs <- forM ([1 .. 10] :: [Int]) $ \_ -> runExceptT' (proxySMPMessage pc NRMInteractive sess Nothing sId noMsgFlags "hi")
rs `shouldSatisfy` elem (Left (ProxyProtocolError (SMP.PROXY SMP.NO_SESSION)))
-- Bug B (same root cause as the proxy, in the messaging agent): getSMPServerClient inserts an
-- empty SessionVar into smpClients, then connects inside newProtocolClient's tryAllErrors, which
-- rethrows async exceptions. If the connecting thread is cancelled mid-connect, putTMVar is