Skip to content

Commit 41920b8

Browse files
committed
Reduce flakiness of tests:
* Retry testnet tests when they fail * Retry parts of complex tests when they fail * Reduce number of BFT nodes * Set BFT nodes to 1 * Update cardano-crypto dependency
1 parent 289f905 commit 41920b8

File tree

6 files changed

+68
-74
lines changed

6 files changed

+68
-74
lines changed

.github/workflows/haskell.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ jobs:
2424
strategy:
2525
fail-fast: false
2626
matrix:
27+
# Add more elements to this list to run multiple instances of the build in CI. Increasing the
28+
# number instances is a good way to trigger flaky build failures
29+
n: [1]
30+
2731
ghc: ["8.10.7"]
2832
os: [ubuntu-latest, macos-latest, windows-latest]
2933

@@ -257,7 +261,7 @@ jobs:
257261
if: ${{ always() }}
258262
continue-on-error: true
259263
with:
260-
name: chairman-test-artifacts-${{ matrix.os }}-${{ matrix.ghc }}
264+
name: chairman-test-artifacts-${{ matrix.os }}-${{ matrix.n }}-${{ matrix.ghc }}
261265
path: ${{ runner.temp }}/chairman/
262266

263267
release:

cardano-testnet/src/Testnet/Byron.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ testnet testnetOptions H.Conf {..} = do
237237
sprocket <- H.noteShow $ Sprocket tempBaseAbsPath (socketDir </> "node-" <> si)
238238
_spocketSystemNameFile <- H.noteShow $ IO.sprocketSystemName sprocket
239239
-- TODO: Better error message need to indicate a sprocket was not created
240-
H.assertByDeadlineM deadline $ H.doesSprocketExist sprocket
240+
H.byDeadlineM 10 deadline $ H.assertM $ H.doesSprocketExist sprocket
241241

242242
forM_ nodeIndexes $ \i -> do
243243
si <- H.noteShow $ show @Int i

cardano-testnet/src/Testnet/Cardano.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,7 @@ testnet testnetOptions H.Conf {..} = do
833833
forM_ allNodeNames $ \node -> do
834834
sprocket <- H.noteShow $ Sprocket tempBaseAbsPath (socketDir </> node)
835835
_spocketSystemNameFile <- H.noteShow $ IO.sprocketSystemName sprocket
836-
H.assertByDeadlineM deadline $ H.doesSprocketExist sprocket
836+
H.byDeadlineM 10 deadline $ H.assertM $ H.doesSprocketExist sprocket
837837

838838
forM_ allNodeNames $ \node -> do
839839
nodeStdoutFile <- H.noteTempFile logDir $ node <> ".stdout.log"

cardano-testnet/src/Testnet/Shelley.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ testnet testnetOptions H.Conf {..} = do
454454
forM_ allNodes $ \node -> do
455455
sprocket <- H.noteShow $ Sprocket tempBaseAbsPath (socketDir </> node)
456456
_spocketSystemNameFile <- H.noteShow $ IO.sprocketSystemName sprocket
457-
H.assertByDeadlineM deadline $ H.doesSprocketExist sprocket
457+
H.byDeadlineM 10 deadline $ H.assertM $ H.doesSprocketExist sprocket
458458

459459
forM_ allNodes $ \node -> do
460460
nodeStdoutFile <- H.noteTempFile logDir $ node <> ".stdout.log"

cardano-testnet/src/Testnet/Utils.hs

+3-4
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,19 @@ module Testnet.Utils
1010
import Cardano.Api
1111
import Prelude
1212

13+
import Cardano.CLI.Shelley.Output
1314
import Control.Concurrent (threadDelay)
1415
import Control.Exception.Safe (MonadCatch)
1516
import Control.Monad
1617
import Control.Monad.IO.Class
1718
import Data.Aeson (fromJSON)
1819
import GHC.Stack
20+
import Hedgehog.Extras.Test.Process (ExecConfig)
21+
import Hedgehog.Internal.Property (MonadTest)
1922
import System.Directory (doesFileExist, removeFile)
2023

21-
import Cardano.CLI.Shelley.Output
22-
2324
import qualified Hedgehog.Extras.Test.Base as H
2425
import qualified Hedgehog.Extras.Test.File as H
25-
import Hedgehog.Extras.Test.Process (ExecConfig)
26-
import Hedgehog.Internal.Property (MonadTest)
2726
import qualified Test.Process as H
2827

