diff --git a/lib/core-integration/src/Cardano/Wallet/BenchShared.hs b/lib/core-integration/src/Cardano/Wallet/BenchShared.hs index 94c31fc808d..d2daf2c7ad4 100644 --- a/lib/core-integration/src/Cardano/Wallet/BenchShared.hs +++ b/lib/core-integration/src/Cardano/Wallet/BenchShared.hs @@ -99,8 +99,8 @@ import System.Exit ( ExitCode (..), die ) import System.FilePath ( () ) -import System.IO - ( BufferMode (..), hSetBuffering, stderr, stdout ) +import Test.Utils.Startup + ( withNoBuffering ) import UnliftIO.Concurrent ( threadDelay ) import UnliftIO.Exception @@ -121,12 +121,9 @@ execBenchWithNode -> (Trace IO Text -> cfg -> CardanoNodeConn -> IO ()) -- ^ Action to run -> IO ExitCode -execBenchWithNode networkConfig action = do +execBenchWithNode networkConfig action = withNoBuffering $ do args <- getRestoreBenchArgs - hSetBuffering stdout NoBuffering - hSetBuffering stderr NoBuffering - (_logCfg, tr') <- initBenchmarkLogging "bench-restore" Info let tr = if argQuiet args then nullTracer else tr' installSignalHandlers (return ()) diff --git a/lib/core/test/unit/Cardano/Wallet/Api/Server/TlsSpec.hs b/lib/core/test/unit/Cardano/Wallet/Api/Server/TlsSpec.hs index c55d770058f..8ba29bce4a0 100644 --- a/lib/core/test/unit/Cardano/Wallet/Api/Server/TlsSpec.hs +++ b/lib/core/test/unit/Cardano/Wallet/Api/Server/TlsSpec.hs @@ -78,7 +78,7 @@ import Test.Hspec ( Spec, describe, it, shouldBe, shouldThrow ) import Test.Utils.Paths ( getTestData ) -import Test.Utils.Windows +import Test.Utils.Platform ( pendingOnWine ) import UnliftIO.Async ( async, link ) diff --git a/lib/core/test/unit/Cardano/Wallet/Api/ServerSpec.hs b/lib/core/test/unit/Cardano/Wallet/Api/ServerSpec.hs index 210874ec11a..7456f8c2f87 100644 --- a/lib/core/test/unit/Cardano/Wallet/Api/ServerSpec.hs +++ b/lib/core/test/unit/Cardano/Wallet/Api/ServerSpec.hs @@ -81,7 +81,7 @@ import Test.QuickCheck.Monadic ( PropertyM, assert, monadicIO, monitor, run ) import Test.QuickCheck.Property ( counterexample, property ) -import Test.Utils.Windows +import Test.Utils.Platform ( skipOnWindows ) import UnliftIO.Async ( concurrently_, race_ ) diff --git a/lib/core/test/unit/Cardano/Wallet/DB/MVarSpec.hs b/lib/core/test/unit/Cardano/Wallet/DB/MVarSpec.hs index 744f450419c..440223536b8 100644 --- a/lib/core/test/unit/Cardano/Wallet/DB/MVarSpec.hs +++ b/lib/core/test/unit/Cardano/Wallet/DB/MVarSpec.hs @@ -35,7 +35,7 @@ import Test.Hspec ( Spec, before, describe ) import Test.QuickCheck ( Arbitrary (..) ) -import Test.Utils.Darwin +import Test.Utils.Platform ( pendingOnMacOS ) import qualified Cardano.Wallet.DB.MVar as MVar diff --git a/lib/core/test/unit/Main.hs b/lib/core/test/unit/Main.hs index f39d23bc141..6affcf99941 100644 --- a/lib/core/test/unit/Main.hs +++ b/lib/core/test/unit/Main.hs @@ -1,10 +1,15 @@ module Main where +import Prelude + import Cardano.Startup ( withUtf8Encoding ) -import Prelude -import qualified Spec import Test.Hspec.Runner + ( defaultConfig, hspecWith ) +import Test.Utils.Startup + ( withLineBuffering ) + +import qualified Spec main :: IO () -main = withUtf8Encoding $ hspecWith defaultConfig Spec.spec +main = withLineBuffering $ withUtf8Encoding $ hspecWith defaultConfig Spec.spec diff --git a/lib/core/test/unit/Network/Wai/Middleware/LoggingSpec.hs b/lib/core/test/unit/Network/Wai/Middleware/LoggingSpec.hs index 3702e5b5f79..5084250cd18 100644 --- a/lib/core/test/unit/Network/Wai/Middleware/LoggingSpec.hs +++ b/lib/core/test/unit/Network/Wai/Middleware/LoggingSpec.hs @@ -96,7 +96,7 @@ import Test.QuickCheck ( Arbitrary (..), choose, counterexample, property, withMaxSuccess ) import Test.QuickCheck.Monadic ( assert, monadicIO, monitor ) -import Test.Utils.Darwin +import Test.Utils.Platform ( pendingOnMacOS ) import UnliftIO.Async ( Async, async, cancel, mapConcurrently, replicateConcurrently_ ) diff --git a/lib/launcher/test/unit/Cardano/LauncherSpec.hs b/lib/launcher/test/unit/Cardano/LauncherSpec.hs index 76e06220f70..95e3f98118c 100644 --- a/lib/launcher/test/unit/Cardano/LauncherSpec.hs +++ b/lib/launcher/test/unit/Cardano/LauncherSpec.hs @@ -61,7 +61,7 @@ import Test.Hspec , shouldReturn , shouldSatisfy ) -import Test.Utils.Windows +import Test.Utils.Platform ( isWindows, pendingOnWine, skipOnWindows ) import UnliftIO.Async ( async, race_, waitAnyCancel ) diff --git a/lib/launcher/test/unit/Cardano/StartupSpec.hs b/lib/launcher/test/unit/Cardano/StartupSpec.hs index 2f57434190a..f225eabc318 100644 --- a/lib/launcher/test/unit/Cardano/StartupSpec.hs +++ b/lib/launcher/test/unit/Cardano/StartupSpec.hs @@ -29,10 +29,10 @@ import Test.Hspec.Core.Spec ( ResultStatus (..) ) import Test.Hspec.Expectations ( Expectation, HasCallStack ) +import Test.Utils.Platform + ( nullFileName, pendingOnWindows ) import Test.Utils.Trace ( captureLogging ) -import Test.Utils.Windows - ( nullFileName, pendingOnWindows ) import UnliftIO.Async ( race ) import UnliftIO.Concurrent diff --git a/lib/shelley/test/integration/Main.hs b/lib/shelley/test/integration/Main.hs index efd3d636588..1c89f8b4b8e 100644 --- a/lib/shelley/test/integration/Main.hs +++ b/lib/shelley/test/integration/Main.hs @@ -115,8 +115,6 @@ import System.Environment ( setEnv ) import System.FilePath ( () ) -import System.IO - ( BufferMode (..), hSetBuffering, stderr, stdout ) import Test.Hspec ( hspec ) import Test.Hspec.Core.Spec @@ -134,6 +132,8 @@ import Test.Integration.Framework.Context ( Context (..), PoolGarbageCollectionEvent (..) ) import Test.Utils.Paths ( getTestData, inNixBuild ) +import Test.Utils.Startup + ( withLineBuffering ) import UnliftIO.Async ( race ) import UnliftIO.Exception @@ -223,16 +223,14 @@ withTestsSetup :: (FilePath -> (Tracer IO TestsLog, Tracers IO) -> IO a) -> IO a withTestsSetup action = do -- Handle SIGTERM properly installSignalHandlersNoLogging - -- Flush test output as soon as a line is printed - hSetBuffering stdout LineBuffering - hSetBuffering stderr LineBuffering -- Stop cardano-cli complaining about file permissions setDefaultFilePermissions -- Enables small test-specific workarounds, like timing out faster if wallet -- deletion fails. setEnv "CARDANO_WALLET_TEST_INTEGRATION" "1" - -- Set UTF-8, regardless of user locale - withUtf8Encoding $ + -- Flush test output as soon as a line is printed. + -- Set UTF-8, regardless of user locale. + withLineBuffering $ withUtf8Encoding $ -- This temporary directory will contain logs, and all other data -- produced by the integration tests. withSystemTempDir stdoutTextTracer "test" $ \testDir -> diff --git a/lib/shelley/test/unit/Cardano/Wallet/Shelley/LaunchSpec.hs b/lib/shelley/test/unit/Cardano/Wallet/Shelley/LaunchSpec.hs index 905d858605b..ad4a9fef3b8 100644 --- a/lib/shelley/test/unit/Cardano/Wallet/Shelley/LaunchSpec.hs +++ b/lib/shelley/test/unit/Cardano/Wallet/Shelley/LaunchSpec.hs @@ -13,7 +13,7 @@ import Options.Applicative ( ParserResult (..), defaultPrefs, execParserPure, info ) import Test.Hspec ( Spec, describe, it, shouldSatisfy ) -import Test.Utils.Windows +import Test.Utils.Platform ( isWindows ) spec :: Spec diff --git a/lib/test-utils/cardano-wallet-test-utils.cabal b/lib/test-utils/cardano-wallet-test-utils.cabal index 15afd5b0f9d..fdcc9b64b9d 100644 --- a/lib/test-utils/cardano-wallet-test-utils.cabal +++ b/lib/test-utils/cardano-wallet-test-utils.cabal @@ -57,17 +57,17 @@ library exposed-modules: Test.Hspec.Extra Test.QuickCheck.Extra - Test.Utils.Darwin Test.Utils.FilePath Test.Utils.Laws Test.Utils.Laws.PartialOrd Test.Utils.Paths Test.Utils.Roundtrip Test.Utils.Resource + Test.Utils.Platform + Test.Utils.Startup Test.Utils.StaticServer Test.Utils.Time Test.Utils.Trace - Test.Utils.Windows test-suite unit default-language: diff --git a/lib/test-utils/src/Test/Hspec/Extra.hs b/lib/test-utils/src/Test/Hspec/Extra.hs index 7464eed90f5..399333d2a09 100644 --- a/lib/test-utils/src/Test/Hspec/Extra.hs +++ b/lib/test-utils/src/Test/Hspec/Extra.hs @@ -39,10 +39,10 @@ import Test.Hspec ) import Test.HUnit.Lang ( HUnitFailure (..), assertFailure, formatFailureReason ) +import Test.Utils.Platform + ( isWindows ) import Test.Utils.Resource ( unBracket ) -import Test.Utils.Windows - ( isWindows ) import UnliftIO.Async ( race ) import UnliftIO.Concurrent diff --git a/lib/test-utils/src/Test/Utils/Darwin.hs b/lib/test-utils/src/Test/Utils/Darwin.hs index 1a960d3b7a4..e69de29bb2d 100644 --- a/lib/test-utils/src/Test/Utils/Darwin.hs +++ b/lib/test-utils/src/Test/Utils/Darwin.hs @@ -1,27 +0,0 @@ --- | --- Copyright: © 2018-2021 IOHK --- License: Apache-2.0 --- --- Utility function for making test suites pass on Darwin/macOS. - -module Test.Utils.Darwin - ( pendingOnMacOS - ) where - -import Prelude - -import Control.Monad - ( when ) -import System.Info - ( os ) -import Test.Hspec.Core.Spec - ( pendingWith ) -import Test.Hspec.Expectations - ( Expectation, HasCallStack ) - --- | Mark test pending if running on macOS -pendingOnMacOS :: HasCallStack => String -> Expectation -pendingOnMacOS reason = when isDarwin $ pendingWith reason - -isDarwin :: Bool -isDarwin = os == "darwin" diff --git a/lib/test-utils/src/Test/Utils/FilePath.hs b/lib/test-utils/src/Test/Utils/FilePath.hs index 002f5a05f00..6c983f7ea13 100644 --- a/lib/test-utils/src/Test/Utils/FilePath.hs +++ b/lib/test-utils/src/Test/Utils/FilePath.hs @@ -14,7 +14,7 @@ import System.FilePath.Windows ( makeValid ) import Test.QuickCheck ( Arbitrary (..), elements, listOf1, scale ) -import Test.Utils.Windows +import Test.Utils.Platform ( isWindows ) -- | A file or directory name. The 'Arbitrary' instance will generate values diff --git a/lib/test-utils/src/Test/Utils/Windows.hs b/lib/test-utils/src/Test/Utils/Platform.hs similarity index 74% rename from lib/test-utils/src/Test/Utils/Windows.hs rename to lib/test-utils/src/Test/Utils/Platform.hs index fbdfa0309df..50adeb5a297 100644 --- a/lib/test-utils/src/Test/Utils/Windows.hs +++ b/lib/test-utils/src/Test/Utils/Platform.hs @@ -2,19 +2,26 @@ {-# LANGUAGE ScopedTypeVariables #-} -- | --- Copyright: © 2018-2020 IOHK +-- Copyright: © 2018-2021 IOHK -- License: Apache-2.0 -- --- Utility function for making test suites pass on Windows. +-- Utility function for making test suites pass on difficult platforms. -module Test.Utils.Windows - ( skipOnWindows +module Test.Utils.Platform + ( -- * Skipping tests + skipOnWindows , pendingOnWindows , pendingOnWine + , pendingOnMacOS + + -- * OS detection , whenWindows , isWindows - , nullFileName + , isMacOS , getIsWine + + -- * Cross-platform compatibility + , nullFileName ) where import Prelude @@ -45,11 +52,16 @@ pendingOnWine reason = whenWindows $ do wine <- getIsWine when wine $ pendingWith reason -whenWindows :: IO () -> IO () -whenWindows = when isWindows +-- | Mark test pending if running on macOS +pendingOnMacOS :: HasCallStack => String -> Expectation +pendingOnMacOS reason = when isMacOS $ pendingWith reason -isWindows :: Bool +isWindows, isMacOS :: Bool isWindows = os == "mingw32" +isMacOS = os == "darwin" + +whenWindows :: IO () -> IO () +whenWindows = when isWindows -- | Use the presence of @winepath.exe@ to detect when running tests under Wine. getIsWine :: IO Bool diff --git a/lib/test-utils/src/Test/Utils/Startup.hs b/lib/test-utils/src/Test/Utils/Startup.hs new file mode 100644 index 00000000000..4050f776652 --- /dev/null +++ b/lib/test-utils/src/Test/Utils/Startup.hs @@ -0,0 +1,39 @@ +module Test.Utils.Startup + ( withLineBuffering + , withNoBuffering + ) where + +import Prelude + +import Control.Monad + ( void ) +import Control.Monad.IO.Unlift + ( MonadUnliftIO ) +import UnliftIO.Exception + ( IOException, bracket, tryJust ) +import UnliftIO.IO + ( BufferMode (..), hGetBuffering, hSetBuffering, stderr, stdout ) + +withLineBuffering, withNoBuffering :: MonadUnliftIO m => m a -> m a +withLineBuffering = withBuffering LineBuffering +withNoBuffering = withBuffering NoBuffering + +withBuffering :: MonadUnliftIO m => BufferMode -> m a -> m a +withBuffering mode = bracket before after . const + where + before = do + prev <- (,) <$> getBuf stdout <*> getBuf stderr + setBuf stdout (Just mode) + setBuf stderr (Just mode) + pure prev + after (prevOut, prevErr) = do + setBuf stdout prevOut + setBuf stderr prevErr + + getBuf = tryErr . hGetBuffering + setBuf h = maybe (pure ()) (void . tryErr . hSetBuffering h) + + -- Swallow any IO errors + tryErr = fmap (either (const Nothing) Just) . tryJust isAlright + isAlright :: IOException -> Maybe () + isAlright = const (Just ())