Skip to content

Commit

Permalink
Add genesis-create hedgehog test
Browse files Browse the repository at this point in the history
  • Loading branch information
newhoggy committed Jul 10, 2020
1 parent 412345b commit 78dfefa
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 115 deletions.
10 changes: 10 additions & 0 deletions cardano-cli/cardano-cli.cabal
Expand Up @@ -174,15 +174,23 @@ test-suite cardano-cli-pioneers
type: exitcode-stdio-1.0

build-depends: base
, aeson
, bech32
, cardano-api
, cardano-cli
, cardano-prelude
, containers
, directory
, hedgehog
, lens
, lens-aeson
, optparse-applicative
, temporary
, text
, time
, transformers-except
, unordered-containers
, vector

other-modules: Test.CLI.Byron.Golden.TextEnvelope.PaymentKeys
Test.CLI.Byron.Golden.TextEnvelope.Tx
Expand All @@ -203,6 +211,8 @@ test-suite cardano-cli-pioneers
Test.CLI.Shelley.Golden.TextEnvelope.Tx.Tx
Test.CLI.Shelley.Golden.TextEnvelope.Tx.TxBody
Test.CLI.Shelley.Golden.TextEnvelope.Tx.Witness
Test.CLI.TextEnvelope.Golden.Genesis.Create
Test.CLI.TextEnvelope.Tests
Test.CLI.Shelley.Tests
Test.ITN
Test.OptParse
Expand Down
13 changes: 13 additions & 0 deletions cardano-cli/hie.yaml
@@ -0,0 +1,13 @@
cradle:
cabal:
- path: "src"
component: "lib:cardano-cli"

- path: "app/cardano-cli.hs"
component: "cardano-cli:exe:cardano-cli"

# - path: "test"
# component: "cardano-cli:test:cardano-cli-test"

