Skip to content

Commit ca91cae

Browse files
Add timout property test for timeLimitsChainSync
1 parent 6b4e35b commit ca91cae

File tree

5 files changed

+128
-4
lines changed

5 files changed

+128
-4
lines changed

cardano-diffusion/cardano-diffusion.cabal

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ library protocols-tests-lib
295295
hs-source-dirs: protocols/tests-lib
296296
exposed-modules:
297297
Cardano.Network.Protocol.Handshake.Test
298+
Cardano.Network.Protocol.ChainSync.Codec.TimeLimits.Test
298299

299300
reexported-modules:
300301
Ouroboros.Network.Protocol.BlockFetch.Codec.CDDL as Cardano.Network.Protocol.BlockFetch.Codec.CDDL,
@@ -335,13 +336,14 @@ library protocols-tests-lib
335336
QuickCheck,
336337
base >=4.14 && <4.23,
337338
bytestring,
338-
cardano-diffusion:api,
339+
cardano-diffusion:{api, protocols},
339340
cborg,
340341
containers,
341342
contra-tracer,
342-
io-classes,
343+
io-classes:{io-classes, si-timers},
343344
io-sim,
344-
ouroboros-network:{api, framework, protocols-tests-lib},
345+
ouroboros-network:{api, framework, protocols, protocols-tests-lib},
346+
random,
345347
tasty,
346348
tasty-quickcheck,
347349
text,

cardano-diffusion/changelog.d/20251211_130157_edgr_chainsync_timeouts.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ For top level release notes, leave all the headers commented out.
1111
- Added parameter `PeerTrustable` to `timeLimitsChainSync`.
1212
- Changed timeout behavior: No timeout when peer is trusted and ChainSync state is `StNext StMustReply`.
1313

14+
### Non-Breaking
15+
16+
- Added property tests to validate the timeout behavior of the `timeLimitsChainSync` function.