2928

cardano-testnet/test/Spec/Cli/KesPeriodInfo.hs

+57-66
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,41 @@ module Spec.Cli.KesPeriodInfo
88
( hprop_kes_period_info
99
) where
1010

11-
12-
import Prelude
13-
1411
import Cardano.Api
15-
import Cardano.Api.Shelley
16-
12+
import Cardano.Api.Shelley (PoolId)
1713
import Control.Monad (void)
18-
import qualified Data.Aeson as J
19-
import qualified Data.Map.Strict as Map
2014
import Data.Monoid (Last (..))
2115
import Data.Set (Set)
22-
import qualified Data.Set as Set
23-
import qualified Data.Text as T
2416
import GHC.Stack (callStack)
25-
import qualified System.Directory as IO
17+
import Hedgehog (Property, (===))
18+
import Prelude
2619
import System.Environment (getEnvironment)
2720
import System.FilePath ((</>))
2821

2922
import Cardano.CLI.Shelley.Output
3023
import Cardano.CLI.Shelley.Run.Query
3124

32-
import Hedgehog (Property, (===))
25+
import Testnet.Cardano (TestnetOptions (..), TestnetRuntime (..), defaultTestnetOptions, testnet)
26+
import Testnet.Utils (waitUntilEpoch)
27+
28+
import qualified Data.Aeson as J
29+
import qualified Data.Map.Strict as Map
30+
import qualified Data.Set as Set
31+
import qualified Data.Text as T
3332
import qualified Hedgehog as H
3433
import qualified Hedgehog.Extras.Stock.IO.Network.Sprocket as IO
3534
import qualified Hedgehog.Extras.Test.Base as H
36-
import qualified Hedgehog.Extras.Test.Concurrent as H
3735
import qualified Hedgehog.Extras.Test.File as H
3836
import qualified Hedgehog.Extras.Test.Process as H
3937
import qualified System.Info as SYS
4038
import qualified Test.Base as H
4139
import qualified Test.Process as H
4240
import qualified Test.Runtime as TR
41+
import qualified System.Directory as IO
4342
import qualified Testnet.Cardano as TC
44-
import Testnet.Cardano (TestnetOptions (..), TestnetRuntime (..),
45-
defaultTestnetNodeOptions, defaultTestnetOptions, testnet)
43+
import Testnet.Cardano (defaultTestnetNodeOptions)
4644
import qualified Testnet.Conf as H
4745
import Testnet.Conf (ProjectBase (..), YamlFilePath (..))
48-
import Testnet.Utils (waitUntilEpoch)
4946

5047
import Testnet.Properties.Cli.KesPeriodInfo
5148

@@ -107,7 +104,7 @@ hprop_kes_period_info = H.integration . H.runFinallies . H.workspace "chairman"
107104

108105
utxo1Json <- H.leftFailM . H.readJsonFile $ work </> "utxo-1.json"
109106
UTxO utxo1 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxo1Json
110-
txin <- H.noteShow $ head $ Map.keys utxo1
107+
txin <- H.noteShow =<< H.headM (Map.keys utxo1)
111108

112109
-- Staking keys
113110
utxoStakingVkey2 <- H.note $ tempAbsPath </> "shelley/utxo-keys/utxo2-stake.vkey"
@@ -188,27 +185,24 @@ hprop_kes_period_info = H.integration . H.runFinallies . H.workspace "chairman"
188185
, "--testnet-magic", show @Int testnetMagic
189186
]
190187

191-
-- Things take long on non-linux machines
192-
if H.isLinux
193-
then H.threadDelay 5000000
194-
else H.threadDelay 10000000
188+
delegsAndRewards <- H.byDurationM 3 12 $ do
189+
-- Check to see if pledge's stake address was registered
195190

196-
-- Check to see if pledge's stake address was registered
197-
198-
void $ H.execCli' execConfig
199-
[ "query", "stake-address-info"
200-
, "--address", poolownerstakeaddr
201-
, "--testnet-magic", show @Int testnetMagic
202-
, "--out-file", work </> "pledgeownerregistration.json"
203-
]
191+
void $ H.execCli' execConfig
192+
[ "query", "stake-address-info"
193+
, "--address", poolownerstakeaddr
194+
, "--testnet-magic", show @Int testnetMagic
195+
, "--out-file", work </> "pledgeownerregistration.json"
196+
]
204197

