diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 5e7d61ab7a1..992be8988b7 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -120,14 +120,6 @@ steps: concurrency: 8 concurrency_group: 'linux-integration-tests' - - label: Run Haskell E2E Tests (linux) - command: 'nix develop --command bash -c "just e2e-local"' - soft_fail: - - exit_status: 130 - timeout_in_minutes: 30 - agents: - system: ${linux} - - block: Run Ruby E2E Tests (linux) if: build.env("RELEASE_CANDIDATE") == null depends_on: [] @@ -587,15 +579,18 @@ steps: key: trigger-windows-e2e-tests - label: ⚙️ Windows E2E Tests + timeout_in_minutes: 120 depends_on: - trigger-windows-e2e-tests commands: + - diff -r configs/cardano/preprod lib/integration/configs/cardano/preprod # ensure the configs don't diverge despite being duplicated - ./scripts/buildkite/main/windows-e2e.bat agents: system: ${windows} env: - TESTS_E2E_FIXTURES: "$FIXTURE_DECRYPTION_KEY" - NODE_DB_DIR: "test\\e2e\\state\\node_db\\preprod" + NODE_DB_DIR: "test\\e2e\\state\\node\\db" + NODE_DIR: "test\\e2e\\state\\node" + WALLET_DB_DIR: "test\\e2e\\state\\wallet" AGGREGATOR_ENDPOINT: "${PREPROD_AGGREGATOR_ENDPOINT}" GENESIS_VERIFICATION_KEY: "${PREPROD_GENESIS_VERIFICATION_KEY}" concurrency: 1 diff --git a/cabal.project b/cabal.project index 919f4e5594a..be3e14b91bb 100644 --- a/cabal.project +++ b/cabal.project @@ -89,7 +89,6 @@ packages: lib/wai-middleware-logging/ lib/wallet-benchmarks/ lib/wallet/ - lib/wallet-e2e/ -------------------------------------------------------------------------------- -- BEGIN OpenAPI diff --git a/flake.nix b/flake.nix index e339fafcbe9..49321d252da 100644 --- a/flake.nix +++ b/flake.nix @@ -214,7 +214,8 @@ inherit (project.hsPkgs.cardano-wallet.components.exes) mock-token-metadata-server; inherit (project.hsPkgs.cardano-wallet-benchmarks.components.exes) benchmark-history; inherit (project.hsPkgs.local-cluster.components.exes) local-cluster; - inherit (project.hsPkgs.cardano-wallet-integration.components.exes) integration-exe; + integration-exe = project.hsPkgs.cardano-wallet-integration.components.exes.integration-exe; + e2e = project.hsPkgs.cardano-wallet-integration.components.tests.e2e; inherit (project.hsPkgs.local-cluster.components.exes) test-local-cluster-exe; # Adrestia tool belt @@ -227,8 +228,6 @@ deployments = pkgs.cardano-node-deployments; }; - cardano-wallet-e2e = project.hsPkgs.cardano-wallet-e2e.components.exes.wallet-e2e; - # Provide db-converter, so daedalus can ship it without needing to # pin an ouroborus-network rev. inherit (project.hsPkgs.ouroboros-consensus-byron.components.exes) db-converter; diff --git a/justfile b/justfile index 279879fadd0..907b243ae53 100644 --- a/justfile +++ b/justfile @@ -72,31 +72,17 @@ unit-tests-local-cluster-match match: unit-tests-cabal: just unit-tests-cabal-match "" -# run wallet-e2e suite against the preprod network -e2e-preprod: - nix shell \ - '.#cardano-node' '.#cardano-wallet' '.#cardano-wallet-e2e' \ - -c wallet-e2e preprod \ - -s lib/wallet-e2e/test-state/preprod \ - -c lib/wallet-e2e/config/cardano-node/preprod \ - -t lib/wallet-e2e/test-output/preprod +# run cardano-wallet-integration:e2e suite against the preprod network +e2e: + # ugly env workaround as the default values work with cabal but not nix + WALLET_DB_DIR=test/e2e/state/wallet \ + NODE_DIR=test/e2e/state/node \ + NODE_DB_DIR=test/e2e/state/node/db \ + nix shell '.#cardano-node' '.#cardano-wallet' '.#e2e' -c e2e add_missing_json_goldens: CREATE_MISSING_GOLDEN=1 just unit-tests-cabal-match "JSON" -# run wallet-e2e suite against the local test cluster -e2e-local: - nix shell \ - '.#local-cluster' '.#cardano-node' '.#cardano-wallet' '.#cardano-wallet-e2e' \ - -c wallet-e2e local \ - -s lib/wallet-e2e/test-state/local \ - -c lib/local-cluster/test/data/cluster-configs \ - -t lib/wallet-e2e/test-output/local - -# run wallet-e2e suite against the manually started node/wallet -e2e-manual: - nix run '.#cardano-wallet-e2e' -- manual - # run any integration test matching the given pattern via cabal integration-tests-cabal-match match: just integration-tests-cabal-options '--match="{{match}}"' diff --git a/lib/benchmarks/exe/latency-bench.hs b/lib/benchmarks/exe/latency-bench.hs index 17a9100798a..364d7e310bd 100644 --- a/lib/benchmarks/exe/latency-bench.hs +++ b/lib/benchmarks/exe/latency-bench.hs @@ -671,8 +671,7 @@ withShelleyServer tracers action = withFaucet $ \faucetClientEnv -> do putMVar ctx Context - { _cleanup = pure () - , _manager = (baseUrl, manager) + { _manager = (baseUrl, manager) , _walletPort = Port . fromIntegral $ portFromURL baseUrl , _faucet = faucet , _networkParameters = np @@ -682,6 +681,7 @@ withShelleyServer tracers action = withFaucet $ \faucetClientEnv -> do , _smashUrl = "" , _mainEra = maxBound , _mintSeaHorseAssets = error "mintSeaHorseAssets not available" + , _preprodWallets = [] } race_ (takeMVar ctx >>= action massiveWalletMnemonic') diff --git a/lib/integration/cardano-wallet-integration.cabal b/lib/integration/cardano-wallet-integration.cabal index 51548253d7e..52ae8cba10b 100644 --- a/lib/integration/cardano-wallet-integration.cabal +++ b/lib/integration/cardano-wallet-integration.cabal @@ -205,6 +205,7 @@ library scenarios Test.Integration.Scenario.CLI.Shelley.HWWallets Test.Integration.Scenario.CLI.Shelley.Transactions Test.Integration.Scenario.CLI.Shelley.Wallets + Test.Integration.Scenario.Preprod common integration-common import: language, opts-exe @@ -216,6 +217,33 @@ common integration-common executable integration-exe import: integration-common main-is: integration-tests-exe.hs + hs-source-dirs: exe + +test-suite e2e + import: integration-common + type: exitcode-stdio-1.0 + data-files: configs + hs-source-dirs: configs + build-depends: + , aeson + , bytestring + , cardano-addresses + , cardano-wallet-api + , cardano-wallet-exe + , cardano-wallet-integration:framework + , cardano-wallet-launcher + , cardano-wallet-primitive + , cardano-wallet-test-utils + , contra-tracer + , directory + , file-embed + , filepath + , hspec + , network-uri + , temporary + , text + , with-utf8 + main-is: e2e.hs test-suite integration import: integration-common diff --git a/lib/integration/configs/.gitattributes b/lib/integration/configs/.gitattributes new file mode 100644 index 00000000000..bf78ec20471 --- /dev/null +++ b/lib/integration/configs/.gitattributes @@ -0,0 +1,9 @@ +# Pin line endings for genesis files. +# +# Genesis files are +# * human-readable text data +# * but they also have a hash. +# +# `cardano-node` is sensitive to the line endings in the genesis file. +# +**/*.json text eol=lf diff --git a/lib/wallet-e2e/config/cardano-node/preprod/alonzo-genesis.json b/lib/integration/configs/cardano/preprod/alonzo-genesis.json similarity index 100% rename from lib/wallet-e2e/config/cardano-node/preprod/alonzo-genesis.json rename to lib/integration/configs/cardano/preprod/alonzo-genesis.json diff --git a/lib/wallet-e2e/config/cardano-node/preprod/byron-genesis.json b/lib/integration/configs/cardano/preprod/byron-genesis.json similarity index 100% rename from lib/wallet-e2e/config/cardano-node/preprod/byron-genesis.json rename to lib/integration/configs/cardano/preprod/byron-genesis.json diff --git a/lib/wallet-e2e/config/cardano-node/preprod/config.json b/lib/integration/configs/cardano/preprod/config.json similarity index 97% rename from lib/wallet-e2e/config/cardano-node/preprod/config.json rename to lib/integration/configs/cardano/preprod/config.json index 563fbde095b..ab3b5dfcc57 100644 --- a/lib/wallet-e2e/config/cardano-node/preprod/config.json +++ b/lib/integration/configs/cardano/preprod/config.json @@ -68,11 +68,6 @@ "stdout" ] ], - "hasEKG": 12788, - "hasPrometheus": [ - "127.0.0.1", - 12798 - ], "minSeverity": "Info", "options": { "mapBackends": { diff --git a/lib/wallet-e2e/config/cardano-node/preprod/conway-genesis.json b/lib/integration/configs/cardano/preprod/conway-genesis.json similarity index 100% rename from lib/wallet-e2e/config/cardano-node/preprod/conway-genesis.json rename to lib/integration/configs/cardano/preprod/conway-genesis.json diff --git a/lib/integration/configs/cardano/preprod/download.sh b/lib/integration/configs/cardano/preprod/download.sh new file mode 100755 index 00000000000..76109cdefb8 --- /dev/null +++ b/lib/integration/configs/cardano/preprod/download.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -euo pipefail + +rm ./*.json +curl https://book.play.dev.cardano.org/environments-pre/preprod/config.json > config.json +curl https://book.play.dev.cardano.org/environments-pre/preprod/conway-genesis.json > conway-genesis.json +curl https://book.play.dev.cardano.org/environments-pre/preprod/topology.json > topology.json +curl https://book.play.dev.cardano.org/environments-pre/preprod/byron-genesis.json > byron-genesis.json +curl https://book.play.dev.cardano.org/environments-pre/preprod/shelley-genesis.json > shelley-genesis.json +curl https://book.play.dev.cardano.org/environments-pre/preprod/alonzo-genesis.json > alonzo-genesis.json diff --git a/lib/wallet-e2e/config/cardano-node/preprod/shelley-genesis.json b/lib/integration/configs/cardano/preprod/shelley-genesis.json similarity index 100% rename from lib/wallet-e2e/config/cardano-node/preprod/shelley-genesis.json rename to lib/integration/configs/cardano/preprod/shelley-genesis.json diff --git a/lib/integration/configs/cardano/preprod/topology.json b/lib/integration/configs/cardano/preprod/topology.json new file mode 100644 index 00000000000..2241cbcb9aa --- /dev/null +++ b/lib/integration/configs/cardano/preprod/topology.json @@ -0,0 +1,23 @@ +{ + "bootstrapPeers": [ + { + "address": "preprod-node.play.dev.cardano.org", + "port": 3001 + } + ], + "localRoots": [ + { + "accessPoints": [], + "advertise": false, + "trustable": false, + "valency": 1 + } + ], + "publicRoots": [ + { + "accessPoints": [], + "advertise": false + } + ], + "useLedgerAfterSlot": 64454371 +} diff --git a/lib/integration/configs/cardano/refresh.sh b/lib/integration/configs/cardano/refresh.sh new file mode 100755 index 00000000000..157ca1e48b4 --- /dev/null +++ b/lib/integration/configs/cardano/refresh.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +for dir in preprod; do + (cd "$dir" && ./download.sh) +done diff --git a/lib/integration/exe/e2e.hs b/lib/integration/exe/e2e.hs new file mode 100644 index 00000000000..bff548deabd --- /dev/null +++ b/lib/integration/exe/e2e.hs @@ -0,0 +1,290 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TypeApplications #-} +{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} +{-# HLINT ignore "Redundant return" #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE TemplateHaskell #-} + +module Main where + +import Prelude + +import qualified Cardano.Launcher.Wallet as Launcher +import qualified Data.Aeson as Aeson +import qualified Data.Aeson.KeyMap as KeyMap +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as BL +import qualified Data.Text as T +import qualified Test.Integration.Scenario.Preprod as Preprod + +import Cardano.Launcher.Node + ( CardanoNodeConfig (..) + , isWindows + , withCardanoNode + ) +import Cardano.Launcher.Wallet + ( CardanoWalletConfig (..) + , CardanoWalletConn (CardanoWalletConn) + , withCardanoWallet + ) +import Cardano.Mnemonic + ( SomeMnemonic (..) + ) +import Cardano.Wallet.Api.Types + ( ApiEra (..) + ) +import Cardano.Wallet.Application.CLI + ( Port (..) + ) +import Cardano.Wallet.Primitive.NetworkId + ( NetworkDiscriminant (Testnet) + ) +import Cardano.Wallet.Unsafe + ( unsafeMkMnemonic + ) +import Control.Monad + ( forM_ + ) +import Control.Monad.IO.Class + ( liftIO + ) +import Control.Tracer + ( contramap + , nullTracer + , stdoutTracer + ) +import Data.FileEmbed + ( embedDir + ) +import Data.Maybe + ( fromMaybe + ) +import Data.MaybeK + ( MaybeK (..) + ) +import Main.Utf8 + ( withUtf8 + ) +import Network.URI + ( parseURI + ) +import System.Directory + ( createDirectoryIfMissing + , getCurrentDirectory + ) +import System.Environment + ( lookupEnv + ) +import System.FilePath + ( takeDirectory + , () + ) +import System.IO.Temp + ( withSystemTempDirectory + ) +import Test.Hspec + ( Spec + , aroundAll + , hspec + ) +import Test.Integration.Framework.Context + ( Context (..) + ) +import Test.Integration.Framework.DSL + ( PreprodSetupLog (..) + , setupPreprodWallets + ) +import Test.Integration.Framework.Setup + ( httpManager + ) +import Test.Utils.Paths + ( getTestDataPath + ) + +-- ENV configuration ----------------------------------------------------------- + +data E2EConfig = E2EConfig + { walletDbDir :: FilePath + , nodeDir :: FilePath + , nodeDbDir :: FilePath + , preprodMnemonics :: [SomeMnemonic] + } + +getConfig :: IO E2EConfig +getConfig = do + walletDbDir <- fromMaybe defaultWalletDbDir <$> lookupEnv "WALLET_DB_DIR" + nodeDbDir <- fromMaybe defaultNodeDbDir <$> lookupEnv "NODE_DB_DIR" + nodeDir <- fromMaybe defaultNodeDir <$> lookupEnv "NODE_DIR" + preprodMnemonics <- getPreprodMnemonics + pure $ E2EConfig {..} + where + -- Probably too fine grained control with all these settings, but works for now + defaultNodeDbDir = repoRoot "test" "e2e" "state" "node" "db" + defaultNodeDir = repoRoot "test" "e2e" "state" "node" + defaultWalletDbDir = repoRoot "test" "e2e" "state" "wallet" + + repoRoot = ".." ".." -- works when run with 'cabal test' + + getPreprodMnemonics :: IO [SomeMnemonic] + getPreprodMnemonics + = map (SomeMnemonic . unsafeMkMnemonic @15 . T.words) + . T.split isNewlineOrSemicolon + . T.pack + . fromMaybe (error errMsg) + <$> lookupEnv envVarName + where + isNewlineOrSemicolon c = c == '\n' || c == ';' + envVarName = "HAL_E2E_PREPROD_MNEMONICS" + errMsg = unlines + [ envVarName <> " is not set." + , "Please set it to a '\\n' or ';'-separated list of ' '-separated mnemonics." + , "" + , "Example:" + , "fish fish fish fish fish fish fish fish fish fish fish fish fish fish fish" + , "buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo" + ] + +-- main ------------------------------------------------------------------------ + +main :: IO () +main = withUtf8 $ do + config <- getConfig + hspec (spec' config) + where + spec' :: E2EConfig -> Spec + spec' config = + aroundAll (configureContext config) + $ Preprod.spec @('Testnet 1) + +-- setup ----------------------------------------------------------------------- + +configureContext :: E2EConfig -> (Context -> IO ()) -> IO () +configureContext E2EConfig{walletDbDir,nodeDbDir,nodeDir,preprodMnemonics} action = do + cwd <- getCurrentDirectory + let nodeSocket = if isWindows + then "\\\\.\\pipe\\socket" + else cwd nodeDbDir "node.socket" + withConfigDir $ \configDir -> do + let nodeConfig = + CardanoNodeConfig + { nodeDir = cwd nodeDir + , nodeConfigFile = cwd configDir "config.json" + , nodeTopologyFile = cwd configDir "topology.json" + , nodeDatabaseDir = cwd nodeDbDir + , nodeDlgCertFile = Nothing + , nodeSignKeyFile = Nothing + , nodeOpCertFile = Nothing + , nodeKesKeyFile = Nothing + , nodeVrfKeyFile = Nothing + , nodePort = Nothing + , nodeLoggingHostname = Nothing + , nodeExecutable = Nothing + , nodeOutputFile = Nothing + , nodeSocketPathFile = JustK nodeSocket + } + + withCardanoNode nullTracer nodeConfig $ \(JustK node) -> do + let walletConfig = + CardanoWalletConfig + { walletPort = 8090 + , walletDatabaseDir = walletDbDir + , walletNetwork = Launcher.Testnet $ + configDir "byron-genesis.json" + , executable = Nothing + , workingDir = Nothing + , extraArgs = [] + } + withCardanoWallet nullTracer node walletConfig $ \wallet -> do + action =<< contextFromNetwork wallet + where + contextFromNetwork :: CardanoWalletConn -> IO Context + contextFromNetwork (CardanoWalletConn port _) = do + manager <- httpManager + let mUri = parseURI $ "http://localhost:" <> show port <> "/" + let baseUri = case mUri of + Just uri -> uri + Nothing -> error "Invalid URI" + + let ctx = Context + { _manager = (baseUri, manager) + , _walletPort = + Port $ fromIntegral port + , _mainEra = + ApiConway + , _faucet = + error "_faucet not implemented" + , _networkParameters = + error "_networkParameters not implemented" + , _testnetMagic = + error "_testnetMagic not implemented" + , _poolGarbageCollectionEvents = + error "_poolGarbageCollectionEvents not implemented" + , _smashUrl = + error "_smashUrl not implemented" + , _mintSeaHorseAssets = + error "_mintSeaHorseAssets not implemented" + , _preprodWallets = + [] + } + ctx' <- setupPreprodWallets setupTr preprodMnemonics ctx + return ctx' + + setupTr = contramap setupAsBuildkiteSections stdoutTracer + + setupAsBuildkiteSections :: PreprodSetupLog -> String + setupAsBuildkiteSections WaitingForNodeConnection = "--- Waiting for node connection" + setupAsBuildkiteSections CreatingWallets = "--- Creating wallets" + setupAsBuildkiteSections WaitingForWalletsToSync = "--- Syncing wallets" + setupAsBuildkiteSections PreprodSetupReady = "--- Running tests" + +-- node configs ---------------------------------------------------------------- + +-- | Get access to a tmp directory containing node configs. +-- +-- The configs are based on the configs in the repository, embedded at +-- compile-time, and tweaked for less verbose logs. +withConfigDir :: (FilePath -> IO a) -> IO a +withConfigDir action = liftIO $ + withSystemTempDirectory "e2e-node-configs" $ \tmpDir -> do + -- Write the embedded config dir to the temporary dir + forM_ embeddedConfigs $ \(relPath, content) -> do + let dest = tmpDir relPath + createDirectoryIfMissing True (takeDirectory dest) + BS.writeFile dest content + + -- Customize node config; we don't need this verbose logs + adjustKeysToFalse (tmpDir "config.json") + [ "TraceConnectionManager" + , "TraceDNSResolver" + , "TraceDNSSubscription" + , "TraceHandshake" + , "TraceInboundGovernor" + , "TraceLocalInboundGovernor" + , "TraceLedgerPeers" + , "TraceLocalConnectionManager" + , "TraceLocalRootPeers" + , "TraceMempool" + , "TraceMempoolSynced" + , "TracePeerSelection" + , "TracePeerSelectionActions" + , "TracePeerSelectionCounters" + , "TracePublicRootPeers" + ] + action tmpDir + where + adjustKeysToFalse :: FilePath -> [KeyMap.Key] -> IO () + adjustKeysToFalse filePath keys = do + content <- BL.readFile filePath + case Aeson.decode content :: Maybe Aeson.Value of + Just (Aeson.Object o) -> do + let o' = foldr (\key acc -> KeyMap.insert key (Aeson.Bool False) acc) o keys + BL.writeFile filePath (Aeson.encode (Aeson.Object o')) + _ -> error "config.json is not a JSON object or failed to parse." + +-- | Embed all files in the config directory at compile time. +-- This gives a list of pairs (relative filepath, file contents). +embeddedConfigs :: [(FilePath, BS.ByteString)] +embeddedConfigs = $(embedDir + $(getTestDataPath ("configs" "cardano" "preprod"))) diff --git a/lib/integration/framework/Test/Integration/Framework/Context.hs b/lib/integration/framework/Test/Integration/Framework/Context.hs index d84b1da3a6c..5fd1253ebe1 100644 --- a/lib/integration/framework/Test/Integration/Framework/Context.hs +++ b/lib/integration/framework/Test/Integration/Framework/Context.hs @@ -31,6 +31,7 @@ import Cardano.Wallet.Primitive.Types ( EpochNo , NetworkParameters , PoolRetirementCertificate + , WalletId ) import Cardano.Wallet.Primitive.Types.Coin ( Coin (..) @@ -68,10 +69,7 @@ import Servant.Client -- | Context for integration tests. -- data Context = Context - { _cleanup - :: IO () - -- ^ A cleanup action. - , _manager + { _manager :: (URI, Manager) -- ^ The underlying base URL and manager used by the wallet client. , _walletPort @@ -100,6 +98,10 @@ data Context = Context -- cardano-wallet:integration, or when the wallet supports minting. -- -- Cannot be used by several tests at a time. (!) + , _preprodWallets + :: [WalletId] + -- ^ Only non-empty when when running against preprod. + } deriving Generic diff --git a/lib/integration/framework/Test/Integration/Framework/DSL.hs b/lib/integration/framework/Test/Integration/Framework/DSL.hs index 56634cea072..db07bb3afa6 100644 --- a/lib/integration/framework/Test/Integration/Framework/DSL.hs +++ b/lib/integration/framework/Test/Integration/Framework/DSL.hs @@ -231,7 +231,12 @@ module Test.Integration.Framework.DSL , deleteTransactionViaCLI , getTransactionViaCLI - -- utilities + -- * Preprod e2e + , setupPreprodWallets + , fixturePreprodWallets + , PreprodSetupLog (..) + + -- * utilities , getRetirementEpoch , replaceStakeKey -- * Re-exports @@ -465,10 +470,16 @@ import Control.Monad.Trans.Resource , runResourceT ) import Control.Retry - ( capDelay + ( RetryStatus + , capDelay , constantDelay + , fibonacciBackoff , retrying ) +import Control.Tracer + ( Tracer + , traceWith + ) import Cryptography.Hash.Blake ( Blake2b_160 , blake2b224 @@ -534,6 +545,9 @@ import Data.List.NonEmpty import Data.List.NonEmpty.Extra ( (!?) ) +import Data.Map + ( Map + ) import Data.Maybe ( catMaybes , fromJust @@ -2273,6 +2287,102 @@ fixtureWallet fixtureWallet ctx = fst <$> fixtureWalletWithMnemonics nextShelleyMnemonic ctx "shelley" +data PreprodSetupLog + = WaitingForNodeConnection + | CreatingWallets + | WaitingForWalletsToSync + | PreprodSetupReady + +setupPreprodWallets :: Tracer IO PreprodSetupLog -> [SomeMnemonic] -> Context -> IO Context +setupPreprodWallets tr mnemonics ctx = do + traceWith tr WaitingForNodeConnection + waitForConnection + + traceWith tr CreatingWallets + createWalletsIfNeeded mnemonics + + wallets <- getResponse <$> request @[ApiWallet] ctx + (Link.listWallets @'Shelley) Default Empty + unless (length wallets == length mnemonics) $ + expectationFailure $ unwords + [ "Setup error: have", show (length mnemonics), "mnemonics but only" + , show wallets, "have now been created." + ] + + let walletIds = map (getApiT . view #id) wallets + + traceWith tr WaitingForWalletsToSync + waitForAllWalletsToSync + traceWith tr PreprodSetupReady + + pure ctx{ _preprodWallets = walletIds } + where + createWalletsIfNeeded :: [SomeMnemonic] -> IO () + createWalletsIfNeeded = mapM_ createWalletIfNeeded + + createWalletIfNeeded :: SomeMnemonic -> IO () + createWalletIfNeeded (SomeMnemonic mnemonic) = do + (s, response) <- request @ApiWallet ctx (Link.postWallet @'Shelley) Default $ Json + [aesonQQ| { + "name": "Faucet Wallet", + "mnemonic_sentence": #{mnemonicToText mnemonic}, + "passphrase": #{fixturePassphrase} + } |] + case response of + Right _ | s == HTTP.status201 -> pure () + Left e | s == HTTP.status409 -> show e `shouldContain` "wallet_already_exists" + _ -> expectationFailure $ unwords + [ "setupPreprodWallets, createWalletsIfNeeded: unexpected response" + , show (s, response) + ] + + waitForConnection :: IO () + waitForConnection = void $ retrying + (capDelay (30*oneSecond) $ fibonacciBackoff oneSecond) + shouldWait + (\_retryStatus -> request @ApiNetworkInformation ctx + Link.getNetworkInfo Default Empty) + where + shouldWait + :: RetryStatus + -> (HTTP.Status, Either RequestException ApiNetworkInformation) + -> IO Bool + shouldWait _ (_, Right info) = pure $ info ^. #syncProgress . #getApiT <= NotResponding + shouldWait _ (_, Left _err) = pure True + + waitForAllWalletsToSync :: IO () + waitForAllWalletsToSync = do + eventuallyUsingDelay (5 * s) (90 * minutes) "setupPreprodWallets: all wallets are synced" $ do + wallets :: [ApiWallet] <- getResponse <$> request @[ApiWallet] ctx + (Link.listWallets @'Shelley) Default Empty + let progress = map (getApiT . view #state) wallets + all (== Ready) progress `shouldBe` True + where + s = 1_000_000 + minutes = 60 + +fixturePreprodWallets :: (HasCallStack, MonadUnliftIO m) => Context -> m [ApiWallet] +fixturePreprodWallets ctx = do + wallets <- getResponse <$> request @[ApiWallet] ctx + (Link.listWallets @'Shelley) Default Empty + + let keyByWalletId :: ApiWallet -> (WalletId, ApiWallet) + keyByWalletId w = (getApiT $ w ^. #id, w) + + walletsById :: Map WalletId ApiWallet + walletsById = Map.fromList $ map keyByWalletId wallets + + lookupWallet :: WalletId -> ApiWallet + lookupWallet wid = fromMaybe err $ Map.lookup wid walletsById + where + err = error $ unwords + [ "fixturePreprodWallets: expected", show wid, "to be an" + , "existing wallet. The wallets that could be found are:\n\n" + ] ++ unlines (map show wallets) + + -- Use the information from 'wallets' + pure $ map lookupWallet $ _preprodWallets ctx + fixtureShelleyWallet :: (HasCallStack, MonadUnliftIO m) => Context diff --git a/lib/integration/framework/Test/Integration/Framework/Setup.hs b/lib/integration/framework/Test/Integration/Framework/Setup.hs index 343a1f9e581..8e4a652099e 100644 --- a/lib/integration/framework/Test/Integration/Framework/Setup.hs +++ b/lib/integration/framework/Test/Integration/Framework/Setup.hs @@ -457,8 +457,7 @@ setupContext putMVar ctx Context - { _cleanup = pure () - , _manager = (baseUrl, manager) + { _manager = (baseUrl, manager) , _walletPort = CLI.Port . fromIntegral $ portFromURL baseUrl , _faucet = faucet , _networkParameters = networkParameters @@ -472,6 +471,7 @@ setupContext runFaucetQ batchSize (nPerAddr, c, addrs) + , _preprodWallets = [] } withContext :: TestingCtx -> (Context -> IO ()) -> IO () diff --git a/lib/integration/scenarios/Test/Integration/Scenario/Preprod.hs b/lib/integration/scenarios/Test/Integration/Scenario/Preprod.hs new file mode 100644 index 00000000000..02dc68deb72 --- /dev/null +++ b/lib/integration/scenarios/Test/Integration/Scenario/Preprod.hs @@ -0,0 +1,280 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DuplicateRecordFields #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE NumericUnderscores #-} +{-# LANGUAGE OverloadedLabels #-} +{-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} + +{- HLINT ignore "Use head" -} +{- HLINT ignore "Use :" -} + +module Test.Integration.Scenario.Preprod where + +import Prelude + +import qualified Cardano.Wallet.Api.Link as Link +import qualified Network.HTTP.Types.Status as HTTP + +import Cardano.Wallet.Api.Types + ( ApiT (..) + , ApiTransaction + , ApiTxId (..) + , ApiTxInput (source) + , ApiWallet + , WalletStyle (..) + ) +import Cardano.Wallet.Api.Types.Amount + ( ApiAmount (..) + ) +import Cardano.Wallet.Pools + ( StakePool + ) +import Cardano.Wallet.Primitive.NetworkId + ( HasSNetworkId (..) + ) +import Cardano.Wallet.Primitive.Types.Coin + ( Coin (..) + ) +import Cardano.Wallet.Primitive.Types.Tx.TxMeta + ( Direction (..) + , TxStatus (..) + ) +import Control.Monad.IO.Unlift + ( MonadUnliftIO (..) + ) +import Data.Generics.Internal.VL.Lens + ( view + , (^.) + ) +import Data.List + ( sortOn + ) +import Data.Maybe + ( isJust + ) +import Data.Ord + ( Down (..) + ) +import Data.Text + ( Text + ) +import Numeric.Natural + ( Natural + ) +import Test.Hspec + ( SpecWith + , describe + , expectationFailure + , it + , pendingWith + , shouldBe + , shouldSatisfy + ) +import Test.Integration.Framework.DSL + ( Context + , Headers (..) + , Payload (..) + , between + , counterexample + , eventuallyUsingDelay + , expectField + , expectResponseCode + , expectSuccess + , fixturePassphrase + , fixturePreprodWallets + , getFromResponse + , getResponse + , json + , listAddresses + , request + , verify + , (.<) + ) + +spec :: forall n . HasSNetworkId n => SpecWith Context +spec = do + describe "transactions" $ do + it "simple transaction (TRANS_CREATE_01x)" $ \ctx -> do + -- Note on 'richestWalletFirst': + -- + -- By always sending money from the richer wallet to the poorer wallet, + -- the setup should last longer without needing manual intervention. + [wa, wb] <- richestWalletFirst <$> fixturePreprodWallets ctx + let amt = 1_000_000 + let expectedMinFee = 150_000 + let expectedMaxFee = 200_000 + let ApiAmount initialBalanceA = wa ^. #balance . #available + let ApiAmount initialBalanceB = wb ^. #balance . #available + + payload <- mkTxPayload @IO ctx wb amt fixturePassphrase + + rTx <- + request @(ApiTransaction n) + ctx + (Link.createTransactionOld @'Shelley wa) + Default + payload + ra <- + request @ApiWallet + ctx + (Link.getWallet @'Shelley wa) + Default + Empty + + verify + rTx + [ expectSuccess + , expectResponseCode HTTP.status202 + , expectField (#fee . #toNatural) + $ between (expectedMinFee, expectedMaxFee) + , expectField (#amount . #toNatural) + $ between (expectedMinFee + amt, expectedMaxFee + amt) + , expectField #inputs $ \inputs' -> do + inputs' `shouldSatisfy` all (isJust . source) + , expectField (#direction . #getApiT) (`shouldBe` Outgoing) + , expectField (#status . #getApiT) (`shouldBe` Pending) + , expectField #metadata (`shouldBe` Nothing) + ] + + verify + ra + [ expectSuccess + , expectField (#balance . #total) + $ between + ( ApiAmount (initialBalanceA - expectedMaxFee - amt) + , ApiAmount (initialBalanceA - expectedMinFee - amt) + ) + , expectField + (#balance . #available . #toNatural) + (.< initialBalanceA) + ] + + let txid = getFromResponse #id rTx + let linkSrc = Link.getTransaction @'Shelley wa (ApiTxId txid) + let ApiAmount fee = getFromResponse #fee rTx + eventually "transaction is no longer pending on source wallet" $ do + rSrc <- request @(ApiTransaction n) ctx linkSrc Default Empty + verify + rSrc + [ expectResponseCode HTTP.status200 + , expectField (#amount . #toNatural) + $ between (expectedMinFee + amt, expectedMaxFee + amt) + , expectField #inputs $ \inputs' -> do + inputs' `shouldSatisfy` all (isJust . source) + , expectField (#direction . #getApiT) (`shouldBe` Outgoing) + , expectField (#status . #getApiT) (`shouldBe` InLedger) + , expectField (#metadata) (`shouldBe` Nothing) + , expectField (#fee . #toNatural) + $ between (expectedMinFee, expectedMaxFee) + ] + + let linkDest = Link.getTransaction @'Shelley wb (ApiTxId txid) + eventually "transaction is discovered by destination wallet" $ do + rDst <- request @(ApiTransaction n) ctx linkDest Default Empty + verify + rDst + [ expectField (#amount . #toNatural) (`shouldBe` amt) + , expectField (#direction . #getApiT) (`shouldBe` Incoming) + ] + + eventually "wa and wb balances are as expected" $ do + rb <- + request @ApiWallet + ctx + (Link.getWallet @'Shelley wb) + Default + Empty + expectField + (#balance . #available) + (`shouldBe` ApiAmount (initialBalanceB + amt)) + rb + + ra2 <- + request @ApiWallet + ctx + (Link.getWallet @'Shelley wa) + Default + Empty + expectField + (#balance . #available) + (`shouldBe` ApiAmount (initialBalanceA - fee - amt)) + ra2 + + describe "stake pools" $ do + describe "list" $ do + let listPools :: Context -> Maybe Coin -> IO [StakePool] + listPools ctx stake = do + r <- request @[ApiT StakePool] @IO ctx + (Link.listStakePools stake) Default Empty + expectResponseCode HTTP.status200 r + return $ map getApiT $ getResponse r + let expectOr True _ = pure () + expectOr False msg = expectationFailure msg + let arbitraryStake = Just $ Coin 1_000_000_000 + it "some have non-zero rewards, stake, producedBlocks, saturation" $ \ctx -> do + pools <- listPools ctx arbitraryStake + let rewards + = view (#metrics . #nonMyopicMemberRewards . #getQuantity) + let relativeStake + = view (#metrics . #relativeStake . #getQuantity . #toRational) + let producedBlocks + = view (#metrics . #producedBlocks . #getQuantity) + let saturation + = view (#metrics . #saturation) + counterexample (show pools) $ do + any (\p -> rewards p > 0) pools + `expectOr` "some pools should have non-zero rewards" + any (\p -> relativeStake p > 0) pools + `expectOr` "some pools should have non-zero stake" + any (\p -> producedBlocks p > 0) pools + `expectOr` "some pools should have non-zero producedBlocks" + any (\p -> saturation p > 0) pools + `expectOr` "some pools should have non-zero saturation" + + it "some have metadata" $ \ctx -> do + pendingWith "metadata fetching not configured; could be enabled" + pools <- listPools ctx arbitraryStake + any (isJust . view #metadata) pools + `expectOr` "some pools should have metadata" + where + richestWalletFirst :: [ApiWallet] -> [ApiWallet] + richestWalletFirst = sortOn (Down . view (#balance . #total . #toNatural)) + + mkTxPayload + :: MonadUnliftIO m + => Context + -> ApiWallet + -> Natural + -> Text + -> m Payload + mkTxPayload ctx wDest amt passphrase = do + addrs <- listAddresses @n ctx wDest + let destination = (addrs !! 1) ^. #id + return + $ Json + [json|{ + "payments": [{ + "address": #{destination}, + "amount": { + "quantity": #{amt}, + "unit": "lovelace" + } + }], + "passphrase": #{passphrase} + }|] + + -- For preprod a slightly longer timeout of 5 min is useful + eventually = eventuallyUsingDelay + (10 * s) + 300 -- already in s + where + s = 1_000_000 diff --git a/lib/wallet-e2e/.editorconfig b/lib/wallet-e2e/.editorconfig deleted file mode 100644 index 8f5d8087db3..00000000000 --- a/lib/wallet-e2e/.editorconfig +++ /dev/null @@ -1,12 +0,0 @@ -# EditorConfig is awesome: https://EditorConfig.org - -# top-most EditorConfig file -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = false -insert_final_newline = true diff --git a/lib/wallet-e2e/.envrc b/lib/wallet-e2e/.envrc deleted file mode 100644 index 9461f7d6a6a..00000000000 --- a/lib/wallet-e2e/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -PATH_add scripts diff --git a/lib/wallet-e2e/.gitignore b/lib/wallet-e2e/.gitignore deleted file mode 100644 index 4d67604d74c..00000000000 --- a/lib/wallet-e2e/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.code-workspace diff --git a/lib/wallet-e2e/.vscode/settings.json b/lib/wallet-e2e/.vscode/settings.json deleted file mode 100644 index d3def91314f..00000000000 --- a/lib/wallet-e2e/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.formatOnSave": false -} diff --git a/lib/wallet-e2e/adrgen.config.yml b/lib/wallet-e2e/adrgen.config.yml deleted file mode 100644 index e124ec18c39..00000000000 --- a/lib/wallet-e2e/adrgen.config.yml +++ /dev/null @@ -1,12 +0,0 @@ -default_meta: [] -default_status: proposed -directory: docs/adr -id_digit_number: 4 -supported_statuses: - - proposed - - accepted - - rejected - - superseded - - amended - - deprecated -template_file: docs/adr/adr_template.md diff --git a/lib/wallet-e2e/cardano-wallet-e2e.cabal b/lib/wallet-e2e/cardano-wallet-e2e.cabal deleted file mode 100644 index d2f2f9e8039..00000000000 --- a/lib/wallet-e2e/cardano-wallet-e2e.cabal +++ /dev/null @@ -1,132 +0,0 @@ -cabal-version: 3.0 -name: cardano-wallet-e2e -version: 2025.1.9 -synopsis: End-to-end test suite for the cardano-wallet. -description: Please see README.md -homepage: https://github.com/input-output-hk/cardano-wallet -license: Apache-2.0 -author: Cardano Foundation (High Assurance Lab) -maintainer: hal@cardanofoundation.org -copyright: 2018-2022 IOHK, 2023 Cardano Foundation -category: Testing -build-type: Simple - -common options - default-language: Haskell2010 - default-extensions: - BlockArguments - DataKinds - DeriveAnyClass - DeriveGeneric - DerivingStrategies - FlexibleContexts - FlexibleInstances - GADTs - GeneralizedNewtypeDeriving - KindSignatures - LambdaCase - MultiParamTypeClasses - NamedFieldPuns - NumericUnderscores - OverloadedStrings - PolyKinds - RankNTypes - RecordWildCards - ScopedTypeVariables - StandaloneDeriving - TupleSections - TypeApplications - TypeFamilies - TypeOperators - - ghc-options: - -O2 -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns - -Wmissing-deriving-strategies -Wunused-foralls -Wunused-foralls - -fprint-explicit-foralls -fprint-explicit-kinds - -fprint-potential-instances -Wcompat -Widentities - -Werror=incomplete-patterns -Wredundant-constraints - -Wpartial-fields -Wtabs -Wmissing-local-signatures -fhelpful-errors - -fprint-expanded-synonyms -fwarn-unused-do-bind - -fwarn-incomplete-uni-patterns -freverse-errors - - mixins: - base hiding (Prelude), - relude (Relude as Prelude, Relude.Container.One), - relude - -library - import: options - hs-source-dirs: src - build-depends: - , aeson - , attoparsec-aeson - , base - , base58-bytestring - , cardano-addresses - , cardano-crypto - , cardano-wallet-client - , cardano-wallet-primitive - , effectful-core - , effectful-th - , extra - , faucet - , http-client - , http-types - , local-cluster - , optparse-applicative - , pathtype - , random - , relude - , resourcet - , retry - , sydtest - , tagged - , text - , time - , timespan - , typed-process - - exposed-modules: - Cardano.Wallet.Spec - Cardano.Wallet.Spec.Options - Cardano.Wallet.Spec.Data.AdaBalance - Cardano.Wallet.Spec.Data.Network.Info - Cardano.Wallet.Spec.Data.Network.NodeStatus - Cardano.Wallet.Spec.Data.TestNetwork - Cardano.Wallet.Spec.Data.Wallet - Cardano.Wallet.Spec.Data.WalletId - Cardano.Wallet.Spec.Data.WalletName - Cardano.Wallet.Spec.Effect.Assert - Cardano.Wallet.Spec.Effect.Faucet - Cardano.Wallet.Spec.Effect.Http - Cardano.Wallet.Spec.Effect.Query - Cardano.Wallet.Spec.Effect.Random - Cardano.Wallet.Spec.Effect.Timeout - Cardano.Wallet.Spec.Effect.Trace - Cardano.Wallet.Spec.Interpreters.Config - Cardano.Wallet.Spec.Interpreters.Effectfully - Cardano.Wallet.Spec.Interpreters.Pure - Cardano.Wallet.Spec.Network.Configured - Cardano.Wallet.Spec.Network.Local - Cardano.Wallet.Spec.Network.Manual - Cardano.Wallet.Spec.Network.Node.Cli - Cardano.Wallet.Spec.Network.Preprod - Cardano.Wallet.Spec.Network.Wait - Cardano.Wallet.Spec.Network.Wallet.Cli - Cardano.Wallet.Spec.Stories.Language - Cardano.Wallet.Spec.Stories.Wallet - Cardano.Wallet.Spec.TimeoutSpec - -executable wallet-e2e - import: options - hs-source-dirs: exe - main-is: Main.hs - ghc-options: -threaded -rtsopts -with-rtsopts=-N - build-depends: - , base - , cardano-wallet-e2e - , optparse-applicative - , relude - , sydtest - , tagged - , with-utf8 diff --git a/lib/wallet-e2e/config/cardano-node/preprod/topology.json b/lib/wallet-e2e/config/cardano-node/preprod/topology.json deleted file mode 100644 index 99a36441ff9..00000000000 --- a/lib/wallet-e2e/config/cardano-node/preprod/topology.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "localRoots": [ - { - "accessPoints": [], - "advertise": false, - "valency": 1 - } - ], - "publicRoots": [ - { - "accessPoints": [ - { - "address": "preprod-node.world.dev.cardano.org", - "port": 30000 - } - ], - "advertise": false - } - ], - "useLedgerAfterSlot": 4642000 -} diff --git a/lib/wallet-e2e/docs/adr/0001-use-an-effect-system.md b/lib/wallet-e2e/docs/adr/0001-use-an-effect-system.md deleted file mode 100644 index 3a87947889e..00000000000 --- a/lib/wallet-e2e/docs/adr/0001-use-an-effect-system.md +++ /dev/null @@ -1,25 +0,0 @@ -# 1. Use an effect system - -Date: 2023-07-21 - -## Status - -decided - -## Context - -We want a test scenario to be described using a modular eDSL as a composition of -other mini-eDSLs. This way it stays a high-level abstraction, decoupled from the -details associated with interpreting it in terms of a real-world side effects. - -## Decision - -Use the [`effectful`](https://hackage.haskell.org/package/effectful-2.2.2.0) extensible effect library. - -## Consequences - -> As always, there's no free lunch. The Eff monad doesn't support effect handlers that require the ability to suspend or capture the rest of the computation and resume it later (potentially multiple times). This prevents effectful from providing (in particular): -> * A NonDet effect handler that executes multiple Alternative branches and collects their results. -> * A Coroutine effect. - -> It needs to be noted however that such NonDet effect handler in existing libraries is broken and none of the ones with support for higher order effects provide the Coroutine effect, so arguably it's not a big loss. diff --git a/lib/wallet-e2e/docs/adr/0002-effects-naming-convention.md b/lib/wallet-e2e/docs/adr/0002-effects-naming-convention.md deleted file mode 100644 index 4e928657634..00000000000 --- a/lib/wallet-e2e/docs/adr/0002-effects-naming-convention.md +++ /dev/null @@ -1,28 +0,0 @@ -# 2. Effects naming convention - -Date: 2023-08-09 - -## Status - -decided - -## Context - -We'd like to name effects in a consistent fashion such that they could be -distinguished from the corresponding domain types, e.g. `FxQuery` signinfies -an effect whereas `Query` is a domain type. - -## Decision - -Use `Fx` prefix. - -For example: - -- `FxTrace` -- `FxRandom` -- `FxQuery` - -## Consequences - -Effect names become 2 character longer but are readable, distinguishable -and consistent. diff --git a/lib/wallet-e2e/docs/adr/0003-isolated-cabal-project.md b/lib/wallet-e2e/docs/adr/0003-isolated-cabal-project.md deleted file mode 100644 index edaed9b4018..00000000000 --- a/lib/wallet-e2e/docs/adr/0003-isolated-cabal-project.md +++ /dev/null @@ -1,45 +0,0 @@ -# 3. Isolated cabal project - -Date: 2023-08-10 - -## Status - -decided - -## Context - -The `cardano-wallet` monorepo contains a few cabal packages -[incorporated into a single cabal project](https://cabal.readthedocs.io/en/stable/nix-local-build.html#developing-multiple-packages). - -One consequence of this fact is that cabal tries to find a single build plan -for all the components in a project. It satisfies dependecy constrains -collected across all the components in the project. - -The more components there are, the more constraints is collected and the lower -chance for a build-plan to be found. This also makes it less likely for a newer -version of some lib to get into the build plan because the chances are lower -that it falls into a supported version bounds for all the dependees. - -There is a trade-off between a consistency (all components use a single version -of a dependency) and freshness (some components could benefit from using a newer -version of a dependency) - -## Decision - -Because the Wallet E2E test suite is not linked with the application that is -being tested but instead interacts with it via an API, we decide to allow -different versions of depenencies by decoupling from the cabal.project and -having a separate build plan. - -One particular immediate issue that is solved is that wallet-e2e could use the -sydtes library which transitively depends on the -`optparse-applicative >= 0.17 && < 0.18` while the topmost cabal project -uses `optparse-applicative > 0.18`. - -## Consequences - -The downsides are the following: -- CI has more dependencies to build as it will share built library versions - less often. -- Its not possible to run `cabal build wallet-e2e` from the root directory, - but from the `lib/wallet-e2e` it is. diff --git a/lib/wallet-e2e/docs/adr/adr_template.md b/lib/wallet-e2e/docs/adr/adr_template.md deleted file mode 100644 index fd5a1f796f4..00000000000 --- a/lib/wallet-e2e/docs/adr/adr_template.md +++ /dev/null @@ -1,19 +0,0 @@ -# {title} - -Date: {date} - -## Status - -{status} - -## Context - -What is the issue that we're seeing that is motivating this decision or change? - -## Decision - -What is the change that we're proposing and/or doing? - -## Consequences - -What becomes easier or more difficult to do because of this change? \ No newline at end of file diff --git a/lib/wallet-e2e/exe/Main.hs b/lib/wallet-e2e/exe/Main.hs deleted file mode 100644 index 4ac2697cab5..00000000000 --- a/lib/wallet-e2e/exe/Main.hs +++ /dev/null @@ -1,21 +0,0 @@ -import qualified Test.Syd.OptParse as SydTest - -import Cardano.Wallet.Spec - ( effectsSpec - , walletSpec - ) -import Cardano.Wallet.Spec.Options - ( withTestOptions - ) -import Main.Utf8 - ( withUtf8 - ) -import Test.Syd - ( sydTestWith - ) - -main :: IO () -main = withUtf8 $ withTestOptions $ \testNetwork traceConfiguration -> - sydTestWith SydTest.defaultSettings{SydTest.settingRetries = 1} do - effectsSpec - walletSpec traceConfiguration testNetwork diff --git a/lib/wallet-e2e/hie.yaml b/lib/wallet-e2e/hie.yaml deleted file mode 100644 index 8922fa987ad..00000000000 --- a/lib/wallet-e2e/hie.yaml +++ /dev/null @@ -1,7 +0,0 @@ -cradle: - cabal: - - path: "src" - component: "lib:cardano-wallet-e2e" - - - path: "exe/Main.hs" - component: "cardano-wallet-e2e:exe:wallet-e2e" diff --git a/lib/wallet-e2e/scripts/format b/lib/wallet-e2e/scripts/format deleted file mode 100755 index 69f1e8a761e..00000000000 --- a/lib/wallet-e2e/scripts/format +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -SCRIPT_DIR=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) -E2E_DIR=$(realpath "$SCRIPT_DIR/..") - -fourmolu -i "$E2E_DIR" && LANG=C.UTF-8 stylish-haskell -ir "$E2E_DIR" diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec.hs deleted file mode 100644 index 8a8162c4a92..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec.hs +++ /dev/null @@ -1,81 +0,0 @@ -module Cardano.Wallet.Spec - ( walletSpec - , effectsSpec - , TestNetworkConfig (..) - ) where - -import qualified Cardano.Wallet.Spec.Network.Local as Local -import qualified Cardano.Wallet.Spec.Network.Manual as Manual -import qualified Cardano.Wallet.Spec.Network.Preprod as Preprod - -import Cardano.Wallet.Launch.Cluster.FileOf - ( DirOf - ) -import Cardano.Wallet.Spec.Interpreters.Config - ( TraceConfiguration - ) -import Cardano.Wallet.Spec.Interpreters.Effectfully - ( story - ) -import Cardano.Wallet.Spec.Network.Configured - ( ConfiguredNetwork - ) -import Cardano.Wallet.Spec.Stories.Wallet - ( createdWalletHasZeroAda - , createdWalletListed - , createdWalletRetrievable - ) -import Cardano.Wallet.Spec.TimeoutSpec - ( timeoutSpec - ) -import Control.Monad.Trans.Resource - ( runResourceT - ) -import Test.Syd - ( Spec - , aroundAll - , describe - , sequential - ) - -walletSpec :: TraceConfiguration -> TestNetworkConfig -> Spec -walletSpec tracingConfig config = - aroundAll (configureTracing tracingConfig) - $ aroundAll (configureTestNet config) - $ do - describe "Wallet Backend API" $ sequential do - story - "Created wallet is listed" - createdWalletListed - story - "Created wallet can be retrieved by id" - createdWalletRetrievable - story - "Created wallet has zero ADA balance" - createdWalletHasZeroAda - -configureTracing :: TraceConfiguration -> (TraceConfiguration -> IO ()) -> IO () -configureTracing config f = f config - -effectsSpec :: Spec -effectsSpec = describe "Effect interpreters" do - timeoutSpec - --------------------------------------------------------------------------------- --- Test network setup ---------------------------------------------------------- - -data TestNetworkConfig - = TestNetworkManual - | TestNetworkLocal (DirOf "state") (DirOf "config") - | TestNetworkPreprod (DirOf "state") (DirOf "config") - -configureTestNet :: TestNetworkConfig -> (ConfiguredNetwork -> IO ()) -> IO () -configureTestNet testNetworkConfig withConfiguredNetwork = runResourceT $ do - config <- case testNetworkConfig of - TestNetworkManual -> - pure Manual.configuredNetwork - TestNetworkLocal stateDir nodeConfigDir -> - Local.configuredNetwork stateDir nodeConfigDir Nothing - TestNetworkPreprod stateDir nodeConfigDir -> - Preprod.configuredNetwork stateDir nodeConfigDir - liftIO $ withConfiguredNetwork config diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/AdaBalance.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/AdaBalance.hs deleted file mode 100644 index 24816482f3f..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/AdaBalance.hs +++ /dev/null @@ -1,11 +0,0 @@ -module Cardano.Wallet.Spec.Data.AdaBalance where - -data AdaBalance = AdaBalance - { adaAvailable :: Natural - , adaInRewards :: Natural - , adaTotal :: Natural - } - deriving stock (Show, Eq, Ord) - -zeroAdaBalance :: AdaBalance -zeroAdaBalance = AdaBalance{adaAvailable = 0, adaInRewards = 0, adaTotal = 0} diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/Network/Info.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/Network/Info.hs deleted file mode 100644 index aa35761ff78..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/Network/Info.hs +++ /dev/null @@ -1,10 +0,0 @@ -module Cardano.Wallet.Spec.Data.Network.Info where - -import Cardano.Wallet.Spec.Data.Network.NodeStatus - ( NodeStatus - ) - -newtype NetworkInfo = NetworkInfo - { nodeStatus :: NodeStatus - } - deriving stock (Show) diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/Network/NodeStatus.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/Network/NodeStatus.hs deleted file mode 100644 index 76ce93e5606..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/Network/NodeStatus.hs +++ /dev/null @@ -1,33 +0,0 @@ -module Cardano.Wallet.Spec.Data.Network.NodeStatus where - -import qualified Wallet as W - -data NodeStatus = NodeIsSynced | NodeIsSyncing | NodeIsNotResponding - deriving stock (Eq, Show) - -fromString :: String -> Maybe NodeStatus -fromString "ready" = Just NodeIsSynced -fromString "syncing" = Just NodeIsSyncing -fromString "not_responding" = Just NodeIsNotResponding -fromString _ = Nothing - -toString :: NodeStatus -> String -toString NodeIsSynced = "ready" -toString NodeIsSyncing = "syncing" -toString NodeIsNotResponding = "not_responding" - -fromClientResponse - :: W.GetNetworkInformationResponseBody200Sync_progress -> Maybe NodeStatus -fromClientResponse - (W.GetNetworkInformationResponseBody200Sync_progress _ status) = - case status of - W.GetNetworkInformationResponseBody200Sync_progressStatusOther{} -> - Nothing - W.GetNetworkInformationResponseBody200Sync_progressStatusTyped{} -> - Nothing - W.GetNetworkInformationResponseBody200Sync_progressStatusEnumReady -> - Just NodeIsSynced - W.GetNetworkInformationResponseBody200Sync_progressStatusEnumSyncing -> - Just NodeIsSyncing - W.GetNetworkInformationResponseBody200Sync_progressStatusEnumNot_responding -> - Just NodeIsNotResponding diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/TestNetwork.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/TestNetwork.hs deleted file mode 100644 index fee45f9923a..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/TestNetwork.hs +++ /dev/null @@ -1,20 +0,0 @@ -module Cardano.Wallet.Spec.Data.TestNetwork where - -import qualified Data.Text as T - -data TestNetwork - = -- | Automatically manage a local test cluster. - Local - | -- | Automatically manage a preprod node and wallet. - Preprod - | -- | Rely on a node and wallet managed manually (externally). - Manual - deriving stock (Show) - -fromText :: Text -> Either String TestNetwork -fromText text = - case T.toLower (T.strip text) of - "local" -> pure Local - "preprod" -> pure Preprod - "manual" -> pure Manual - _ -> fail "Invalid test network, must be one of: local, preprod, manual" diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/Wallet.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/Wallet.hs deleted file mode 100644 index a6ce2b1fe54..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/Wallet.hs +++ /dev/null @@ -1,18 +0,0 @@ -module Cardano.Wallet.Spec.Data.Wallet where - -import Cardano.Wallet.Spec.Data.AdaBalance - ( AdaBalance - ) -import Cardano.Wallet.Spec.Data.WalletId - ( WalletId - ) -import Cardano.Wallet.Spec.Data.WalletName - ( WalletName - ) - -data Wallet = Wallet - { walletId :: WalletId - , walletName :: WalletName - , walletBalance :: AdaBalance - } - deriving stock (Show, Eq, Ord) diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/WalletId.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/WalletId.hs deleted file mode 100644 index 06d538325d5..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/WalletId.hs +++ /dev/null @@ -1,15 +0,0 @@ -module Cardano.Wallet.Spec.Data.WalletId - ( WalletId - , walletIdToText - , mkUnsafe - , fromNel - ) where - -newtype WalletId = WalletId {walletIdToText :: Text} - deriving stock (Show, Eq, Ord) - -fromNel :: NonEmpty Text -> WalletId -fromNel = WalletId . unwords . toList - -mkUnsafe :: Text -> WalletId -mkUnsafe = WalletId diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/WalletName.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/WalletName.hs deleted file mode 100644 index ccd9c32a4fa..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Data/WalletName.hs +++ /dev/null @@ -1,18 +0,0 @@ -module Cardano.Wallet.Spec.Data.WalletName - ( WalletName - , toText - , mkUnsafe - ) where - -import Prelude hiding - ( toText - ) - -newtype WalletName = WalletName Text - deriving stock (Show, Eq, Ord) - -toText :: WalletName -> Text -toText (WalletName text) = text - -mkUnsafe :: Text -> WalletName -mkUnsafe = WalletName diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Assert.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Assert.hs deleted file mode 100644 index 716269decad..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Assert.hs +++ /dev/null @@ -1,62 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} - -module Cardano.Wallet.Spec.Effect.Assert - ( -- * Effect - FxAssert - , assert - , assertEq - , assertGt - , assertFail - - -- ** Handlers - , runAssertFailsFast - ) where - -import Cardano.Wallet.Spec.Effect.Trace - ( FxTrace - , trace - ) -import Effectful - ( Eff - , Effect - , (:>) - ) -import Effectful.Dispatch.Dynamic - ( interpret - ) -import Effectful.Fail - ( Fail - ) -import Effectful.TH - ( makeEffect - ) -import Prelude hiding - ( trace - ) - -data FxAssert :: Effect where - Assert :: Text -> Bool -> FxAssert m () - AssertEq :: (Show a, Eq a) => Text -> a -> a -> FxAssert m () - AssertGt :: (Show a, Ord a) => Text -> a -> a -> FxAssert m () - -$(makeEffect ''FxAssert) - -assertFail :: (FxAssert :> es) => Text -> Eff es () -assertFail label = assert label False - -runAssertFailsFast - :: (Fail :> es, FxTrace :> es) - => Eff (FxAssert : es) a - -> Eff es a -runAssertFailsFast = interpret \_ -> \case - Assert msg truth -> do - trace $ "Asserting that " <> msg <> ": " <> show truth - unless truth $ fail $ toString msg - AssertEq msg x y -> do - let equality = x == y - trace $ "Asserting that " <> msg <> ": " <> show equality - unless equality . fail $ show x <> " == " <> show y - AssertGt msg x y -> do - let greater = x > y - trace $ "Asserting that " <> msg <> ": " <> show greater - unless greater . fail $ show x <> " > " <> show y diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Faucet.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Faucet.hs deleted file mode 100644 index 90a3d47d051..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Faucet.hs +++ /dev/null @@ -1,61 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} - -module Cardano.Wallet.Spec.Effect.Faucet where - -import qualified Data.List.NonEmpty as NE -import qualified Data.Text as T - -import Cardano.Mnemonic - ( SomeMnemonic - ) -import Cardano.Wallet.Spec.Effect.Trace - ( FxTrace - , trace - ) -import Effectful - ( Eff - , Effect - , (:>) - ) -import Effectful.Dispatch.Dynamic - ( reinterpret - ) -import Effectful.Fail - ( Fail - ) -import Effectful.State.Static.Shared - ( evalState - , get - , put - ) -import Effectful.TH - ( makeEffect - ) -import Prelude hiding - ( State - , evalState - , get - , gets - , put - , trace - ) - -data FxFaucet :: Effect where - UseFaucetMnemonic :: FxFaucet m SomeMnemonic - -$(makeEffect ''FxFaucet) - -runFaucetPure - :: (FxTrace :> es, Fail :> es) - => NonEmpty SomeMnemonic - -> Eff (FxFaucet : es) a -> Eff es a -runFaucetPure faucetMnemonics = reinterpret (evalState faucetMnemonics) $ - \ _localEnv UseFaucetMnemonic -> do - mnemonics <- get - let (mnemonic, maybeRemainingMnemonics) = NE.uncons mnemonics - case maybeRemainingMnemonics of - Nothing -> fail "No more faucet mnemonics" - Just remainingMnemonics -> do - trace $ "Used faucet mnemonic: " <> T.pack (show mnemonic) - put remainingMnemonics - pure mnemonic diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Http.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Http.hs deleted file mode 100644 index 4c20b662691..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Http.hs +++ /dev/null @@ -1,65 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE UndecidableInstances #-} -{-# OPTIONS_GHC -Wno-orphans #-} - -module Cardano.Wallet.Spec.Effect.Http where - -import qualified Network.HTTP.Client as HC - -import Cardano.Wallet.Spec.Effect.Trace - ( FxTrace - , trace - ) -import Control.Exception - ( try - ) -import Effectful - ( Eff - , Effect - , IOE - , (:>) - ) -import Effectful.Dispatch.Dynamic - ( interpret - ) -import Effectful.Fail - ( Fail - ) -import Effectful.TH - ( makeEffect - ) -import Prelude hiding - ( evalState - , get - , gets - , modify - , trace - ) -import Wallet - ( MonadHTTP - ) -import Wallet.Common - ( MonadHTTP (..) - ) - -data FxHttp :: Effect where - HttpQuery :: HC.Request -> FxHttp m (HC.Response ByteString) - -$(makeEffect ''FxHttp) - -instance (FxHttp :> es) => MonadHTTP (Eff es) where - httpBS = httpQuery - -runHttpClient - :: (FxTrace :> es, Fail :> es, IOE :> es) - => HC.Manager - -> Eff (FxHttp : es) a - -> Eff es a -runHttpClient connectionManager = interpret \_ -> \case - HttpQuery request -> do - trace $ "HTTP request: " <> show request - response <- liftIO $ try $ HC.httpLbs request connectionManager - trace $ "HTTP response: " <> show response - case response of - Left (e :: SomeException) -> fail $ displayException e - Right r -> pure $ fmap toStrict r diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Query.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Query.hs deleted file mode 100644 index d87b238362a..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Query.hs +++ /dev/null @@ -1,395 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} - -module Cardano.Wallet.Spec.Effect.Query where - -import qualified Cardano.Wallet.Spec.Data.Network.NodeStatus as NodeStatus -import qualified Cardano.Wallet.Spec.Data.WalletId as WalletId -import qualified Cardano.Wallet.Spec.Data.WalletName as WalletName -import qualified Data.List.NonEmpty as NE -import qualified Data.Set as Set -import qualified Network.HTTP.Types as Http -import qualified Text.Show as TS -import qualified Wallet as W -import qualified Wallet.Common as WC -import qualified Wallet.Operations.DeleteWallet as DW -import qualified Wallet.Operations.GetWallet as GW -import qualified Wallet.Operations.ListWallets as LW -import qualified Wallet.Operations.PostWallet as PW - -import Cardano.Mnemonic.Extended - ( SomeMnemonic - , someMnemonicToSentence - , someMnemonicToWords - ) -import Cardano.Wallet.Cli.Launcher - ( walletInstanceApiUrl - ) -import Cardano.Wallet.Spec.Data.AdaBalance - ( AdaBalance (..) - ) -import Cardano.Wallet.Spec.Data.Network.Info - ( NetworkInfo (..) - ) -import Cardano.Wallet.Spec.Data.Network.NodeStatus - ( NodeStatus (..) - ) -import Cardano.Wallet.Spec.Data.Wallet - ( Wallet (..) - ) -import Cardano.Wallet.Spec.Data.WalletId - ( WalletId (..) - ) -import Cardano.Wallet.Spec.Data.WalletName - ( WalletName - ) -import Cardano.Wallet.Spec.Effect.Assert - ( FxAssert - , assert - , assertEq - ) -import Cardano.Wallet.Spec.Effect.Http - ( FxHttp - ) -import Cardano.Wallet.Spec.Effect.Trace - ( FxTrace - , trace - ) -import Cardano.Wallet.Spec.Network.Configured - ( ConfiguredNetwork (..) - ) -import Effectful - ( Eff - , Effect - , (:>) - ) -import Effectful.Dispatch.Dynamic - ( interpret - , reinterpret - ) -import Effectful.Error.Static - ( runErrorNoCallStack - ) -import Effectful.Fail - ( Fail - ) -import Effectful.State.Static.Local - ( evalState - , get - , gets - , modify - ) -import Effectful.TH - ( makeEffect - ) -import Network.HTTP.Client - ( responseBody - , responseStatus - ) -import Network.HTTP.Types - ( created201 - , noContent204 - , ok200 - ) -import Prelude hiding - ( evalState - , get - , gets - , modify - , trace - ) - -data FxQuery :: Effect where - ListKnownWallets :: FxQuery m (Set Wallet) - CreateWalletFromMnemonic :: WalletName -> SomeMnemonic -> FxQuery m Wallet - GetWallet :: WalletId -> FxQuery m Wallet - DeleteWallet :: Wallet -> FxQuery m () - QueryNetworkInfo :: FxQuery m NetworkInfo - -$(makeEffect ''FxQuery) - -runQueryMock - :: (FxTrace :> es, Fail :> es) - => Set Wallet - -> Eff (FxQuery : es) a - -> Eff es a -runQueryMock db0 = reinterpret (evalState db0) \_ -> \case - ListKnownWallets -> do - wallets <- get - trace $ "Listing known wallets (" <> show (length wallets) <> ")" - pure wallets - CreateWalletFromMnemonic name mnemonic -> do - let wallet = - Wallet - { walletId = - WalletId.fromNel - $ NE.intersperse "." - $ someMnemonicToWords mnemonic - , walletName = name - , walletBalance = - AdaBalance - { adaAvailable = 0 - , adaInRewards = 0 - , adaTotal = 0 - } - } - trace - $ fold - [ "Creating a wallet '" - , WalletName.toText name - , "': " - , show wallet - ] - wallet <$ modify (Set.insert wallet) - GetWallet wid -> do - trace $ "Getting a wallet " <> show wid - gets (find ((== wid) . walletId) . Set.toList) - >>= maybe - (fail $ "GetWallet (" <> show wid <> ") not found by id") - pure - DeleteWallet wallet -> do - trace $ "Deleting a wallet " <> show wallet - modify (Set.delete wallet) - QueryNetworkInfo -> do - trace "Querying network info ..." - pure NetworkInfo{nodeStatus = NodeIsSynced} - -runQuery - :: ( FxHttp :> es - , Fail :> es - , FxAssert :> es - , FxTrace :> es - ) - => ConfiguredNetwork - -> Eff (FxQuery : es) a - -> Eff es a -runQuery configuredNetwork = interpret \_ -> \case - ListKnownWallets -> do - resp <- runClient LW.listWallets - assert "ListKnownWallets response status" - $ responseStatus resp == ok200 - let walletFromBody (LW.ListWalletsResponseBody200{..}) = - Wallet - { walletId = - WalletId.mkUnsafe listWalletsResponseBody200Id - , walletName = - WalletName.mkUnsafe listWalletsResponseBody200Name - , walletBalance = - AdaBalance - { adaAvailable = - fromIntegral - ( LW.listWalletsResponseBody200BalanceAvailableQuantity - ( LW.listWalletsResponseBody200BalanceAvailable - listWalletsResponseBody200Balance - ) - ) - , adaInRewards = - fromIntegral - ( LW.listWalletsResponseBody200BalanceRewardQuantity - ( LW.listWalletsResponseBody200BalanceReward - listWalletsResponseBody200Balance - ) - ) - , adaTotal = - fromIntegral - ( LW.listWalletsResponseBody200BalanceTotalQuantity - ( LW.listWalletsResponseBody200BalanceTotal - listWalletsResponseBody200Balance - ) - ) - } - } - knownWallets <- case responseBody resp of - LW.ListWalletsResponse200 lwrbs -> - pure $ Set.fromList $ map walletFromBody lwrbs - respBody -> - fail - $ "ListKnownWallets: unexpected response body: " <> show respBody - trace $ "Listing known wallets (" <> show (length knownWallets) <> ")" - pure knownWallets - CreateWalletFromMnemonic name mnemonic -> do - trace $ "Creating a wallet from mnemonic: " <> someMnemonicToSentence mnemonic - resp <- - runClient - $ PW.postWallet - $ PW.PostWalletRequestBodyVariant1 - $ PW.mkPostWalletRequestBodyOneOf1 - (toList (someMnemonicToWords mnemonic)) - (WalletName.toText name) - "Secure Passphrase" - assertEq - "PostWallet response status is 201 Created" - (responseStatus resp) - created201 - case responseBody resp of - PW.PostWalletResponse201 PW.PostWalletResponseBody201{..} -> do - pure - Wallet - { walletId = - WalletId.mkUnsafe postWalletResponseBody201Id - , walletName = - WalletName.mkUnsafe postWalletResponseBody201Name - , walletBalance = - AdaBalance - { adaAvailable = - fromIntegral - ( PW.postWalletResponseBody201BalanceAvailableQuantity - ( PW.postWalletResponseBody201BalanceAvailable - postWalletResponseBody201Balance - ) - ) - , adaInRewards = - fromIntegral - ( PW.postWalletResponseBody201BalanceRewardQuantity - ( PW.postWalletResponseBody201BalanceReward - postWalletResponseBody201Balance - ) - ) - , adaTotal = - fromIntegral - ( PW.postWalletResponseBody201BalanceTotalQuantity - ( PW.postWalletResponseBody201BalanceTotal - postWalletResponseBody201Balance - ) - ) - } - } - respBody -> - fail - $ "CreateWalletFromMnemonic: unexpected response body: " - <> show respBody - GetWallet wid -> do - trace $ "Getting a wallet " <> show wid - resp <- runClient $ GW.getWallet (walletIdToText wid) - assert "GetWallet response status is 200 Ok" - $ responseStatus resp == ok200 - case responseBody resp of - GW.GetWalletResponse200 GW.GetWalletResponseBody200{..} -> - pure - Wallet - { walletId = - WalletId.mkUnsafe getWalletResponseBody200Id - , walletName = - WalletName.mkUnsafe getWalletResponseBody200Name - , walletBalance = - AdaBalance - { adaAvailable = - fromIntegral - ( GW.getWalletResponseBody200BalanceAvailableQuantity - ( GW.getWalletResponseBody200BalanceAvailable - getWalletResponseBody200Balance - ) - ) - , adaInRewards = - fromIntegral - ( GW.getWalletResponseBody200BalanceRewardQuantity - ( GW.getWalletResponseBody200BalanceReward - getWalletResponseBody200Balance - ) - ) - , adaTotal = - fromIntegral - ( GW.getWalletResponseBody200BalanceTotalQuantity - ( GW.getWalletResponseBody200BalanceTotal - getWalletResponseBody200Balance - ) - ) - } - } - respBody -> - fail - $ "GetWallet (" - <> show wid - <> "): unexpected response body: " - <> show respBody - DeleteWallet wallet -> do - trace $ "Deleting a wallet " <> show wallet - resp <- runClient $ DW.deleteWallet (walletIdToText (walletId wallet)) - assert "DeleteWallet response status is 204 NoContent" - $ responseStatus resp == noContent204 - case responseBody resp of - DW.DeleteWalletResponse204 -> pass - respBody -> - fail - $ "DeleteWallet (" - <> show wallet - <> "): unexpected response body: " - <> show respBody - QueryNetworkInfo -> do - trace "Querying network info ..." - W.getNetworkInformation - & runClient - & runErrorNoCallStack - >>= \case - Left (e :: SomeException) -> - environmentException - $ WalletNetworkInfoException configuredNetwork e - Right resp | status <- responseStatus resp -> do - unless (status == ok200) do - environmentException - $ WalletNetworkInfoStatus configuredNetwork status - case responseBody resp of - W.GetNetworkInformationResponseError err -> - environmentException - $ WalletNetworkInfoError configuredNetwork (toText err) - W.GetNetworkInformationResponse406 - W.GetNetworkInformationResponseBody406{..} -> - environmentException - $ WalletNetworkInfoError - configuredNetwork - getNetworkInformationResponseBody406Message - W.GetNetworkInformationResponse200 - W.GetNetworkInformationResponseBody200{..} -> do - nodeStatus <- - NodeStatus.fromClientResponse getNetworkInformationResponseBody200Sync_progress - & maybe - ( environmentException - $ WalletNetworkInfoUnknownNodeStatus configuredNetwork - ) - pure - pure NetworkInfo{nodeStatus} - where - runClient :: WC.ClientT m a -> m a - runClient = - WC.runWithConfiguration - WC.Configuration - { WC.configBaseURL = - walletInstanceApiUrl (configuredNetworkWallet configuredNetwork) - , WC.configSecurityScheme = WC.anonymousSecurityScheme - , WC.configIncludeUserAgent = False - , WC.configApplicationName = "" - } - -environmentException :: (Fail :> es) => ExecutionEnvironmentException -> Eff es a -environmentException = fail . displayException - -data ExecutionEnvironmentException - = WalletNetworkInfoException ConfiguredNetwork SomeException - | WalletNetworkInfoStatus ConfiguredNetwork Http.Status - | WalletNetworkInfoError ConfiguredNetwork Text - | NodeIsNotReady ConfiguredNetwork - | WalletNetworkInfoUnknownNodeStatus ConfiguredNetwork - deriving anyclass (Exception) - -instance Show ExecutionEnvironmentException where - show = \case - WalletNetworkInfoException configuredNetwork se -> - requirement configuredNetwork - <> "However, an exception happened when trying to retrieve \n\ - \network information from the wallet backend: \n\n" - <> displayException se - WalletNetworkInfoUnknownNodeStatus configuredNetwork -> - requirement configuredNetwork - WalletNetworkInfoStatus configuredNetwork _ -> - requirement configuredNetwork - WalletNetworkInfoError configuredNetwork _ -> - requirement configuredNetwork - NodeIsNotReady configuredNetwork -> - requirement configuredNetwork - where - requirement :: ConfiguredNetwork -> String - requirement configuration = - "E2E test suite requires a running cardano-wallet instance \n\ - \connected to a running cardano-node and listenting on " - <> show - (walletInstanceApiUrl (configuredNetworkWallet configuration)) - <> "\n\n" diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Random.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Random.hs deleted file mode 100644 index bbb9fb54234..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Random.hs +++ /dev/null @@ -1,120 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE UndecidableInstances #-} -{-# OPTIONS_GHC -Wno-orphans #-} - -module Cardano.Wallet.Spec.Effect.Random where - -import qualified Cardano.Mnemonic.Extended as Cardano -import qualified Cardano.Wallet.Spec.Data.WalletName as WalletName -import qualified Data.ByteString.Base58 as Base58 -import qualified Data.Text as T -import qualified Effectful.State.Static.Local as State - -import Cardano.Mnemonic - ( SomeMnemonic - ) -import Cardano.Mnemonic.Extended - ( someMnemonicToSentence - ) -import Cardano.Wallet.Spec.Data.WalletName - ( WalletName - ) -import Cardano.Wallet.Spec.Effect.Trace - ( FxTrace - , trace - ) -import Crypto.Encoding.BIP39 - ( toEntropy - ) -import Data.Tagged - ( Tagged (..) - ) -import Effectful - ( Eff - , Effect - , (:>) - ) -import Effectful.Dispatch.Dynamic - ( interpret - , reinterpret - ) -import Effectful.Fail - ( Fail - ) -import Effectful.State.Static.Local - ( State - , evalState - ) -import Effectful.TH - ( makeEffect - ) -import Prelude hiding - ( State - , evalState - , get - , trace - ) -import System.Random - ( StdGen - ) -import System.Random.Stateful - ( StateGenM (..) - , uniformByteStringM - ) - -data FxRandom :: Effect where - RandomMnemonic :: FxRandom m SomeMnemonic - RandomWalletName :: Tagged "Prefix" Text -> FxRandom m WalletName - -$(makeEffect ''FxRandom) - -runRandomMock - :: (FxTrace :> es) - => SomeMnemonic - -> Eff (FxRandom : es) a - -> Eff es a -runRandomMock mnemonic = interpret \_ -> \case - RandomMnemonic -> do - trace $ "Generated a [mock] random mnemonic: " - <> someMnemonicToSentence mnemonic - pure mnemonic - RandomWalletName (Tagged prefix) -> do - let name = WalletName.mkUnsafe $ prefix <> "#12345" - trace $ "Generated a random wallet name: " <> WalletName.toText name - pure name - -instance (State StdGen :> es) => MonadState StdGen (Eff es) where - state = State.state - -runRandom - :: (FxTrace :> es, Fail :> es) - => StdGen - -> Eff (FxRandom : es) a - -> Eff es a -runRandom gen = reinterpret (evalState gen) \_ -> \case - RandomMnemonic -> do - randomByteString <- uniformByteStringM 32 stGen - mnemonic <- - either - (fail . show) - (pure . Cardano.SomeMnemonic . Cardano.entropyToMnemonic) - (toEntropy @256 randomByteString) - trace $ "Generated a random mnemonic: " - <> someMnemonicToSentence mnemonic - pure mnemonic - RandomWalletName (Tagged prefix) -> do - randomSuffix <- uniformByteStringM 10 stGen - let name = - WalletName.mkUnsafe - $ fold - [ T.stripEnd prefix - , " #" - , decodeUtf8 - $ Base58.encodeBase58 - Base58.bitcoinAlphabet - randomSuffix - ] - trace $ "Generated a random wallet name: " <> WalletName.toText name - pure name - where - stGen :: StateGenM StdGen = StateGenM diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Timeout.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Timeout.hs deleted file mode 100644 index fe5c1954e2d..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Timeout.hs +++ /dev/null @@ -1,59 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} - -module Cardano.Wallet.Spec.Effect.Timeout - ( -- * Effect - FxTimeout - , within - - -- ** Handlers - , runTimeout - ) where - -import Cardano.Wallet.Spec.Effect.Assert - ( FxAssert - , assertFail - ) -import Control.Exception - ( catch - ) -import Data.Time.TimeSpan - ( TimeSpan - , timeoutTS - ) -import Effectful - ( Eff - , Effect - , IOE - , (:>) - ) -import Effectful.Dispatch.Dynamic - ( interpret - , localSeqLift - , localSeqUnliftIO - ) -import Effectful.TH - ( makeEffect - ) -import System.Timeout - ( Timeout - ) - --- | An effect for timing out computations. -data FxTimeout :: Effect where - Within :: TimeSpan -> m a -> FxTimeout m a - -$(makeEffect ''FxTimeout) - -runTimeout :: (FxAssert :> es, IOE :> es) => Eff (FxTimeout : es) a -> Eff es a -runTimeout = interpret \env (Within timeSpan action) -> - localSeqLift env \toLocalEs -> - localSeqUnliftIO env \fromLocalEs -> do - result <- - timeoutTS timeSpan (fromLocalEs action) - `catch` \(_ :: Timeout) -> pure Nothing - case result of - Just a -> pure a - Nothing -> do - let msg = "Computation timed out (" <> show timeSpan <> ")" - fromLocalEs $ toLocalEs $ assertFail msg - fail $ toString msg diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Trace.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Trace.hs deleted file mode 100644 index 1f4c65e047a..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Effect/Trace.hs +++ /dev/null @@ -1,61 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE TemplateHaskell #-} - -module Cardano.Wallet.Spec.Effect.Trace where - -import qualified Data.Sequence as Seq - -import Cardano.Wallet.Launch.Cluster.FileOf - ( DirOf (..) - , toFilePath - ) -import Cardano.Wallet.Spec.Interpreters.Config - ( TraceConfiguration (..) - ) -import Data.Sequence - ( (|>) - ) -import Effectful - ( Eff - , Effect - ) -import Effectful.Dispatch.Dynamic - ( reinterpret - ) -import Effectful.State.Static.Local - ( modify - , runState - ) -import Effectful.TH - ( makeEffect - ) -import Prelude hiding - ( modify - , runState - , trace - ) -import System.Path - ( relFile - , (<.>) - , () - ) -import System.Path.Directory - ( createDirectoryIfMissing - ) - -data FxTrace :: Effect where - Trace :: Text -> FxTrace m () - -$(makeEffect ''FxTrace) - -runTracePure :: Eff (FxTrace : es) a -> Eff es (a, Seq Text) -runTracePure = reinterpret (runState Seq.empty) \_ (Trace msg) -> - modify (|> msg) - -recordTraceLog :: TraceConfiguration -> String -> Seq Text -> IO () -recordTraceLog (TraceConfiguration (DirOf outDir)) storyLabel log = do - createDirectoryIfMissing True outDir - let fileName = relFile - [if c == ' ' then '_' else c | c <- storyLabel] <.> "log" - let outFile = outDir fileName - writeFile (toFilePath outFile) $ toString $ unlines $ toList log diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Interpreters/Config.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Interpreters/Config.hs deleted file mode 100644 index 3085681151a..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Interpreters/Config.hs +++ /dev/null @@ -1,8 +0,0 @@ -module Cardano.Wallet.Spec.Interpreters.Config where -import Cardano.Wallet.Launch.Cluster.FileOf - ( DirOf - ) - -newtype TraceConfiguration = TraceConfiguration - { traceConfigurationDir :: DirOf "tracing-dir" - } diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Interpreters/Effectfully.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Interpreters/Effectfully.hs deleted file mode 100644 index ef954cc5063..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Interpreters/Effectfully.hs +++ /dev/null @@ -1,150 +0,0 @@ -module Cardano.Wallet.Spec.Interpreters.Effectfully - ( Story - , story - ) where - -import qualified Network.HTTP.Client as Http - -import Cardano.Mnemonic - ( Mnemonic - , SomeMnemonic (..) - ) -import Cardano.Wallet.Spec.Effect.Assert - ( FxAssert - , runAssertFailsFast - ) -import Cardano.Wallet.Spec.Effect.Faucet - ( FxFaucet - , runFaucetPure - ) -import Cardano.Wallet.Spec.Effect.Http - ( FxHttp - , runHttpClient - ) -import Cardano.Wallet.Spec.Effect.Query - ( FxQuery - , runQuery - ) -import Cardano.Wallet.Spec.Effect.Random - ( FxRandom - , runRandom - ) -import Cardano.Wallet.Spec.Effect.Timeout - ( FxTimeout - , runTimeout - ) -import Cardano.Wallet.Spec.Effect.Trace - ( FxTrace - , recordTraceLog - , runTracePure - ) -import Cardano.Wallet.Spec.Interpreters.Config - ( TraceConfiguration - ) -import Cardano.Wallet.Spec.Network.Configured - ( ConfiguredNetwork - ) -import Cardano.Wallet.Unsafe - ( unsafeMkMnemonic - ) -import Effectful - ( Eff - , IOE - , runEff - ) -import Effectful.Fail - ( Fail - , runFail - ) -import Network.HTTP.Client - ( ManagerSettings (managerResponseTimeout) - ) -import System.Random - ( initStdGen - ) -import Test.Syd - ( HList (..) - , TestDefM - , expectationFailure - , itWithAll - ) - -type Story a = - Eff - [ FxQuery - , FxFaucet - , FxHttp - , FxRandom - , FxTimeout - , FxAssert - , Fail - , FxTrace - , IOE - ] - a - -type StoryConfig = - '[ ConfiguredNetwork - , TraceConfiguration - ] - -onStoryConfig - :: HList StoryConfig - -> (ConfiguredNetwork -> TraceConfiguration -> a) - -> a -onStoryConfig (HCons network (HCons traceOutput HNil)) f = f network traceOutput - -story - :: String - -> Story () - -> TestDefM StoryConfig () () -story label story' = - itWithAll label \config () -> onStoryConfig config - $ \network traceOutput -> do - (result, log) <- interpretStory network story' - recordTraceLog traceOutput label log - case result of - Left err -> expectationFailure err - Right () -> pass - -interpretStory - :: ConfiguredNetwork - -> Story a - -> IO (Either String a, Seq Text) -interpretStory configuredNetwork story' = do - connectionManager <- - Http.newManager - Http.defaultManagerSettings - { managerResponseTimeout = Http.responseTimeoutNone - } - stdGen <- initStdGen - story' - & runQuery configuredNetwork - & runFaucetPure (SomeMnemonic preregKeyWallet :| []) - & runHttpClient connectionManager - & runRandom stdGen - & runTimeout - & runAssertFailsFast - & runFail - & runTracePure - & runEff - -preregKeyWallet :: Mnemonic 15 -preregKeyWallet = - unsafeMkMnemonic @15 - [ "squirrel" - , "material" - , "silly" - , "twice" - , "direct" - , "slush" - , "pistol" - , "razor" - , "become" - , "junk" - , "kingdom" - , "flee" - , "squirrel" - , "silly" - , "twice" - ] diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Interpreters/Pure.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Interpreters/Pure.hs deleted file mode 100644 index e04eef542fe..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Interpreters/Pure.hs +++ /dev/null @@ -1,119 +0,0 @@ -module Cardano.Wallet.Spec.Interpreters.Pure - ( pureStory - , PureStory - ) where - -import qualified Data.Set as Set -import qualified Effectful.Error.Static as E - -import Cardano.Mnemonic - ( SomeMnemonic (..) - ) -import Cardano.Wallet.Launch.Cluster.FileOf - ( DirOf (..) - ) -import Cardano.Wallet.Spec.Effect.Assert - ( FxAssert - , runAssertFailsFast - ) -import Cardano.Wallet.Spec.Effect.Query - ( FxQuery - , runQueryMock - ) -import Cardano.Wallet.Spec.Effect.Random - ( FxRandom - , runRandomMock - ) -import Cardano.Wallet.Spec.Effect.Trace - ( FxTrace - , recordTraceLog - , runTracePure - ) -import Cardano.Wallet.Spec.Interpreters.Config - ( TraceConfiguration (..) - ) -import Cardano.Wallet.Unsafe - ( unsafeMkMnemonic - ) -import Effectful - ( Eff - , runPureEff - ) -import Effectful.Fail - ( Fail - , runFail - ) -import GHC.IO - ( unsafePerformIO - ) -import System.Path - ( absRel - , dynamicMakeAbsoluteFromCwd - ) -import Test.Syd - ( TestDefM - , expectationFailure - , it - ) - -type PureStory a = - Eff - [ FxQuery - , FxRandom - , FxAssert - , FxTrace - , Fail - , E.Error SomeException - ] - a - -defaultTraceConfiguration :: TraceConfiguration -defaultTraceConfiguration = - TraceConfiguration - { traceConfigurationDir = - DirOf @"tracing-dir" - $ unsafePerformIO - $ dynamicMakeAbsoluteFromCwd - $ absRel "lib/wallet-e2e/test-output" - } - -pureStory :: String -> PureStory a -> TestDefM outers () () -pureStory label story = - it label do - interpretStoryPure story & \case - Left err -> expectationFailure (show err) - Right (Left err) -> expectationFailure err - Right (Right (_unit :: a, log)) -> - recordTraceLog defaultTraceConfiguration label log - -interpretStoryPure - :: PureStory a - -> (Either SomeException (Either String (a, Seq Text))) -interpretStoryPure = - runQueryMock Set.empty - >>> runRandomMock predefinedMnemonic - >>> runAssertFailsFast - >>> runTracePure - >>> runFail - >>> E.runErrorNoCallStack - >>> runPureEff - where - predefinedMnemonic = - SomeMnemonic - $ unsafeMkMnemonic @15 - [ "vintage" - , "poem" - , "topic" - , "machine" - , "hazard" - , "cement" - , "dune" - , "glimpse" - , "fix" - , "brief" - , "account" - , "badge" - , "mass" - , "silly" - , "business" - ] diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Configured.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Configured.hs deleted file mode 100644 index 3e5360c96ce..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Configured.hs +++ /dev/null @@ -1,9 +0,0 @@ -module Cardano.Wallet.Spec.Network.Configured where - -import Cardano.Wallet.Cli.Launcher - ( WalletApi - ) - -newtype ConfiguredNetwork = ConfiguredNetwork - { configuredNetworkWallet :: WalletApi - } diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Local.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Local.hs deleted file mode 100644 index 81a97c81824..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Local.hs +++ /dev/null @@ -1,95 +0,0 @@ -module Cardano.Wallet.Spec.Network.Local - ( configuredNetwork - ) where - -import qualified Cardano.Wallet.Spec.Network.Wait as Wait - -import Cardano.Wallet.Cli.Launcher - ( WalletApi (..) - ) -import Cardano.Wallet.Launch.Cluster - ( FaucetFunds (..) - ) -import Cardano.Wallet.Launch.Cluster.Faucet.Serialize - ( saveFunds - ) -import Cardano.Wallet.Launch.Cluster.FileOf - ( DirOf (..) - , FileOf (..) - , toFilePath - ) -import Cardano.Wallet.Spec.Network.Configured - ( ConfiguredNetwork (..) - ) -import Control.Monad.Trans.Resource - ( ResourceT - , allocate - ) -import System.IO - ( openFile - ) -import System.IO.Extra - ( newTempFile - ) -import System.Path - ( absFile - , relFile - , () - ) -import System.Process.Typed - ( proc - , setStderr - , setStdout - , startProcess - , stopProcess - , useHandleClose - ) - -tempFile :: ResourceT IO FilePath -tempFile = fst . snd <$> allocate newTempFile snd - -configuredNetwork - :: DirOf "state" - -> DirOf "config" - -> Maybe FaucetFunds - -> ResourceT IO ConfiguredNetwork -configuredNetwork (DirOf stateDir) (DirOf clusterConfigsDir) faucetFunds = do - walletApi <- startCluster - - unlessM (Wait.untilWalletIsConnected walletApi) do - fail "Wallet is not synced, giving up. Please check wallet logs." - - pure ConfiguredNetwork{configuredNetworkWallet = walletApi, ..} - where - startCluster :: ResourceT IO WalletApi = do - socketPath <- tempFile - let clusterLog = stateDir relFile "cluster.log" - faucetFundsPath <- tempFile - liftIO $ saveFunds (FileOf $ absFile faucetFundsPath) - $ fromMaybe (FaucetFunds [] [] []) faucetFunds - handle <- liftIO $ openFile (toFilePath clusterLog) AppendMode - putStrLn $ "Writing cluster logs to " <> toFilePath clusterLog - let randomPort = 64890 - let start = startProcess - $ setStderr (useHandleClose handle) - $ setStdout (useHandleClose handle) - $ proc - "local-cluster" - [ "--cluster-configs" - , toFilePath clusterConfigsDir - , "--socket-path" - , socketPath - , "--faucet-funds" - , faucetFundsPath - , "--wallet-present" - , "--wallet-port" - , show randomPort - ] - void $ allocate start stopProcess - pure - WalletApi - { walletInstanceApiUrl = - "http://localhost:" <> show randomPort <> "/v2" - , walletInstanceApiHost = "localhost" - , walletInstanceApiPort = randomPort - } diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Manual.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Manual.hs deleted file mode 100644 index fd4ca642b9d..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Manual.hs +++ /dev/null @@ -1,19 +0,0 @@ -module Cardano.Wallet.Spec.Network.Manual where - -import Cardano.Wallet.Cli.Launcher - ( WalletApi (..) - ) -import Cardano.Wallet.Spec.Network.Configured - ( ConfiguredNetwork (..) - ) - -configuredNetwork :: ConfiguredNetwork -configuredNetwork = - ConfiguredNetwork - { configuredNetworkWallet = - WalletApi - { walletInstanceApiUrl = "http://localhost:8090/v2" - , walletInstanceApiHost = "localhost" - , walletInstanceApiPort = 8090 - } - } diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Node/Cli.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Node/Cli.hs deleted file mode 100644 index 98e522ffca3..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Node/Cli.hs +++ /dev/null @@ -1,96 +0,0 @@ -module Cardano.Wallet.Spec.Network.Node.Cli where - -import qualified Data.Aeson as Aeson -import qualified Data.Aeson.Parser as Aeson -import qualified Data.Aeson.Types as Aeson -import qualified Data.String as String - -import Cardano.Node.Cli.Launcher - ( NodeApi - , nodeApiSocket - ) -import Cardano.Wallet.Launch.Cluster.FileOf - ( toFilePath - ) -import Data.Aeson - ( withObject - , (.:) - ) -import Prelude hiding - ( stderr - , stdout - ) -import System.Process.Typed - ( ExitCode (..) - , readProcess - , shell - ) - -data NodeTip = NodeTip - { block :: Natural - , epoch :: Natural - , era :: Text - , hash :: Text - , slot :: Natural - , slotInEpoch :: Natural - , slotsToEpochEnd :: Natural - , syncProgress :: Double - } - deriving stock (Eq, Show, Generic) - -parseNodeTip :: Aeson.Value -> Aeson.Parser NodeTip -parseNodeTip = withObject "NodeTip" \o -> do - block <- o .: "block" - epoch <- o .: "epoch" - era <- o .: "era" - hash <- o .: "hash" - slot <- o .: "slot" - slotInEpoch <- o .: "slotInEpoch" - slotsToEpochEnd <- o .: "slotsToEpochEnd" - syncProgress <- - o .: "syncProgress" >>= either (fail . toString) pure . readEither - pure NodeTip{..} - -data CliError - = CliErrorExitCode Int LByteString - | CliErrorDecode (Aeson.JSONPath, String) LByteString - deriving stock (Eq, Show) - -queryTip :: NodeApi -> IO (Either CliError NodeTip) -queryTip nodeApi = do - (exitCode, stdout, stderr) <- - readProcess . shell - $ String.unwords - [ "cardano-cli" - , "query" - , "tip" - , "--testnet-magic" - , "1" - , "--socket-path" - , toFilePath (nodeApiSocket nodeApi) - ] - case exitCode of - ExitFailure code -> - pure $ Left $ CliErrorExitCode code stderr - ExitSuccess -> do - let parser = Aeson.iparse parseNodeTip - case Aeson.eitherDecodeWith Aeson.value parser stdout of - Left err -> pure $ Left $ CliErrorDecode err stdout - Right tip -> pure $ Right tip - -checkSocket :: NodeApi -> IO Bool -checkSocket nodeApi = do - (exitCode, _stdout, _stderr) <- - readProcess . shell - $ String.unwords - [ "cardano-cli" - , "query" - , "tip" - , "--testnet-magic" - , "1" - , "--socket-path" - , toFilePath (nodeApiSocket nodeApi) - ] - case exitCode of - ExitSuccess -> pure True - ExitFailure _code -> pure False diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Preprod.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Preprod.hs deleted file mode 100644 index 65285e3158b..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Preprod.hs +++ /dev/null @@ -1,84 +0,0 @@ -module Cardano.Wallet.Spec.Network.Preprod - ( configuredNetwork - ) where - -import qualified Cardano.Node.Cli.Launcher as Node -import qualified Cardano.Wallet.Cli.Launcher as Wallet -import qualified Cardano.Wallet.Spec.Network.Wait as Wait - -import Cardano.Node.Cli.Launcher - ( NodeProcessConfig (..) - ) -import Cardano.Wallet.Cli.Launcher - ( WalletProcessConfig (..) - ) -import Cardano.Wallet.Launch.Cluster.FileOf - ( DirOf (DirOf) - , FileOf (..) - ) -import Cardano.Wallet.Spec.Network.Configured - ( ConfiguredNetwork (..) - ) -import Control.Monad.Trans.Resource - ( ResourceT - , allocate - ) -import System.Path - ( relDir - , relFile - , () - ) - -configuredNetwork - :: DirOf "state" - -> DirOf "config" - -> ResourceT IO ConfiguredNetwork -configuredNetwork (DirOf stateDir) (DirOf nodeConfigDir) = do - nodeApi <- startNode - - walletApi <- startWallet nodeApi - - unlessM (Wait.forNodeSocket nodeApi) do - fail "Node socket is not available, giving up. Please check node logs." - - unlessM (Wait.untilNodeIsSynced nodeApi) do - fail "Node is not synced, giving up. Please check node logs." - - unlessM (Wait.untilWalletIsConnected walletApi) do - fail "Wallet is not synced, giving up. Please check wallet logs." - - pure ConfiguredNetwork - { configuredNetworkWallet = walletApi - } - where - startNode = do - let nodeDir = stateDir relDir "node" - let nodeProcessConfig = - NodeProcessConfig - { nodeDir = DirOf nodeDir - , nodeConfig = - FileOf $ nodeConfigDir relFile "config.json" - , nodeTopology = - FileOf $ nodeConfigDir relFile "topology.json" - , nodeDatabase = - DirOf $ nodeDir relDir "db" - } - (_nodeReleaseKey, (_nodeInstance, nodeApi)) <- - allocate (Node.start nodeProcessConfig) (Node.stop . fst) - pure nodeApi - - startWallet nodeApi = do - let walletDir = stateDir relDir "wallet" - let walletProcessConfig = - WalletProcessConfig - { walletDir = DirOf walletDir - , walletDatabase = DirOf $ walletDir relDir "db" - , walletNodeApi = nodeApi - , walletListenHost = Nothing - , walletListenPort = Nothing - , walletByronGenesisForTestnet = Just $ - FileOf $ nodeConfigDir relFile "byron-genesis.json" - } - (_walletReleaseKey, (_walletInstance, walletApi)) <- - allocate (Wallet.start walletProcessConfig) (Wallet.stop . fst) - pure walletApi diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Wait.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Wait.hs deleted file mode 100644 index 589db6ef11b..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Wait.hs +++ /dev/null @@ -1,92 +0,0 @@ -module Cardano.Wallet.Spec.Network.Wait where - -import qualified Cardano.Wallet.Spec.Data.Network.NodeStatus as NodeStatus -import qualified Cardano.Wallet.Spec.Network.Node.Cli as NodeCli -import qualified Cardano.Wallet.Spec.Network.Wallet.Cli as WalletCli - -import Cardano.Node.Cli.Launcher - ( NodeApi - ) -import Cardano.Wallet.Cli.Launcher - ( WalletApi - ) -import Cardano.Wallet.Spec.Data.Network.NodeStatus - ( NodeStatus (..) - ) -import Cardano.Wallet.Spec.Network.Node.Cli - ( CliError - , NodeTip - ) -import Cardano.Wallet.Spec.Network.Wallet.Cli - ( NetworkInformation - ) -import Control.Retry - ( RetryStatus - , capDelay - , fibonacciBackoff - , retrying - ) - -forNodeSocket :: forall m. MonadIO m => NodeApi -> m Bool -forNodeSocket nodeApi = do - let policy = capDelay (seconds 60) (fibonacciBackoff (seconds 1)) - retrying policy shouldRepeat \_ -> liftIO do NodeCli.checkSocket nodeApi - where - shouldRepeat :: RetryStatus -> Bool -> m Bool - shouldRepeat _retryStatus = pure . not - -untilNodeIsSynced :: forall m. MonadIO m => NodeApi -> m Bool -untilNodeIsSynced nodeApi = - either (const False) isSynced <$> retrying - (capDelay (hours 1) (fibonacciBackoff (seconds 1))) - shouldRepeat - \_retryStatus -> liftIO do NodeCli.queryTip nodeApi - where - isSynced :: NodeTip -> Bool - isSynced = (>= 99.99) . NodeCli.syncProgress - - shouldRepeat :: RetryStatus -> Either CliError NodeTip -> m Bool - shouldRepeat _retryStatus = \case - Left (NodeCli.CliErrorExitCode _code out) -> - True <$ putStrLn ("CLI Error: " <> decodeUtf8 out) - Left (NodeCli.CliErrorDecode (_jsonPath, e) _out) -> do - True <$ putStrLn ("Failed to decode cardano-cli response: " <> e) - Right tip -> - not (isSynced tip) <$ putStrLn do - "Node sync progress: " <> show (NodeCli.syncProgress tip) <> "%" - -untilWalletIsConnected :: forall m. MonadIO m => WalletApi -> m Bool -untilWalletIsConnected walletApi = - either (const False) ((== NodeIsSynced) . WalletCli.nodeStatus) - <$> retrying - (capDelay (hours 1) (fibonacciBackoff (seconds 1))) - shouldRepeat - \_retryStatus -> liftIO do - WalletCli.queryNetworkInformation walletApi - where - shouldRepeat - :: RetryStatus - -> Either WalletCli.Error NetworkInformation - -> m Bool - shouldRepeat _retryStatus = \case - Left err -> - True <$ putTextLn ("Waiting for wallet to start: " <> show err) - Right networkInformation -> do - let nodeStatus = WalletCli.nodeStatus networkInformation - (NodeIsSynced /= nodeStatus) - <$ putStrLn - ( "Node status as reported by wallet: " - <> NodeStatus.toString nodeStatus - ) - --------------------------------------------------------------------------------- --- Helpers --------------------------------------------------------------------- - -seconds :: Int -> Int -seconds = (* 1_000_000) - -minutes :: Int -> Int -minutes = (* 60) . seconds - -hours :: Int -> Int -hours = (* 60) . minutes diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Wallet/Cli.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Wallet/Cli.hs deleted file mode 100644 index 4bf0fbecad9..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Network/Wallet/Cli.hs +++ /dev/null @@ -1,158 +0,0 @@ -module Cardano.Wallet.Spec.Network.Wallet.Cli where - -import qualified Cardano.Wallet.Spec.Data.Network.NodeStatus as NodeStatus -import qualified Data.Aeson as Aeson -import qualified Data.Aeson.Parser as Aeson -import qualified Data.Aeson.Types as Aeson -import qualified Data.String as String - -import Cardano.Wallet.Cli.Launcher - ( WalletApi (..) - ) -import Cardano.Wallet.Spec.Data.Network.NodeStatus - ( NodeStatus - ) -import Data.Aeson - ( withObject - , (.:) - ) -import Data.Aeson.Types - ( explicitParseField - ) -import Data.Time - ( UTCTime - ) -import Prelude hiding - ( stderr - , stdout - ) -import System.Process.Typed - ( ExitCode (..) - , readProcess - , shell - ) - -data Error - = CliErrorDecode (Aeson.JSONPath, String) LByteString - | CliErrorExitCode Int LByteString - deriving stock (Eq, Show) - -queryNetworkInformation :: WalletApi -> IO (Either Error NetworkInformation) -queryNetworkInformation walletApi = do - (exitCode, stdout, stderr) <- - readProcess . shell - $ String.unwords - [ "cardano-wallet" - , "network" - , "information" - , "--port" - , show (walletInstanceApiPort walletApi) - ] - case exitCode of - ExitFailure code -> pure $ Left $ CliErrorExitCode code stderr - ExitSuccess -> do - let parser = Aeson.iparse parseNetworkInformation - case Aeson.eitherDecodeWith Aeson.value parser stdout of - Left err -> pure $ Left $ CliErrorDecode err stdout - Right tip -> pure $ Right tip - --------------------------------------------------------------------------------- --- Data types ------------------------------------------------------------------ - -data NetworkInformation = NetworkInformation - { networkInfo :: NetworkInfo - , networkTip :: NetworkTip - , nextEpoch :: NextEpoch - , nodeEra :: Text - , nodeTip :: NodeTip - , nodeStatus :: NodeStatus - , walletMode :: Text - } - deriving stock (Eq, Show) - -parseNetworkInformation :: Aeson.Value -> Aeson.Parser NetworkInformation -parseNetworkInformation = - withObject "NetworkInformation" \o -> do - networkInfo <- explicitParseField parseNetworkInfo o "network_info" - networkTip <- explicitParseField parseNetworkTip o "network_tip" - nextEpoch <- explicitParseField parseNextEpoch o "next_epoch" - nodeEra <- o .: "node_era" - nodeTip <- explicitParseField parseNodeTip o "node_tip" - syncProgress <- o .: "sync_progress" - syncStatus <- withObject "sync_progress" (.: "status") syncProgress - nodeStatus <- - case NodeStatus.fromString syncStatus of - Nothing -> fail $ "Invalid sync_progress value: " <> syncStatus - Just status -> pure status - walletMode <- o .: "wallet_mode" - pure NetworkInformation{..} - -data NetworkInfo = NetworkInfo - { networkId :: Text - , protocolMagic :: Natural - } - deriving stock (Eq, Show) - -parseNetworkInfo :: Aeson.Value -> Aeson.Parser NetworkInfo -parseNetworkInfo = withObject "NetworkInfo" \o -> do - networkId <- o .: "network_id" - protocolMagic <- o .: "protocol_magic" - pure NetworkInfo{..} - -data NetworkTip = NetworkTip - { absoluteSlotNumber :: Natural - , epochNumber :: Natural - , slotNumber :: Natural - , time :: UTCTime - } - deriving stock (Eq, Show) - -parseNetworkTip :: Aeson.Value -> Aeson.Parser NetworkTip -parseNetworkTip = withObject "NetworkTip" \o -> do - absoluteSlotNumber <- o .: "absolute_slot_number" - epochNumber <- o .: "epoch_number" - slotNumber <- o .: "slot_number" - time <- o .: "time" - pure NetworkTip{..} - -data NextEpoch = NextEpoch - { nextEpochNumber :: Natural - , nextEpochStartTime :: UTCTime - } - deriving stock (Eq, Show) - -parseNextEpoch :: Aeson.Value -> Aeson.Parser NextEpoch -parseNextEpoch = withObject "NextEpoch" \o -> do - nextEpochNumber <- o .: "epoch_number" - nextEpochStartTime <- o .: "epoch_start_time" - pure NextEpoch{..} - -data NodeTip = NodeTip - { nodeTipAbsoluteSlotNumber :: Natural - , nodeTipEpochNumber :: Natural - , nodeTipHeight :: TipHeight - , nodeTipSlotNumber :: Natural - , nodeTipTime :: UTCTime - } - deriving stock (Eq, Show) - -parseNodeTip :: Aeson.Value -> Aeson.Parser NodeTip -parseNodeTip = withObject "NodeTip" \o -> do - nodeTipAbsoluteSlotNumber <- o .: "absolute_slot_number" - nodeTipEpochNumber <- o .: "epoch_number" - nodeTipHeight <- explicitParseField parseTipHeight o "height" - nodeTipSlotNumber <- o .: "slot_number" - nodeTipTime <- o .: "time" - pure NodeTip{..} - -data TipHeight = TipHeight - { tipHeightQuantity :: Natural - , tipHeightUnit :: Text - } - deriving stock (Eq, Show) - -parseTipHeight :: Aeson.Value -> Aeson.Parser TipHeight -parseTipHeight = withObject "TipHeight" \o -> do - tipHeightQuantity <- o .: "quantity" - tipHeightUnit <- o .: "unit" - pure TipHeight{..} diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Options.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Options.hs deleted file mode 100644 index b48216c6141..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Options.hs +++ /dev/null @@ -1,133 +0,0 @@ -module Cardano.Wallet.Spec.Options where - -import Cardano.Wallet.Launch.Cluster.FileOf - ( Absolutizer (..) - , DirOf (..) - , newAbsolutizer - ) -import Cardano.Wallet.Spec - ( TestNetworkConfig (..) - ) -import Cardano.Wallet.Spec.Interpreters.Config - ( TraceConfiguration (..) - ) -import Options.Applicative - ( Parser - , eitherReader - , help - , long - , metavar - , option - , short - ) -import System.Path - ( Abs - , parse - ) - -import qualified Options.Applicative as OptParse -import qualified System.Path.PartClass as Path - -withTestOptions :: (TestNetworkConfig -> TraceConfiguration -> IO b) -> IO b -withTestOptions action = do - absolutizer <- newAbsolutizer - TestOptions{..} :: TestOptions <- - OptParse.execParser - $ OptParse.info - (parserTestOptions absolutizer OptParse.<**> OptParse.helper) - (OptParse.fullDesc <> OptParse.progDesc "E2E Wallet test suite") - traceConfiguration <- do - let absTraceDir = testGlobalOptionsTraceOutput testGlobalOptions - pure $ TraceConfiguration absTraceDir - action testNetworkConfig traceConfiguration - -parserTestOptions :: Absolutizer -> Parser TestOptions -parserTestOptions absolutizer = - TestOptions - <$> parserNetworkOptions absolutizer - <*> parserGlobalOptions absolutizer - -data TestOptions = TestOptions - { testNetworkConfig :: TestNetworkConfig - , testGlobalOptions :: TestGlobalOptions - } - -newtype TestGlobalOptions = TestGlobalOptions - { testGlobalOptionsTraceOutput :: DirOf "tracing-dir" - } - -parserGlobalOptions :: Absolutizer -> Parser TestGlobalOptions -parserGlobalOptions absolutizer = TestGlobalOptions <$> traceOutputOption - where - traceOutputOption :: Parser (DirOf "tracing-dir") = - option - (eitherReader (bimap show DirOf . parseAbs absolutizer)) - ( long "tracing-dir" - <> short 't' - <> metavar "TRACE_OUTPUT_DIR" - <> help - "Absolute or relative directory path to save trace output" - ) - -parseAbs :: Path.FileDir t => Absolutizer -> String -> Either String (Abs t) -parseAbs (Absolutizer absolutizer) str = do - dir <- parse str - pure $ absolutizer dir - -parserNetworkOptions - :: Absolutizer - -> Parser TestNetworkConfig -parserNetworkOptions absolutizer = - OptParse.subparser $ cmdManual <> cmdLocal <> cmdPreprod - where - cmdManual = - OptParse.command - "manual" - ( OptParse.info - (pure TestNetworkManual) - ( OptParse.progDesc - "Relies on a node and wallet started manually." - ) - ) - cmdLocal = - OptParse.command - "local" - ( OptParse.info - ( TestNetworkLocal - <$> stateDirOption - <*> nodeConfigsDirOption - ) - (OptParse.progDesc "Automatically starts a local test cluster.") - ) - cmdPreprod = - OptParse.command - "preprod" - ( OptParse.info - ( TestNetworkPreprod - <$> stateDirOption - <*> nodeConfigsDirOption - ) - ( OptParse.progDesc - "Automatically starts a preprod node and wallet." - ) - ) - stateDirOption :: Parser (DirOf "state") = - option - (eitherReader (bimap show DirOf . parseAbs absolutizer)) - ( long "state-dir" - <> short 's' - <> metavar "STATE_DIR" - <> help - "Absolute or relative directory path \ - \ to save node and wallet state" - ) - nodeConfigsDirOption :: Parser (DirOf "config") = - option - (eitherReader (bimap show DirOf . parseAbs absolutizer)) - ( long "node-configs-dir" - <> short 'c' - <> metavar "NODE_CONFIGS_DIR" - <> help - "Absolute or relative directory path \ - \ to a directory with node configs" - ) diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Stories/Language.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Stories/Language.hs deleted file mode 100644 index d62d0c4b4dd..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Stories/Language.hs +++ /dev/null @@ -1,14 +0,0 @@ -module Cardano.Wallet.Spec.Stories.Language (FxStory) where - -import Effectful - ( Eff - , (:>) - ) - -type FxStory otherEffects knownEffects a = - Fxs otherEffects knownEffects => Eff otherEffects a - -type family Fxs otherEffects knownEffects :: Constraint where - Fxs otherEffects '[] = () - Fxs otherEffects (knownEffect ': otherKnownEffects) = - (knownEffect :> otherEffects, Fxs otherEffects otherKnownEffects) diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Stories/Wallet.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/Stories/Wallet.hs deleted file mode 100644 index e43b33bd710..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/Stories/Wallet.hs +++ /dev/null @@ -1,110 +0,0 @@ -module Cardano.Wallet.Spec.Stories.Wallet - ( testEnvironmentIsReady - , createdWalletListed - , createdWalletRetrievable - , createdWalletHasZeroAda - , faucetWalletHasNonZeroAda - ) where - -import Cardano.Wallet.Spec.Data.AdaBalance - ( zeroAdaBalance - ) -import Cardano.Wallet.Spec.Data.Network.Info - ( NetworkInfo (..) - ) -import Cardano.Wallet.Spec.Data.Network.NodeStatus - ( NodeStatus (..) - ) -import Cardano.Wallet.Spec.Data.Wallet - ( Wallet (..) - , walletId - ) -import Cardano.Wallet.Spec.Effect.Assert - ( FxAssert - , assert - , assertEq - , assertGt - ) -import Cardano.Wallet.Spec.Effect.Faucet - ( FxFaucet - , useFaucetMnemonic - ) -import Cardano.Wallet.Spec.Effect.Query - ( FxQuery - , createWalletFromMnemonic - , deleteWallet - , getWallet - , listKnownWallets - , queryNetworkInfo - ) -import Cardano.Wallet.Spec.Effect.Random - ( FxRandom - , randomMnemonic - , randomWalletName - ) -import Cardano.Wallet.Spec.Effect.Timeout - ( FxTimeout - , within - ) -import Cardano.Wallet.Spec.Stories.Language - ( FxStory - ) -import Data.Set - ( member - , notMember - ) -import Data.Time.TimeSpan - ( minutes - ) - -testEnvironmentIsReady :: FxStory fxs '[FxQuery, FxRandom, FxAssert] () -testEnvironmentIsReady = do - NetworkInfo{nodeStatus} <- queryNetworkInfo - assertEq "the Cardano Node is running and synced" nodeStatus NodeIsSynced - -createdWalletListed :: FxStory fxs '[FxQuery, FxRandom, FxTimeout, FxAssert] () -createdWalletListed = do - wallet <- createFreshWallet - wallets <- listKnownWallets - assert "the new wallet is known" (wallet `member` wallets) - within (minutes 2.0) do deleteWallet wallet - wallets' <- listKnownWallets - assert "the wallet is forgotten" (wallet `notMember` wallets') - -createdWalletRetrievable :: FxStory fxs '[FxQuery, FxRandom, FxAssert] () -createdWalletRetrievable = do - createdWallet <- createFreshWallet - retrievedWallet <- getWallet (walletId createdWallet) - assertEq "same wallet retrieved by id" createdWallet retrievedWallet - -createdWalletHasZeroAda :: FxStory fxs '[FxQuery, FxRandom, FxAssert] () -createdWalletHasZeroAda = do - wallet <- createFreshWallet - assertEq - "freshly created wallet has 0 ADA balance" - (walletBalance wallet) - zeroAdaBalance - -faucetWalletHasNonZeroAda - :: FxStory fxs '[FxQuery, FxRandom, FxFaucet, FxAssert] () -faucetWalletHasNonZeroAda = do - wallet <- createFaucetWallet - assertGt - "faucet wallet has non-zero ADA balance" - (walletBalance wallet) - zeroAdaBalance - --------------------------------------------------------------------------------- --- Re-usable sequences of actions ---------------------------------------------- - -createFreshWallet :: FxStory fxs '[FxQuery, FxRandom] Wallet -createFreshWallet = do - name <- randomWalletName "Test Wallet" - mnemonic <- randomMnemonic - createWalletFromMnemonic name mnemonic - -createFaucetWallet :: FxStory fxs '[FxQuery, FxRandom, FxFaucet] Wallet -createFaucetWallet = do - name <- randomWalletName "Faucet Wallet" - mnemonic <- useFaucetMnemonic - createWalletFromMnemonic name mnemonic diff --git a/lib/wallet-e2e/src/Cardano/Wallet/Spec/TimeoutSpec.hs b/lib/wallet-e2e/src/Cardano/Wallet/Spec/TimeoutSpec.hs deleted file mode 100644 index b8a737b6969..00000000000 --- a/lib/wallet-e2e/src/Cardano/Wallet/Spec/TimeoutSpec.hs +++ /dev/null @@ -1,82 +0,0 @@ -module Cardano.Wallet.Spec.TimeoutSpec - ( timeoutSpec - ) where - -import Cardano.Wallet.Spec.Effect.Assert - ( FxAssert - , runAssertFailsFast - ) -import Cardano.Wallet.Spec.Effect.Timeout - ( FxTimeout - , runTimeout - , within - ) -import Cardano.Wallet.Spec.Effect.Trace - ( FxTrace - , runTracePure - ) -import Cardano.Wallet.Spec.Stories.Language - ( FxStory - ) -import Control.Concurrent - ( threadDelay - ) -import Data.Time.TimeSpan - ( milliseconds - , seconds - , toMicroseconds - ) -import Effectful - ( Eff - , IOE - , runEff - ) -import Effectful.Fail - ( Fail - , runFail - ) -import Prelude hiding - ( State - , evalState - , get - , modify - ) -import Test.Syd - ( Spec - , describe - , expectationFailure - , it - ) - --- | This story will not timeout as it takes less than 1 second. -noTimeout :: FxStory fxs '[FxTimeout, IOE] () -noTimeout = within (seconds 1) do - liftIO . threadDelay . round - $ toMicroseconds (seconds 1) - toMicroseconds (milliseconds 100) - --- | This story will timeout as it takes longer than 1 second. -timeoutIn10Milliseconds :: FxStory fxs '[FxTimeout, IOE] () -timeoutIn10Milliseconds = within (seconds 1) do - liftIO $ threadDelay 1010000 - -type Story a = Eff [FxTimeout, FxAssert, FxTrace, Fail, IOE] a - -run :: Story a -> IO (Either String (a, Seq Text)) -run = - runTimeout - >>> runAssertFailsFast - >>> runTracePure - >>> runFail - >>> runEff - -timeoutSpec :: Spec -timeoutSpec = describe "Timeouts" do - it "no timeout" do - r <- run noTimeout - case r of - Left _ -> expectationFailure "should not timeout" - Right _ -> pass - it "timeout in 10 milliseconds" do - run timeoutIn10Milliseconds >>= \case - Left _ -> pass - Right _ -> expectationFailure "should timeout" diff --git a/lib/wallet-e2e/test-output/.gitignore b/lib/wallet-e2e/test-output/.gitignore deleted file mode 100644 index 5e7d2734cfc..00000000000 --- a/lib/wallet-e2e/test-output/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/lib/wallet-e2e/test-state/local/.gitignore b/lib/wallet-e2e/test-state/local/.gitignore deleted file mode 100644 index 5e7d2734cfc..00000000000 --- a/lib/wallet-e2e/test-state/local/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/lib/wallet-e2e/test-state/preprod/.gitignore b/lib/wallet-e2e/test-state/preprod/.gitignore deleted file mode 100644 index 5e7d2734cfc..00000000000 --- a/lib/wallet-e2e/test-state/preprod/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/scripts/buildkite/main/windows-e2e.bat b/scripts/buildkite/main/windows-e2e.bat index d3c096eaae7..7fa06c1d6ae 100755 --- a/scripts/buildkite/main/windows-e2e.bat +++ b/scripts/buildkite/main/windows-e2e.bat @@ -24,21 +24,11 @@ ls %NODE_DB_DIR% REM ------------- ruby tests ------------- cd test\e2e - -echo "Running Ruby tests" -echo "Setting up preprod environment" -rm -rf state\configs\preprod - call bundle install +call bundle exec rake get_latest_windows_tests[%BUILDKITE_BRANCH%,bins,any,latest] +cd ..\.. -call bundle exec rake setup[preprod,%BUILDKITE_BRANCH%] -echo "Displaying versions" -call bundle exec rake display_versions -echo "Starting node and wallet" -call bundle exec rake start_node_and_wallet[preprod] -echo "Waiting for node to sync" -call bundle exec rake wait_until_node_synced -echo "Running tests" -call bundle exec rake spec SPEC_OPTS="-e 'Stake Pools'" -echo "Stopping node and wallet" -call bundle exec rake stop_node_and_wallet[preprod] +echo %NODE_DB_DIR% +echo %WALLET_DB_DIR% +test\e2e\bins\cardano-wallet-integration-test-e2e.exe +exit /b %ERRORLEVEL% diff --git a/scripts/cabal-lib.sh b/scripts/cabal-lib.sh index 3023b9bffba..9e2976b3737 100644 --- a/scripts/cabal-lib.sh +++ b/scripts/cabal-lib.sh @@ -27,7 +27,7 @@ list_sources() { # to be serialised for use in the tests. They are not intended to be built # with the project. # Exclude prototypes dir because it's a different project. - git ls-files 'lib/**/*.hs' | grep -v Main.hs | grep -v prototypes/ | grep -v lib/wallet/extra | grep -v lib/wallet-e2e + git ls-files 'lib/**/*.hs' | grep -v Main.hs | grep -v prototypes/ | grep -v lib/wallet/extra } # usage: query_plan_json PACKAGE COMP:NAME KEY