Skip to content

Commit eb5a227

Browse files
committed
Refactor common steps into buildAndTest hook.
1 parent 3fbddb4 commit eb5a227

File tree

1 file changed

+141
-136
lines changed

1 file changed

+141
-136
lines changed

rules_haskell_tests/tests/RunTests.hs

Lines changed: 141 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import Control.Exception.Safe (bracket_)
77
import Data.Foldable (for_)
88
import Data.List (isInfixOf, sort)
9+
import GHC.Stack (HasCallStack)
910
import System.Directory (copyFile)
1011
import System.FilePath ((</>))
1112
import System.Info (os)
@@ -14,7 +15,7 @@ import System.Environment (lookupEnv)
1415
import System.Exit (ExitCode(..))
1516

1617
import qualified System.Process as Process
17-
import Test.Hspec.Core.Spec (SpecM)
18+
import Test.Hspec.Core.Spec (SpecM, SpecWith)
1819
import Test.Hspec (context, hspec, it, describe, runIO, around_, afterAll_)
1920

2021
import BinModule (b)
@@ -23,139 +24,134 @@ import GenModule (a)
2324
import IntegrationTesting
2425

2526
main :: IO ()
26-
main = hspec $ afterAll_ shutdownBazel $ around_ printMemoryHook $ do
27-
it "bazel test" $ do
28-
assertSuccess (bazel ["test", "//..."])
29-
30-
it "bazel test prof" $ do
31-
ghcVersion <- lookupEnv "GHC_VERSION"
32-
33-
-- In .github/workflows/workflow.yaml we specify --test_tag_filters
34-
-- -dont_test_on_darwin. However, specifiying --test_tag_filters
35-
-- -requires_dynamic here alone would override that filter. So,
36-
-- we have to duplicate that filter here.
37-
let tagFilter | os == "darwin" = "-dont_test_on_darwin,-requires_dynamic,-skip_profiling" ++ (
38-
-- skip tests for specific GHC version, see https://github.com/tweag/rules_haskell/issues/2073
39-
maybe "" (",-dont_build_on_macos_with_ghc_" ++) ghcVersion)
40-
| otherwise = "-requires_dynamic,-skip_profiling"
41-
assertSuccess (bazel ["test", "-c", "dbg", "//...", "--build_tag_filters", tagFilter, "--test_tag_filters", tagFilter])
42-
43-
it "bazel build worker" $ do
44-
assertSuccess (bazel ["build", "@rules_haskell//tools/worker:bin"])
45-
46-
describe "stack_snapshot pinning" $
47-
it "handles packages in subdirectories correctly" $ do
48-
-- NOTE Keep in sync with
49-
-- .github/workflows/workflow.yaml
50-
let withBackup filename k =
51-
withSystemTempDirectory "bazel_backup" $ \tmp_dir -> do
52-
bracket_
53-
(copyFile filename (tmp_dir </> "backup"))
54-
(copyFile (tmp_dir </> "backup") filename)
55-
k
56-
-- Test that pinning works and produces buildable targets.
57-
-- Backup the lock file to avoid unintended changes when run locally.
58-
withBackup "stackage-pinning-test_snapshot.json" $ do
59-
assertSuccess (bazel ["run", "@stackage-pinning-test-unpinned//:pin"])
60-
assertSuccess (bazel ["build", "@stackage-pinning-test//:hspec"])
61-
62-
describe "repl" $ do
63-
it "for libraries" $ do
64-
assertSuccess (bazel ["run", "//tests/repl-targets:hs-lib-bad@repl", "--", "-ignore-dot-ghci", "-e", "1 + 2"])
65-
66-
it "for binaries" $ do
67-
assertSuccess (bazel ["run", "//tests/binary-indirect-cbits:binary-indirect-cbits@repl", "--", "-ignore-dot-ghci", "-e", ":main"])
68-
69-
assertSuccess (bazel ["run", "//tests/repl-targets:hs-test-bad@repl", "--", "-ignore-dot-ghci", "-e", "1 + 2"])
70-
71-
it "with rebindable syntax" $ do
72-
let p' (stdout, _stderr) = lines stdout == ["True"]
73-
outputSatisfy p' (bazel ["run", "//tests/repl-targets:rebindable-syntax@repl", "--", "-ignore-dot-ghci", "-e", "check"])
74-
75-
it "sets classpath" $ do
76-
assertSuccess (bazel ["run", "//tests/java_classpath:java_classpath@repl", "--", "-ignore-dot-ghci", "-e", ":main"])
77-
78-
-- Test `compiler_flags` from toolchain and rule for REPL
79-
it "compiler flags" $ do
80-
assertSuccess (bazel ["run", "//tests/repl-flags:compiler_flags@repl", "--", "-ignore-dot-ghci", "-e", ":main"])
81-
82-
-- Test make variable expansion in `compiler_flags` and `repl_ghci_args`.
83-
describe "make variables" $ do
27+
main = hspec $ around_ printMemoryHook $ do
28+
29+
describe "rules_haskell_tests" $ afterAll_ (shutdownBazel ".") $ do
30+
it "bazel test" $ do
31+
assertSuccess (bazel ["test", "//..."])
32+
33+
it "bazel test prof" $ do
34+
ghcVersion <- lookupEnv "GHC_VERSION"
35+
36+
-- In .github/workflows/workflow.yaml we specify --test_tag_filters
37+
-- -dont_test_on_darwin. However, specifiying --test_tag_filters
38+
-- -requires_dynamic here alone would override that filter. So,
39+
-- we have to duplicate that filter here.
40+
let tagFilter | os == "darwin" = "-dont_test_on_darwin,-requires_dynamic,-skip_profiling" ++ (
41+
-- skip tests for specific GHC version, see https://github.com/tweag/rules_haskell/issues/2073
42+
maybe "" (",-dont_build_on_macos_with_ghc_" ++) ghcVersion)
43+
| otherwise = "-requires_dynamic,-skip_profiling"
44+
assertSuccess (bazel ["test", "-c", "dbg", "//...", "--build_tag_filters", tagFilter, "--test_tag_filters", tagFilter])
45+
46+
it "bazel build worker" $ do
47+
assertSuccess (bazel ["build", "@rules_haskell//tools/worker:bin"])
48+
49+
describe "stack_snapshot pinning" $
50+
it "handles packages in subdirectories correctly" $ do
51+
-- NOTE Keep in sync with
52+
-- .github/workflows/workflow.yaml
53+
let withBackup filename k =
54+
withSystemTempDirectory "bazel_backup" $ \tmp_dir -> do
55+
bracket_
56+
(copyFile filename (tmp_dir </> "backup"))
57+
(copyFile (tmp_dir </> "backup") filename)
58+
k
59+
-- Test that pinning works and produces buildable targets.
60+
-- Backup the lock file to avoid unintended changes when run locally.
61+
withBackup "stackage-pinning-test_snapshot.json" $ do
62+
assertSuccess (bazel ["run", "@stackage-pinning-test-unpinned//:pin"])
63+
assertSuccess (bazel ["build", "@stackage-pinning-test//:hspec"])
64+
65+
describe "repl" $ do
66+
it "for libraries" $ do
67+
assertSuccess (bazel ["run", "//tests/repl-targets:hs-lib-bad@repl", "--", "-ignore-dot-ghci", "-e", "1 + 2"])
68+
69+
it "for binaries" $ do
70+
assertSuccess (bazel ["run", "//tests/binary-indirect-cbits:binary-indirect-cbits@repl", "--", "-ignore-dot-ghci", "-e", ":main"])
71+
72+
assertSuccess (bazel ["run", "//tests/repl-targets:hs-test-bad@repl", "--", "-ignore-dot-ghci", "-e", "1 + 2"])
73+
74+
it "with rebindable syntax" $ do
75+
let p' (stdout, _stderr) = lines stdout == ["True"]
76+
outputSatisfy p' (bazel ["run", "//tests/repl-targets:rebindable-syntax@repl", "--", "-ignore-dot-ghci", "-e", "check"])
77+
78+
it "sets classpath" $ do
79+
assertSuccess (bazel ["run", "//tests/java_classpath:java_classpath@repl", "--", "-ignore-dot-ghci", "-e", ":main"])
80+
81+
-- Test `compiler_flags` from toolchain and rule for REPL
8482
it "compiler flags" $ do
85-
assertSuccess (bazel ["run", "//tests/repl-make-variables:test-compiler-flags@repl", "--", "-ignore-dot-ghci", "-e", ":main"])
86-
it "indirect repl flags" $ do
87-
assertSuccess (bazel ["run", "//tests/repl-make-variables:repl-indirect-flags", "--", "-ignore-dot-ghci", "-e", ":main"])
88-
it "direct repl flags" $ do
89-
assertSuccess (bazel ["run", "//tests/repl-make-variables:repl-direct-flags", "--", "-ignore-dot-ghci", "-e", ":main"])
90-
91-
-- Test `repl_ghci_args` from toolchain and rule for REPL
92-
it "repl flags" $ do
93-
assertSuccess (bazel ["run", "//tests/repl-flags:repl_flags@repl", "--", "-ignore-dot-ghci", "-e", "foo"])
94-
95-
it "fails on multiple definitions" $ do
96-
assertSuccess (bazel ["run", "//tests/repl-multiple-definition:repl", "--", "-ignore-dot-ghci", "-e", "final"])
97-
98-
describe "multi_repl" $ do
99-
it "loads transitive library dependencies" $ do
100-
let p' (stdout, _stderr) = lines stdout == ["tests/multi_repl/bc/src/BC/C.hs"]
101-
outputSatisfy p' (bazel ["run", "//tests/multi_repl:c_only_repl", "--", "-ignore-dot-ghci", "-e", ":show targets"])
102-
it "loads transitive source dependencies" $ do
103-
let p' (stdout, _stderr) = sort (lines stdout) == ["tests/multi_repl/a/src/A/A.hs","tests/multi_repl/bc/src/BC/B.hs","tests/multi_repl/bc/src/BC/C.hs"]
104-
outputSatisfy p' (bazel ["run", "//tests/multi_repl:c_multi_repl", "--", "-ignore-dot-ghci", "-e", ":show targets"])
105-
it "loads core library dependencies" $ do
106-
let p' (stdout, _stderr) = sort (lines stdout) == ["tests/multi_repl/core_package_dep/Lib.hs"]
107-
outputSatisfy p' (bazel ["run", "//tests/multi_repl:core_package_dep", "--", "-ignore-dot-ghci", "-e", ":show targets"])
108-
it "doesn't allow to manually load modules" $ do
109-
assertFailure (bazel ["run", "//tests/multi_repl:c_multi_repl", "--", "-ignore-dot-ghci", "-e", ":load BC.C", "-e", "c"])
110-
111-
describe "ghcide" $ do
112-
it "loads RunTests.hs" $
113-
assertSuccess (Process.proc "./.ghcide" ["tests/RunTests.hs"])
114-
it "loads module with module dependency" $
115-
assertSuccess (Process.proc "./.ghcide" ["tests/binary-with-lib/Main.hs"])
116-
117-
describe "failures" $ do
118-
-- Make sure not to include haskell_repl (@repl) or alias (-repl) targets
119-
-- in the query. Those would not fail under bazel test.
120-
all_failure_tests <- bazelQuery "kind('haskell_library|haskell_binary|haskell_test', //tests/failures/...) intersect attr('tags', 'manual', //tests/failures/...)"
121-
122-
for_ all_failure_tests $ \test -> do
123-
it test $ do
124-
assertFailure (bazel ["build", test])
125-
126-
context "known issues" $ do
127-
it "haskell_doc fails with plugins #1549" $
128-
-- https://github.com/tweag/rules_haskell/issues/1549
129-
assertFailure (bazel ["build", "//tests/haddock-with-plugin"])
130-
it "transitive re-exports do not work #1145" $
131-
-- https://github.com/tweag/rules_haskell/issues/1145
132-
assertFailure (bazel ["build", "//tests/package-reexport-transitive"])
133-
it "doctest failure with foreign import #1559" $
134-
-- https://github.com/tweag/rules_haskell/issues/1559
135-
assertFailure (bazel ["build", "//tests/haskell_doctest_ffi_1559:doctest-a"])
136-
137-
-- Test that the repl still works if we shadow some Prelude functions
138-
it "repl name shadowing" $ do
139-
let p (stdout, stderr) = not $ any ("error" `isInfixOf`) [stdout, stderr]
140-
outputSatisfy p (bazel ["run", "//tests/repl-name-conflicts:lib@repl", "--", "-ignore-dot-ghci", "-e", "stdin"])
141-
142-
it "Repl works with remote_download_toplevel" $ do
143-
let p (stdout, stderr) = not $ any ("error" `isInfixOf`) [stdout, stderr]
144-
withSystemTempDirectory "bazel_disk_cache" $ \tmp_disk_cache -> do
145-
assertSuccess $ bazel ["run", "//tests/multi_repl:c_only_repl", "--disk_cache=" <> tmp_disk_cache]
146-
assertSuccess $ bazel ["clean"]
147-
outputSatisfy p
148-
(bazel ["run", "//tests/multi_repl:c_only_repl", "--disk_cache=" <> tmp_disk_cache, "--remote_download_toplevel"])
149-
150-
it "bazel test examples" $ do
151-
assertSuccess $ (bazel ["build", "//..."]) { Process.cwd = Just "../examples" }
152-
assertSuccess $ (bazel ["test", "//..."]) { Process.cwd = Just "../examples" }
153-
assertSuccess $ (bazel ["shutdown"]) { Process.cwd = Just "../examples" }
154-
155-
it "bazel test tutorial" $ do
156-
assertSuccess $ (bazel ["build", "//..."]) { Process.cwd = Just "../tutorial" }
157-
assertSuccess (bazel ["test", "//..."]) { Process.cwd = Just "../tutorial" }
158-
assertSuccess (bazel ["shutdown"]) { Process.cwd = Just "../tutorial" }
83+
assertSuccess (bazel ["run", "//tests/repl-flags:compiler_flags@repl", "--", "-ignore-dot-ghci", "-e", ":main"])
84+
85+
-- Test make variable expansion in `compiler_flags` and `repl_ghci_args`.
86+
describe "make variables" $ do
87+
it "compiler flags" $ do
88+
assertSuccess (bazel ["run", "//tests/repl-make-variables:test-compiler-flags@repl", "--", "-ignore-dot-ghci", "-e", ":main"])
89+
it "indirect repl flags" $ do
90+
assertSuccess (bazel ["run", "//tests/repl-make-variables:repl-indirect-flags", "--", "-ignore-dot-ghci", "-e", ":main"])
91+
it "direct repl flags" $ do
92+
assertSuccess (bazel ["run", "//tests/repl-make-variables:repl-direct-flags", "--", "-ignore-dot-ghci", "-e", ":main"])
93+
94+
-- Test `repl_ghci_args` from toolchain and rule for REPL
95+
it "repl flags" $ do
96+
assertSuccess (bazel ["run", "//tests/repl-flags:repl_flags@repl", "--", "-ignore-dot-ghci", "-e", "foo"])
97+
98+
it "fails on multiple definitions" $ do
99+
assertSuccess (bazel ["run", "//tests/repl-multiple-definition:repl", "--", "-ignore-dot-ghci", "-e", "final"])
100+
101+
describe "multi_repl" $ do
102+
it "loads transitive library dependencies" $ do
103+
let p' (stdout, _stderr) = lines stdout == ["tests/multi_repl/bc/src/BC/C.hs"]
104+
outputSatisfy p' (bazel ["run", "//tests/multi_repl:c_only_repl", "--", "-ignore-dot-ghci", "-e", ":show targets"])
105+
it "loads transitive source dependencies" $ do
106+
let p' (stdout, _stderr) = sort (lines stdout) == ["tests/multi_repl/a/src/A/A.hs","tests/multi_repl/bc/src/BC/B.hs","tests/multi_repl/bc/src/BC/C.hs"]
107+
outputSatisfy p' (bazel ["run", "//tests/multi_repl:c_multi_repl", "--", "-ignore-dot-ghci", "-e", ":show targets"])
108+
it "loads core library dependencies" $ do
109+
let p' (stdout, _stderr) = sort (lines stdout) == ["tests/multi_repl/core_package_dep/Lib.hs"]
110+
outputSatisfy p' (bazel ["run", "//tests/multi_repl:core_package_dep", "--", "-ignore-dot-ghci", "-e", ":show targets"])
111+
it "doesn't allow to manually load modules" $ do
112+
assertFailure (bazel ["run", "//tests/multi_repl:c_multi_repl", "--", "-ignore-dot-ghci", "-e", ":load BC.C", "-e", "c"])
113+
114+
describe "ghcide" $ do
115+
it "loads RunTests.hs" $
116+
assertSuccess (Process.proc "./.ghcide" ["tests/RunTests.hs"])
117+
it "loads module with module dependency" $
118+
assertSuccess (Process.proc "./.ghcide" ["tests/binary-with-lib/Main.hs"])
119+
120+
describe "failures" $ do
121+
-- Make sure not to include haskell_repl (@repl) or alias (-repl) targets
122+
-- in the query. Those would not fail under bazel test.
123+
all_failure_tests <- bazelQuery "kind('haskell_library|haskell_binary|haskell_test', //tests/failures/...) intersect attr('tags', 'manual', //tests/failures/...)"
124+
125+
for_ all_failure_tests $ \test -> do
126+
it test $ do
127+
assertFailure (bazel ["build", test])
128+
129+
context "known issues" $ do
130+
it "haskell_doc fails with plugins #1549" $
131+
-- https://github.com/tweag/rules_haskell/issues/1549
132+
assertFailure (bazel ["build", "//tests/haddock-with-plugin"])
133+
it "transitive re-exports do not work #1145" $
134+
-- https://github.com/tweag/rules_haskell/issues/1145
135+
assertFailure (bazel ["build", "//tests/package-reexport-transitive"])
136+
it "doctest failure with foreign import #1559" $
137+
-- https://github.com/tweag/rules_haskell/issues/1559
138+
assertFailure (bazel ["build", "//tests/haskell_doctest_ffi_1559:doctest-a"])
139+
140+
-- Test that the repl still works if we shadow some Prelude functions
141+
it "repl name shadowing" $ do
142+
let p (stdout, stderr) = not $ any ("error" `isInfixOf`) [stdout, stderr]
143+
outputSatisfy p (bazel ["run", "//tests/repl-name-conflicts:lib@repl", "--", "-ignore-dot-ghci", "-e", "stdin"])
144+
145+
it "Repl works with remote_download_toplevel" $ do
146+
let p (stdout, stderr) = not $ any ("error" `isInfixOf`) [stdout, stderr]
147+
withSystemTempDirectory "bazel_disk_cache" $ \tmp_disk_cache -> do
148+
assertSuccess $ bazel ["run", "//tests/multi_repl:c_only_repl", "--disk_cache=" <> tmp_disk_cache]
149+
assertSuccess $ bazel ["clean"]
150+
outputSatisfy p
151+
(bazel ["run", "//tests/multi_repl:c_only_repl", "--disk_cache=" <> tmp_disk_cache, "--remote_download_toplevel"])
152+
153+
buildAndTest "../examples"
154+
buildAndTest "../tutorial"
159155

