Skip to content

Commit 9c8eccb

Browse files
committed
Run plugins' test suites with server in the same process
1 parent 75e365a commit 9c8eccb

File tree

21 files changed

+167
-261
lines changed

21 files changed

+167
-261
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,27 +133,27 @@ jobs:
133133

134134
- name: Test hls-brittany-plugin
135135
if: ${{ matrix.test }}
136-
run: cabal test hls-brittany-plugin || cabal test hls-brittany-plugin --test-options="-j1"
136+
run: cabal test hls-brittany-plugin --test-options="--rerun-update" || cabal test hls-brittany-plugin --test-options="--rerun"
137137

138138
- name: Test hls-class-plugin
139139
if: ${{ matrix.test }}
140-
run: cabal test hls-class-plugin || cabal test hls-class-plugin --test-options="-j1"
140+
run: cabal test hls-class-plugin --test-options="--rerun-update" || cabal test hls-class-plugin --test-options="--rerun"
141141

142142
- name: Test hls-eval-plugin
143143
if: ${{ matrix.test }}
144-
run: cabal test hls-eval-plugin --test-options="-j1 --rerun" || cabal test hls-eval-plugin --test-options="-j1 --rerun"
144+
run: cabal test hls-eval-plugin --test-options="--rerun-update" || cabal test hls-eval-plugin --test-options="--rerun"
145145

146146
- name: Test hls-haddock-comments-plugin
147147
if: ${{ matrix.test }}
148-
run: cabal test hls-haddock-comments-plugin || cabal test hls-haddock-comments-plugin --test-options="-j1"
148+
run: cabal test hls-haddock-comments-plugin --test-options="--rerun-update" || cabal test hls-haddock-comments-plugin --test-options="--rerun"
149149

150150
- name: Test hls-splice-plugin
151151
if: ${{ matrix.test }}
152-
run: cabal test hls-splice-plugin || cabal test hls-splice-plugin --test-options="-j1"
152+
run: cabal test hls-splice-plugin --test-options="--rerun-update" || cabal test hls-splice-plugin --test-options="--rerun"
153153

154154
- name: Test hls-stylish-haskell-plugin
155155
if: ${{ matrix.test }}
156-
run: cabal test hls-stylish-haskell-plugin || cabal test hls-stylish-haskell-plugin --test-options="-j1"
156+
run: cabal test hls-stylish-haskell-plugin --test-options="--rerun-update" || cabal test hls-stylish-haskell-plugin --test-options="--rerun"
157157

158158
- name: Test hls-tactics-plugin test suite
159159
if: ${{ matrix.test }}

hls-test-utils/hls-test-utils.cabal

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,16 @@ library
4242
, directory
4343
, extra
4444
, filepath
45+
, ghcide ^>=1.1.0.0
46+
, hls-plugin-api ^>=1.1.0.0
4547
, hspec
4648
, hspec-core
4749
, lens
50+
, lsp ==1.1.1.0
4851
, lsp-test ==0.13.0.0
4952
, lsp-types ^>=1.1
53+
, shake
5054
, tasty
51-
, tasty-ant-xml >=1.1.6
5255
, tasty-expected-failure
5356
, tasty-golden
5457
, tasty-hunit

hls-test-utils/src/Test/Hls.hs

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,108 @@ module Test.Hls
99
module Control.Applicative.Combinators,
1010
defaultTestRunner,
1111
goldenGitDiff,
12-
testCommand,
1312
def,
13+
runSessionWithServer,
14+
runSessionWithServerFormatter,
15+
runSessionWithServer',
16+
PluginDescriptor,
17+
IdeState,
1418
)
1519
where
1620