cardano-diffusion/protocols/lib/Cardano/Network/Protocol/ChainSync/Codec/TimeLimits.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import System.Random (StdGen, randomR)
2828
-- +----------------+----------------------------+-------------------------------------------------------------+
2929
-- | Trustable peer | ChainSync State | timeout (s) |
3030
-- +================+============================+=============================================================+
31-
-- | | @'StIdle'@ | 'waitForever' (i.e. never times out) |
31+
-- | | @'StIdle'@ | corresponds to 'ChainSyncIdleTimeout' |
3232
-- +----------------+----------------------------+-------------------------------------------------------------+
3333
-- | | @'StNext' 'StCanAwait'@ | 'shortWait' |
3434
-- +----------------+----------------------------+-------------------------------------------------------------+
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
{-# OPTIONS_GHC -Wno-orphans #-}
2+
3+
module Cardano.Network.Protocol.ChainSync.Codec.TimeLimits.Test where
4+
5+
import Control.Monad.Class.MonadTime.SI ( DiffTime )
6+
import System.Random (mkStdGen)
7+
8+
import Cardano.Network.PeerSelection.PeerTrustable (PeerTrustable (..))
9+
import Cardano.Network.Protocol.ChainSync.Codec.TimeLimits (timeLimitsChainSync)
10+
11+
import Ouroboros.Network.Protocol.ChainSync.Codec (ChainSyncIdleTimeout (..),
12+
maxChainSyncTimeout, minChainSyncTimeout)
13+
import Ouroboros.Network.Protocol.ChainSync.Type (SingChainSync (..),
14+
SingNextKind (..))
15+
import Ouroboros.Network.Protocol.Limits (ProtocolTimeLimitsWithRnd (..),
16+
shortWait)
17+
18+
import Test.QuickCheck (Arbitrary (..), Property, oneof, property, elements)
19+
import Test.Tasty (TestTree, testGroup)
20+
import Test.Tasty.QuickCheck (testProperty, (===))
21+
22+
23+
tests :: TestTree
24+
tests =
25+
testGroup "Ouroboros.Network.Protocol"
26+
[ testGroup "ChainSync"
27+
[ testGroup "TimeLimits"
28+
[ testProperty "timeout in 'StIntersect'"
29+
prop_short_wait_timeout_in_intersect
30+
, testProperty "timeout in 'StNext' 'StCanWait'"
31+
prop_short_wait_timeout_in_canwait
32+
, testProperty "timeout in 'StIdle' state"
33+
prop_timeout_in_idle
34+
, testProperty "timeout range for non-trustable peers in 'StNext' 'StMustReply' state"
35+
prop_timeout_range_for_not_trustable_in_mustreply
36+
, testProperty "no timeout for trustable peers in 'StNext' 'StMustReply' state"
37+
prop_no_timeout_for_trustable_peers_in_mustreply
38+
]
39+
]
40+
]
41+
42+
-- | For state 'StIntersect', the timeout is always 'shortWait'
43+
prop_short_wait_timeout_in_intersect
44+
:: PeerTrustable -> ChainSyncIdleTimeout -> Int -> Property
45+
prop_short_wait_timeout_in_intersect peerTrustable idleTimeout seed =
46+
timeout === shortWait
47+
where
48+
limits = timeLimitsChainSync idleTimeout peerTrustable
49+
(timeout, _) =
50+
timeLimitForStateWithRnd limits SingIntersect (mkStdGen seed)
51+
52+
-- | For state 'StNext' 'StCanAwait', the timeout is always 'shortWait'
53+
prop_short_wait_timeout_in_canwait
54+
:: PeerTrustable -> ChainSyncIdleTimeout -> Int -> Property
55+
prop_short_wait_timeout_in_canwait peerTrustable idleTimeout seed =
56+
timeout === shortWait
57+
where
58+
limits = timeLimitsChainSync idleTimeout peerTrustable
59+
(timeout, _) =
60+
timeLimitForStateWithRnd limits (SingNext SingCanAwait) (mkStdGen seed)
61+
62+
-- | For state 'StIdle', the timeout is 'ChainSyncIdleTimeout'
63+
prop_timeout_in_idle
64+
:: PeerTrustable -> ChainSyncIdleTimeout -> Int -> Property
65+
prop_timeout_in_idle peerTrustable idleTimeout seed =
66+
timeout === timeout'
67+
where
68+
timeout' = case idleTimeout of
69+
ChainSyncNoIdleTimeout -> Nothing
70+
ChainSyncIdleTimeout t -> Just t
71+
limits = timeLimitsChainSync idleTimeout peerTrustable
72+
(timeout, _) = timeLimitForStateWithRnd limits SingIdle (mkStdGen seed)
73+
74+
-- | For non-trustable peers and in 'StNext' 'StMustReply' state, the timeout is
75+
-- always within the specified range
76+
prop_timeout_range_for_not_trustable_in_mustreply
77+
:: ChainSyncIdleTimeout -> Int -> Property
78+
prop_timeout_range_for_not_trustable_in_mustreply idleTimeout seed =
79+
property $
80+
maybe
81+
False
82+
(\t -> t >= minChainSyncTimeout && t <= maxChainSyncTimeout)
83+
timeout
84+
where
85+
limits = timeLimitsChainSync idleTimeout IsNotTrustable
86+
(timeout, _) =
87+
timeLimitForStateWithRnd limits (SingNext SingMustReply) (mkStdGen seed)
88+
89+
-- | For trustable peers, there's never a timeout in 'StNext' 'StMustReply'
90+
-- state
91+
prop_no_timeout_for_trustable_peers_in_mustreply
92+
:: ChainSyncIdleTimeout -> Int -> Property
93+
prop_no_timeout_for_trustable_peers_in_mustreply idleTimeout seed =
94+
timeout === Nothing
95+
where
96+
limits = timeLimitsChainSync idleTimeout IsTrustable
97+
(timeout, _) =
98+
timeLimitForStateWithRnd limits (SingNext SingMustReply) (mkStdGen seed)
99+
100+
101+
-- TODO Duplicated code: move ouroboros-network-tests-lib OrphanInstances
102+
103+
instance Arbitrary PeerTrustable where
104+
arbitrary = elements [IsTrustable, IsNotTrustable]
105+
106+
instance Arbitrary ChainSyncIdleTimeout where
107+
arbitrary = oneof
108+
[ pure ChainSyncNoIdleTimeout
109+
, ChainSyncIdleTimeout <$> arbitrary
110+
]
111+
112+
instance Arbitrary DiffTime where
113+
arbitrary = fromRational <$> arbitrary
114+
115+
instance Show ChainSyncIdleTimeout where
116+
show ChainSyncNoIdleTimeout = "ChainSyncNoIdleTimeout"
117+
show (ChainSyncIdleTimeout t) = "ChainSyncIdleTimeout " ++ show t

cardano-diffusion/protocols/tests/Main.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module Main (main) where
22

33
import Test.Tasty
44

5+
import Cardano.Network.Protocol.ChainSync.Codec.TimeLimits.Test qualified (tests)
56
import Cardano.Network.Protocol.Handshake.Test qualified (tests)
67

78
main :: IO ()
@@ -12,5 +13,6 @@ tests =
1213
testGroup "ouroboros-network-protocols"
1314

1415
[ -- protocols
16+
Cardano.Network.Protocol.ChainSync.Codec.TimeLimits.Test.tests,
1517
Cardano.Network.Protocol.Handshake.Test.tests
1618
]

0 commit comments

Comments
 (0)