160156
-- * Bazel commands
161157

@@ -169,14 +165,23 @@ bazelQuery :: String -> SpecM a [String]
169165
bazelQuery q = lines <$> runIO (Process.readProcess "bazel" ["query", q] "")
170166

171167
-- | Shutdown Bazel
172-
shutdownBazel :: IO ()
173-
shutdownBazel = do
168+
shutdownBazel :: String -> IO ()
169+
shutdownBazel path = do
174170
-- Related to https://github.com/tweag/rules_haskell/issues/2089
175171
-- We experience intermittent "Exit Code: ExitFailure (-9)" errors. Shutdown
176172
-- Bazel when done executing tests for the workspace.
177-
assertSuccess (bazel ["shutdown"])
173+
assertSuccess (bazel ["shutdown"]) { Process.cwd = Just path }
178174
pure ()
179175

176+
buildAndTest :: HasCallStack => String -> SpecWith ()
177+
buildAndTest path = describe path $ afterAll_ (shutdownBazel path) $ do
178+
it "bazel build" $ do
179+
assertSuccess $ (bazel ["build", "//..."]) { Process.cwd = Just path }
180+
it "bazel test" $ do
181+
assertSuccess $ (bazel ["test", "//..."]) { Process.cwd = Just path }
182+
183+
-- * Print Memory Hooks
184+
180185
-- | Print memory information before and after each test
181186
printMemoryHook :: IO () -> IO ()
182187
printMemoryHook action = bracket_

0 commit comments

Comments
 (0)