- path: "test"
component: "cardano-cli:test:cardano-cli-pioneers"
134 changes: 134 additions & 0 deletions cardano-cli/test/Test/CLI/TextEnvelope/Golden/Genesis/Create.hs
@@ -0,0 +1,134 @@
{-# LANGUAGE OverloadedStrings #-}

module Test.CLI.TextEnvelope.Golden.Genesis.Create
( golden_genesisCreate
) where

import Cardano.Prelude hiding (to)

import Data.Maybe
( fromJust
)
import Control.Lens
( (^?)
, (^..)
, each
)
import Prelude(String)

import qualified Control.Lens as CL
import qualified Data.Aeson as J
import qualified Data.Aeson.Lens as J
import qualified Data.HashMap.Strict as HM
import qualified Data.List as L
import qualified Data.Set as S
import qualified Data.Text as T
import qualified Data.Time.Clock as DT
import qualified Data.Time.Format as DT
import qualified Data.Vector as DV
import qualified System.Directory as IO
import qualified System.IO as IO
import qualified System.IO.Temp as IO

import Hedgehog
( Property
, forAll
, (===)
)

import qualified Hedgehog as H
import qualified Hedgehog.Gen as G
import qualified Hedgehog.Range as R
import qualified Test.OptParse as OP

{- HLINT ignore "Use camelCase" -}

-- | Convert an object to an array of array.
--
-- For example: {"a": 1, "b": 2} -> [["a", 1], ["b", 2]]
objectToArray :: J.Value -> J.Value
objectToArray v = case v of
J.Object o -> J.Array (DV.fromList (fmap (\(ek, ev) -> J.Array (DV.fromList [J.String ek, ev])) (HM.toList o)))
a -> a

-- | Assert the file contains the given number of occurences of the given string
assertFileOccurences :: Int -> String -> FilePath -> H.PropertyT IO ()
assertFileOccurences n s fp = do
signingKeyContents <- liftIO $ IO.readFile fp

length (filter (s `L.isInfixOf`) (L.lines signingKeyContents)) === n

-- | Format the given time as an ISO 8601 date-time string
formatIso8601 :: DT.UTCTime -> String
formatIso8601 = DT.formatTime DT.defaultTimeLocale (DT.iso8601DateFormat (Just "%H:%M:%SZ"))

-- | Return the supply value with the result of the supplied function as a tuple
withSnd :: (a -> b) -> a -> (a, b)
withSnd f a = (a, f a)

golden_genesisCreate :: Property
golden_genesisCreate = OP.propertyOnce $ do
liftIO $ IO.createDirectoryIfMissing True "cardano-cli/tmp"
tempDir <- liftIO $ IO.createTempDirectory "cardano-cli/tmp" "test"
let genesisFile = tempDir <> "/genesis.json"
let cleanupPaths = [tempDir]

fmtStartTime <- fmap formatIso8601 $ liftIO DT.getCurrentTime

(supply , fmtSupply ) <- fmap (withSnd show) $ forAll $ G.int (R.linear 10000000 4000000000)
(delegateCount, fmtDelegateCount) <- fmap (withSnd show) $ forAll $ G.int (R.linear 4 19)

-- Create the genesis json file and required keys
OP.execCardanoCLIParser cleanupPaths $
OP.evalCardanoCLIParser
[ "shelley","genesis","create"
, "--testnet-magic", "12"
, "--start-time", fmtStartTime
, "--supply", fmtSupply
, "--gen-genesis-keys", fmtDelegateCount
, "--gen-utxo-keys", fmtDelegateCount
, "--genesis-dir", tempDir
]

OP.assertFilesExist [genesisFile]

genesisContents <- liftIO $ IO.readFile genesisFile

H.annotate genesisContents

actualSupply <- forAll $ pure $ fromJust $ genesisContents ^? J.key "maxLovelaceSupply" . J._Integral
actualStartTime <- forAll $ pure $ fromJust $ genesisContents ^? J.key "systemStart" . J._String <&> T.unpack
actualDelegateCount <- forAll $ pure $ fromJust $ genesisContents ^? J.key "genDelegs" . J._Object <&> HM.size
actualTotalSupply <- forAll $ pure $ sum $ genesisContents ^.. J.key "initialFunds" . J._Object . CL.to HM.toList . each . CL._2 . J._Integral
actualDelegates <- forAll $ pure $ fromJust $ genesisContents ^? J.key "genDelegs" . CL.to objectToArray . J._Array

actualSupply === supply
actualStartTime === fmtStartTime
actualDelegateCount === delegateCount
actualTotalSupply === supply -- Check that the sum of the initial fund amounts matches the total supply

-- Check uniqueness and count of hash keys
let hashKeys = actualDelegates ^.. each . J.nth 0 . J._String

S.size (S.fromList hashKeys) === length hashKeys -- This isn't strictless necessary because we use aeson which guarantees uniqueness of keys
S.size (S.fromList hashKeys) === delegateCount

-- Check uniqueness and count of hash keys
let delegateKeys = actualDelegates ^.. each . J.nth 1 . J.key "delegate" . J._String

S.size (S.fromList delegateKeys) === length delegateKeys
S.size (S.fromList delegateKeys) === delegateCount

for_ [1 .. delegateCount] $ \i -> do
-- Check Genesis keys
assertFileOccurences 1"Genesis signing key" $ tempDir <> "/genesis-keys/genesis" <> show i <> ".skey"
assertFileOccurences 1"Genesis verification key" $ tempDir <> "/genesis-keys/genesis" <> show i <> ".vkey"

-- Check delegate keys
assertFileOccurences 1"Node operator signing key" $ tempDir <> "/delegate-keys/delegate" <> show i <> ".skey"
assertFileOccurences 1"Node operator verification key" $ tempDir <> "/delegate-keys/delegate" <> show i <> ".vkey"
assertFileOccurences 1"Node operational certificate issue counter" $ tempDir <> "/delegate-keys/delegate" <> show i <> ".counter"

-- Check utxo keys
assertFileOccurences 1"Genesis UTxO signing key" $ tempDir <> "/utxo-keys/utxo" <> show i <> ".skey"
assertFileOccurences 1"Genesis UTxO verification key" $ tempDir <> "/utxo-keys/utxo" <> show i <> ".vkey"
19 changes: 19 additions & 0 deletions cardano-cli/test/Test/CLI/TextEnvelope/Tests.hs
@@ -0,0 +1,19 @@
{-# LANGUAGE OverloadedStrings #-}

module Test.CLI.TextEnvelope.Tests
( cliTests
) where

import Cardano.Prelude

import Test.CLI.TextEnvelope.Golden.Genesis.Create
(golden_genesisCreate)

import qualified Hedgehog as H

cliTests :: IO Bool
cliTests =
H.checkSequential
$ H.Group "TextEnvelope Goldens"
[ ("golden_genesisCreate", golden_genesisCreate)
]
3 changes: 3 additions & 0 deletions cardano-cli/test/cardano-cli-pioneers.hs
Expand Up @@ -6,6 +6,7 @@ import System.IO (BufferMode (..))
import qualified System.IO as IO

import qualified Test.CLI.Shelley.Tests
import qualified Test.CLI.TextEnvelope.Tests
import qualified Test.ITN
import qualified Test.Pioneers.Exercise1
import qualified Test.Pioneers.Exercise2
Expand All @@ -22,6 +23,8 @@ main = do
, Test.CLI.Shelley.Tests.metaDatatests
, Test.CLI.Shelley.Tests.txTests

, Test.CLI.TextEnvelope.Tests.cliTests

, Test.Pioneers.Exercise1.tests
, Test.Pioneers.Exercise2.tests
, Test.Pioneers.Exercise3.tests
Expand Down
114 changes: 0 additions & 114 deletions cardano-cli/test/cli/genesis-create/run

This file was deleted.

2 changes: 1 addition & 1 deletion nix/haskell.nix
Expand Up @@ -69,7 +69,7 @@ let
# Needed for the CLI tests.
# Coreutils because we need 'paste'.
packages.cardano-cli.components.tests.cardano-cli-test.build-tools =
lib.mkForce [buildPackages.bc buildPackages.jq buildPackages.coreutils buildPackages.shellcheck];
lib.mkForce [buildPackages.jq buildPackages.coreutils buildPackages.shellcheck];
}
{
# Stamp executables with the git revision
Expand Down

0 comments on commit 78dfefa

Please sign in to comment.