mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-03-30 14:16:00 +00:00
* smp server: optimize concurrency and memory usage, refactor * hide clients IntMap * reduce STM contention * comment * version * correct stats for subscriptions * version * comment * remove subscribed clients from map * version * optimze, refactor * version * debug test * enable all tests * remove test logs * retry failed tests with debug logging * increase test timeout * sync between tests
161 lines
5.9 KiB
Haskell
161 lines
5.9 KiB
Haskell
{-# LANGUAGE ScopedTypeVariables #-}
|
|
|
|
module CoreTests.RetryIntervalTests where
|
|
|
|
import Control.Concurrent (threadDelay)
|
|
import Control.Concurrent.Async (concurrently_)
|
|
import Control.Concurrent.STM
|
|
import Control.Monad (when)
|
|
import Data.Time.Clock (UTCTime, diffUTCTime, getCurrentTime, nominalDiffTimeToSeconds)
|
|
import Simplex.Messaging.Agent.RetryInterval
|
|
import Test.Hspec hiding (fit, it)
|
|
import Util
|
|
|
|
retryIntervalTests :: Spec
|
|
retryIntervalTests = do
|
|
describe "Retry interval with 2 modes and lock" $ do
|
|
testRetryIntervalSameMode
|
|
testRetryIntervalSwitchMode
|
|
describe "Foreground retry interval" $ do
|
|
testRetryForeground
|
|
testRetryToBackground
|
|
testRetrySkipWhenForeground
|
|
|
|
testRI :: RetryInterval2
|
|
testRI =
|
|
RetryInterval2
|
|
{ riSlow =
|
|
RetryInterval
|
|
{ initialInterval = 20000,
|
|
increaseAfter = 40000,
|
|
maxInterval = 40000
|
|
},
|
|
riFast = testFastRI
|
|
}
|
|
|
|
testFastRI :: RetryInterval
|
|
testFastRI =
|
|
RetryInterval
|
|
{ initialInterval = 10000,
|
|
increaseAfter = 20000,
|
|
maxInterval = 40000
|
|
}
|
|
|
|
testRetryIntervalSameMode :: Spec
|
|
testRetryIntervalSameMode =
|
|
it "should increase elapased time and interval when the mode stays the same" $ do
|
|
lock <- newEmptyTMVarIO
|
|
intervals <- newTVarIO []
|
|
reportedIntervals <- newTVarIO []
|
|
ts <- newTVarIO =<< getCurrentTime
|
|
withRetryLock2 testRI lock $ \(RI2State slow fast) loop -> do
|
|
ints <- addInterval intervals ts
|
|
atomically $ modifyTVar' reportedIntervals ((slow, fast) :)
|
|
when (length ints < 9) $ loop RIFast
|
|
(reverse <$> readTVarIO intervals) `shouldReturn` [0, 1, 1, 1, 2, 3, 4, 4, 4]
|
|
(reverse <$> readTVarIO reportedIntervals)
|
|
`shouldReturn` [ (20000, 10000),
|
|
(20000, 10000),
|
|
(20000, 15000),
|
|
(20000, 22500),
|
|
(20000, 33750),
|
|
(20000, 40000),
|
|
(20000, 40000),
|
|
(20000, 40000),
|
|
(20000, 40000)
|
|
]
|
|
|
|
testRetryIntervalSwitchMode :: Spec
|
|
testRetryIntervalSwitchMode =
|
|
it "should increase elapased time and interval when the mode switches" $ do
|
|
lock <- newEmptyTMVarIO
|
|
intervals <- newTVarIO []
|
|
reportedIntervals <- newTVarIO []
|
|
ts <- newTVarIO =<< getCurrentTime
|
|
withRetryLock2 testRI lock $ \(RI2State slow fast) loop -> do
|
|
ints <- addInterval intervals ts
|
|
atomically $ modifyTVar' reportedIntervals ((slow, fast) :)
|
|
when (length ints < 11) $ loop $ if length ints <= 5 then RIFast else RISlow
|
|
(reverse <$> readTVarIO intervals) `shouldReturn` [0, 1, 1, 1, 2, 3, 2, 2, 3, 4, 4]
|
|
(reverse <$> readTVarIO reportedIntervals)
|
|
`shouldReturn` [ (20000, 10000),
|
|
(20000, 10000),
|
|
(20000, 15000),
|
|
(20000, 22500),
|
|
(20000, 33750),
|
|
(20000, 40000),
|
|
(20000, 40000),
|
|
(30000, 40000),
|
|
(40000, 40000),
|
|
(40000, 40000),
|
|
(40000, 40000)
|
|
]
|
|
|
|
testRetryForeground :: Spec
|
|
testRetryForeground =
|
|
it "should increase elapased time and interval" $ do
|
|
intervals <- newTVarIO []
|
|
reportedIntervals <- newTVarIO []
|
|
ts <- newTVarIO =<< getCurrentTime
|
|
let isForeground = pure True
|
|
withRetryForeground testFastRI isForeground (pure True) $ \delay loop -> do
|
|
ints <- addInterval intervals ts
|
|
atomically $ modifyTVar' reportedIntervals (delay :)
|
|
when (length ints < 8) $ loop
|
|
(reverse <$> readTVarIO intervals) `shouldReturn` [0, 1, 1, 1, 2, 3, 4, 4]
|
|
(reverse <$> readTVarIO reportedIntervals)
|
|
`shouldReturn` [10000, 10000, 15000, 22500, 33750, 40000, 40000, 40000]
|
|
|
|
testRetryToBackground :: Spec
|
|
testRetryToBackground =
|
|
it "should not change interval when moving to background" $ do
|
|
intervals <- newTVarIO []
|
|
reportedIntervals <- newTVarIO []
|
|
ts <- newTVarIO =<< getCurrentTime
|
|
foreground <- newTVarIO True
|
|
concurrently_
|
|
( do
|
|
threadDelay 50000
|
|
atomically $ writeTVar foreground False
|
|
)
|
|
( withRetryForeground testFastRI (readTVar foreground) (pure True) $ \delay loop -> do
|
|
ints <- addInterval intervals ts
|
|
atomically $ modifyTVar' reportedIntervals (delay :)
|
|
when (length ints < 8) $ loop
|
|
)
|
|
(reverse <$> readTVarIO intervals) `shouldReturn` [0, 1, 1, 1, 2, 3, 4, 4]
|
|
(reverse <$> readTVarIO reportedIntervals)
|
|
`shouldReturn` [10000, 10000, 15000, 22500, 33750, 40000, 40000, 40000]
|
|
|
|
testRetrySkipWhenForeground :: Spec
|
|
testRetrySkipWhenForeground =
|
|
it "should repeat loop as soon as moving to foreground" $ do
|
|
intervals <- newTVarIO []
|
|
reportedIntervals <- newTVarIO []
|
|
ts <- newTVarIO =<< getCurrentTime
|
|
foreground <- newTVarIO False
|
|
concurrently_
|
|
( do
|
|
threadDelay 65000
|
|
atomically $ writeTVar foreground True
|
|
threadDelay 10000
|
|
atomically $ writeTVar foreground False
|
|
threadDelay 100000
|
|
atomically $ writeTVar foreground True
|
|
)
|
|
( withRetryForeground testFastRI (readTVar foreground) (pure True) $ \delay loop -> do
|
|
ints <- addInterval intervals ts
|
|
atomically $ modifyTVar' reportedIntervals (delay :)
|
|
when (length ints < 12) $ loop
|
|
)
|
|
(reverse <$> readTVarIO intervals) `shouldReturn` [0, 1, 1, 1, 2, 0, 1, 1, 1, 2, 3, 1]
|
|
(reverse <$> readTVarIO reportedIntervals)
|
|
`shouldReturn` [10000, 10000, 15000, 22500, 33750, 10000, 10000, 15000, 22500, 33750, 40000, 10000]
|
|
|
|
addInterval :: TVar [Int] -> TVar UTCTime -> IO [Int]
|
|
addInterval intervals ts = do
|
|
ts' <- getCurrentTime
|
|
atomically $ do
|
|
int :: Int <- truncate . (* 100) . nominalDiffTimeToSeconds <$> stateTVar ts (\t -> (diffUTCTime ts' t, ts'))
|
|
stateTVar intervals $ \ints -> (int : ints, int : ints)
|