Skip to content

Commit 242c006

Browse files
committed
cardano-testnet: add single entrypoint for starting Shelley Babbage and Cardano testnets
1 parent 521b64a commit 242c006

File tree

17 files changed

+256
-318
lines changed

17 files changed

+256
-318
lines changed

cardano-node-chairman/test/Spec/Chairman/Cardano.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import qualified Hedgehog.Extras.Test.Base as H
1616
import qualified Hedgehog.Extras.Test.Process as H
1717
import qualified System.Directory as IO
1818
import qualified Test.Base as H
19+
import qualified Test.Runtime as H
1920
import qualified Testnet.Cardano as H
2021
import qualified Testnet.Conf as H
2122

@@ -29,6 +30,6 @@ hprop_chairman = H.integration . H.runFinallies . H.workspace "chairman" $ \temp
2930
configurationTemplate <- H.noteShow $ base </> "configuration/defaults/byron-mainnet/configuration.yaml"
3031
conf <- H.mkConf (H.ProjectBase base) (H.YamlFilePath configurationTemplate) tempAbsPath' Nothing
3132

32-
allNodes <- fmap H.nodeName . H.allNodes <$> H.testnet H.defaultTestnetOptions conf
33+
allNodes <- fmap H.nodeName . H.allNodes <$> H.cardanoTestnet H.defaultTestnetOptions conf
3334

3435
chairmanOver 120 50 conf allNodes

cardano-node-chairman/test/Spec/Chairman/Shelley.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Spec.Chairman.Shelley
66

77
import Control.Monad ((=<<))
88
import Data.Function
9+
import Data.Functor
910
import Data.Maybe
1011
import Spec.Chairman.Chairman (chairmanOver)
1112
import System.FilePath ((</>))
@@ -15,6 +16,7 @@ import qualified Hedgehog.Extras.Test.Base as H
1516
import qualified Hedgehog.Extras.Test.Process as H
1617
import qualified System.Directory as IO
1718
import qualified Test.Base as H
19+
import qualified Test.Runtime as H
1820
import qualified Testnet.Conf as H
1921
import qualified Testnet.Shelley as H
2022

@@ -28,6 +30,6 @@ hprop_chairman = H.integration . H.runFinallies . H.workspace "chairman" $ \temp
2830
configurationTemplate <- H.noteShow $ base </> "configuration/defaults/byron-mainnet/configuration.yaml"
2931
conf <- H.mkConf (H.ProjectBase base) (H.YamlFilePath configurationTemplate) tempAbsPath' Nothing
3032

31-
allNodes <- H.testnet H.defaultTestnetOptions conf
33+
allNodes <- fmap H.nodeName . H.allNodes <$> H.shelleyTestnet H.defaultTestnetOptions conf
3234

3335
chairmanOver 120 21 conf allNodes

cardano-testnet/cardano-testnet.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ library
5757
Test.Base
5858
Test.Process
5959
Test.Runtime
60+
Testnet
6061
Testnet.Babbage
6162
Testnet.Byron
6263
Testnet.Cardano

cardano-testnet/src/Test/Process.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module Test.Process
33
, assertByDeadlineMCustom
44
, bashPath
55
, execCli
6+
, execCli_
67
, execCli'
78
, execCreateScriptContext
89
, execCreateScriptContext'
@@ -52,6 +53,13 @@ execCli
5253
-> m String
5354
execCli = GHC.withFrozenCallStack $ H.execFlex "cardano-cli" "CARDANO_CLI"
5455

56+
-- | Run cardano-cli, discarding return value
57+
execCli_
58+
:: (MonadTest m, MonadCatch m, MonadIO m, HasCallStack)
59+
=> [String]
60+
-> m ()
61+
execCli_ = void . execCli
62+
5563
-- | Run cardano-cli, returning the stdout
5664
execCli'
5765
:: (MonadTest m, MonadCatch m, MonadIO m, HasCallStack)

