diff --git a/sydtest-test/default.nix b/sydtest-test/default.nix index 224bb84..eb41d0c 100644 --- a/sydtest-test/default.nix +++ b/sydtest-test/default.nix @@ -1,6 +1,7 @@ -{ mkDerivation, base, bytestring, fast-myers-diff, lib +{ mkDerivation, async, base, bytestring, fast-myers-diff, lib , opt-env-conf-test, path, path-io, QuickCheck, random -, safe-coloured-text, stm, sydtest, sydtest-discover, text, vector +, safe-coloured-text, stm, sydtest, sydtest-discover, text, time +, vector }: mkDerivation { pname = "sydtest-test"; @@ -8,8 +9,9 @@ mkDerivation { src = ./.; libraryHaskellDepends = [ base ]; testHaskellDepends = [ - base bytestring fast-myers-diff opt-env-conf-test path path-io - QuickCheck random safe-coloured-text stm sydtest text vector + async base bytestring fast-myers-diff opt-env-conf-test path + path-io QuickCheck random safe-coloured-text stm sydtest text time + vector ]; testToolDepends = [ sydtest-discover ]; doHaddock = false; diff --git a/sydtest-test/package.yaml b/sydtest-test/package.yaml index 467fc4e..8b46bdf 100644 --- a/sydtest-test/package.yaml +++ b/sydtest-test/package.yaml @@ -36,6 +36,8 @@ tests: - sydtest >=0.17 - text - vector + - time + - async sydtest-output-test: main: Main.hs diff --git a/sydtest-test/sydtest-test.cabal b/sydtest-test/sydtest-test.cabal index 1527dfb..2d8df90 100644 --- a/sydtest-test/sydtest-test.cabal +++ b/sydtest-test/sydtest-test.cabal @@ -88,6 +88,7 @@ test-suite sydtest-test Test.Syd.AroundSpec Test.Syd.DescriptionsSpec Test.Syd.DiffSpec + Test.Syd.ExceptionSpec Test.Syd.ExpectationSpec Test.Syd.FootgunSpec Test.Syd.GoldenSpec @@ -107,6 +108,7 @@ test-suite sydtest-test sydtest-discover:sydtest-discover build-depends: QuickCheck + , async , base >=4.7 && <5 , bytestring , fast-myers-diff @@ -117,5 +119,6 @@ test-suite sydtest-test , stm , sydtest >=0.17 , text + , time , vector default-language: Haskell2010 diff --git a/sydtest-test/test/Test/Syd/ExceptionSpec.hs b/sydtest-test/test/Test/Syd/ExceptionSpec.hs new file mode 100644 index 0000000..c282cfd --- /dev/null +++ b/sydtest-test/test/Test/Syd/ExceptionSpec.hs @@ -0,0 +1,37 @@ +{-# LANGUAGE NumericUnderscores #-} + +module Test.Syd.ExceptionSpec where + +import Control.Concurrent (threadDelay) +import Control.Concurrent.Async +import Data.Time.Clock +import Test.Syd + +spec :: TestDefM outers () () +spec = describe "exception handling" $ do + it "stops immediatly with async" $ do + -- Tests that when an async exception is sent to sydTest (for example, + -- ctrl-c), it behaves as expected and terminates immediately and does not + -- do anything surprising. + startTime <- liftIO getCurrentTime + + -- Runs two threads, one will be done in 1s, and the other is a test suite + -- with one test which should run for 10s. + -- When the first threads terminate, it will throw AsyncCancel in the + -- sydTest test suite, which should terminate asap. + -- This will be checked using the timer t. That's fragile, but we know that: + -- + -- t should be more than 100ms (because of the first threadDelay) + -- t should be no much more than 100ms. Especially, it should not be 10s + -- (waiting for the complete threadDelay in the test suite) or even more if + -- the exception is completly ignored (or test is retried) + _ <- race (threadDelay 100_000) $ do + sydTest $ do + it "is a dumb slow test" $ do + threadDelay 10_000_000 + + endTime <- liftIO getCurrentTime + + -- Less than 1 second + (endTime `diffUTCTime` startTime) `shouldSatisfy` (< 1) + pure () diff --git a/sydtest/CHANGELOG.md b/sydtest/CHANGELOG.md index a07d558..e7917f3 100644 --- a/sydtest/CHANGELOG.md +++ b/sydtest/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.17.0.2] - 2024-09-26 + +### Changed + +- Sydtest won't crash anymore, behave weirdly, or leak resources when executed + in a REPL and interrupted by C-c. + ## [0.17.0.1] - 2024-09-26 ### Changed diff --git a/sydtest/default.nix b/sydtest/default.nix index cc97ad4..d7f0d03 100644 --- a/sydtest/default.nix +++ b/sydtest/default.nix @@ -6,7 +6,7 @@ }: mkDerivation { pname = "sydtest"; - version = "0.17.0.1"; + version = "0.17.0.2"; src = ./.; libraryHaskellDepends = [ async autodocodec base bytestring containers dlist fast-myers-diff diff --git a/sydtest/package.yaml b/sydtest/package.yaml index 46f52da..22be904 100644 --- a/sydtest/package.yaml +++ b/sydtest/package.yaml @@ -1,5 +1,5 @@ name: sydtest -version: 0.17.0.1 +version: 0.17.0.2 github: "NorfairKing/sydtest" license: OtherLicense license-file: LICENSE.md diff --git a/sydtest/src/Test/Syd/Run.hs b/sydtest/src/Test/Syd/Run.hs index ad86c68..5fd23c6 100644 --- a/sydtest/src/Test/Syd/Run.hs +++ b/sydtest/src/Test/Syd/Run.hs @@ -374,8 +374,13 @@ runGoldenTestWithArg createGolden TestRunSettings {..} _ wrapper = do exceptionHandlers :: [Handler (Either SomeException a)] exceptionHandlers = - [ -- Re-throw AsyncException, otherwise execution will not terminate on SIGINT (ctrl-c). - Handler (\e -> throwIO (e :: AsyncException)), + [ -- Re-throw SomeAsyncException, otherwise execution will not terminate on SIGINT (ctrl-c). + -- This is also critical for correctness, because library such as async + -- uses this signal for `concurrently`, and `race`, ..., and if we ignore + -- this exception, we can end in a context where half of the logic has + -- stopped and yet we continue. + -- See https://github.com/NorfairKing/sydtest/issues/80 + Handler (\e -> throwIO (e :: SomeAsyncException)), -- Catch all the rest Handler (\e -> return $ Left (e :: SomeException)) ] diff --git a/sydtest/sydtest.cabal b/sydtest/sydtest.cabal index 03e332a..1d001a1 100644 --- a/sydtest/sydtest.cabal +++ b/sydtest/sydtest.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: sydtest -version: 0.17.0.1 +version: 0.17.0.2 synopsis: A modern testing framework for Haskell with good defaults and advanced testing features. description: A modern testing framework for Haskell with good defaults and advanced testing features. Sydtest aims to make the common easy and the hard possible. See https://github.com/NorfairKing/sydtest#readme for more information. category: Testing