Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace utest with MUnit #1277

Merged
merged 33 commits into from Jan 27, 2020
Merged

Replace utest with MUnit #1277

merged 33 commits into from Jan 27, 2020

Conversation

gabro
Copy link
Member

@gabro gabro commented Jan 9, 2020

Previously we used a heavily customized BaseSuite on top of utest. We didn't really use any feature of utest, except some pretty printing utility for the stack traces.

@olafurpg recently created https://github.com/olafurpg/funsuite which (not coincidentally) is extremely similar to our custom BaseSuite, and it provides some extra goodies that help in simplifying our suites.

This PR:

  • replaces utest with funsuite
  • uses some nice features from funsuite, such as .flaky, .fail and assume(...) to simplify our test suites
  • adds (implicit loc Location) to all our custom check... and assert... methods in order to benefit from the fancy pretty printing in funsuite
  • de-duplicates and refactors our custom assertions so to re-use as much as possible from funsuite
  • turns test suites into classes (this is still open for debate, @olafurpg)

Still missing:

  • there's a single test that uses intercept from utest, which is currently missing from funsuite
  • there are two utilities (assertNoDiffOrShowObtained and unifiedDiff) that are present in funsuite but are not exposed by the public API (and I think they should)

Main benefits of this PR:

  • we don't have to maintain an untested testing library inside Metals
  • funsuite offers some utilities that simplify our test suites
  • funsuite it's based on JUnit, so I expect it will be easier to do a few integrations we discussed about (e.g. reporting flaky failures)