1721
import Control.Applicative.Combinators
22+
import Control.Concurrent (forkIO, killThread)
23+
import Control.Exception.Base
1824
import Control.Monad.IO.Class
19-
import Data.ByteString.Lazy (ByteString)
20-
import Data.Default (def)
25+
import Data.ByteString.Lazy (ByteString)
26+
import Data.Default (def)
27+
import qualified Data.Text as T
28+
import Development.IDE (IdeState, hDuplicateTo',
29+
noLogging)
30+
import Development.IDE.Main
31+
import qualified Development.IDE.Main as Ghcide
32+
import qualified Development.IDE.Plugin.HLS.GhcIde as Ghcide
33+
import Development.IDE.Types.Options
34+
import Development.Shake (ShakeOptions (shakeThreads))
35+
import GHC.IO.Handle
36+
import Ide.Plugin.Config (Config, formattingProvider)
37+
import Ide.PluginUtils (pluginDescToIdePlugins)
38+
import Ide.Types
2139
import Language.LSP.Test
2240
import Language.LSP.Types
41+
import Language.LSP.Types.Capabilities (ClientCapabilities)
42+
import System.Directory (getCurrentDirectory,
43+
setCurrentDirectory)
44+
import System.IO.Extra
45+
import System.Process.Extra (createPipe)
2346
import Test.Hls.Util
24-
import Test.Tasty hiding (Timeout)
47+
import Test.Tasty hiding (Timeout)
2548
import Test.Tasty.ExpectedFailure
2649
import Test.Tasty.Golden
2750
import Test.Tasty.HUnit
2851
import Test.Tasty.Ingredients.Rerun
2952
import Test.Tasty.Runners
30-
import Test.Tasty.Runners.AntXML
3153