cardano-testnet/src/Test/Runtime.hs

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,22 @@
22
{-# LANGUAGE DeriveGeneric #-}
33
{-# LANGUAGE DuplicateRecordFields #-}
44
{-# LANGUAGE LambdaCase #-}
5-
{-# LANGUAGE NamedFieldPuns #-}
65

76
module Test.Runtime
87
( LeadershipSlot(..)
98
, NodeLoggingFormat(..)
109
, PaymentKeyPair(..)
1110
, StakingKeyPair(..)
1211
, TestnetRuntime(..)
12+
, NodeRuntime(..)
1313
, TestnetNode(..)
1414
, PoolNode(..)
1515
, PoolNodeKeys(..)
1616
, Delegator(..)
17+
, allNodes
1718
, bftSprockets
1819
, poolSprockets
19-
, poolNodeToTestnetNode
20+
, poolNodeStdout
2021
, readNodeLoggingFormat
2122
) where
2223

@@ -49,7 +50,7 @@ data TestnetRuntime = TestnetRuntime
4950
, delegators :: [Delegator]
5051
}
5152

52-
data TestnetNode = TestnetNode
53+
data NodeRuntime = NodeRuntime
5354
{ nodeName :: String
5455
, nodeSprocket :: Sprocket
5556
, nodeStdinHandle :: IO.Handle
@@ -58,14 +59,11 @@ data TestnetNode = TestnetNode
5859
, nodeProcessHandle :: IO.ProcessHandle
5960
}
6061

62+
newtype TestnetNode = TestnetNode {unTestnetNode :: NodeRuntime}
63+
6164
data PoolNode = PoolNode
62-
{ poolNodeName :: String
63-
, poolNodeSprocket :: Sprocket
64-
, poolNodeStdinHandle :: IO.Handle
65-
, poolNodeStdout :: FilePath
66-
, poolNodeStderr :: FilePath
67-
, poolNodeProcessHandle :: IO.ProcessHandle
68-
, poolNodeKeys :: PoolNodeKeys
65+
{ poolRuntime :: NodeRuntime
66+
, poolKeys :: PoolNodeKeys
6967
}
7068

7169
data PoolNodeKeys = PoolNodeKeys
@@ -97,31 +95,20 @@ data LeadershipSlot = LeadershipSlot
9795
, slotTime :: Text
9896
} deriving (Eq, Show, Generic, FromJSON)
9997

100-
poolNodeToTestnetNode :: PoolNode -> TestnetNode
101-
poolNodeToTestnetNode PoolNode
102-
{ poolNodeName
103-
, poolNodeSprocket
104-
, poolNodeStdinHandle
105-
, poolNodeStdout
106-
, poolNodeStderr
107-
, poolNodeProcessHandle
108-
} = TestnetNode
109-
{ nodeName = poolNodeName
110-
, nodeSprocket = poolNodeSprocket
111-
, nodeStdinHandle = poolNodeStdinHandle
112-
, nodeStdout = poolNodeStdout
113-
, nodeStderr = poolNodeStderr
114-
, nodeProcessHandle = poolNodeProcessHandle
115-
}
98+
poolNodeStdout :: PoolNode -> FilePath
99+
poolNodeStdout = nodeStdout . poolRuntime
116100

117101
bftSprockets :: TestnetRuntime -> [Sprocket]
118-
bftSprockets = fmap nodeSprocket . bftNodes
102+
bftSprockets = fmap (nodeSprocket . unTestnetNode) . bftNodes
119103

120104
poolSprockets :: TestnetRuntime -> [Sprocket]
121-
poolSprockets = fmap poolNodeSprocket . poolNodes
105+
poolSprockets = fmap (nodeSprocket . poolRuntime) . poolNodes
122106

123107
readNodeLoggingFormat :: String -> Either String NodeLoggingFormat
124108
readNodeLoggingFormat = \case
125109
"json" -> Right NodeLoggingFormatAsJson
126110
"text" -> Right NodeLoggingFormatAsText
127111
s -> Left $ "Unrecognised node logging format: " <> show s <> ". Valid options: \"json\", \"text\""
112+
113+
allNodes :: TestnetRuntime -> [NodeRuntime]
114+
allNodes tr = fmap unTestnetNode (bftNodes tr) <> fmap poolRuntime (poolNodes tr)

cardano-testnet/src/Testnet.hs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module Testnet
2+
( TestnetOptions(..)
3+
, Testnet.testnet
4+
) where
5+
6+
import Data.Eq (Eq)
7+
import Text.Show (Show)
8+
9+
import qualified Hedgehog.Extras.Test.Base as H
10+
11+
import Testnet.Babbage
12+
import Testnet.Cardano
13+
import Testnet.Conf
14+
import Testnet.Shelley
15+
16+
data TestnetOptions
17+
= ShelleyOnlyTestnetOptions ShelleyTestnetOptions
18+
| BabbageOnlyTestnetOptions BabbageTestnetOptions
19+
| CardanoOnlyTestnetOptions CardanoTestnetOptions
20+
deriving (Eq, Show)
21+
22+
testnet :: TestnetOptions -> Conf -> H.Integration TestnetRuntime
23+
testnet options = case options of
24+
ShelleyOnlyTestnetOptions o -> shelleyTestnet o
25+
BabbageOnlyTestnetOptions o -> babbageTestnet o
26+
CardanoOnlyTestnetOptions o -> cardanoTestnet o
27+

cardano-testnet/src/Testnet/Babbage.hs

Lines changed: 19 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
{-# OPTIONS_GHC -Wno-unused-local-binds -Wno-unused-matches #-}
99

1010
module Testnet.Babbage
11-
( TestnetOptions(..)
11+
( BabbageTestnetOptions(..)
1212
, defaultTestnetOptions
1313
, TestnetNodeOptions(..)
1414
, defaultTestnetNodeOptions
@@ -17,64 +17,57 @@ module Testnet.Babbage
1717
, TestnetNode (..)
1818
, PaymentKeyPair(..)
1919

20-
, testnet
20+
, babbageTestnet
2121
) where
2222

2323
import Control.Applicative (Applicative (..))
24-
import Control.Monad (Monad (..), fmap, forM, forM_, return, void, when, (=<<))
24+
import Control.Monad
2525
import Data.Aeson (encode, object, toJSON, (.=))
2626
import Data.Bool (Bool (..))
2727
import Data.Eq (Eq)
2828
import Data.Function (flip, ($), (.))
29-
import Data.Functor ((<$>), (<&>))
29+
import Data.Functor
3030
import Data.Int (Int)
31-
import Data.Maybe (Maybe (..))
32-
import Data.Ord (Ord ((<=)))
3331
import Data.Semigroup (Semigroup ((<>)))
3432
import Data.String (String)
3533
import GHC.Float (Double)
36-
import Hedgehog.Extras.Stock.IO.Network.Sprocket (Sprocket (..))
3734
import Hedgehog.Extras.Stock.Time (showUTCTimeSeconds)
3835
import System.FilePath.Posix ((</>))
36+
3937
import Test.Runtime (Delegator (..), NodeLoggingFormat (..), PaymentKeyPair (..),
4038
PoolNode (PoolNode), PoolNodeKeys (..), StakingKeyPair (..), TestnetNode (..),
4139
TestnetRuntime (..))
40+
import Testnet.Utils
4241
import Text.Show (Show (show))
4342

4443
import qualified Data.HashMap.Lazy as HM
4544
import qualified Data.List as L
4645
import qualified Data.Time.Clock as DTC
47-
import qualified Hedgehog as H
4846
import qualified Hedgehog.Extras.Stock.Aeson as J
49-
import qualified Hedgehog.Extras.Stock.IO.Network.Sprocket as IO
5047
import qualified Hedgehog.Extras.Stock.OS as OS
51-
import qualified Hedgehog.Extras.Stock.String as S
5248
import qualified Hedgehog.Extras.Test.Base as H
5349
import qualified Hedgehog.Extras.Test.File as H
54-
import qualified Hedgehog.Extras.Test.Process as H
5550
import qualified System.Info as OS
56-
import qualified System.IO as IO
57-
import qualified System.Process as IO
5851
import qualified Test.Assert as H
59-
import qualified Test.Process as H
6052
import qualified Testnet.Conf as H
6153

54+
import Test.Process (execCli_)
6255
{- HLINT ignore "Reduce duplication" -}
6356
{- HLINT ignore "Redundant <&>" -}
6457
{- HLINT ignore "Redundant flip" -}
6558
{- HLINT ignore "Redundant id" -}
6659
{- HLINT ignore "Use let" -}
6760

68-
data TestnetOptions = TestnetOptions
61+
data BabbageTestnetOptions = BabbageTestnetOptions
6962
{ numSpoNodes :: Int
7063
, slotDuration :: Int
7164
, securityParam :: Int
7265
, totalBalance :: Int
7366
, nodeLoggingFormat :: NodeLoggingFormat
7467
} deriving (Eq, Show)
7568

76-
defaultTestnetOptions :: TestnetOptions
77-
defaultTestnetOptions = TestnetOptions
69+
defaultTestnetOptions :: BabbageTestnetOptions
70+
defaultTestnetOptions = BabbageTestnetOptions
7871
{ numSpoNodes = 3
7972
, slotDuration = 1000
8073
, securityParam = 10
@@ -92,8 +85,8 @@ defaultTestnetNodeOptions = TestnetNodeOptions
9285
startTimeOffsetSeconds :: DTC.NominalDiffTime
9386
startTimeOffsetSeconds = if OS.isWin32 then 90 else 15
9487

95-
testnet :: TestnetOptions -> H.Conf -> H.Integration TestnetRuntime
96-
testnet testnetOptions H.Conf {..} = do
88+
babbageTestnet :: BabbageTestnetOptions -> H.Conf -> H.Integration TestnetRuntime
89+
babbageTestnet testnetOptions H.Conf {..} = do
9790
H.createDirectoryIfMissing (tempAbsPath </> "logs")
9891

9992
H.lbsWriteFile (tempAbsPath </> "byron.genesis.spec.json") . encode $ object
@@ -124,7 +117,7 @@ testnet testnetOptions H.Conf {..} = do
124117
currentTime <- H.noteShowIO DTC.getCurrentTime
125118
startTime <- H.noteShow $ DTC.addUTCTime startTimeOffsetSeconds currentTime
126119

127-
void . H.execCli $
120+
execCli_
128121
[ "byron", "genesis", "genesis"
129122
, "--protocol-magic", show @Int testnetMagic
130123
, "--start-time", showUTCTimeSeconds startTime
@@ -180,7 +173,7 @@ testnet testnetOptions H.Conf {..} = do
180173

181174
let numPoolNodes = 3 :: Int
182175

183-
void . H.execCli $
176+
execCli_
184177
[ "genesis", "create-staked"
185178
, "--genesis-dir", tempAbsPath
186179
, "--testnet-magic", show @Int testnetMagic
@@ -340,49 +333,19 @@ testnet testnetOptions H.Conf {..} = do
340333
]
341334
]
342335

343-
(poolSprockets, poolStdins, poolStdouts, poolStderrs, poolProcessHandles) <- fmap L.unzip5 . forM spoNodes $ \node -> do
344-
dbDir <- H.noteShow $ tempAbsPath </> "db/" <> node
345-
nodeStdoutFile <- H.noteTempFile logDir $ node <> ".stdout.log"
346-
nodeStderrFile <- H.noteTempFile logDir $ node <> ".stderr.log"
347-
sprocket <- H.noteShow $ Sprocket tempBaseAbsPath (socketDir </> node)
348-
349-
H.createDirectoryIfMissing dbDir
350-
H.createDirectoryIfMissing $ tempBaseAbsPath </> socketDir
351-
352-
hNodeStdout <- H.openFile nodeStdoutFile IO.WriteMode
353-
hNodeStderr <- H.openFile nodeStderrFile IO.WriteMode
354-
355-
H.diff (L.length (IO.sprocketArgumentName sprocket)) (<=) IO.maxSprocketArgumentNameLength
356-
357-
portString <- fmap S.strip . H.readFile $ tempAbsPath </> node </> "port"
358-
359-
(Just stdIn, _, _, hProcess, _) <- H.createProcess =<<
360-
( H.procNode
336+
poolNodes <- forM (L.zip spoNodes poolKeys) $ \(node,key) -> do
337+
runtime <- startNode socketDir tempBaseAbsPath tempAbsPath logDir node
361338
[ "run"
362339
, "--config", tempAbsPath </> "configuration.yaml"
363340
, "--topology", tempAbsPath </> node </> "topology.json"
364341
, "--database-path", tempAbsPath </> node </> "db"
365-
, "--socket-path", IO.sprocketArgumentName sprocket
366342
, "--shelley-kes-key", tempAbsPath </> node </> "kes.skey"
367343
, "--shelley-vrf-key", tempAbsPath </> node </> "vrf.skey"
368344
, "--byron-delegation-certificate", tempAbsPath </> node </> "byron-delegation.cert"
369345
, "--byron-signing-key", tempAbsPath </> node </> "byron-delegate.key"
370346
, "--shelley-operational-certificate", tempAbsPath </> node </> "opcert.cert"
371-
, "--port", portString
372-
] <&>
373-
( \cp -> cp
374-
{ IO.std_in = IO.CreatePipe
375-
, IO.std_out = IO.UseHandle hNodeStdout
376-
, IO.std_err = IO.UseHandle hNodeStderr
377-
, IO.cwd = Just tempBaseAbsPath
378-
}
379-
)
380-
)
381-
382-
when (OS.os `L.elem` ["darwin", "linux"]) $ do
383-
H.onFailure . H.noteIO_ $ IO.readProcess "lsof" ["-iTCP:" <> portString, "-sTCP:LISTEN", "-n", "-P"] ""
384-
385-
return (sprocket, stdIn, nodeStdoutFile, nodeStderrFile, hProcess)
347+
]
348+
return $ PoolNode runtime key
386349

387350
now <- H.noteShowIO DTC.getCurrentTime
388351
deadline <- H.noteShow $ DTC.addUTCTime 90 now
@@ -401,14 +364,7 @@ testnet testnetOptions H.Conf {..} = do
401364
{ configurationFile
402365
, shelleyGenesisFile = tempAbsPath </> "genesis/shelley/genesis.json"
403366
, testnetMagic
404-
, poolNodes = L.zipWith7 PoolNode
405-
spoNodes
406-
poolSprockets
407-
poolStdins
408-
poolStdouts
409-
poolStderrs
410-
poolProcessHandles
411-
poolKeys
367+
, poolNodes
412368
, wallets = wallets
413369
, bftNodes = []
414370
, delegators = delegators

0 commit comments

Comments
 (0)