205-
pledgerStakeInfo <- H.leftFailM . H.readJsonFile $ work </> "pledgeownerregistration.json"
206-
delegsAndRewardsMap <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards pledgerStakeInfo
207-
let delegsAndRewards = mergeDelegsAndRewards delegsAndRewardsMap
198+
pledgerStakeInfo <- H.leftFailM . H.readJsonFile $ work </> "pledgeownerregistration.json"
199+
delegsAndRewardsMap <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards pledgerStakeInfo
200+
delegsAndRewards <- H.noteShow $ mergeDelegsAndRewards delegsAndRewardsMap
208201

209-
length delegsAndRewards === 1
202+
length delegsAndRewards === 1
203+
return delegsAndRewards
210204

211-
let (pledgerSAddr, _rewards, _poolId) = head delegsAndRewards
205+
(pledgerSAddr, _rewards, _poolId) <- H.headM delegsAndRewards
212206

213207
-- Pledger and owner are and can be the same
214208
T.unpack (serialiseAddress pledgerSAddr) === poolownerstakeaddr
@@ -227,7 +221,7 @@ hprop_kes_period_info = H.integration . H.runFinallies . H.workspace "chairman"
227221

228222
utxoWithStaking1Json <- H.leftFailM . H.readJsonFile $ work </> "utxo-addr-with-staking-1.json"
229223
UTxO utxoWithStaking1 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxoWithStaking1Json
230-
txinForStakeReg <- H.noteShow $ head $ Map.keys utxoWithStaking1
224+
txinForStakeReg <- H.noteShow =<< H.headM (Map.keys utxoWithStaking1)
231225

232226
void $ H.execCli [ "stake-address", "registration-certificate"
233227
, "--stake-verification-key-file", utxoStakingVkey2
@@ -262,21 +256,21 @@ hprop_kes_period_info = H.integration . H.runFinallies . H.workspace "chairman"
262256
]
263257

264258
H.note_ $ "Check to see if " <> utxoStakingVkey2 <> " was registered..."
265-
H.threadDelay 10000000
266259

267-
void $ H.execCli' execConfig
268-
[ "query", "stake-address-info"
269-
, "--address", utxostakingaddr
270-
, "--testnet-magic", show @Int testnetMagic
271-
, "--out-file", work </> "stake-address-info-utxo-staking-vkey-2.json"
272-
]
273-
274-
userStakeAddrInfoJSON <- H.leftFailM . H.readJsonFile $ work </> "stake-address-info-utxo-staking-vkey-2.json"
275-
delegsAndRewardsMapUser <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards userStakeAddrInfoJSON
276-
let delegsAndRewardsUser = mergeDelegsAndRewards delegsAndRewardsMapUser
277-
userStakeAddrInfo = filter (\(sAddr,_,_) -> utxostakingaddr == T.unpack (serialiseAddress sAddr)) delegsAndRewardsUser
278-
(userSAddr, _rewards, _poolId) = head userStakeAddrInfo
260+
userSAddr <- H.byDurationM 3 12 $ do
261+
void $ H.execCli' execConfig
262+
[ "query", "stake-address-info"
263+
, "--address", utxostakingaddr
264+
, "--testnet-magic", show @Int testnetMagic
265+
, "--out-file", work </> "stake-address-info-utxo-staking-vkey-2.json"
266+
]
279267

268+
userStakeAddrInfoJSON <- H.leftFailM . H.readJsonFile $ work </> "stake-address-info-utxo-staking-vkey-2.json"
269+
delegsAndRewardsMapUser <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards userStakeAddrInfoJSON
270+
delegsAndRewardsUser <- H.noteShow $ mergeDelegsAndRewards delegsAndRewardsMapUser
271+
userStakeAddrInfo <- H.noteShow $ filter (\(sAddr,_,_) -> utxostakingaddr == T.unpack (serialiseAddress sAddr)) delegsAndRewardsUser
272+
(userSAddr, _rewards, _poolId) <- H.headM userStakeAddrInfo
273+
return userSAddr
280274

281275
H.note_ $ "Check staking key: " <> show utxoStakingVkey2 <> " was registered"
282276
T.unpack (serialiseAddress userSAddr) === utxostakingaddr
@@ -295,7 +289,7 @@ hprop_kes_period_info = H.integration . H.runFinallies . H.workspace "chairman"
295289

296290
utxo2Json <- H.leftFailM . H.readJsonFile $ work </> "utxo-2.json"
297291
UTxO utxo2 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxo2Json
298-
txin2 <- H.noteShow $ head $ Map.keys utxo2
292+
txin2 <- H.noteShow =<< H.headM (Map.keys utxo2)
299293

300294
H.note_ "Create delegation certificate of pledger"
301295

@@ -337,22 +331,19 @@ hprop_kes_period_info = H.integration . H.runFinallies . H.workspace "chairman"
337331
, "--testnet-magic", show @Int testnetMagic
338332
]
339333

340-
if H.isLinux
341-
then H.threadDelay 5000000
342-
else H.threadDelay 20000000
343-
344-
void $ H.execCli' execConfig
345-
[ "query", "stake-pools"
346-
, "--testnet-magic", show @Int testnetMagic
347-
, "--out-file", work </> "current-registered.pools.json"
348-
]
334+
H.byDurationM 3 12 $ do
335+
void $ H.execCli' execConfig
336+
[ "query", "stake-pools"
337+
, "--testnet-magic", show @Int testnetMagic
338+
, "--out-file", work </> "current-registered.pools.json"
339+
]
349340

350-
currRegPools <- H.leftFailM . H.readJsonFile $ work </> "current-registered.pools.json"
351-
poolIds <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(Set PoolId) currRegPools
352-
poolId <- H.noteShow $ head $ Set.toList poolIds
341+
currRegPools <- H.leftFailM . H.readJsonFile $ work </> "current-registered.pools.json"
342+
poolIds <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(Set PoolId) currRegPools
343+
poolId <- H.noteShow =<< H.headM (Set.toList poolIds)
353344

354-
H.note_ "Check stake pool was successfully registered"
355-
T.unpack (serialiseToBech32 poolId) === stakePoolId
345+
H.note_ "Check stake pool was successfully registered"
346+
T.unpack (serialiseToBech32 poolId) === stakePoolId
356347

357348
H.note_ "Check pledge was successfully delegated"
358349
void $ H.execCli' execConfig
@@ -364,9 +355,10 @@ hprop_kes_period_info = H.integration . H.runFinallies . H.workspace "chairman"
364355

365356
pledgeStakeAddrInfoJSON <- H.leftFailM . H.readJsonFile $ work </> "pledge-stake-address-info.json"
366357
delegsAndRewardsMapPledge <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards pledgeStakeAddrInfoJSON
367-
let delegsAndRewardsPledge = mergeDelegsAndRewards delegsAndRewardsMapPledge
368-
pledgeStakeAddrInfo = filter (\(sAddr,_,_) -> poolownerstakeaddr == T.unpack (serialiseAddress sAddr)) delegsAndRewardsPledge
369-
(pledgeSAddr, _rewards, pledgerDelegPoolId) = head pledgeStakeAddrInfo
358+
delegsAndRewardsPledge <- H.noteShow $ mergeDelegsAndRewards delegsAndRewardsMapPledge
359+
pledgeStakeAddrInfo <- H.noteShow $ filter (\(sAddr,_,_) -> poolownerstakeaddr == T.unpack (serialiseAddress sAddr)) delegsAndRewardsPledge
360+
361+
(pledgeSAddr, _rewards, pledgerDelegPoolId) <- H.headM pledgeStakeAddrInfo
370362

371363
H.note_ "Check pledge has been delegated to pool"
372364
case pledgerDelegPoolId of
@@ -467,4 +459,3 @@ hprop_kes_period_info = H.integration . H.runFinallies . H.workspace "chairman"
467459
-- TODO: Linking to the node log file like this is fragile.
468460
spoLogFile <- H.note $ tempAbsPath </> "logs/node-pool1.stdout.log"
469461
prop_node_minted_block spoLogFile
470-

0 commit comments

Comments
 (0)