32-
-- | ingredient: xml runner writes json file of test results (https://github.com/ocharles/tasty-ant-xml/blob/master/Test/Tasty/Runners/AntXML.hs)
33-
-- rerunningTests allow rerun of failed tests (https://github.com/ocharles/tasty-rerun/blob/master/src/Test/Tasty/Ingredients/Rerun.hs)
54+
-- | Run 'defaultMainWithRerun' with -j1, and silence stderr
3455
defaultTestRunner :: TestTree -> IO ()
35-
defaultTestRunner =
36-
defaultMainWithIngredients
37-
[antXMLRunner, rerunningTests [listingTests, consoleTestReporter]]
56+
defaultTestRunner = muteStderr . defaultMainWithRerun . adjustOption (const $ NumThreads 1)
3857

3958
gitDiff :: FilePath -> FilePath -> [String]
4059
gitDiff fRef fNew = ["git", "diff", "--no-index", "--text", "--exit-code", fRef, fNew]
4160

4261
goldenGitDiff :: TestName -> FilePath -> IO ByteString -> TestTree
4362
goldenGitDiff name = goldenVsStringDiff name gitDiff
4463

45-
testCommand :: String
46-
testCommand = "test-server"
64+
runSessionWithServer :: PluginDescriptor IdeState -> FilePath -> Session a -> IO a
65+
runSessionWithServer plugin = runSessionWithServer' [plugin] def def fullCaps
66+
67+
runSessionWithServerFormatter :: PluginDescriptor IdeState -> String -> FilePath -> Session a -> IO a
68+
runSessionWithServerFormatter plugin formatter =
69+
runSessionWithServer'
70+
[plugin]
71+
def {formattingProvider = T.pack formatter}
72+
def
73+
fullCaps
74+
75+
-- | Silence stderr, running an action
76+
muteStderr :: IO () -> IO ()
77+
muteStderr action = withTempFile $ \tmp ->
78+
bracket (openFile tmp AppendMode) hClose $ \h -> do
79+
old <- hDuplicate stderr
80+
h `hDuplicateTo'` stderr
81+
bracket_ action (hClose old) (old `hDuplicateTo'` stderr)
82+
83+
84+
-- | Host a server, and run a test session on it
85+
-- Note: cwd will be shifted into @root@ in @Session a@
86+
runSessionWithServer' ::
87+
-- | plugins to load on the server
88+
[PluginDescriptor IdeState] ->
89+
-- | lsp config for the server
90+
Config ->
91+
-- | config for the test session
92+
SessionConfig ->
93+
ClientCapabilities ->
94+
FilePath ->
95+
Session a ->
96+
IO a
97+
runSessionWithServer' plugin conf sconf caps root s = do
98+
(inR, inW) <- createPipe
99+
(outR, outW) <- createPipe
100+
-- restore cwd after running the session; otherwise the path to test data will be invalid
101+
cwd <- getCurrentDirectory
102+
threadId <-
103+
forkIO $
104+
Ghcide.defaultMain
105+
def
106+
{ argsHandleIn = pure inR,
107+
argsHandleOut = pure outW,
108+
argsLogger = pure noLogging,
109+
argsDefaultHlsConfig = conf,
110+
argsIdeOptions = \config sessionLoader ->
111+
let ideOptions = (argsIdeOptions def config sessionLoader) {optTesting = IdeTesting True}
112+
in ideOptions {optShakeOptions = (optShakeOptions ideOptions) {shakeThreads = 2}},
113+
argsHlsPlugins = pluginDescToIdePlugins $ plugin ++ Ghcide.descriptors
114+
}
115+
runSessionWithHandles inW outR sconf caps root s
116+
`finally` (killThread threadId >> setCurrentDirectory cwd)

plugins/hls-brittany-plugin/hls-brittany-plugin.cabal

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,9 @@ library
3131

3232
default-language: Haskell2010
3333

34-
executable test-server
35-
default-language: Haskell2010
36-
build-depends:
37-
, base
38-
, data-default
39-
, ghcide
40-
, hls-brittany-plugin
41-
, hls-plugin-api
42-
, shake
43-
main-is: Server.hs
44-
hs-source-dirs: test
45-
ghc-options: -threaded
46-
4734
test-suite tests
4835
type: exitcode-stdio-1.0
4936
default-language: Haskell2010
50-
build-tool-depends:
51-
hls-brittany-plugin:test-server -any,
5237
hs-source-dirs: test
5338
main-is: Main.hs
5439
build-depends:

plugins/hls-brittany-plugin/test/Main.hs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,36 @@
22
module Main(main) where
33

44
import qualified Data.ByteString.Lazy as BS
5-
import qualified Data.Text.Encoding as T
6-
import qualified Data.Text.IO as T
7-
import Test.Hls
5+
import qualified Data.Text.Encoding as T
6+
import qualified Data.Text.IO as T
7+
import qualified Ide.Plugin.Brittany as Brittany
8+
import Test.Hls
89

910
main :: IO ()
1011
main = defaultTestRunner tests
1112

13+
plugin :: PluginDescriptor IdeState
14+
plugin = Brittany.descriptor "brittany"
15+
1216
tests :: TestTree
1317
tests = testGroup "brittany" [
14-
goldenGitDiff "formats a document with LF endings" "test/testdata/BrittanyLF.formatted_document.hs" $ runSession testCommand fullCaps "test/testdata" $ do
18+
goldenGitDiff "formats a document with LF endings" "test/testdata/BrittanyLF.formatted_document.hs" $ runSessionWithServerFormatter plugin "brittany" "test/testdata" $ do
1519
doc <- openDoc "BrittanyLF.hs" "haskell"
1620
formatDoc doc (FormattingOptions 4 True Nothing Nothing Nothing)
1721
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
1822

19-
, goldenGitDiff "formats a document with CRLF endings" "test/testdata/BrittanyCRLF.formatted_document.hs" $ runSession testCommand fullCaps "test/testdata" $ do
23+
, goldenGitDiff "formats a document with CRLF endings" "test/testdata/BrittanyCRLF.formatted_document.hs" $ runSessionWithServerFormatter plugin "brittany" "test/testdata" $ do
2024
doc <- openDoc "BrittanyCRLF.hs" "haskell"
2125
formatDoc doc (FormattingOptions 4 True Nothing Nothing Nothing)
2226
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
2327

24-
, goldenGitDiff "formats a range with LF endings" "test/testdata/BrittanyLF.formatted_range.hs" $ runSession testCommand fullCaps "test/testdata" $ do
28+
, goldenGitDiff "formats a range with LF endings" "test/testdata/BrittanyLF.formatted_range.hs" $ runSessionWithServerFormatter plugin "brittany" "test/testdata" $ do
2529
doc <- openDoc "BrittanyLF.hs" "haskell"
2630
let range = Range (Position 1 0) (Position 2 22)
2731
formatRange doc (FormattingOptions 4 True Nothing Nothing Nothing) range
2832
BS.fromStrict . T.encodeUtf8 <$> documentContents doc
2933

30-
, goldenGitDiff "formats a range with CRLF endings" "test/testdata/BrittanyCRLF.formatted_range.hs" $ runSession testCommand fullCaps "test/testdata" $ do
34+
, goldenGitDiff "formats a range with CRLF endings" "test/testdata/BrittanyCRLF.formatted_range.hs" $ runSessionWithServerFormatter plugin "brittany" "test/testdata" $ do
3135
doc <- openDoc "BrittanyCRLF.hs" "haskell"
3236
let range = Range (Position 1 0) (Position 2 22)
3337
formatRange doc (FormattingOptions 4 True Nothing Nothing Nothing) range

plugins/hls-brittany-plugin/test/Server.hs

Lines changed: 0 additions & 19 deletions
This file was deleted.

plugins/hls-class-plugin/hls-class-plugin.cabal

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,29 +45,16 @@ library
4545

4646
ghc-options: -Wno-unticked-promoted-constructors
4747

48-
executable test-server
48+
test-suite tests
49+
type: exitcode-stdio-1.0
4950
default-language: Haskell2010
50-
build-depends:
51-
, base
52-
, data-default
53-
, ghcide
54-
, hls-class-plugin
55-
, hls-plugin-api
56-
57-
main-is: Server.hs
5851
hs-source-dirs: test
59-
ghc-options: -threaded
60-
61-
test-suite tests
62-
type: exitcode-stdio-1.0
63-
default-language: Haskell2010
64-
build-tool-depends: hls-class-plugin:test-server -any
65-
hs-source-dirs: test
66-
main-is: Main.hs
52+
main-is: Main.hs
6753
build-depends:
6854
, base
6955
, bytestring
7056
, filepath
57+
, hls-class-plugin
7158
, hls-test-utils
7259
, lens
7360
, lsp-test

plugins/hls-class-plugin/test/Main.hs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,22 @@ where
1010
import Control.Lens hiding ((<.>))
1111
import qualified Data.ByteString.Lazy as BS
1212
import qualified Data.Text.Encoding as T
13+
import qualified Ide.Plugin.Class as Class
1314
import qualified Language.LSP.Types.Lens as J
1415
import System.FilePath
1516
import Test.Hls
1617

1718
main :: IO ()
1819
main = defaultTestRunner tests
1920

21+
plugin :: PluginDescriptor IdeState
22+
plugin = Class.descriptor "class"
23+
2024
tests :: TestTree
2125
tests = testGroup
2226
"class"
2327
[ testCase "Produces addMinimalMethodPlaceholders code actions for one instance" $ do
24-
runSession testCommand fullCaps classPath $ do
28+
runSessionWithServer plugin classPath $ do
2529
doc <- openDoc "T1.hs" "haskell"
2630
_ <- waitForDiagnosticsFromSource doc "typecheck"
2731
caResults <- getAllCodeActions doc
@@ -61,7 +65,7 @@ classPath = "test" </> "testdata"
6165
glodenTest :: String -> FilePath -> FilePath -> ([CodeAction] -> Session ()) -> TestTree
6266
glodenTest name fp deco execute
6367
= goldenGitDiff name (classPath </> fpWithDeco <.> "expected" <.> "hs")
64-
$ runSession testCommand fullCaps classPath
68+
$ runSessionWithServer plugin classPath
6569
$ do
6670
doc <- openDoc (fp <.> "hs") "haskell"
6771
_ <- waitForDiagnosticsFromSource doc "typecheck"

plugins/hls-class-plugin/test/Server.hs

Lines changed: 0 additions & 18 deletions
This file was deleted.

plugins/hls-eval-plugin/hls-eval-plugin.cabal

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,23 +92,9 @@ library
9292
DataKinds
9393
TypeOperators
9494

95-
executable test-server
96-
default-language: Haskell2010
97-
build-depends:
98-
, base
99-
, data-default
100-
, ghcide
101-
, hls-eval-plugin
102-
, hls-plugin-api
103-
104-
main-is: Server.hs
105-
hs-source-dirs: test
106-
ghc-options: -threaded
107-
10895
test-suite tests
10996
type: exitcode-stdio-1.0
11097
default-language: Haskell2010
111-
build-tool-depends: hls-eval-plugin:test-server -any
11298
hs-source-dirs: test
11399
main-is: Main.hs
114100

0 commit comments

Comments
 (0)