diff --git a/build.sbt b/build.sbt index 1ec7a566aa..024f78c9d4 100644 --- a/build.sbt +++ b/build.sbt @@ -231,7 +231,7 @@ ThisBuild / scalacOptions ++= Seq( ) ThisBuild / Test / testOptions ++= - Seq(Tests.Argument("-oI")) ++ + Seq(Tests.Argument(TestFrameworks.ScalaTest, "-oID")) ++ sys.env .get("ENSO_TEST_JUNIT_DIR") .map { junitDir => @@ -758,6 +758,7 @@ lazy val `logging-service-logback` = project "org.slf4j" % "slf4j-api" % slf4jVersion, "io.sentry" % "sentry-logback" % "6.28.0", "io.sentry" % "sentry" % "6.28.0", + "org.scalatest" %% "scalatest" % scalatestVersion % Test, "org.netbeans.api" % "org-openide-util-lookup" % netbeansApiVersion % "provided" ) ++ logbackPkg ) @@ -1552,9 +1553,6 @@ lazy val runtime = (project in file("engine/runtime")) }, Test / parallelExecution := false, Test / logBuffered := false, - Test / testOptions += Tests.Argument( - "-oD" - ), // show timings for individual tests scalacOptions += "-Ymacro-annotations", scalacOptions ++= Seq("-Ypatmat-exhaust-depth", "off"), libraryDependencies ++= jmh ++ jaxb ++ GraalVM.langsPkgs ++ Seq( diff --git a/engine/language-server/src/test/resources/application-test.conf b/engine/language-server/src/test/resources/application-test.conf index 244c41c38c..18bdd32f25 100644 --- a/engine/language-server/src/test/resources/application-test.conf +++ b/engine/language-server/src/test/resources/application-test.conf @@ -22,11 +22,15 @@ logging-service { io.methvin.watcher = error } appenders = [ + { + name = "memory" + forward-to = console + }, { name = "console" - pattern = "[%level] [%d{yyyy-MM-ddTHH:mm:ssXXX}] [%logger] %msg%n%nopex" + pattern = "[%level] [%d{yyyy-MM-ddTHH:mm:ssXXX}] [%logger] %msg%n" } ] - default-appender = console + default-appender = memory log-level = "error" } diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/boot/resource/RepoInitializationSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/boot/resource/RepoInitializationSpec.scala index 4c47a92db1..de7e918faf 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/boot/resource/RepoInitializationSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/boot/resource/RepoInitializationSpec.scala @@ -7,6 +7,7 @@ import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} import org.enso.languageserver.data._ import org.enso.languageserver.event.InitializedEvent import org.enso.languageserver.filemanager.{ContentRoot, ContentRootWithFile} +import org.enso.logger.ReportLogsOnFailure import org.enso.searcher.sql.{SchemaVersion, SqlDatabase, SqlSuggestionsRepo} import org.enso.testkit.{FlakySpec, ToScalaFutureConversions} import org.scalatest.BeforeAndAfterAll @@ -16,7 +17,6 @@ import org.sqlite.SQLiteException import java.nio.file.{Files, StandardOpenOption} import java.util.UUID - import scala.concurrent.Await import scala.concurrent.duration._ @@ -27,7 +27,8 @@ class RepoInitializationSpec with Matchers with BeforeAndAfterAll with ToScalaFutureConversions - with FlakySpec { + with FlakySpec + with ReportLogsOnFailure { import system.dispatcher diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootManagerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootManagerSpec.scala index 3e5b2704a4..df03f4ae52 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootManagerSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootManagerSpec.scala @@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.ContentRootManagerProtocol.{ ContentRootsAddedNotification, SubscribeToNotifications } +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api import org.enso.testkit.{EitherValue, WithTemporaryDirectory} import org.scalatest.concurrent.Futures @@ -30,7 +31,8 @@ class ContentRootManagerSpec with Inside with EitherValue with OptionValues - with WithTemporaryDirectory { + with WithTemporaryDirectory + with ReportLogsOnFailure { var rootManager: ContentRootManagerWrapper = _ var rootActor: ActorRef = _ diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootSerializationSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootSerializationSpec.scala index 7fee59ebab..9e4a694ef7 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootSerializationSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootSerializationSpec.scala @@ -3,12 +3,16 @@ package org.enso.languageserver.filemanager import io.circe.Json import io.circe.syntax._ import io.circe.literal._ +import org.enso.logger.ReportLogsOnFailure import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import java.util.UUID -class ContentRootSerializationSpec extends AnyWordSpec with Matchers { +class ContentRootSerializationSpec + extends AnyWordSpec + with Matchers + with ReportLogsOnFailure { "ContentRoot" should { "correctly serialize" in { val id = UUID.randomUUID() diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/FileSystemSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/FileSystemSpec.scala index 81830da490..6e52c86f41 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/FileSystemSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/FileSystemSpec.scala @@ -2,6 +2,7 @@ package org.enso.languageserver.filemanager import org.apache.commons.io.FileUtils import org.enso.languageserver.effect.Effects +import org.enso.logger.ReportLogsOnFailure import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike @@ -13,7 +14,11 @@ import scala.collection.mutable.ArrayBuffer import scala.io.Source import scala.jdk.CollectionConverters._ -class FileSystemSpec extends AnyWordSpecLike with Matchers with Effects { +class FileSystemSpec + extends AnyWordSpecLike + with Matchers + with Effects + with ReportLogsOnFailure { import FileSystemApi._ diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsResolverSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsResolverSpec.scala index b40df61605..0bfa6616b1 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsResolverSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsResolverSpec.scala @@ -1,6 +1,7 @@ package org.enso.languageserver.libraries import org.enso.editions.LibraryName +import org.enso.logger.ReportLogsOnFailure import org.enso.pkg.{ Component, ComponentGroup, @@ -13,7 +14,10 @@ import org.enso.pkg.{ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class ComponentGroupsResolverSpec extends AnyWordSpec with Matchers { +class ComponentGroupsResolverSpec + extends AnyWordSpec + with Matchers + with ReportLogsOnFailure { import ComponentGroupsResolverSpec._ diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsValidatorSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsValidatorSpec.scala index 535ce27539..e021052910 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsValidatorSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsValidatorSpec.scala @@ -2,11 +2,15 @@ package org.enso.languageserver.libraries import io.circe.DecodingFailure import org.enso.editions.LibraryName +import org.enso.logger.ReportLogsOnFailure import org.enso.pkg.{ComponentGroups, Config, GroupName, GroupReference} import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class ComponentGroupsValidatorSpec extends AnyWordSpec with Matchers { +class ComponentGroupsValidatorSpec + extends AnyWordSpec + with Matchers + with ReportLogsOnFailure { import ComponentGroupsValidator._ import ComponentGroupsValidatorSpec._ diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/EditionNameSerializationSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/EditionNameSerializationSpec.scala index 168e6b87e6..c5d5974c55 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/EditionNameSerializationSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/EditionNameSerializationSpec.scala @@ -5,10 +5,14 @@ import org.enso.languageserver.libraries.EditionReference.{ CurrentProjectEdition, NamedEdition } +import org.enso.logger.ReportLogsOnFailure import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class EditionNameSerializationSpec extends AnyWordSpec with Matchers { +class EditionNameSerializationSpec + extends AnyWordSpec + with Matchers + with ReportLogsOnFailure { "EditionName" should { "serialize and deserialize to the same thing" in { val edition1: EditionReference = CurrentProjectEdition diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/LibraryEntrySerializationSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/LibraryEntrySerializationSpec.scala index bb616f3abc..a759c94a6d 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/LibraryEntrySerializationSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/LibraryEntrySerializationSpec.scala @@ -1,10 +1,14 @@ package org.enso.languageserver.libraries import io.circe.syntax._ +import org.enso.logger.ReportLogsOnFailure import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class LibraryEntrySerializationSpec extends AnyWordSpec with Matchers { +class LibraryEntrySerializationSpec + extends AnyWordSpec + with Matchers + with ReportLogsOnFailure { "LibraryEntry" should { "serialize and deserialize to the same thing" in { val entry1 = diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/LocalLibraryManagerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/LocalLibraryManagerSpec.scala index 651b1f6f19..63d005cf93 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/LocalLibraryManagerSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/LocalLibraryManagerSpec.scala @@ -5,6 +5,7 @@ import akka.testkit._ import org.enso.distribution.FileSystem.PathSyntax import org.enso.editions.LibraryName import org.enso.librarymanager.LibraryLocations +import org.enso.logger.ReportLogsOnFailure import org.enso.pkg.PackageManager import org.enso.testkit.WithTemporaryDirectory import org.scalatest.matchers.should.Matchers @@ -20,7 +21,8 @@ class LocalLibraryManagerSpec with AnyWordSpecLike with Matchers with BeforeAndAfterAll - with WithTemporaryDirectory { + with WithTemporaryDirectory + with ReportLogsOnFailure { val Timeout: FiniteDuration = 10.seconds diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/monitoring/HealthCheckEndpointSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/monitoring/HealthCheckEndpointSpec.scala index 8d3df321d8..45cb680b32 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/monitoring/HealthCheckEndpointSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/monitoring/HealthCheckEndpointSpec.scala @@ -11,6 +11,7 @@ import org.enso.languageserver.monitoring.HealthCheckEndpointSpec.{ } import org.enso.languageserver.monitoring.MonitoringProtocol.{Ping, Pong} import org.enso.languageserver.requesthandler.monitoring.PingHandler +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.must.Matchers @@ -22,7 +23,8 @@ class HealthCheckEndpointSpec with Matchers with FlakySpec with ScalatestRouteTest - with Directives { + with Directives + with ReportLogsOnFailure { implicit val timeout: RouteTestTimeout = RouteTestTimeout(25.seconds) diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/monitoring/IdlenessEndpointSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/monitoring/IdlenessEndpointSpec.scala index bf1989f8fd..065432e0a1 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/monitoring/IdlenessEndpointSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/monitoring/IdlenessEndpointSpec.scala @@ -5,6 +5,7 @@ import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.server.Directives import akka.http.scaladsl.testkit.{RouteTestTimeout, ScalatestRouteTest} import org.enso.languageserver.TestClock +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers @@ -16,7 +17,8 @@ class IdlenessEndpointSpec with Matchers with FlakySpec with ScalatestRouteTest - with Directives { + with Directives + with ReportLogsOnFailure { implicit val timeout: RouteTestTimeout = RouteTestTimeout(25.seconds) diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/requesthandler/monitoring/PingHandlerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/requesthandler/monitoring/PingHandlerSpec.scala index d573dd5c2f..32eb134410 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/requesthandler/monitoring/PingHandlerSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/requesthandler/monitoring/PingHandlerSpec.scala @@ -6,6 +6,7 @@ import org.enso.jsonrpc.Id.Number import org.enso.jsonrpc.{Request, ResponseResult, Unused} import org.enso.languageserver.monitoring.MonitoringApi import org.enso.languageserver.monitoring.MonitoringProtocol.{Ping, Pong} +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.must.Matchers @@ -17,7 +18,8 @@ class PingHandlerSpec with ImplicitSender with AnyFlatSpecLike with Matchers - with FlakySpec { + with FlakySpec + with ReportLogsOnFailure { "A PingHandler" must "scatter pings to all subsystems" in { //given diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala index 019bb44055..7c1b922226 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala @@ -19,6 +19,7 @@ import org.enso.languageserver.session.SessionRouter.{ DeliverToBinaryController, DeliverToJsonController } +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api import org.enso.testkit.RetrySpec import org.scalatest.BeforeAndAfterAll @@ -35,7 +36,8 @@ class ContextEventsListenerSpec with AnyWordSpecLike with Matchers with BeforeAndAfterAll - with RetrySpec { + with RetrySpec + with ReportLogsOnFailure { override def afterAll(): Unit = { TestKit.shutdownActorSystem(system) diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala index 28ebf774af..f72b1c3542 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala @@ -13,6 +13,7 @@ import org.enso.languageserver.event.InitializedEvent import org.enso.languageserver.filemanager._ import org.enso.languageserver.session.JsonSession import org.enso.languageserver.session.SessionRouter.DeliverToJsonController +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.data.{Tree, TypeGraph} import org.enso.polyglot.runtime.Runtime.Api import org.enso.polyglot.{ExportedSymbol, ModuleExports, Suggestion} @@ -37,7 +38,8 @@ class SuggestionsHandlerSpec with AnyWordSpecLike with Matchers with BeforeAndAfterAll - with RetrySpec { + with RetrySpec + with ReportLogsOnFailure { import system.dispatcher diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/vcsmanager/GitSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/vcsmanager/GitSpec.scala index f0e01a8763..5871a1fad9 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/vcsmanager/GitSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/vcsmanager/GitSpec.scala @@ -10,6 +10,7 @@ import org.eclipse.jgit.api.{Git => JGit} import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.storage.file.FileRepositoryBuilder import org.eclipse.jgit.revwalk.RevCommit +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec import scala.concurrent.duration._ @@ -19,7 +20,8 @@ class GitSpec extends AnyWordSpecLike with Matchers with Effects - with FlakySpec { + with FlakySpec + with ReportLogsOnFailure { override def opTimeout = 5.seconds diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BinaryFileManipulationTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BinaryFileManipulationTest.scala index e65eb4fe9b..e7c5f69c37 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BinaryFileManipulationTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BinaryFileManipulationTest.scala @@ -5,6 +5,7 @@ import org.apache.commons.io.FileUtils import org.enso.languageserver.protocol.binary._ import org.enso.languageserver.util.binary.BinaryDecoder import org.enso.languageserver.websocket.binary.factory._ +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec import java.io.File @@ -12,10 +13,12 @@ import java.nio.ByteBuffer import java.nio.file.Files import java.security.MessageDigest import java.util.UUID - import scala.io.Source -class BinaryFileManipulationTest extends BaseBinaryServerTest with FlakySpec { +class BinaryFileManipulationTest + extends BaseBinaryServerTest + with FlakySpec + with ReportLogsOnFailure { implicit private val decoder: BinaryDecoder[OutboundMessage] = OutboundMessageDecoder diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BinarySessionManagementTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BinarySessionManagementTest.scala index e2794c95fa..40079c775b 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BinarySessionManagementTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BinarySessionManagementTest.scala @@ -1,7 +1,6 @@ package org.enso.languageserver.websocket.binary import java.util.UUID - import com.google.flatbuffers.FlatBufferBuilder import org.enso.languageserver.protocol.binary.{ InboundPayload, @@ -13,9 +12,13 @@ import org.enso.languageserver.websocket.binary.factory.{ InboundMessageFactory, SessionInitFactory } +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec -class BinarySessionManagementTest extends BaseBinaryServerTest with FlakySpec { +class BinarySessionManagementTest + extends BaseBinaryServerTest + with FlakySpec + with ReportLogsOnFailure { implicit private val decoder: BinaryDecoder[OutboundMessage] = OutboundMessageDecoder diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/VisualizationProtocolTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/VisualizationProtocolTest.scala index 6e1fbb10ab..c0d28463ee 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/VisualizationProtocolTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/VisualizationProtocolTest.scala @@ -2,7 +2,6 @@ package org.enso.languageserver.websocket.binary import java.nio.ByteBuffer import java.util.UUID - import org.enso.languageserver.protocol.binary.{ OutboundMessage, OutboundPayload, @@ -13,13 +12,15 @@ import org.enso.languageserver.runtime.ContextRegistryProtocol.{ VisualizationUpdate } import org.enso.languageserver.util.binary.BinaryDecoder +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec import org.scalatest.concurrent.Eventually class VisualizationProtocolTest extends BaseBinaryServerTest with Eventually - with FlakySpec { + with FlakySpec + with ReportLogsOnFailure { implicit private val decoder: BinaryDecoder[OutboundMessage] = OutboundMessageDecoder diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/CapabilitiesTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/CapabilitiesTest.scala index e9cb8acf63..3d1e32e736 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/CapabilitiesTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/CapabilitiesTest.scala @@ -3,11 +3,12 @@ package org.enso.languageserver.websocket.json import io.circe.literal._ import io.circe.parser.parse import io.circe.syntax.EncoderOps +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api import java.util.UUID -class CapabilitiesTest extends BaseServerTest { +class CapabilitiesTest extends BaseServerTest with ReportLogsOnFailure { "capability/acquire" must { diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ContextRegistryTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ContextRegistryTest.scala index 3ce6173390..9fd0f7e963 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ContextRegistryTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ContextRegistryTest.scala @@ -8,11 +8,12 @@ import org.enso.languageserver.runtime.{ import org.enso.languageserver.websocket.json.{ ExecutionContextJsonMessages => json } +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api import java.util.UUID -class ContextRegistryTest extends BaseServerTest { +class ContextRegistryTest extends BaseServerTest with ReportLogsOnFailure { "ContextRegistry" must { diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileManagerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileManagerTest.scala index 07d0a81c2a..2583ffd04e 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileManagerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileManagerTest.scala @@ -6,6 +6,7 @@ import org.apache.commons.io.FileUtils import org.bouncycastle.util.encoders.Hex import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} import org.enso.languageserver.data._ +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api import org.enso.testkit.RetrySpec @@ -16,7 +17,10 @@ import java.security.MessageDigest import java.util.UUID import scala.concurrent.duration._ -class FileManagerTest extends BaseServerTest with RetrySpec { +class FileManagerTest + extends BaseServerTest + with RetrySpec + with ReportLogsOnFailure { override def mkConfig: Config = { val directoriesDir = Files.createTempDirectory(null).toRealPath() diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileNotificationsTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileNotificationsTest.scala index aab7ef27d1..ab42f76782 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileNotificationsTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileNotificationsTest.scala @@ -2,11 +2,15 @@ package org.enso.languageserver.websocket.json import java.io.File import io.circe.literal._ +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api import org.enso.testkit.FlakySpec import org.enso.text.editing.model.{Position, Range, TextEdit} -class FileNotificationsTest extends BaseServerTest with FlakySpec { +class FileNotificationsTest + extends BaseServerTest + with FlakySpec + with ReportLogsOnFailure { def file(name: String): File = new File(testContentRoot.file, name) diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/InputOutputRedirectionTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/InputOutputRedirectionTest.scala index 39b6d4fcc8..d295b3d333 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/InputOutputRedirectionTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/InputOutputRedirectionTest.scala @@ -1,9 +1,13 @@ package org.enso.languageserver.websocket.json import io.circe.literal._ +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api import org.enso.testkit.RetrySpec -class InputOutputRedirectionTest extends BaseServerTest with RetrySpec { +class InputOutputRedirectionTest + extends BaseServerTest + with RetrySpec + with ReportLogsOnFailure { "Standard output redirection controller" must { diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/LibrariesTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/LibrariesTest.scala index fdb5b084a5..c0b4dba0ef 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/LibrariesTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/LibrariesTest.scala @@ -19,6 +19,7 @@ import org.enso.librarymanager.published.repository.{ ExampleRepository, LibraryManifest } +import org.enso.logger.ReportLogsOnFailure import org.enso.pkg.{Config, Contact, Package, PackageManager} import org.enso.yaml.YamlHelper @@ -26,7 +27,7 @@ import java.nio.file.Files import java.nio.file.Path import scala.concurrent.duration._ -class LibrariesTest extends BaseServerTest { +class LibrariesTest extends BaseServerTest with ReportLogsOnFailure { private val libraryRepositoryPort: Int = 47308 private val exampleRepo = new ExampleRepository( diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/MonitoringTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/MonitoringTest.scala index d071c9030b..05e608b474 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/MonitoringTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/MonitoringTest.scala @@ -1,9 +1,13 @@ package org.enso.languageserver.websocket.json import io.circe.literal._ +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec -class MonitoringTest extends BaseServerTest with FlakySpec { +class MonitoringTest + extends BaseServerTest + with FlakySpec + with ReportLogsOnFailure { "Monitoring subsystem" must { diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ProfilingManagerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ProfilingManagerTest.scala index 8b705e00df..3373335c95 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ProfilingManagerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ProfilingManagerTest.scala @@ -3,10 +3,11 @@ package org.enso.languageserver.websocket.json import org.enso.distribution.DistributionManager import org.enso.languageserver.profiling.ProfilingManager import org.enso.languageserver.runtime.RuntimeConnector +import org.enso.logger.ReportLogsOnFailure import java.nio.file.Files -class ProfilingManagerTest extends BaseServerTest { +class ProfilingManagerTest extends BaseServerTest with ReportLogsOnFailure { private val json = ProfilingJsonMessages diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ProjectSettingsManagerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ProjectSettingsManagerTest.scala index fdabbb17f3..c4ab3587b5 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ProjectSettingsManagerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ProjectSettingsManagerTest.scala @@ -2,10 +2,13 @@ package org.enso.languageserver.websocket.json import io.circe.literal._ import org.enso.distribution.FileSystem +import org.enso.logger.ReportLogsOnFailure import java.nio.file.Files -class ProjectSettingsManagerTest extends BaseServerTest { +class ProjectSettingsManagerTest + extends BaseServerTest + with ReportLogsOnFailure { override def beforeEach(): Unit = { super.beforeEach() diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ReceivesTreeUpdatesHandlerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ReceivesTreeUpdatesHandlerTest.scala index 8c67db844b..f54d7bf8ca 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ReceivesTreeUpdatesHandlerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/ReceivesTreeUpdatesHandlerTest.scala @@ -2,9 +2,13 @@ package org.enso.languageserver.websocket.json import java.nio.file.{Files, Paths} import io.circe.literal._ +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec -class ReceivesTreeUpdatesHandlerTest extends BaseServerTest with FlakySpec { +class ReceivesTreeUpdatesHandlerTest + extends BaseServerTest + with FlakySpec + with ReportLogsOnFailure { override val isFileWatcherEnabled = true diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/RefactoringTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/RefactoringTest.scala index 1ac8660a6c..24c58ff658 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/RefactoringTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/RefactoringTest.scala @@ -1,11 +1,12 @@ package org.enso.languageserver.websocket.json import io.circe.literal._ +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api import java.util.UUID -class RefactoringTest extends BaseServerTest { +class RefactoringTest extends BaseServerTest with ReportLogsOnFailure { "refactoring/renameProject" should { diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/RuntimeTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/RuntimeTest.scala index 91ec61cf88..fa9411cf67 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/RuntimeTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/RuntimeTest.scala @@ -2,9 +2,10 @@ package org.enso.languageserver.websocket.json import io.circe.literal._ import org.enso.languageserver.runtime.TestComponentGroups +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api -class RuntimeTest extends BaseServerTest { +class RuntimeTest extends BaseServerTest with ReportLogsOnFailure { "runtime/getComponentGroups" should { diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SessionManagementTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SessionManagementTest.scala index 05bdb840ff..d386dc83a8 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SessionManagementTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SessionManagementTest.scala @@ -3,8 +3,9 @@ package org.enso.languageserver.websocket.json import io.circe.literal._ import io.circe.parser.parse import io.circe.syntax.EncoderOps +import org.enso.logger.ReportLogsOnFailure -class SessionManagementTest extends BaseServerTest { +class SessionManagementTest extends BaseServerTest with ReportLogsOnFailure { "A server" when { diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerEventsTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerEventsTest.scala index 363e674a44..58fb28bcc8 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerEventsTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerEventsTest.scala @@ -3,6 +3,7 @@ package org.enso.languageserver.websocket.json import io.circe.literal._ import org.enso.languageserver.search.Suggestions import org.enso.languageserver.websocket.json.{SearchJsonMessages => json} +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.{ExportedSymbol, ModuleExports} import org.enso.polyglot.data.Tree import org.enso.polyglot.runtime.Runtime.Api @@ -10,7 +11,10 @@ import org.enso.testkit.FlakySpec import scala.collection.immutable.ListSet -class SuggestionsHandlerEventsTest extends BaseServerTest with FlakySpec { +class SuggestionsHandlerEventsTest + extends BaseServerTest + with FlakySpec + with ReportLogsOnFailure { "SuggestionsHandlerEvents" must { diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerTest.scala index 305730edd0..b5b1822eb9 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/SuggestionsHandlerTest.scala @@ -1,14 +1,15 @@ package org.enso.languageserver.websocket.json import java.util.UUID - import io.circe.literal._ import org.enso.languageserver.websocket.json.{SearchJsonMessages => json} +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.{FlakySpec, RetrySpec} class SuggestionsHandlerTest extends BaseServerTest with FlakySpec - with RetrySpec { + with RetrySpec + with ReportLogsOnFailure { "SuggestionsHandler" must { diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/TextOperationsTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/TextOperationsTest.scala index da205acac9..2db49965d7 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/TextOperationsTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/TextOperationsTest.scala @@ -5,6 +5,7 @@ import io.circe.literal._ import org.enso.languageserver.event.{BufferClosed, JsonSessionTerminated} import org.enso.languageserver.filemanager.Path import org.enso.languageserver.session.JsonSession +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api import org.enso.testkit.FlakySpec import org.enso.text.editing.model @@ -12,10 +13,12 @@ import org.enso.text.editing.model import java.io.File import java.nio.charset.StandardCharsets import java.nio.file.Files - import scala.concurrent.duration._ -class TextOperationsTest extends BaseServerTest with FlakySpec { +class TextOperationsTest + extends BaseServerTest + with FlakySpec + with ReportLogsOnFailure { override def isFileWatcherEnabled = true diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VcsManagerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VcsManagerTest.scala index 47dea4d495..0225da0858 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VcsManagerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VcsManagerTest.scala @@ -10,6 +10,7 @@ import org.eclipse.jgit.storage.file.FileRepositoryBuilder import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} import org.enso.languageserver.data._ import org.enso.languageserver.vcsmanager.VcsApi +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec import java.io.File @@ -19,7 +20,10 @@ import java.time.{Clock, LocalDate} import scala.concurrent.duration._ import scala.jdk.CollectionConverters._ -class VcsManagerTest extends BaseServerTest with FlakySpec { +class VcsManagerTest + extends BaseServerTest + with FlakySpec + with ReportLogsOnFailure { override def mkConfig: Config = { val directoriesDir = Files.createTempDirectory(null).toRealPath() diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VisualizationOperationsTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VisualizationOperationsTest.scala index cb44622117..7a8f58c581 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VisualizationOperationsTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VisualizationOperationsTest.scala @@ -5,10 +5,13 @@ import org.enso.languageserver.runtime.{ MethodPointer, VisualizationConfiguration } +import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api import org.enso.text.editing.model -class VisualizationOperationsTest extends BaseServerTest { +class VisualizationOperationsTest + extends BaseServerTest + with ReportLogsOnFailure { "executionContext/attachVisualization" must { diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/WorkspaceOperationsTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/WorkspaceOperationsTest.scala index 4a8d84a316..529ff7fff5 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/WorkspaceOperationsTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/WorkspaceOperationsTest.scala @@ -3,11 +3,15 @@ package org.enso.languageserver.websocket.json import buildinfo.Info import io.circe.literal.JsonStringContext import org.enso.languageserver.data.Config +import org.enso.logger.ReportLogsOnFailure import org.enso.testkit.FlakySpec import java.io.{File, FileOutputStream} -class WorkspaceOperationsTest extends BaseServerTest with FlakySpec { +class WorkspaceOperationsTest + extends BaseServerTest + with FlakySpec + with ReportLogsOnFailure { override def initializeProjectPackage: Boolean = false diff --git a/lib/scala/logging-config/src/main/java/org/enso/logger/LoggerSetup.java b/lib/scala/logging-config/src/main/java/org/enso/logger/LoggerSetup.java index 07cd36488d..a07a23211c 100644 --- a/lib/scala/logging-config/src/main/java/org/enso/logger/LoggerSetup.java +++ b/lib/scala/logging-config/src/main/java/org/enso/logger/LoggerSetup.java @@ -60,6 +60,14 @@ public abstract class LoggerSetup { */ public abstract boolean setupConsoleAppender(Level logLevel); + /** + * Setup writing logger's log event to a memory. + * + * @param logLevel the maximal level of logs that will be displayed + * @return true if logger was setup correctly, false otherwise + */ + public abstract boolean setupMemoryAppender(Level logLevel); + /** * Setup forwarding logger's log event to a sentry,io service. Requires the presence of the * sentry's dependency appropriate to the logging implementation. diff --git a/lib/scala/logging-config/src/main/java/org/enso/logger/config/Appender.java b/lib/scala/logging-config/src/main/java/org/enso/logger/config/Appender.java index 14ade68c15..85af339a2d 100644 --- a/lib/scala/logging-config/src/main/java/org/enso/logger/config/Appender.java +++ b/lib/scala/logging-config/src/main/java/org/enso/logger/config/Appender.java @@ -10,7 +10,7 @@ import org.slf4j.event.Level; * to do with the recorded log events */ public abstract sealed class Appender - permits FileAppender, SocketAppender, SentryAppender, ConsoleAppender { + permits ConsoleAppender, FileAppender, MemoryAppender, SentryAppender, SocketAppender { /** * Returns the name of the appender @@ -37,6 +37,8 @@ public abstract sealed class Appender return SentryAppender.parse(config); case ConsoleAppender.appenderName: return ConsoleAppender.parse(config); + case MemoryAppender.appenderName: + return MemoryAppender.parse(config); default: return null; } diff --git a/lib/scala/logging-config/src/main/java/org/enso/logger/config/LoggingServiceConfig.java b/lib/scala/logging-config/src/main/java/org/enso/logger/config/LoggingServiceConfig.java index 8462687b2f..d5f6926331 100644 --- a/lib/scala/logging-config/src/main/java/org/enso/logger/config/LoggingServiceConfig.java +++ b/lib/scala/logging-config/src/main/java/org/enso/logger/config/LoggingServiceConfig.java @@ -141,6 +141,10 @@ public class LoggingServiceConfig implements BaseConfig { return (ConsoleAppender) appenders.getOrDefault(ConsoleAppender.appenderName, null); } + public MemoryAppender getMemoryAppender() { + return (MemoryAppender) appenders.getOrDefault(MemoryAppender.appenderName, null); + } + public SentryAppender getSentryAppender() { return (SentryAppender) appenders.getOrDefault(SentryAppender.appenderName, null); } diff --git a/lib/scala/logging-config/src/main/java/org/enso/logger/config/MemoryAppender.java b/lib/scala/logging-config/src/main/java/org/enso/logger/config/MemoryAppender.java new file mode 100644 index 0000000000..ef77217f51 --- /dev/null +++ b/lib/scala/logging-config/src/main/java/org/enso/logger/config/MemoryAppender.java @@ -0,0 +1,54 @@ +package org.enso.logger.config; + +import com.typesafe.config.Config; +import java.nio.file.Path; +import org.enso.logger.LoggerSetup; +import org.slf4j.event.Level; + +/** + * Configuration for appender that keeps log events in memory and, optionally, forwards them to the + * underlying appneder. + */ +public final class MemoryAppender extends Appender { + + public static final String appenderName = "memory"; + + private final String forwardTo; + + private MemoryAppender(String forwardTo) { + this.forwardTo = forwardTo; + } + + public static MemoryAppender parse(Config config) { + String fowardTo = config.hasPath(forwardToKey) ? config.getString(forwardToKey) : "console"; + return new MemoryAppender(fowardTo); + } + + @Override + public boolean setup(Level logLevel, LoggerSetup appenderSetup) { + return appenderSetup.setupMemoryAppender(logLevel); + } + + @Override + public boolean setupForPath( + Level logLevel, Path logRoot, String logPrefix, LoggerSetup loggerSetup) { + LogToFile logToFileOpt = loggerSetup.getConfig().logToFile(); + if (logToFileOpt.enabled()) { + Level minLevel = + Level.intToLevel(Math.min(logToFileOpt.logLevel().toInt(), logLevel.toInt())); + loggerSetup.setupFileAppender(minLevel, logRoot, logPrefix); + } + return loggerSetup.setupMemoryAppender(logLevel); + } + + public String getTarget() { + return forwardTo; + } + + @Override + public String getName() { + return appenderName; + } + + private static final String forwardToKey = "forward-to"; +} diff --git a/lib/scala/logging-service-logback/src/main/java/org/enso/logger/LogbackSetup.java b/lib/scala/logging-service-logback/src/main/java/org/enso/logger/LogbackSetup.java index bb629a6590..2e2f759e08 100644 --- a/lib/scala/logging-service-logback/src/main/java/org/enso/logger/LogbackSetup.java +++ b/lib/scala/logging-service-logback/src/main/java/org/enso/logger/LogbackSetup.java @@ -151,7 +151,8 @@ public final class LogbackSetup extends LoggerSetup { } final PatternLayoutEncoder encoder = new PatternLayoutEncoder(); encoder.setPattern(appenderConfig.getPattern()); - env.finalizeEncoder(encoder); + encoder.setContext(env.ctx); + encoder.start(); FileAppender fileAppender; @@ -210,6 +211,13 @@ public final class LogbackSetup extends LoggerSetup { @Override public boolean setupConsoleAppender(Level logLevel) { LoggerAndContext env = contextInit(logLevel, config, !logToFileEnabled()); + var consoleAppender = getConsoleAppender(env.ctx, config); + env.finalizeAppender(consoleAppender); + return true; + } + + private ch.qos.logback.core.Appender getConsoleAppender( + LoggerContext ctx, LoggingServiceConfig config) { org.enso.logger.config.ConsoleAppender appenderConfig = config.getConsoleAppender(); final PatternLayoutEncoder encoder = new PatternLayoutEncoder(); try { @@ -222,13 +230,34 @@ public final class LogbackSetup extends LoggerSetup { e.printStackTrace(); encoder.setPattern(Appender.defaultPattern); } - env.finalizeEncoder(encoder); + encoder.setContext(ctx); + encoder.start(); ConsoleAppender consoleAppender = new ConsoleAppender<>(); consoleAppender.setName("enso-console"); consoleAppender.setEncoder(encoder); + return consoleAppender; + } - env.finalizeAppender(consoleAppender); + @Override + public boolean setupMemoryAppender(Level logLevel) { + LoggerAndContext env = contextInit(logLevel, config, !logToFileEnabled()); + org.enso.logger.config.MemoryAppender appenderConfig = config.getMemoryAppender(); + ch.qos.logback.core.Appender target; + switch (appenderConfig.getTarget()) { + case org.enso.logger.config.ConsoleAppender.appenderName: + target = getConsoleAppender(env.ctx, config); + break; + default: + target = null; + } + if (target == null) { + throw new RuntimeException("unsupported appender " + appenderConfig.getTarget()); + } + target.setContext(env.ctx); + target.start(); + var memoryAppender = new MemoryAppender(target); + env.finalizeAppender(memoryAppender); return true; } @@ -308,11 +337,6 @@ public final class LogbackSetup extends LoggerSetup { private record LoggerAndContext( Level level, LoggerContext ctx, Logger logger, Filter filter) { - void finalizeEncoder(ch.qos.logback.core.encoder.Encoder encoder) { - encoder.setContext(ctx); - encoder.start(); - } - void finalizeAppender(ch.qos.logback.core.Appender appender) { if (filter == null) { ThresholdFilter threshold = new ThresholdFilter(); diff --git a/lib/scala/logging-service-logback/src/main/java/org/enso/logger/MemoryAppender.java b/lib/scala/logging-service-logback/src/main/java/org/enso/logger/MemoryAppender.java new file mode 100644 index 0000000000..fd05de1216 --- /dev/null +++ b/lib/scala/logging-service-logback/src/main/java/org/enso/logger/MemoryAppender.java @@ -0,0 +1,59 @@ +package org.enso.logger; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.AppenderBase; +import java.util.ArrayList; +import java.util.List; + +/** + * Appender that keeps all log events internally and can either discard them or forward to the + * underlying appender. + */ +public class MemoryAppender extends AppenderBase { + private final Appender underlying; + + private final List events; + private volatile boolean forwardLogs; + + public MemoryAppender(Appender underlying) { + this.underlying = underlying; + this.events = new ArrayList<>(); + this.forwardLogs = true; + } + + protected void append(ILoggingEvent e) { + if (forwardLogs) { + underlying.doAppend(e); + } else { + events.add(e); + } + } + + public void reset() { + this.forwardLogs = true; + this.underlying.start(); + events.clear(); + } + + public void flush() { + // Ensure context set + underlying.start(); + for (var element : events) { + underlying.doAppend(element); + } + underlying.stop(); + } + + public void stopForwarding() { + this.forwardLogs = false; + this.underlying.stop(); + } + + @Override + public String getName() { + return NAME; + } + + public static final String NAME = "memory"; +} diff --git a/lib/scala/logging-service-logback/src/test/scala/org/enso/logger/ReportLogsOnFailure.scala b/lib/scala/logging-service-logback/src/test/scala/org/enso/logger/ReportLogsOnFailure.scala new file mode 100644 index 0000000000..06c123d383 --- /dev/null +++ b/lib/scala/logging-service-logback/src/test/scala/org/enso/logger/ReportLogsOnFailure.scala @@ -0,0 +1,51 @@ +package org.enso.logger + +import ch.qos.logback.classic.spi.ILoggingEvent +import ch.qos.logback.core.Appender +import org.scalatest.{Args, Failed, Outcome, Status, TestSuite} +import org.slf4j.{Logger, LoggerFactory} + +trait ReportLogsOnFailure extends TestSuite { + + private lazy val appender: Appender[ILoggingEvent] = { + val ctx = LoggerFactory.getILoggerFactory; + val rootLogger = ctx + .getLogger(Logger.ROOT_LOGGER_NAME) + .asInstanceOf[ch.qos.logback.classic.Logger] + rootLogger.getAppender(MemoryAppender.NAME) + } + + abstract override protected def runTest( + testName: String, + args: Args + ): Status = { + appender match { + case memoryAppender: MemoryAppender => + memoryAppender.stopForwarding() + super.runTest(testName, args) + case _ => + super.runTest(testName, args) + } + + } + + abstract override def withFixture(test: NoArgTest): Outcome = { + appender match { + case memoryAppender: MemoryAppender => + try { + super.withFixture(test) match { + case outcome @ Failed(_) => + memoryAppender.flush() + outcome + case outcome => + outcome + } + } finally { + memoryAppender.reset() + } + case _ => + super.withFixture(test) + } + } + +} diff --git a/lib/scala/project-manager/src/test/resources/application-test.conf b/lib/scala/project-manager/src/test/resources/application-test.conf index b1a7f8f0c7..688e6b1c3b 100644 --- a/lib/scala/project-manager/src/test/resources/application-test.conf +++ b/lib/scala/project-manager/src/test/resources/application-test.conf @@ -10,12 +10,16 @@ logging-service { akka = error } appenders = [ + { + name = "memory" + forward-to = console + }, { name = "console" pattern = "[%level{lowercase=true}] [%d{yyyy-MM-dd'T'HH:mm:ssXXX}] [%logger] %msg%n%nopex" } ] - default-appender = console + default-appender = memory log-level = "warn" } diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/LanguageServerGatewaySpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/LanguageServerGatewaySpec.scala index 73f66039e0..a6bf281020 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/LanguageServerGatewaySpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/LanguageServerGatewaySpec.scala @@ -3,6 +3,7 @@ package org.enso.projectmanager.infrastructure.languageserver import akka.testkit.TestDuration import io.circe.literal._ import nl.gn0s1s.bump.SemVer +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.test.Net._ import org.enso.projectmanager.{BaseServerSpec, ProjectManagementOps} import org.enso.runtimeversionmanager.test.OverrideTestVersionSuite @@ -13,7 +14,8 @@ import scala.concurrent.duration._ class LanguageServerGatewaySpec extends BaseServerSpec with OverrideTestVersionSuite - with ProjectManagementOps { + with ProjectManagementOps + with ReportLogsOnFailure { override val testVersion: SemVer = SemVer(0, 0, 1) diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/LanguageServerSupervisorSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/LanguageServerSupervisorSpec.scala index 4e0225776e..32d7d7e0d8 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/LanguageServerSupervisorSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/LanguageServerSupervisorSpec.scala @@ -3,6 +3,7 @@ package org.enso.projectmanager.infrastructure.languageserver import akka.actor.{ActorRef, ActorSystem, Props} import akka.testkit.{ImplicitSender, TestActor, TestKit, TestProbe} import com.miguno.akka.testing.VirtualTime +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.boot.configuration.SupervisionConfig import org.enso.projectmanager.infrastructure.http.AkkaBasedWebSocketConnectionFactory import org.enso.projectmanager.infrastructure.languageserver.LanguageServerBootLoader.ServerBooted @@ -27,7 +28,8 @@ class LanguageServerSupervisorSpec with Matchers with BeforeAndAfterAll with MockitoSugar - with FlakySpec { + with FlakySpec + with ReportLogsOnFailure { "A language supervisor" should "monitor language server by sending ping requests on regular basis" taggedAs Flaky in new TestCtx { //given diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/ProjectRenameActionSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/ProjectRenameActionSpec.scala index f7108c06ac..1e1dd846a3 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/ProjectRenameActionSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/infrastructure/languageserver/ProjectRenameActionSpec.scala @@ -3,6 +3,7 @@ package org.enso.projectmanager.infrastructure.languageserver import akka.actor.ActorSystem import akka.testkit._ import com.miguno.akka.testing.VirtualTime +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.data.Socket import org.enso.projectmanager.infrastructure.languageserver.LanguageServerProtocol.{ ProjectRenamed, @@ -26,7 +27,8 @@ class ProjectRenameActionSpec with Matchers with BeforeAndAfterAll with MockitoSugar - with FlakySpec { + with FlakySpec + with ReportLogsOnFailure { "A project rename action" should "delegate request to the Language Server" taggedAs Flaky in new TestCtx { //given diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ConfigApiSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ConfigApiSpec.scala index 2a844496a2..722259e766 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ConfigApiSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ConfigApiSpec.scala @@ -1,13 +1,15 @@ package org.enso.projectmanager.protocol import io.circe.literal._ +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.{BaseServerSpec, ProjectManagementOps} import org.enso.testkit.FlakySpec class ConfigApiSpec extends BaseServerSpec with FlakySpec - with ProjectManagementOps { + with ProjectManagementOps + with ReportLogsOnFailure { "global-config/get" must { "return none for missing keys" in { diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/EngineManagementApiSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/EngineManagementApiSpec.scala index b525109bd0..62d050116c 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/EngineManagementApiSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/EngineManagementApiSpec.scala @@ -2,12 +2,16 @@ package org.enso.projectmanager.protocol import akka.testkit.TestDuration import io.circe.literal._ +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.BaseServerSpec import org.enso.testkit.FlakySpec import scala.concurrent.duration.DurationInt -class EngineManagementApiSpec extends BaseServerSpec with FlakySpec { +class EngineManagementApiSpec + extends BaseServerSpec + with FlakySpec + with ReportLogsOnFailure { "engine/*" must { "report no installed engines by default" in { diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/LoggingServiceEndpointSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/LoggingServiceEndpointSpec.scala index 006afcb20d..2a71ecf41d 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/LoggingServiceEndpointSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/LoggingServiceEndpointSpec.scala @@ -1,13 +1,17 @@ package org.enso.projectmanager.protocol import io.circe.literal.JsonStringContext +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.BaseServerSpec import org.enso.testkit.FlakySpec import scala.concurrent.Future import java.net.URI -class LoggingServiceEndpointSpec extends BaseServerSpec with FlakySpec { +class LoggingServiceEndpointSpec + extends BaseServerSpec + with FlakySpec + with ReportLogsOnFailure { class TestException extends RuntimeException { override def toString: String = "test-exception" diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateDefaultToLatestSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateDefaultToLatestSpec.scala index 0d63713e69..e6e29bb02b 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateDefaultToLatestSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateDefaultToLatestSpec.scala @@ -2,12 +2,14 @@ package org.enso.projectmanager.protocol import io.circe.literal.JsonStringContext import nl.gn0s1s.bump.SemVer +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.BaseServerSpec import org.enso.runtimeversionmanager.test.OverrideTestVersionSuite class ProjectCreateDefaultToLatestSpec extends BaseServerSpec - with OverrideTestVersionSuite { + with OverrideTestVersionSuite + with ReportLogsOnFailure { override val testVersion: SemVer = SemVer(0, 1, 0) diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateHandleMissingRuntimeSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateHandleMissingRuntimeSpec.scala index b87f11c5b5..eba353ca84 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateHandleMissingRuntimeSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateHandleMissingRuntimeSpec.scala @@ -1,10 +1,13 @@ package org.enso.projectmanager.protocol +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.TestDistributionConfiguration import org.enso.runtimeversionmanager.runner.JVMSettings import org.enso.runtimeversionmanager.test.FakeReleases -class ProjectCreateHandleMissingRuntimeSpec extends ProjectCreateSpecBase { +class ProjectCreateHandleMissingRuntimeSpec + extends ProjectCreateSpecBase + with ReportLogsOnFailure { override val distributionConfiguration = new TestDistributionConfiguration( distributionRoot = testDistributionRoot.toPath, diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateMissingComponentsSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateMissingComponentsSpec.scala index e0205168da..31928b20ba 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateMissingComponentsSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectCreateMissingComponentsSpec.scala @@ -1,6 +1,10 @@ package org.enso.projectmanager.protocol -class ProjectCreateMissingComponentsSpec extends ProjectCreateSpecBase { +import org.enso.logger.ReportLogsOnFailure + +class ProjectCreateMissingComponentsSpec + extends ProjectCreateSpecBase + with ReportLogsOnFailure { "project/create" should { behave like correctlyHandleMissingComponents() } diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectManagementApiSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectManagementApiSpec.scala index 0ea829f004..fdef060445 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectManagementApiSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectManagementApiSpec.scala @@ -4,6 +4,7 @@ import akka.testkit.TestDuration import io.circe.literal._ import nl.gn0s1s.bump.SemVer import org.apache.commons.io.FileUtils +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.boot.configuration.TimeoutConfig import org.enso.projectmanager.{BaseServerSpec, ProjectManagementOps} import org.enso.runtimeversionmanager.CurrentVersion @@ -14,7 +15,6 @@ import org.scalactic.source.Position import java.io.File import java.nio.file.{Files, Paths} import java.util.UUID - import scala.concurrent.duration._ import scala.io.Source @@ -22,7 +22,8 @@ class ProjectManagementApiSpec extends BaseServerSpec with FlakySpec with OverrideTestVersionSuite - with ProjectManagementOps { + with ProjectManagementOps + with ReportLogsOnFailure { override val testVersion: SemVer = SemVer(0, 0, 1) diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectOpenMissingComponentsSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectOpenMissingComponentsSpec.scala index 910d563cfc..66d2c4d3f8 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectOpenMissingComponentsSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectOpenMissingComponentsSpec.scala @@ -1,10 +1,12 @@ package org.enso.projectmanager.protocol import nl.gn0s1s.bump.SemVer +import org.enso.logger.ReportLogsOnFailure import org.enso.runtimeversionmanager.test.OverrideTestVersionSuite class ProjectOpenMissingComponentsSpec extends ProjectOpenSpecBase - with OverrideTestVersionSuite { + with OverrideTestVersionSuite + with ReportLogsOnFailure { override val testVersion: SemVer = defaultVersion diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectShutdownSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectShutdownSpec.scala index 35104ddfaa..7433356417 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectShutdownSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/protocol/ProjectShutdownSpec.scala @@ -4,6 +4,7 @@ import akka.actor.ActorRef import io.circe.literal._ import nl.gn0s1s.bump.SemVer import org.enso.jsonrpc.ClientControllerFactory +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.boot.configuration.TimeoutConfig import org.enso.projectmanager.event.ClientEvent.ClientDisconnected import zio.{ZAny, ZIO} @@ -20,7 +21,8 @@ class ProjectShutdownSpec extends BaseServerSpec with FlakySpec with OverrideTestVersionSuite - with ProjectManagementOps { + with ProjectManagementOps + with ReportLogsOnFailure { override val testVersion: SemVer = SemVer(0, 0, 1) diff --git a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/service/validation/ProjectNameValidatorSpec.scala b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/service/validation/ProjectNameValidatorSpec.scala index 373f0c4742..3df79af585 100644 --- a/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/service/validation/ProjectNameValidatorSpec.scala +++ b/lib/scala/project-manager/src/test/scala/org/enso/projectmanager/service/validation/ProjectNameValidatorSpec.scala @@ -1,5 +1,6 @@ package org.enso.projectmanager.service.validation +import org.enso.logger.ReportLogsOnFailure import org.enso.projectmanager.control.effect.Effects import org.scalatest.EitherValues import org.scalatest.matchers.must.Matchers @@ -11,7 +12,8 @@ class ProjectNameValidatorSpec extends AnyWordSpec with Matchers with EitherValues - with Effects { + with Effects + with ReportLogsOnFailure { val projectNameValidator = new ProjectNameValidator[ZIO[ZAny, *, *]]()