on master help sign in
Fix flaky LSP stress tests (#2004)

Previously, we only checked two diagnostics messages. However, the second diagnostics messages does not actually need to correspond to the latest change but can just be a message that has been in the queue from one of the 1000 changes before. Now we make sure to actually check all (or at least every second) diagnostic. This was technically also an issue before but since we only emitted diagnostics when they changed and we alternate between two states it worked fine. The way we implement debouncing means that we can now also end up emitting two consecutive diagnostics changes for the same set of diagnostics which made this test flaky.

commit1fee8b0890b8db9618440f164d846966d1db6890 authorMoritz Kiefer <moritz.kiefer@purelyfunctional.org> dateThu 4 Jul 2019, 14:44 (7 years ago) parent5e3fcff
1 file changed+17−9
src/Development/IDE/Core/Shake.hs+17−9
src/Development/IDE/Core/Shake.hs+17−9
@@ -51,6 +51,7 @@ import qualified Data.Map as Map
5151import qualified Data.ByteString.Char8 as BS
5252import Data.Dynamic
5353import Data.Maybe
54+import Data.Map.Strict (Map)
5455import Data.Either.Extra
5556import Data.List.Extra
5657import qualified Data.Text as T
@@ -80,11 +81,14 @@ import Language.Haskell.LSP.Types
8081-- information we stash inside the shakeExtra field
8182data ShakeExtras = ShakeExtras
8283 {eventer :: LSP.FromServerMessage -> IO ()
83− ,debouncer :: Debouncer Uri
84+ ,debouncer :: Debouncer NormalizedUri
8485 ,logger :: Logger
8586 ,globals :: Var (HMap.HashMap TypeRep Dynamic)
8687 ,state :: Var Values
8788 ,diagnostics :: Var DiagnosticStore
89+ ,publishedDiagnostics :: Var (Map NormalizedUri [Diagnostic])
90+ -- ^ This represents the set of diagnostics that we have published.
91+ -- Due to debouncing not every change might get published.
8892 }
8993
9094getShakeExtras :: Action ShakeExtras
@@ -224,6 +228,7 @@ shakeOpen eventer logger opts rules = do
224228 globals <- newVar HMap.empty
225229 state <- newVar HMap.empty
226230 diagnostics <- newVar mempty
231+ publishedDiagnostics <- newVar mempty
227232 debouncer <- newDebouncer
228233 pure ShakeExtras{..}
229234 (shakeDb, shakeClose) <- shakeOpenDatabase opts{shakeExtra = addShakeExtra shakeExtras $ shakeExtra opts} rules
@@ -382,22 +387,25 @@ updateFileDiagnostics ::
382387 -> ShakeExtras
383388 -> [Diagnostic] -- ^ current results
384389 -> Action ()
385−updateFileDiagnostics fp k ShakeExtras{diagnostics, state, debouncer, eventer} current = liftIO $ do
390+updateFileDiagnostics fp k ShakeExtras{diagnostics, publishedDiagnostics, state, debouncer, eventer} current = liftIO $ do
386391 modTime <- join <$> getValues state GetModificationTime fp
387392 mask_ $ do
388393 -- Mask async exceptions to ensure that updated diagnostics are always
389394 -- published. Otherwise, we might never publish certain diagnostics if
390395 -- an exception strikes between modifyVar but before
391396 -- publishDiagnosticsNotification.
392− (newDiags, oldDiags) <- modifyVar diagnostics $ \old -> do
393− let oldDiags = getFileDiagnostics fp old
397+ newDiags <- modifyVar diagnostics $ \old -> do
394398 let newDiagsStore = setStageDiagnostics fp (vfsVersion =<< modTime) (T.pack $ show k) current old
395399 let newDiags = getFileDiagnostics fp newDiagsStore
396− pure (newDiagsStore, (newDiags, oldDiags))
397− let uri = fromNormalizedUri $ filePathToUri' fp
398− when (newDiags /= oldDiags) $ do
399− let delay = if null newDiags then 0.1 else 0
400− registerEvent debouncer delay uri $ eventer $ publishDiagnosticsNotification uri newDiags
400+ pure (newDiagsStore, newDiags)
401+ let uri = filePathToUri' fp
402+ let delay = if null newDiags then 0.1 else 0
403+ registerEvent debouncer delay uri $ do
404+ mask_ $ modifyVar_ publishedDiagnostics $ \published -> do
405+ let lastPublish = Map.findWithDefault [] uri published
406+ when (lastPublish /= newDiags) $
407+ eventer $ publishDiagnosticsNotification (fromNormalizedUri uri) newDiags
408+ pure (Map.insert uri newDiags published)
401409
402410publishDiagnosticsNotification :: Uri -> [Diagnostic] -> LSP.FromServerMessage
403411publishDiagnosticsNotification uri diags =