6
6
import Control.Exception.Safe (bracket_ )
7
7
import Data.Foldable (for_ )
8
8
import Data.List (isInfixOf , sort )
9
+ import GHC.Stack (HasCallStack )
9
10
import System.Directory (copyFile )
10
11
import System.FilePath ((</>) )
11
12
import System.Info (os )
@@ -14,7 +15,7 @@ import System.Environment (lookupEnv)
14
15
import System.Exit (ExitCode (.. ))
15
16
16
17
import qualified System.Process as Process
17
- import Test.Hspec.Core.Spec (SpecM )
18
+ import Test.Hspec.Core.Spec (SpecM , SpecWith )
18
19
import Test.Hspec (context , hspec , it , describe , runIO , around_ , afterAll_ )
19
20
20
21
import BinModule (b )
@@ -23,139 +24,134 @@ import GenModule (a)
23
24
import IntegrationTesting
24
25
25
26
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
84
82
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"
159
155
160
156
-- * Bazel commands
161
157
@@ -169,14 +165,23 @@ bazelQuery :: String -> SpecM a [String]
169
165
bazelQuery q = lines <$> runIO (Process. readProcess " bazel" [" query" , q] " " )
170
166
171
167
-- | Shutdown Bazel
172
- shutdownBazel :: IO ()
173
- shutdownBazel = do
168
+ shutdownBazel :: String -> IO ()
169
+ shutdownBazel path = do
174
170
-- Related to https://github.com/tweag/rules_haskell/issues/2089
175
171
-- We experience intermittent "Exit Code: ExitFailure (-9)" errors. Shutdown
176
172
-- Bazel when done executing tests for the workspace.
177
- assertSuccess (bazel [" shutdown" ])
173
+ assertSuccess (bazel [" shutdown" ]) { Process. cwd = Just path }
178
174
pure ()
179
175
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
+
180
185
-- | Print memory information before and after each test
181
186
printMemoryHook :: IO () -> IO ()
182
187
printMemoryHook action = bracket_
0 commit comments