Comment on lines 75 to 99
override def funsuiteRunTest(options: TestOptions, body: => Any): Any = {
// We are unable to infer the JDK jars on Appveyor
// tests.BasePCSuite.indexJDK(BasePCSuite.scala:44)
val testName =
if (isCI && BuildInfo.scalaCompilerVersion != BuildInfoVersions.scala212)
s"${BuildInfo.scalaCompilerVersion}-${options.name}"
else options.name
super.test(options.copy(name = testName)) {
try {
fun
} catch {
case NonFatal(e)
if e.getMessage != null &&
e.getMessage.contains("x$1") &&
!hasJdkSources =>
// ignore failing test if jdk sources are missing
()
super.funsuiteRunTest(
options.copy(name = testName), {
try {
body
} catch {
case NonFatal(e)
if e.getMessage != null &&
e.getMessage.contains("x$1") &&
!hasJdkSources =>
// ignore failing test if jdk sources are missing
()
}
}
}
)
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we're at it, is this still true for Windows on GitHub Actions? The comment mentions Appveyor

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I remember sources are available on Github Actions.

Comment on lines 9 to 28
def unifiedDiff(expected: String, obtained: String): String = {
def splitIntoLines(string: String): Seq[String] =
string.trim.replace("\r\n", "\n").split("\n")

val references = splitIntoLines(expected).asJava
val definition = splitIntoLines(obtained).asJava
val diff = difflib.DiffUtils.diff(references, definition)
difflib.DiffUtils
.generateUnifiedDiff(
"references",
"definition",
references,
diff,
1
)
.asScala
.iterator
.filterNot(_.startsWith("@@"))
.mkString("\n")
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exists almost verbatim in funsuite, but it's a private method

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can make it public in FunSuite

Comment on lines 30 to 14
def assertNoDiffOrPrintObtained(
obtained: String,
expected: String
)(implicit loc: Location): Unit = {
// FIXME(gabro): surface this in funsuite Assertions
funsuite.internal.Diffs.assertNoDiffOrPrintExpected(obtained, expected)
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What the comment says

}
override def funsuiteTests(): Seq[Test] = {
if (skipSuite) Seq.empty
else super.funsuiteTests()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The skipSuite utility may end up in funsuite (as discussed with @olafurpg)

cancelServer()
if (context.test.tags.contains(Ignore)) return
newServer(context.test.name)
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved cancelServer and newServer to separate methods to that we can invoke them without having to invoke beforeEach

} yield ()
}
testAsync("completion") {
assume(!isWindows, "This test is flaky on Windows")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assume saves us from indentation

super.testAsync(options, maxDuration)(run)
}
}
override def skipSuite: Boolean = isWindows
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using skipSuite is way more straightforward than overriding testAsync

Comment on lines 55 to 59
// FIXME(gabro): intercept is not available in FunSuite
// // check that we get an exception using the default nio method
// intercept[FileAlreadyExistsException] {
// Files.createDirectories(symlinkPluginsPath)
// }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the assertion I had to disable, because intercept is missing in funsuite

@@ -182,8 +182,7 @@ object DefinitionLspSuite extends BaseLspSuite("definition") {
// requires org.scalamacros:macroparadise and io.spire-match:kind-projector.
// Navigation continues to mostly work, except for areas that have compilation
// errors.
// NOTE(olafur): ignored because this test case is flaky and regularly failing the CI.
ignore("missing-compiler-plugin") {
test("missing-compiler-plugin".flaky) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This re-enables the test, but marks it as flaky

@gabro gabro requested review from olafurpg and tgodzik January 9, 2020 12:08
Copy link
Member

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much @gabro I'm really excited to see this migration 😍 LGTM 👍 👍 👍

"true".equalsIgnoreCase(System.getenv("CI"))
def beforeAll(): Unit = ()
def afterAll(): Unit = ()
def intercept[T: ClassTag](exprs: Unit): T = macro Asserts.interceptProxy[T]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we override def isFlakyFailureOk = isCI?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, we should be able to implement a basic intercept assertion that's not macro based

def intercept[T <: Throwable]body: => Unit)(implicit ev: ClassTag[T]): T = {
  try {
    body
    fail("expected exception but body evaluated successfully")
  }
  catch {
    case NonFatal(e) =>
      if (!ev.isAssignableFrom(e)) fail("expected ${ev.runtimeClass}, obtained ${e.getClass}")
  }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm torn about this. What's the benefit of marking flaky tests and then ignoring them vs just ignoring them? Or a bit further: why don't we just remove those tests?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as per intercept, I've added it to unblock this PR, although I think it would make sense in funsuite, so that it's properly tested

}
override def funsuiteTests(): Seq[Test] = {
if (skipSuite) Seq.empty
else super.funsuiteTests()
}

def testAsync(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have considered adding built-in support in FunSuite that captures Future[_] values and automatically awaits then with a default timeout, which would avoid testAsync

@gabro
Copy link
Member Author

gabro commented Jan 9, 2020

Tests are failing with

2020-01-09T11:56:39.4513466Z INFO  tests.TestingServer#didOpen
2020-01-09T11:56:41.4248778Z Exception in thread "pool-14-thread-1" java.lang.NoClassDefFoundError: javax/tools/DiagnosticListener
2020-01-09T11:56:41.4249022Z 	at scala.tools.util.PathResolverBase$Calculated$.javaBootClasspath(PathResolver.scala:277)
2020-01-09T11:56:41.4249520Z 	at scala.tools.util.PathResolverBase$Calculated$.basis(PathResolver.scala:283)
2020-01-09T11:56:41.4249664Z 	at scala.tools.util.PathResolverBase$Calculated$.containers$lzycompute(PathResolver.scala:293)
2020-01-09T11:56:41.4249839Z 	at scala.tools.util.PathResolverBase$Calculated$.containers(PathResolver.scala:293)
2020-01-09T11:56:41.4249992Z 	at scala.tools.util.PathResolverBase.containers(PathResolver.scala:309)
2020-01-09T11:56:41.4250153Z 	at scala.tools.util.PathResolver.computeResult(PathResolver.scala:341)
2020-01-09T11:56:41.4250301Z 	at scala.tools.util.PathResolver.computeResult(PathResolver.scala:332)
2020-01-09T11:56:41.4250447Z 	at scala.tools.util.PathResolverBase.result(PathResolver.scala:314)
2020-01-09T11:56:41.4250601Z 	at scala.tools.nsc.backend.JavaPlatform$class.classPath(JavaPlatform.scala:28)
2020-01-09T11:56:41.4250756Z 	at scala.tools.nsc.Global$GlobalPlatform.classPath(Global.scala:115)
2020-01-09T11:56:41.4250901Z 	at scala.tools.nsc.Global.scala$tools$nsc$Global$$recursiveClassPath(Global.scala:131)
2020-01-09T11:56:41.4251060Z 	at scala.tools.nsc.Global$GlobalMirror.rootLoader(Global.scala:64)
2020-01-09T11:56:41.4251209Z 	at scala.reflect.internal.Mirrors$Roots$RootClass.<init>(Mirrors.scala:307)
2020-01-09T11:56:41.4251360Z 	at scala.reflect.internal.Mirrors$Roots.RootClass$lzycompute(Mirrors.scala:321)
2020-01-09T11:56:41.4251515Z 	at scala.reflect.internal.Mirrors$Roots.RootClass(Mirrors.scala:321)
2020-01-09T11:56:41.4251657Z 	at scala.reflect.internal.Mirrors$Roots$EmptyPackageClass.<init>(Mirrors.scala:330)
2020-01-09T11:56:41.4251822Z 	at scala.reflect.internal.Mirrors$Roots.EmptyPackageClass$lzycompute(Mirrors.scala:336)
2020-01-09T11:56:41.4251977Z 	at scala.reflect.internal.Mirrors$Roots.EmptyPackageClass(Mirrors.scala:336)
2020-01-09T11:56:41.4252131Z 	at scala.reflect.internal.Mirrors$Roots.EmptyPackageClass(Mirrors.scala:276)
2020-01-09T11:56:41.4252278Z 	at scala.reflect.internal.Mirrors$RootsBase.init(Mirrors.scala:250)
2020-01-09T11:56:41.4252869Z 	at scala.tools.nsc.Global.rootMirror$lzycompute(Global.scala:73)
2020-01-09T11:56:41.4253005Z 	at scala.tools.nsc.Global.rootMirror(Global.scala:71)
2020-01-09T11:56:41.4253145Z 	at scala.tools.nsc.Global.rootMirror(Global.scala:39)
2020-01-09T11:56:41.4253297Z 	at scala.reflect.internal.Definitions$DefinitionsClass.ObjectClass$lzycompute(Definitions.scala:257)
2020-01-09T11:56:41.4253466Z 	at scala.reflect.internal.Definitions$DefinitionsClass.ObjectClass(Definitions.scala:257)
2020-01-09T11:56:41.4253628Z 	at scala.reflect.internal.Definitions$DefinitionsClass.init(Definitions.scala:1390)
2020-01-09T11:56:41.4253761Z 	at scala.tools.nsc.Global$Run.<init>(Global.scala:1242)
2020-01-09T11:56:41.4253905Z 	at scala.tools.nsc.interactive.Global$TyperRun.<init>(Global.scala:1321)
2020-01-09T11:56:41.4254055Z 	at scala.tools.nsc.interactive.Global.newTyperRun(Global.scala:1344)
2020-01-09T11:56:41.4254207Z 	at scala.tools.nsc.interactive.Global.<init>(Global.scala:299)
2020-01-09T11:56:41.4254340Z 	at scala.meta.internal.pc.MetalsGlobal.<init>(MetalsGlobal.scala:31)
2020-01-09T11:56:41.4254458Z 	at scala.meta.internal.pc.ScalaPresentationCompiler.newCompiler(ScalaPresentationCompiler.scala:183)
2020-01-09T11:56:41.4254693Z 	at scala.meta.internal.pc.ScalaPresentationCompiler$$anonfun$1.apply(ScalaPresentationCompiler.scala:60)
2020-01-09T11:56:41.4254986Z 	at scala.meta.internal.pc.ScalaPresentationCompiler$$anonfun$1.apply(ScalaPresentationCompiler.scala:60)
2020-01-09T11:56:41.4255180Z 	at scala.meta.internal.pc.CompilerAccess.loadCompiler(CompilerAccess.scala:36)
2020-01-09T11:56:41.4255317Z 	at scala.meta.internal.pc.CompilerAccess.withSharedCompiler(CompilerAccess.scala:120)
2020-01-09T11:56:41.4255485Z 	at scala.meta.internal.pc.CompilerAccess$$anonfun$withNonInterruptableCompiler$1.apply(CompilerAccess.scala:110)
2020-01-09T11:56:41.4255634Z 	at scala.meta.internal.pc.CompilerAccess$$anonfun$onCompilerJobQueue$1.apply$mcV$sp(CompilerAccess.scala:198)
2020-01-09T11:56:41.4255802Z 	at scala.meta.internal.pc.CompilerJobQueue$Job.run(CompilerJobQueue.scala:101)
2020-01-09T11:56:41.4255961Z 	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
2020-01-09T11:56:41.4256125Z 	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
2020-01-09T11:56:41.4256278Z 	at java.base/java.lang.Thread.run(Thread.java:834)
2020-01-09T11:56:41.4256429Z Caused by: java.lang.ClassNotFoundException: javax.tools.DiagnosticListener
2020-01-09T11:56:41.4256571Z 	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
2020-01-09T11:56:41.4256729Z 	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
2020-01-09T11:56:41.4256877Z 	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
2020-01-09T11:56:41.4257017Z 	... 42 more
2020-01-09T11:56:42.2099874Z Exception in thread "Evaluating Worksheet Main.worksheet.sc" java.lang.NoClassDefFoundError: javax/tools/DiagnosticListener
2020-01-09T11:56:42.2102687Z 	at scala.tools.util.PathResolverBase$Calculated$.javaBootClasspath(PathResolver.scala:277)
2020-01-09T11:56:42.2103133Z 	at scala.tools.util.PathResolverBase$Calculated$.basis(PathResolver.scala:283)
2020-01-09T11:56:42.2103487Z 	at scala.tools.util.PathResolverBase$Calculated$.containers$lzycompute(PathResolver.scala:293)
2020-01-09T11:56:42.2103825Z 	at scala.tools.util.PathResolverBase$Calculated$.containers(PathResolver.scala:293)
2020-01-09T11:56:42.2104150Z 	at scala.tools.util.PathResolverBase.containers(PathResolver.scala:309)
2020-01-09T11:56:42.2104467Z 	at scala.tools.util.PathResolver.computeResult(PathResolver.scala:341)
2020-01-09T11:56:42.2104923Z 	at scala.tools.util.PathResolver.computeResult(PathResolver.scala:332)
2020-01-09T11:56:42.2105265Z 	at scala.tools.util.PathResolverBase.result(PathResolver.scala:314)
2020-01-09T11:56:42.2105581Z 	at scala.tools.nsc.backend.JavaPlatform$class.classPath(JavaPlatform.scala:28)
2020-01-09T11:56:42.2106289Z 	at scala.tools.nsc.Global$GlobalPlatform.classPath(Global.scala:115)
2020-01-09T11:56:42.2106672Z 	at scala.tools.nsc.Global.scala$tools$nsc$Global$$recursiveClassPath(Global.scala:131)
2020-01-09T11:56:42.2106830Z 	at scala.tools.nsc.Global$GlobalMirror.rootLoader(Global.scala:64)
2020-01-09T11:56:42.2106933Z 	at scala.reflect.internal.Mirrors$Roots$RootClass.<init>(Mirrors.scala:307)
2020-01-09T11:56:42.2107119Z 	at scala.reflect.internal.Mirrors$Roots.RootClass$lzycompute(Mirrors.scala:321)
2020-01-09T11:56:42.2107242Z 	at scala.reflect.internal.Mirrors$Roots.RootClass(Mirrors.scala:321)
2020-01-09T11:56:42.2107363Z 	at scala.reflect.internal.Mirrors$Roots$EmptyPackageClass.<init>(Mirrors.scala:330)
2020-01-09T11:56:42.2107491Z 	at scala.reflect.internal.Mirrors$Roots.EmptyPackageClass$lzycompute(Mirrors.scala:336)
2020-01-09T11:56:42.2107596Z 	at scala.reflect.internal.Mirrors$Roots.EmptyPackageClass(Mirrors.scala:336)
2020-01-09T11:56:42.2107714Z 	at scala.reflect.internal.Mirrors$Roots.EmptyPackageClass(Mirrors.scala:276)
2020-01-09T11:56:42.2107836Z 	at scala.reflect.internal.Mirrors$RootsBase.init(Mirrors.scala:250)
2020-01-09T11:56:42.2107947Z 	at scala.tools.nsc.Global.rootMirror$lzycompute(Global.scala:73)
2020-01-09T11:56:42.2108042Z 	at scala.tools.nsc.Global.rootMirror(Global.scala:71)
2020-01-09T11:56:42.2108148Z 	at scala.tools.nsc.Global.rootMirror(Global.scala:39)
2020-01-09T11:56:42.2108441Z 	at scala.reflect.internal.Definitions$DefinitionsClass.ObjectClass$lzycompute(Definitions.scala:257)
2020-01-09T11:56:42.2108581Z 	at scala.reflect.internal.Definitions$DefinitionsClass.ObjectClass(Definitions.scala:257)
2020-01-09T11:56:42.2108704Z 	at scala.reflect.internal.Definitions$DefinitionsClass.init(Definitions.scala:1390)
2020-01-09T11:56:42.2108803Z 	at scala.tools.nsc.Global$Run.<init>(Global.scala:1242)
2020-01-09T11:56:42.2108918Z 	at mdoc.internal.markdown.MarkdownCompiler.compileSources(MarkdownCompiler.scala:210)
2020-01-09T11:56:42.2109038Z 	at mdoc.internal.markdown.MarkdownCompiler.compile(MarkdownCompiler.scala:223)
2020-01-09T11:56:42.2109164Z 	at mdoc.internal.markdown.MarkdownCompiler$.buildDocument(MarkdownCompiler.scala:47)
2020-01-09T11:56:42.2109272Z 	at mdoc.internal.worksheets.WorksheetProvider.evaluateWorksheet(WorksheetProvider.scala:39)
2020-01-09T11:56:42.2109393Z 	at mdoc.internal.worksheets.Mdoc.evaluateWorksheet(Mdoc.scala:45)
2020-01-09T11:56:42.2109503Z 	at mdoc.internal.worksheets.Mdoc.evaluateWorksheet(Mdoc.scala:18)
2020-01-09T11:56:42.2109632Z 	at scala.meta.internal.worksheets.WorksheetProvider.$anonfun$evaluateWorksheet$2(WorksheetProvider.scala:225)
2020-01-09T11:56:42.2109736Z 	at scala.Option.map(Option.scala:230)
2020-01-09T11:56:42.2109868Z 	at scala.meta.internal.worksheets.WorksheetProvider.scala$meta$internal$worksheets$WorksheetProvider$$evaluateWorksheet(WorksheetProvider.scala:223)
2020-01-09T11:56:42.2110007Z 	at scala.meta.internal.worksheets.WorksheetProvider$$anon$1.run(WorksheetProvider.scala:142)
2020-01-09T11:56:42.2110130Z Caused by: java.lang.ClassNotFoundException: javax.tools.DiagnosticListener
2020-01-09T11:56:42.2110250Z 	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
2020-01-09T11:56:42.2110352Z 	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
2020-01-09T11:56:42.2110465Z 	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
2020-01-09T11:56:42.2110571Z 	... 37 more

By the looks of it, I would say it's an issue with Java 11, but I don't know how I could have possibly have introduced it.

@gabro
Copy link
Member Author

gabro commented Jan 9, 2020

Ok, it's exactly scalacenter/bloop#743 but again, I don't know why it's popping up now

@olafurpg olafurpg changed the title Replace utest with funsuite Replace utest with MUnit Jan 11, 2020
@olafurpg
Copy link
Member

I updated this PR to the latest version of FunSuite, which is now called "MUnit" and has been moved to the scalameta organization https://github.com/scalameta/munit

Let's see if CI complains again about the same cryptic error 🤔

@olafurpg
Copy link
Member

Screenshot 2020-01-11 at 21 39 34

The new assertion errors look nice :)

@olafurpg
Copy link
Member

@gabro The tests are failing with the same error. I'm able to reproduce locally

jabba install adopt@1.11.0-5
jabba use adopt@1.11.0-5
sbt
> slow/testOnly tests.feature.Worksheet211LspSuite

I believe that test case should not be running in JDK 11 because Scala 2.11 doesn't properly run in JDK 11.

@olafurpg
Copy link
Member

This should fix the issue

commit ca55f62794c8d53906ea2a82302a434f3e0abc98
Author: Olafur Pall Geirsson <lgeirsson@twitter.com>
Date:   Sat Jan 11 22:30:29 2020 +0000

    Flip "skipSuite" condition

diff --git a/tests/unit/src/main/scala/tests/BaseWorksheetLspSuite.scala b/tests/unit/src/main/scala/tests/BaseWorksheetLspSuite.scala
index cc6d173..c8d33ca 100644
--- a/tests/unit/src/main/scala/tests/BaseWorksheetLspSuite.scala
+++ b/tests/unit/src/main/scala/tests/BaseWorksheetLspSuite.scala
@@ -13,7 +13,7 @@ abstract class BaseWorksheetLspSuite(scalaVersion: String)
   override def userConfig: UserConfiguration =
     super.userConfig.copy(worksheetScreenWidth = 40, worksheetCancelTimeout = 1)
 
-  override def skipSuite: Boolean = isValidScalaVersionForEnv(scalaVersion)
+  override def skipSuite: Boolean = !isValidScalaVersionForEnv(scalaVersion)
 
   testAsync("completion") {
     assume(!isWindows, "This test is flaky on Windows")

@olafurpg olafurpg force-pushed the funsuite branch 2 times, most recently from 9465b9d to a6864c3 Compare January 13, 2020 13:08
Copy link
Member Author

@gabro gabro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some todos here and there

if e.getMessage != null &&
e.getMessage.contains("x$1") &&
!hasJdkSources =>
// ignore failing test if jdk sources are missing
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would try removing this

expected: String
)(implicit loc: Location): Unit = {
// FIXME(gabro): surface this in funsuite Assertions
munit.Diffs.assertNoDiff(obtained, expected)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this print the obtained when it fails?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. That’s the default behavior

Copy link
Member Author

@gabro gabro Jan 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, than we can just remove this method and use assertNoDiff directly

}
def assertEmpty(string: String): Unit = {
if (!string.isEmpty) {
def intercept[T <: Throwable](
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intercept is now in munit

() => ()
)
}
def skipSuite: Boolean = false
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace with munitIgnore (which is now in munit)

@gabro
Copy link
Member Author

gabro commented Jan 21, 2020

Upgraded to the latest MUnit and rebased. Let's see if the CI is happy!

@gabro gabro force-pushed the funsuite branch 2 times, most recently from d6fb906 to 26131c6 Compare January 21, 2020 03:57
Olafur Pall Geirsson and others added 11 commits January 25, 2020 11:48
The latest MUnit release includes fixes for handling ANSI colored
strings.
The test failed in 2.11 with
```diff
=> Diff (- obtained, + expected)
   x match {
-\tcase Some(x) =>
+\tcase Some(value) =>
```

Previously, before MUnit, we ran the "2.11" test on 2.13 due to a
copy-paste bug.
@olafurpg
Copy link
Member

This test failure is happening consistently in CI but I'm unable to reproduce locally (tried both JDK 8 and JDK 11)

==> X tests.feature.CompletionCrossLspSuite.match-213  4.712s java.util.NoSuchElementException: next on empty iterator

Need to look closer, but I can't figure out why this PR should cause the failure.

@gabro
Copy link
Member Author

gabro commented Jan 25, 2020

I see this happening locally when running the entire suite and not just the single test. Sometimes match-211 fails as well 🤔

@olafurpg
Copy link
Member

Interesting 🤔 I'll try that locally. I BTW removed match-211 since it was a duplicate of match-213 due to a copy-paste bug. The test fails in 2.11 since it asserts behavior that is only valid in 2.13

Olafur Pall Geirsson added 4 commits January 25, 2020 13:43
We should try to eliminate all flaky tests. These tests are causing more
problems than they're worth so it's better to ignore their failures than
fail the build.
I'm unable to reproduce the CI test failures.
Previously, this test passed because the old assertNoDiff implementation
trimmed lines that had only whitespace.
@olafurpg
Copy link
Member

CI is green now! An important change is that failures in tests that are marked with .flaky no longer fail the build. I believe this is an improvement from before where we would frequently merge PRs with a failed CI marker and leave a comment like "ignoring flaky test failure".

In the future, I'd like to start collecting statistics for how frequently flaky tests are failing so that we can take action to fix flaky test failures. For example, it would be good to know if test is failing only 1% of the time of 99% of the time.

@olafurpg olafurpg self-requested a review January 25, 2020 14:41
Copy link
Member Author

@gabro gabro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve taken another pass and I think there are some more minor improvements we could squeeze in

build.sbt Outdated Show resolved Hide resolved
tests/cross/src/main/scala/tests/BasePCSuite.scala Outdated Show resolved Hide resolved
tests/slow/src/test/scala/tests/pants/PantsLspSuite.scala Outdated Show resolved Hide resolved
tests/unit/src/main/scala/tests/BaseDigestSuite.scala Outdated Show resolved Hide resolved
tests/unit/src/test/scala/tests/BspSwitchLspSuite.scala Outdated Show resolved Hide resolved
Olafur Pall Geirsson added 2 commits January 26, 2020 10:28
@olafurpg
Copy link
Member

@gabro Great suggestions! Done.

Copy link
Contributor

@tgodzik tgodzik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks! This should be a fun improvement.

@olafurpg olafurpg merged commit bf8d355 into scalameta:master Jan 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants