From 0a60366ac97bca4d21acc18c9e2c95fd5dc58de8 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Fri, 17 May 2024 14:43:41 +0200 Subject: [PATCH 01/16] chore: improve dependency handling and remove the mongodb driver (we will use datagrip to query) --- build.gradle.kts | 5 +++++ gradle/libs.versions.toml | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index ce95561c..2bf5258f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -38,6 +38,11 @@ subprojects { val testImplementation by configurations val compileOnly by configurations + configurations.named("runtimeClasspath").configure { + exclude("org.jetbrains.kotlin") + exclude("org.jetbrains.kotlinx") + } + compileOnly(rootProject.libs.kotlin.stdlib) testImplementation(rootProject.libs.testing.jupiter.engine) testImplementation(rootProject.libs.testing.jupiter.vintage.engine) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 40bcf1b4..423581bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,10 +14,8 @@ diktat-plugin="1.0.1" jmhreport-plugin="0.9.0" # Library dependencies -bson="5.0.0" -mongodb-driver="4.11.0" kotlin-stdlib="1.9.22" -kotlinx-coroutines="1.8.0-RC2" +kotlinx-coroutines="1.7.3" jupiter="5.10.2" mockito="5.11.0" mockito-kotlin="5.3.1" @@ -37,19 +35,19 @@ changelog={ id="org.jetbrains.changelog", version.ref="intellij-changelog-plugin jmhreport={ id="io.morethan.jmhreport", version.ref="jmhreport-plugin" } [libraries] -mongodb-bson={ group="org.mongodb", name="bson", version.ref="bson" } -mongodb-driver={ group="org.mongodb", name="mongodb-driver-kotlin-coroutine", version.ref="mongodb-driver" } - +## Kotlin compileOnly libraries. They must not be bundled because they are already part of the +## JetBrains ecosystem. kotlin-stdlib={ group="org.jetbrains.kotlin", name="kotlin-stdlib", version.ref="kotlin-stdlib" } kotlin-coroutines-core={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-core", version.ref="kotlinx-coroutines" } kotlin-coroutines-swing={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-swing", version.ref="kotlinx-coroutines" } kotlin-coroutines-test={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-test", version.ref="kotlinx-coroutines" } - +###################################################### +## Production Libraries. segment={ group="com.segment.analytics.java", name="analytics", version.ref="segment" } - +###################################################### +## Testing Libraries. testing-jupiter-engine={ group="org.junit.jupiter", name="junit-jupiter-engine", version.ref="jupiter" } testing-jupiter-vintage-engine={ group="org.junit.vintage", name="junit-vintage-engine", version.ref="jupiter" } - testing-jsoup= { group="org.jsoup", name="jsoup", version.ref="jsoup" } testing-mockito-core={ group="org.mockito", name="mockito-core", version.ref="mockito" } testing-mockito-kotlin={ group="org.mockito.kotlin", name="mockito-kotlin", version.ref="mockito-kotlin" } @@ -65,7 +63,9 @@ testing-remoteRobotDeps-retrofitGson={ group="com.squareup.retrofit2", name="con testing-jmh-core={ group="org.openjdk.jmh", name="jmh-core", version.ref="jmh" } testing-jmh-annotationProcessor={ group="org.openjdk.jmh", name="jmh-generator-annprocess", version.ref="jmh" } testing-jmh-generatorByteCode={ group="org.openjdk.jmh", name="jmh-generator-bytecode", version.ref="jmh" } - +###################################################### +## Libraries and plugins only used for the buildScript. buildScript-plugin-kotlin={ group="org.jetbrains.kotlin", name="kotlin-gradle-plugin", version="1.9.23" } buildScript-plugin-versions={ group="com.github.ben-manes", name="gradle-versions-plugin", version.ref="versions-plugin" } buildScript-plugin-spotless={ group="com.diffplug.spotless", name="spotless-plugin-gradle", version="6.25.0" } +###################################################### \ No newline at end of file From eeafd9b8b71af9dcafb852dfd8afda8ccbfde476 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Fri, 17 May 2024 14:46:06 +0200 Subject: [PATCH 02/16] chore: do not use the driverVersion in tests --- packages/jetbrains-plugin/build.gradle.kts | 1 - .../main/kotlin/com/mongodb/jbplugin/meta/BuildInformation.kt | 1 - .../kotlin/com/mongodb/jbplugin/meta/BuildInformationTest.kt | 3 ++- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/jetbrains-plugin/build.gradle.kts b/packages/jetbrains-plugin/build.gradle.kts index f9f2be44..e1779a10 100644 --- a/packages/jetbrains-plugin/build.gradle.kts +++ b/packages/jetbrains-plugin/build.gradle.kts @@ -83,7 +83,6 @@ tasks { destinationFile.set(project.layout.projectDirectory.file("src/main/resources/build.properties")) property("pluginVersion", rootProject.version) - property("driverVersion", rootProject.libs.versions.mongodb.driver.get()) property("segmentApiKey", System.getenv("BUILD_SEGMENT_API_KEY") ?: "") } diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/meta/BuildInformation.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/meta/BuildInformation.kt index 246bf078..6aef96a6 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/meta/BuildInformation.kt +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/meta/BuildInformation.kt @@ -17,6 +17,5 @@ object BuildInformation { it.load(BuildInformation::class.java.getResourceAsStream("/build.properties")) } val pluginVersion = properties["pluginVersion"]!!.toString() - val driverVersion = properties["driverVersion"]!!.toString() val segmentApiKey = properties["segmentApiKey"]!!.toString() } diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/meta/BuildInformationTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/meta/BuildInformationTest.kt index c9858e5c..d83052c9 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/meta/BuildInformationTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/meta/BuildInformationTest.kt @@ -1,12 +1,13 @@ package com.mongodb.jbplugin.meta import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Test class BuildInformationTest { @Test fun `loads all build information from the resource file`() { - assertEquals("4.11.0", BuildInformation.driverVersion) + assertNotNull(BuildInformation.pluginVersion) assertEquals("", BuildInformation.segmentApiKey) } } From 784fa234657b256efc9fb0bde58ca084b81435a0 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Fri, 17 May 2024 18:40:08 +0200 Subject: [PATCH 03/16] chore: example query infrastructure --- gradle/libs.versions.toml | 3 +- .../ActivatePluginPostStartupActivity.kt | 22 ++++++++ .../com/mongodb/jbplugin/SayHiListener.kt | 29 ----------- .../jbplugin/dataaccess/BaseAccessAdapter.kt | 50 +++++++++++++++++++ .../dataaccess/DataGripQueryAdapter.kt | 36 +++++++++++++ .../dataaccess/ServerInfoRepository.kt | 24 +++++++++ .../actions/GetMongoDBVersionAction.kt | 37 ++++++++++++++ .../src/main/resources/META-INF/plugin.xml | 8 ++- ... ActivatePluginPostStartupActivityTest.kt} | 4 +- ...ctivatePluginPostStartupActivityUiTest.kt} | 5 +- .../mongodb-access-adapter/build.gradle.kts | 3 ++ 11 files changed, 184 insertions(+), 37 deletions(-) create mode 100644 packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivity.kt delete mode 100644 packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/SayHiListener.kt create mode 100644 packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/BaseAccessAdapter.kt create mode 100644 packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/DataGripQueryAdapter.kt create mode 100644 packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/ServerInfoRepository.kt create mode 100644 packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt rename packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/{SayHiListenerTest.kt => ActivatePluginPostStartupActivityTest.kt} (84%) rename packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/{SayHiListenerUiTest.kt => ActivatePluginPostStartupActivityUiTest.kt} (81%) create mode 100644 packages/mongodb-access-adapter/build.gradle.kts diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 423581bd..55abd7aa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,6 @@ spotless-plugin="6.25.0" jmh-plugin="0.7.2" diktat-plugin="1.0.1" jmhreport-plugin="0.9.0" - # Library dependencies kotlin-stdlib="1.9.22" kotlinx-coroutines="1.7.3" @@ -25,6 +24,7 @@ jmh="1.37" segment="3.5.1" jsoup="1.17.2" video-recorder="2.0" +gson="2.10.1" [plugins] intellij={ id="org.jetbrains.intellij", version.ref="intellij-plugin" } @@ -44,6 +44,7 @@ kotlin-coroutines-test={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines ###################################################### ## Production Libraries. segment={ group="com.segment.analytics.java", name="analytics", version.ref="segment" } +gson={ group="com.google.code.gson", name="gson", version.ref="gson" } ###################################################### ## Testing Libraries. testing-jupiter-engine={ group="org.junit.jupiter", name="junit-jupiter-engine", version.ref="jupiter" } diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivity.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivity.kt new file mode 100644 index 00000000..030e29c5 --- /dev/null +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivity.kt @@ -0,0 +1,22 @@ +package com.mongodb.jbplugin + +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.StartupActivity +import com.mongodb.jbplugin.observability.probe.PluginActivatedProbe +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +/** + * This notifies that the plugin has been activated. + * + * @param cs + */ +class ActivatePluginPostStartupActivity(private val cs: CoroutineScope) : StartupActivity, DumbAware { + override fun runActivity(project: Project) { + cs.launch { + val pluginActivated = project.getService(PluginActivatedProbe::class.java) + pluginActivated.pluginActivated() + } + } +} diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/SayHiListener.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/SayHiListener.kt deleted file mode 100644 index 86391a18..00000000 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/SayHiListener.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.mongodb.jbplugin - -import com.intellij.openapi.project.DumbAware -import com.intellij.openapi.project.Project -import com.intellij.openapi.rd.util.launchChildOnUi -import com.intellij.openapi.startup.StartupActivity -import com.intellij.openapi.ui.Messages -import com.mongodb.jbplugin.meta.BuildInformation -import com.mongodb.jbplugin.observability.probe.PluginActivatedProbe -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch - -/** - * Example listener, we will get rid of this. - * - * @param cs - */ -class SayHiListener(private val cs: CoroutineScope) : StartupActivity, DumbAware { - override fun runActivity(project: Project) { - val pluginActivated = project.getService(PluginActivatedProbe::class.java) - - cs.launch { - pluginActivated.pluginActivated() - cs.launchChildOnUi { - Messages.showInfoMessage(project, BuildInformation.driverVersion, "Build Info") - } - } - } -} diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/BaseAccessAdapter.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/BaseAccessAdapter.kt new file mode 100644 index 00000000..6bf3a0dd --- /dev/null +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/BaseAccessAdapter.kt @@ -0,0 +1,50 @@ +package com.mongodb.jbplugin.dataaccess + +import com.google.gson.Gson +import com.intellij.database.console.session.DatabaseSession +import com.intellij.database.console.session.DatabaseSessionManager +import com.intellij.database.dataSource.LocalDataSource +import com.intellij.openapi.project.Project +import kotlinx.coroutines.* +import java.util.concurrent.TimeoutException +import java.util.concurrent.atomic.AtomicBoolean +import kotlin.coroutines.resume +import kotlin.time.Duration + +internal class BaseAccessAdapter( + private val project: Project, + private val dataSource: LocalDataSource +) { + private val gson = Gson() + + suspend inline fun runQuery(queryString: String, timeout: Duration): List = withContext(Dispatchers.IO) { + suspendCancellableCoroutine { callback -> + val session = getSession() + val hasFinished = AtomicBoolean(false) + + launch { + val query = DataGripQueryAdapter(queryString, T::class.java, gson, session) { + if (!hasFinished.compareAndSet(false, true)) { + callback.resume(it) + } + } + + session.messageBus.dataProducer.processRequest(query) + + delay(timeout) + if (!hasFinished.compareAndSet(false, true)) { + callback.cancel(TimeoutException("Timeout running query '$queryString'")) + } + } + } + } + + private fun getSession(): DatabaseSession { + val sessions = DatabaseSessionManager.getSessions(project, dataSource) + if (sessions.isEmpty()) { + return DatabaseSessionManager.openSession(project, dataSource, "mongodb") + } + + return sessions[0] + } +} \ No newline at end of file diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/DataGripQueryAdapter.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/DataGripQueryAdapter.kt new file mode 100644 index 00000000..7f0f8a97 --- /dev/null +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/DataGripQueryAdapter.kt @@ -0,0 +1,36 @@ +package com.mongodb.jbplugin.dataaccess + +import com.google.gson.Gson +import com.intellij.database.dataSource.DatabaseConnectionCore +import com.intellij.database.datagrid.DataRequest + +internal class DataGripQueryAdapter( + private val queryScript: String, + private val resultClass: Class, + private val gson: Gson, + ownerEx: OwnerEx, + private val continuation: (List) -> Unit, +): DataRequest.RawRequest(ownerEx) { + override fun processRaw(p0: Context?, p1: DatabaseConnectionCore?) { + val remoteConnection = p1!!.remoteConnection + val statement = remoteConnection.prepareStatement(queryScript.trimIndent()) + + val listOfResults = mutableListOf() + val resultSet = statement.executeQuery() + + if (resultClass.isPrimitive || resultClass == String::class.java) { + while (resultSet.next()) { + listOfResults.add(resultSet.getObject(1) as T) + } + } else { + while (resultSet.next()) { + val hashMap = resultSet.getObject(1) as Map + val result = gson.fromJson(gson.toJson(hashMap), resultClass) + listOfResults.add(result) + } + } + + continuation(listOfResults) + } + +} \ No newline at end of file diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/ServerInfoRepository.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/ServerInfoRepository.kt new file mode 100644 index 00000000..06e48850 --- /dev/null +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/ServerInfoRepository.kt @@ -0,0 +1,24 @@ +package com.mongodb.jbplugin.dataaccess + +import com.intellij.database.dataSource.LocalDataSource +import com.intellij.openapi.components.Service +import com.intellij.openapi.project.Project +import kotlin.time.Duration.Companion.seconds + +data class ServerInfo(val version: String) + +@Service(Service.Level.PROJECT) +class ServerInfoRepository( + private val project: Project +) { + suspend fun getServerInfo(ds: LocalDataSource): ServerInfo { + val (versionString) = BaseAccessAdapter(project, ds).runQuery( + """ + db.version() + """.trimIndent(), + timeout = 1.seconds + ) + + return ServerInfo(versionString) + } +} \ No newline at end of file diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt new file mode 100644 index 00000000..5c993bcb --- /dev/null +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt @@ -0,0 +1,37 @@ +package com.mongodb.jbplugin.observability.actions + +import com.intellij.database.dataSource.localDataSource +import com.intellij.database.psi.DbDataSource +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.components.Service +import com.intellij.openapi.rd.util.launchChildOnUi +import com.intellij.openapi.ui.Messages +import com.mongodb.jbplugin.dataaccess.ServerInfoRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +@Service(Service.Level.PROJECT) +class GetMongoDBVersionActionService( + private val coroutineScope: CoroutineScope +) { + fun actionPerformed(event: AnActionEvent) { + coroutineScope.launch { + val repository = event.project!!.getService(ServerInfoRepository::class.java) + val dataSource = event.dataContext.getData(PlatformDataKeys.PSI_ELEMENT) as DbDataSource + + val buildInfo = repository.getServerInfo(dataSource.localDataSource!!) + + coroutineScope.launchChildOnUi { + Messages.showMessageDialog(buildInfo.version, "Show DB Version", null) + } + } + } +} + +class GetMongoDBVersionAction: AnAction() { + override fun actionPerformed(event: AnActionEvent) { + event.project!!.getService(GetMongoDBVersionActionService::class.java).actionPerformed(event) + } +} \ No newline at end of file diff --git a/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml b/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml index 0f527d95..07f46cd7 100644 --- a/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml +++ b/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml @@ -10,8 +10,14 @@ com.intellij.database - + + + + + + \ No newline at end of file diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/SayHiListenerTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivityTest.kt similarity index 84% rename from packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/SayHiListenerTest.kt rename to packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivityTest.kt index f982a3b4..7c1a8f26 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/SayHiListenerTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivityTest.kt @@ -11,12 +11,12 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking -class SayHiListenerTest { +class ActivatePluginPostStartupActivityTest { @Test fun `emits a plugin activated probe`() = runBlocking { val pluginActivatedProbe = mock() val project = mockProject(pluginActivatedProbe = pluginActivatedProbe) - val listener = SayHiListener(CoroutineScope(Dispatchers.Default)) + val listener = ActivatePluginPostStartupActivity(CoroutineScope(Dispatchers.Default)) listener.runActivity(project) diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/SayHiListenerUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivityUiTest.kt similarity index 81% rename from packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/SayHiListenerUiTest.kt rename to packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivityUiTest.kt index 9cbf567b..3a251ad9 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/SayHiListenerUiTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivityUiTest.kt @@ -5,20 +5,17 @@ import com.mongodb.jbplugin.fixtures.RequiresProject import com.mongodb.jbplugin.fixtures.UiTest import com.mongodb.jbplugin.fixtures.components.SayHelloMessageBoxFixture import com.mongodb.jbplugin.fixtures.findVisible -import com.mongodb.jbplugin.meta.BuildInformation import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @UiTest -class SayHiListenerUiTest { +class ActivatePluginPostStartupActivityUiTest { @Test @RequiresProject("basic-java-project-with-mongodb") fun `shows a notification message`(remoteRobot: RemoteRobot) { val sayHelloMessageBox = remoteRobot.findVisible() assertEquals("Build Info", sayHelloMessageBox.title) - assertEquals(BuildInformation.driverVersion, sayHelloMessageBox.body) - sayHelloMessageBox.ok() } } diff --git a/packages/mongodb-access-adapter/build.gradle.kts b/packages/mongodb-access-adapter/build.gradle.kts new file mode 100644 index 00000000..0ce6a166 --- /dev/null +++ b/packages/mongodb-access-adapter/build.gradle.kts @@ -0,0 +1,3 @@ +dependencies { + +} \ No newline at end of file From 620ebe86415bbf152f5c0e73cbb3767308e744cf Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Tue, 21 May 2024 19:19:08 +0200 Subject: [PATCH 04/16] chore: draft how accessing mongodb will work --- build.gradle.kts | 2 + gradle/libs.versions.toml | 5 ++ packages/jetbrains-plugin/build.gradle.kts | 2 + .../dataaccess/ServerInfoRepository.kt | 24 --------- .../actions/GetMongoDBVersionAction.kt | 8 +-- .../mongodb-access-adapter/build.gradle.kts | 3 +- .../datagrip-access-adapter/build.gradle.kts | 22 ++++++++ .../DataGripBasedReadModelProvider.kt | 40 ++++++++++++++ .../datagrip/adapter/DataGripMongoDBDriver.kt | 53 +++++++++++++++++++ .../datagrip/adapter}/DataGripQueryAdapter.kt | 5 +- .../datagrip/adapter/DataSourceQuery.kt} | 12 +++-- .../jbplugin/accessadapter/MongoDBDriver.kt | 27 ++++++++++ .../accessadapter/MongoDBReadModelProvider.kt | 9 ++++ .../accessadapter/slice/BuildInfoSlice.kt | 20 +++++++ .../accessadapter/MongoDBDriverTest.kt | 48 +++++++++++++++++ .../accessadapter/slice/BuildInfoSliceTest.kt | 21 ++++++++ settings.gradle.kts | 1 + 17 files changed, 265 insertions(+), 37 deletions(-) delete mode 100644 packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/ServerInfoRepository.kt create mode 100644 packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts create mode 100644 packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt create mode 100644 packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDBDriver.kt rename packages/{jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess => mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter}/DataGripQueryAdapter.kt (92%) rename packages/{jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/BaseAccessAdapter.kt => mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataSourceQuery.kt} (78%) create mode 100644 packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriver.kt create mode 100644 packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBReadModelProvider.kt create mode 100644 packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSlice.kt create mode 100644 packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriverTest.kt create mode 100644 packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSliceTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 2bf5258f..b4f6cd36 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -44,6 +44,8 @@ subprojects { } compileOnly(rootProject.libs.kotlin.stdlib) + compileOnly(rootProject.libs.kotlin.coroutines.core) + compileOnly(rootProject.libs.kotlin.reflect) testImplementation(rootProject.libs.testing.jupiter.engine) testImplementation(rootProject.libs.testing.jupiter.vintage.engine) testImplementation(rootProject.libs.testing.mockito.core) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 55abd7aa..e2f41574 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,6 +25,8 @@ segment="3.5.1" jsoup="1.17.2" video-recorder="2.0" gson="2.10.1" +mongodb-driver="5.1.0" +owasp-encoder="1.2.3" [plugins] intellij={ id="org.jetbrains.intellij", version.ref="intellij-plugin" } @@ -38,6 +40,7 @@ jmhreport={ id="io.morethan.jmhreport", version.ref="jmhreport-plugin" } ## Kotlin compileOnly libraries. They must not be bundled because they are already part of the ## JetBrains ecosystem. kotlin-stdlib={ group="org.jetbrains.kotlin", name="kotlin-stdlib", version.ref="kotlin-stdlib" } +kotlin-reflect={ group="org.jetbrains.kotlin", name="kotlin-reflect", version.ref="kotlin-stdlib" } kotlin-coroutines-core={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-core", version.ref="kotlinx-coroutines" } kotlin-coroutines-swing={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-swing", version.ref="kotlinx-coroutines" } kotlin-coroutines-test={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-test", version.ref="kotlinx-coroutines" } @@ -45,6 +48,8 @@ kotlin-coroutines-test={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines ## Production Libraries. segment={ group="com.segment.analytics.java", name="analytics", version.ref="segment" } gson={ group="com.google.code.gson", name="gson", version.ref="gson" } +mongodb-driver={ group="org.mongodb", name="mongodb-driver-kotlin-sync", version.ref="mongodb-driver" } +owasp-encoder={ group="org.owasp.encoder", name="encoder", version.ref="owasp-encoder" } ###################################################### ## Testing Libraries. testing-jupiter-engine={ group="org.junit.jupiter", name="junit-jupiter-engine", version.ref="jupiter" } diff --git a/packages/jetbrains-plugin/build.gradle.kts b/packages/jetbrains-plugin/build.gradle.kts index e1779a10..3099119c 100644 --- a/packages/jetbrains-plugin/build.gradle.kts +++ b/packages/jetbrains-plugin/build.gradle.kts @@ -24,11 +24,13 @@ intellij { dependencies { implementation(project(":packages:mongodb-access-adapter")) + implementation(project(":packages:mongodb-access-adapter:datagrip-access-adapter")) implementation(project(":packages:mongodb-autocomplete-engine")) implementation(project(":packages:mongodb-dialects")) implementation(project(":packages:mongodb-linting-engine")) implementation(project(":packages:mongodb-mql-model")) + implementation(libs.mongodb.driver) implementation(libs.segment) jmh(libs.kotlin.stdlib) diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/ServerInfoRepository.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/ServerInfoRepository.kt deleted file mode 100644 index 06e48850..00000000 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/ServerInfoRepository.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.mongodb.jbplugin.dataaccess - -import com.intellij.database.dataSource.LocalDataSource -import com.intellij.openapi.components.Service -import com.intellij.openapi.project.Project -import kotlin.time.Duration.Companion.seconds - -data class ServerInfo(val version: String) - -@Service(Service.Level.PROJECT) -class ServerInfoRepository( - private val project: Project -) { - suspend fun getServerInfo(ds: LocalDataSource): ServerInfo { - val (versionString) = BaseAccessAdapter(project, ds).runQuery( - """ - db.version() - """.trimIndent(), - timeout = 1.seconds - ) - - return ServerInfo(versionString) - } -} \ No newline at end of file diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt index 5c993bcb..25d5eb4b 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt @@ -8,7 +8,8 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys import com.intellij.openapi.components.Service import com.intellij.openapi.rd.util.launchChildOnUi import com.intellij.openapi.ui.Messages -import com.mongodb.jbplugin.dataaccess.ServerInfoRepository +import com.mongodb.jbplugin.accessadapter.datagrip.DataGripBasedReadModelProvider +import com.mongodb.jbplugin.accessadapter.slice.BuildInfoSlice import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -18,10 +19,9 @@ class GetMongoDBVersionActionService( ) { fun actionPerformed(event: AnActionEvent) { coroutineScope.launch { - val repository = event.project!!.getService(ServerInfoRepository::class.java) + val readModelProvider = event.project!!.getService(DataGripBasedReadModelProvider::class.java) val dataSource = event.dataContext.getData(PlatformDataKeys.PSI_ELEMENT) as DbDataSource - - val buildInfo = repository.getServerInfo(dataSource.localDataSource!!) + val buildInfo = readModelProvider.slice(dataSource.localDataSource!!, BuildInfoSlice) coroutineScope.launchChildOnUi { Messages.showMessageDialog(buildInfo.version, "Show DB Version", null) diff --git a/packages/mongodb-access-adapter/build.gradle.kts b/packages/mongodb-access-adapter/build.gradle.kts index 0ce6a166..cf311cab 100644 --- a/packages/mongodb-access-adapter/build.gradle.kts +++ b/packages/mongodb-access-adapter/build.gradle.kts @@ -1,3 +1,4 @@ dependencies { - + implementation(libs.owasp.encoder) + implementation(libs.mongodb.driver) } \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts b/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts new file mode 100644 index 00000000..444e9691 --- /dev/null +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts @@ -0,0 +1,22 @@ +repositories { + maven("https://www.jetbrains.com/intellij-repository/releases/") +} +dependencies { + implementation(libs.gson) + implementation(libs.mongodb.driver) + implementation(project(":packages:mongodb-access-adapter")) + + compileOnly(libs.testing.intellij.ideImpl) + compileOnly(libs.testing.intellij.coreUi) + compileOnly("com.jetbrains.intellij.database:database-sql:241.15989.150") + compileOnly("com.jetbrains.intellij.database:database-connectivity:241.15989.150") + compileOnly("com.jetbrains.intellij.database:database-core-impl:241.15989.150") { + exclude("com.jetbrains.fus.reporting", "ap-validation") + } + compileOnly("com.jetbrains.intellij.database:database-jdbc-console:241.15989.150") + compileOnly("com.jetbrains.intellij.database:database:241.15989.150") + compileOnly("com.jetbrains.intellij.platform:images:241.15989.157") + compileOnly("com.jetbrains.intellij.grid:grid-impl:241.15989.150") + compileOnly("com.jetbrains.intellij.grid:grid:241.15989.150") + compileOnly("com.jetbrains.intellij.grid:grid-core-impl:241.15989.150") +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt new file mode 100644 index 00000000..2eefb4e0 --- /dev/null +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt @@ -0,0 +1,40 @@ +package com.mongodb.jbplugin.accessadapter.datagrip + +import com.intellij.database.dataSource.LocalDataSource +import com.intellij.openapi.components.Service +import com.intellij.openapi.project.Project +import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.mongodb.jbplugin.accessadapter.MongoDBReadModelProvider +import com.mongodb.jbplugin.accessadapter.Slice +import com.mongodb.jbplugin.accessadapter.datagrip.adapter.DataGripMongoDBDriver +import com.mongodb.jbplugin.accessadapter.slice.BuildInfoSlice +import kotlinx.coroutines.runBlocking + +@Service(Service.Level.PROJECT) +class DataGripBasedReadModelProvider( + private val project: Project, +) : MongoDBReadModelProvider { + private val cachedValues: MutableMap> = mutableMapOf() + + override fun slice(dataSource: LocalDataSource, slice: Slice): T { + return cachedValues + .computeIfAbsent(slice.javaClass.canonicalName, fromSlice(dataSource, BuildInfoSlice)) + .value as T + } + + private inline fun fromSlice(dataSource: LocalDataSource, slice: Slice): (String) -> CachedValue { + val cacheManager = CachedValuesManager.getManager(project) + return { + cacheManager.createCachedValue { + runBlocking { + val driver = DataGripMongoDBDriver(project, dataSource) + val sliceData = slice.queryUsingDriver(driver) + + CachedValueProvider.Result.create(sliceData, dataSource) + } + } + } + } +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDBDriver.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDBDriver.kt new file mode 100644 index 00000000..3ad4ef6e --- /dev/null +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDBDriver.kt @@ -0,0 +1,53 @@ +package com.mongodb.jbplugin.accessadapter.datagrip.adapter + +import com.intellij.database.dataSource.LocalDataSource +import com.intellij.openapi.project.Project +import com.mongodb.jbplugin.accessadapter.MongoDBDriver +import com.mongodb.jbplugin.accessadapter.Namespace +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.bson.Document +import kotlin.reflect.KClass +import kotlin.time.Duration + +class DataGripMongoDBDriver( + val project: Project, + val dataSource: LocalDataSource +) : MongoDBDriver { + override suspend fun runCommand(command: Document, result: KClass, timeout: Duration): T = withContext(Dispatchers.IO) { + DataSourceQuery(project, dataSource, result).runQuery( + """db.runCommand(${command.toJson()})""", + timeout + )[0] + } + + override suspend fun findOne( + namespace: Namespace, + query: Document, + options: Document, + result: KClass, + timeout: Duration + ): T? = withContext(Dispatchers.IO) { + DataSourceQuery(project, dataSource, result).runQuery( + """db.getSiblingDB("${namespace.database}") + .getCollection("${namespace.collection}") + .findOne(${query.toJson()}, ${options.toJson()}) """.trimMargin(), + timeout + ).getOrNull(0) + } + + override suspend fun findAll( + namespace: Namespace, + query: Document, + result: KClass, + limit: Int, + timeout: Duration + ) = withContext(Dispatchers.IO) { + DataSourceQuery(project, dataSource, result).runQuery( + """db.getSiblingDB("${namespace.database}") + .getCollection("${namespace.collection}") + .find(${query.toJson()}).limit(${limit}) """.trimMargin(), + timeout + ) + } +} \ No newline at end of file diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/DataGripQueryAdapter.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripQueryAdapter.kt similarity index 92% rename from packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/DataGripQueryAdapter.kt rename to packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripQueryAdapter.kt index 7f0f8a97..0ff5e3a0 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/DataGripQueryAdapter.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripQueryAdapter.kt @@ -1,10 +1,10 @@ -package com.mongodb.jbplugin.dataaccess +package com.mongodb.jbplugin.accessadapter.datagrip.adapter import com.google.gson.Gson import com.intellij.database.dataSource.DatabaseConnectionCore import com.intellij.database.datagrid.DataRequest -internal class DataGripQueryAdapter( +class DataGripQueryAdapter( private val queryScript: String, private val resultClass: Class, private val gson: Gson, @@ -32,5 +32,4 @@ internal class DataGripQueryAdapter( continuation(listOfResults) } - } \ No newline at end of file diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/BaseAccessAdapter.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataSourceQuery.kt similarity index 78% rename from packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/BaseAccessAdapter.kt rename to packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataSourceQuery.kt index 6bf3a0dd..becfefa0 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/dataaccess/BaseAccessAdapter.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataSourceQuery.kt @@ -1,4 +1,4 @@ -package com.mongodb.jbplugin.dataaccess +package com.mongodb.jbplugin.accessadapter.datagrip.adapter import com.google.gson.Gson import com.intellij.database.console.session.DatabaseSession @@ -9,21 +9,23 @@ import kotlinx.coroutines.* import java.util.concurrent.TimeoutException import java.util.concurrent.atomic.AtomicBoolean import kotlin.coroutines.resume +import kotlin.reflect.KClass import kotlin.time.Duration -internal class BaseAccessAdapter( +class DataSourceQuery( private val project: Project, - private val dataSource: LocalDataSource + private val dataSource: LocalDataSource, + private val result: KClass ) { private val gson = Gson() - suspend inline fun runQuery(queryString: String, timeout: Duration): List = withContext(Dispatchers.IO) { + suspend fun runQuery(queryString: String, timeout: Duration): List = withContext(Dispatchers.IO) { suspendCancellableCoroutine { callback -> val session = getSession() val hasFinished = AtomicBoolean(false) launch { - val query = DataGripQueryAdapter(queryString, T::class.java, gson, session) { + val query = DataGripQueryAdapter(queryString, result.java, gson, session) { if (!hasFinished.compareAndSet(false, true)) { callback.resume(it) } diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriver.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriver.kt new file mode 100644 index 00000000..6f1dbdbb --- /dev/null +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriver.kt @@ -0,0 +1,27 @@ +package com.mongodb.jbplugin.accessadapter + +import org.bson.Document +import org.owasp.encoder.Encode +import kotlin.reflect.KClass +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +data class Namespace(val database: String, val collection: String) { + override fun toString(): String { + return "${database}.${collection}" + } +} + +fun String.toNS(): Namespace { + val (db, coll) = trim().split(".", limit = 2) + return Namespace( + Encode.forJavaScript(db), + Encode.forJavaScript(coll) + ) +} + +interface MongoDBDriver { + suspend fun runCommand(command: Document, result: KClass, timeout: Duration = 1.seconds): T + suspend fun findOne(namespace: Namespace, query: Document, options: Document, result: KClass, timeout: Duration = 1.seconds): T? + suspend fun findAll(namespace: Namespace, query: Document, result: KClass, limit: Int = 10, timeout: Duration = 1.seconds): List +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBReadModelProvider.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBReadModelProvider.kt new file mode 100644 index 00000000..66c89004 --- /dev/null +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBReadModelProvider.kt @@ -0,0 +1,9 @@ +package com.mongodb.jbplugin.accessadapter + +interface Slice { + suspend fun queryUsingDriver(from: MongoDBDriver): State +} + +interface MongoDBReadModelProvider { + fun slice(dataSource: DataSource, slice: Slice): T +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSlice.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSlice.kt new file mode 100644 index 00000000..8cf750b0 --- /dev/null +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSlice.kt @@ -0,0 +1,20 @@ +package com.mongodb.jbplugin.accessadapter.slice + +import com.mongodb.jbplugin.accessadapter.MongoDBDriver +import com.mongodb.jbplugin.accessadapter.Slice +import org.bson.Document + +data class BuildInfo( + val version: String, + val gitVersion: String +) +data object BuildInfoSlice : Slice { + override suspend fun queryUsingDriver(from: MongoDBDriver): BuildInfo { + return from.runCommand( + Document(mapOf( + "buildInfo" to 1, + )), + BuildInfo::class + ) + } +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriverTest.kt b/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriverTest.kt new file mode 100644 index 00000000..c9514eb3 --- /dev/null +++ b/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriverTest.kt @@ -0,0 +1,48 @@ +package com.mongodb.jbplugin.accessadapter + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class MongoDBDriverTest { + @Test + fun `parses a namespace`() { + val namespace = "mydb.mycoll".toNS() + assertEquals("mydb", namespace.database) + assertEquals("mycoll", namespace.collection) + } + + @Test + fun `parses a namespace where collections have dots in a name`() { + val namespace = "mydb.myco.ll".toNS() + assertEquals("mydb", namespace.database) + assertEquals("myco.ll", namespace.collection) + } + + @Test + fun `escapes characters that can be dangerous in javascript`() { + val namespace = """mydb.myco"ll""".toNS() + assertEquals("mydb", namespace.database) + assertEquals("myco\\x22ll", namespace.collection) + } + + @Test + fun `removes trailing spaces`() { + val namespace = """ mydb.myco"ll """.toNS() + assertEquals("mydb", namespace.database) + assertEquals("myco\\x22ll", namespace.collection) + } + + @Test + fun `serialises to a valid namespace string`() { + val namespace = Namespace("mydb", "my.cool.col") + assertEquals("mydb.my.cool.col", namespace.toString()) + } + + @Test + fun `can parse back a serialised namespace`() { + val namespace = Namespace("mydb", "my.cool.col") + val deserialized = namespace.toString().toNS() + + assertEquals(namespace, deserialized) + } +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSliceTest.kt b/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSliceTest.kt new file mode 100644 index 00000000..978aadea --- /dev/null +++ b/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSliceTest.kt @@ -0,0 +1,21 @@ +package com.mongodb.jbplugin.accessadapter.slice + +import com.mongodb.jbplugin.accessadapter.MongoDBDriver +import kotlinx.coroutines.runBlocking +import org.bson.Document +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.mockito.Mockito + +class BuildInfoSliceTest { + @Test + fun `returns a valid build info`(): Unit = runBlocking { + val command = Document(mapOf("buildInfo" to 1)) + val driver = Mockito.mock() + Mockito.`when`(driver.runCommand(command, BuildInfo::class)).thenReturn(BuildInfo("7.8.0", "1235abc")) + + val data = BuildInfoSlice.queryUsingDriver(driver) + Assertions.assertEquals("7.8.0", data.version) + Assertions.assertEquals("1235abc", data.gitVersion) + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 447a5f0a..834348c4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,5 +14,6 @@ include( "packages:mongodb-autocomplete-engine", "packages:mongodb-linting-engine", "packages:mongodb-access-adapter", + "packages:mongodb-access-adapter:datagrip-access-adapter", "packages:jetbrains-plugin", ) \ No newline at end of file From c29663674d72f504902f53684b093daa0ce67488 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 16:53:57 +0200 Subject: [PATCH 05/16] chore: data access layer --- gradle/diktat.yml | 6 +- gradle/libs.versions.toml | 19 ++- .../actions/GetMongoDBVersionAction.kt | 25 ++- .../src/main/resources/META-INF/plugin.xml | 2 +- .../datagrip-access-adapter/build.gradle.kts | 55 +++++-- .../DataGripBasedReadModelProvider.kt | 44 ++++-- .../datagrip/adapter/DataGripMongoDBDriver.kt | 53 ------- .../datagrip/adapter/DataGripMongoDbDriver.kt | 129 ++++++++++++++++ .../datagrip/adapter/DataGripQueryAdapter.kt | 35 ----- .../datagrip/adapter/DataSourceQuery.kt | 52 ------- .../accessadapter/datagrip/IntegrationTest.kt | 144 ++++++++++++++++++ .../adapter/DataGripMongoDbDriverTest.kt | 33 ++++ .../jbplugin/accessadapter/MongoDBDriver.kt | 27 ---- .../accessadapter/MongoDBReadModelProvider.kt | 9 -- .../jbplugin/accessadapter/MongoDbDriver.kt | 69 +++++++++ .../accessadapter/MongoDbReadModelProvider.kt | 28 ++++ .../jbplugin/accessadapter/slice/BuildInfo.kt | 30 ++++ .../accessadapter/slice/BuildInfoSlice.kt | 20 --- ...goDBDriverTest.kt => MongoDbDriverTest.kt} | 2 +- ...BuildInfoSliceTest.kt => BuildInfoTest.kt} | 11 +- 20 files changed, 557 insertions(+), 236 deletions(-) rename packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/{observability => }/actions/GetMongoDBVersionAction.kt (68%) delete mode 100644 packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDBDriver.kt create mode 100644 packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriver.kt delete mode 100644 packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripQueryAdapter.kt delete mode 100644 packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataSourceQuery.kt create mode 100644 packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt create mode 100644 packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt delete mode 100644 packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriver.kt delete mode 100644 packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBReadModelProvider.kt create mode 100644 packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt create mode 100644 packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbReadModelProvider.kt create mode 100644 packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfo.kt delete mode 100644 packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSlice.kt rename packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/{MongoDBDriverTest.kt => MongoDbDriverTest.kt} (98%) rename packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/{BuildInfoSliceTest.kt => BuildInfoTest.kt} (74%) diff --git a/gradle/diktat.yml b/gradle/diktat.yml index 3fdb54cb..625c70e9 100644 --- a/gradle/diktat.yml +++ b/gradle/diktat.yml @@ -17,4 +17,8 @@ - name: TOO_MANY_PARAMETERS enabled: true configuration: - maxParameterListSize: '10' \ No newline at end of file + maxParameterListSize: '10' +- name: FILE_NAME_INCORRECT + enabled: false +- name: LOCAL_VARIABLE_EARLY_DECLARATION + enabled: false \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e2f41574..b05d973f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,8 +13,8 @@ jmh-plugin="0.7.2" diktat-plugin="1.0.1" jmhreport-plugin="0.9.0" # Library dependencies -kotlin-stdlib="1.9.22" -kotlinx-coroutines="1.7.3" +kotlin-stdlib="1.9.24" +kotlinx-coroutines="1.8.0" jupiter="5.10.2" mockito="5.11.0" mockito-kotlin="5.3.1" @@ -27,6 +27,8 @@ video-recorder="2.0" gson="2.10.1" mongodb-driver="5.1.0" owasp-encoder="1.2.3" +testContainers="1.19.8" +intellij-database="241.15989.150" [plugins] intellij={ id="org.jetbrains.intellij", version.ref="intellij-plugin" } @@ -45,6 +47,14 @@ kotlin-coroutines-core={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines kotlin-coroutines-swing={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-swing", version.ref="kotlinx-coroutines" } kotlin-coroutines-test={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-test", version.ref="kotlinx-coroutines" } ###################################################### +## IntelliJ compileOnly libraries. They must not be bundled because they are already part of the +## JetBrains ecosystem. +intellij-database-sql={ group="com.jetbrains.intellij.database", name="database-sql", version.ref="intellij-database" } +intellij-database-connectivity={ group="com.jetbrains.intellij.database", name="database-connectivity", version.ref="intellij-database" } +intellij-database-jdbc-console={ group="com.jetbrains.intellij.database", name="database-jdbc-console", version.ref="intellij-database" } +intellij-database-core-base={ group="com.jetbrains.intellij.database", name="database", version.ref="intellij-database" } +intellij-database-core-impl={ group="com.jetbrains.intellij.database", name="database-core-impl", version.ref="intellij-database" } +###################################################### ## Production Libraries. segment={ group="com.segment.analytics.java", name="analytics", version.ref="segment" } gson={ group="com.google.code.gson", name="gson", version.ref="gson" } @@ -62,13 +72,16 @@ testing-remoteRobot={ group="com.intellij.remoterobot", name="remote-robot", ver testing-remoteRobotDeps-remoteFixtures={ group="com.intellij.remoterobot", name="remote-fixtures", version.ref="intellij-remoteRobot"} testing-remoteRobotDeps-ideLauncher={ group="com.intellij.remoterobot", name="ide-launcher", version.ref="intellij-remoteRobot"} testing-remoteRobotDeps-okHttp={ group="com.squareup.okhttp3", name="okhttp", version.ref="okHttp" } -testing-intellij-ideImpl={ group="com.jetbrains.intellij.platform", name="ide-impl", version.ref="intellij-testBuild" } +testing-intellij-ideImpl={ group="com.jetbrains.intellij.platform", name="ide", version.ref="intellij-testBuild" } testing-intellij-coreUi={ group="com.jetbrains.intellij.platform", name="core-ui", version.ref="intellij-testBuild" } testing-remoteRobotDeps-retrofit={ group="com.squareup.retrofit2", name="retrofit", version.ref="retrofit" } testing-remoteRobotDeps-retrofitGson={ group="com.squareup.retrofit2", name="converter-gson", version.ref="retrofit" } testing-jmh-core={ group="org.openjdk.jmh", name="jmh-core", version.ref="jmh" } testing-jmh-annotationProcessor={ group="org.openjdk.jmh", name="jmh-generator-annprocess", version.ref="jmh" } testing-jmh-generatorByteCode={ group="org.openjdk.jmh", name="jmh-generator-bytecode", version.ref="jmh" } +testing-testContainers-core= { group="org.testcontainers", name="testcontainers", version.ref="testContainers" } +testing-testContainers-mongodb= { group="org.testcontainers", name="mongodb", version.ref="testContainers" } +testing-testContainers-jupiter= { group="org.testcontainers", name="junit-jupiter", version.ref="testContainers"} ###################################################### ## Libraries and plugins only used for the buildScript. buildScript-plugin-kotlin={ group="org.jetbrains.kotlin", name="kotlin-gradle-plugin", version="1.9.23" } diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/actions/GetMongoDBVersionAction.kt similarity index 68% rename from packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt rename to packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/actions/GetMongoDBVersionAction.kt index 25d5eb4b..c08b4f91 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/observability/actions/GetMongoDBVersionAction.kt +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/actions/GetMongoDBVersionAction.kt @@ -1,4 +1,9 @@ -package com.mongodb.jbplugin.observability.actions +/** + * A Simple, example action, that prints out in a modal popup the version of the + * connected MongoDB Cluster. + */ + +package com.mongodb.jbplugin.actions import com.intellij.database.dataSource.localDataSource import com.intellij.database.psi.DbDataSource @@ -9,19 +14,24 @@ import com.intellij.openapi.components.Service import com.intellij.openapi.rd.util.launchChildOnUi import com.intellij.openapi.ui.Messages import com.mongodb.jbplugin.accessadapter.datagrip.DataGripBasedReadModelProvider -import com.mongodb.jbplugin.accessadapter.slice.BuildInfoSlice +import com.mongodb.jbplugin.accessadapter.slice.BuildInfo import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +/** + * Service that implements the action. + * + * @param coroutineScope + */ @Service(Service.Level.PROJECT) -class GetMongoDBVersionActionService( +class GetMongoDbVersionActionService( private val coroutineScope: CoroutineScope ) { fun actionPerformed(event: AnActionEvent) { coroutineScope.launch { val readModelProvider = event.project!!.getService(DataGripBasedReadModelProvider::class.java) val dataSource = event.dataContext.getData(PlatformDataKeys.PSI_ELEMENT) as DbDataSource - val buildInfo = readModelProvider.slice(dataSource.localDataSource!!, BuildInfoSlice) + val buildInfo = readModelProvider.slice(dataSource.localDataSource!!, BuildInfo.Slice) coroutineScope.launchChildOnUi { Messages.showMessageDialog(buildInfo.version, "Show DB Version", null) @@ -30,8 +40,11 @@ class GetMongoDBVersionActionService( } } -class GetMongoDBVersionAction: AnAction() { +/** + * Action that can be run within the contextual menu of a connection in the data explorer. + */ +class GetMongoDbVersionAction : AnAction() { override fun actionPerformed(event: AnActionEvent) { - event.project!!.getService(GetMongoDBVersionActionService::class.java).actionPerformed(event) + event.project!!.getService(GetMongoDbVersionActionService::class.java).actionPerformed(event) } } \ No newline at end of file diff --git a/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml b/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml index 07f46cd7..8be472b9 100644 --- a/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml +++ b/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml @@ -16,7 +16,7 @@ + class="com.mongodb.jbplugin.actions.GetMongoDbVersionAction" text="Show MongoDB Version"> diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts b/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts index 444e9691..5d8bf996 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts @@ -1,22 +1,53 @@ + + repositories { maven("https://www.jetbrains.com/intellij-repository/releases/") + maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies") +} + +plugins { + alias(libs.plugins.intellij) +} + + +tasks { + named("test", Test::class) { + environment("TESTCONTAINERS_RYUK_DISABLED", "true") + val homePath = project.layout.buildDirectory.dir("idea-sandbox/config-test").get().asFile.absolutePath + + jvmArgs(listOf( + "--add-opens=java.base/java.lang=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt=ALL-UNNAMED", + "--add-opens=java.desktop/javax.swing=ALL-UNNAMED", + "--add-opens=java.desktop/sun.awt=ALL-UNNAMED", + "-Dpolyglot.engine.WarnInterpreterOnly=false", + "-Dpolyglot.log.level=OFF", + "-Didea.home.path=${homePath}" + )) + } } + +intellij { + version.set(libs.versions.intellij.min) // Target IDE Version + type.set(libs.versions.intellij.type) // Target IDE Platform + + plugins.set(listOf("com.intellij.java", "com.intellij.database")) +} + dependencies { implementation(libs.gson) implementation(libs.mongodb.driver) implementation(project(":packages:mongodb-access-adapter")) - compileOnly(libs.testing.intellij.ideImpl) - compileOnly(libs.testing.intellij.coreUi) - compileOnly("com.jetbrains.intellij.database:database-sql:241.15989.150") - compileOnly("com.jetbrains.intellij.database:database-connectivity:241.15989.150") - compileOnly("com.jetbrains.intellij.database:database-core-impl:241.15989.150") { - exclude("com.jetbrains.fus.reporting", "ap-validation") + testImplementation("com.jetbrains.intellij.platform:test-framework-junit5:241.15989.155") { + exclude("ai.grazie.spell") + exclude("ai.grazie.utils") + exclude("ai.grazie.nlp") + exclude("ai.grazie.model") + exclude("org.jetbrains.teamcity") } - compileOnly("com.jetbrains.intellij.database:database-jdbc-console:241.15989.150") - compileOnly("com.jetbrains.intellij.database:database:241.15989.150") - compileOnly("com.jetbrains.intellij.platform:images:241.15989.157") - compileOnly("com.jetbrains.intellij.grid:grid-impl:241.15989.150") - compileOnly("com.jetbrains.intellij.grid:grid:241.15989.150") - compileOnly("com.jetbrains.intellij.grid:grid-core-impl:241.15989.150") + + testImplementation(libs.testing.testContainers.core) + testImplementation(libs.testing.testContainers.jupiter) + testImplementation(libs.testing.testContainers.mongodb) } \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt index 2eefb4e0..122419f5 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt @@ -1,3 +1,8 @@ +/** + * Represents a service that allows access to a MongoDB cluster + * configured through a DataGrip DataSource. + */ + package com.mongodb.jbplugin.accessadapter.datagrip import com.intellij.database.dataSource.LocalDataSource @@ -6,30 +11,47 @@ import com.intellij.openapi.project.Project import com.intellij.psi.util.CachedValue import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager -import com.mongodb.jbplugin.accessadapter.MongoDBReadModelProvider +import com.mongodb.jbplugin.accessadapter.MongoDbReadModelProvider import com.mongodb.jbplugin.accessadapter.Slice -import com.mongodb.jbplugin.accessadapter.datagrip.adapter.DataGripMongoDBDriver -import com.mongodb.jbplugin.accessadapter.slice.BuildInfoSlice +import com.mongodb.jbplugin.accessadapter.datagrip.adapter.DataGripMongoDbDriver import kotlinx.coroutines.runBlocking +private typealias MapOfCachedValues = MutableMap> + +/** + * The service to be injected to access MongoDB. Usually you will use + * it like this: + * + * ```kt + * val readModelProvider = event.project!!.getService(DataGripBasedReadModelProvider::class.java) + * val dataSource = event.dataContext.getData(PlatformDataKeys.PSI_ELEMENT) as DbDataSource + * val buildInfo = readModelProvider.slice(dataSource.localDataSource!!, BuildInfoSlice) + * ``` + * + * It will aggressively cache data at the project level, to avoid hitting MongoDB. Also, the provided + * driver is very slow, so it's better to avoid querying on performance sensitive contexts. + * + * @param project + */ @Service(Service.Level.PROJECT) class DataGripBasedReadModelProvider( private val project: Project, -) : MongoDBReadModelProvider { - private val cachedValues: MutableMap> = mutableMapOf() +) : MongoDbReadModelProvider { + private val cachedValues: MapOfCachedValues = mutableMapOf() - override fun slice(dataSource: LocalDataSource, slice: Slice): T { - return cachedValues - .computeIfAbsent(slice.javaClass.canonicalName, fromSlice(dataSource, BuildInfoSlice)) + override fun slice(dataSource: LocalDataSource, slice: Slice): T = cachedValues + .computeIfAbsent(slice.javaClass.canonicalName, fromSlice(dataSource, slice)) .value as T - } - private inline fun fromSlice(dataSource: LocalDataSource, slice: Slice): (String) -> CachedValue { + private fun fromSlice( + dataSource: LocalDataSource, + slice: Slice + ): (String) -> CachedValue { val cacheManager = CachedValuesManager.getManager(project) return { cacheManager.createCachedValue { runBlocking { - val driver = DataGripMongoDBDriver(project, dataSource) + val driver = DataGripMongoDbDriver(project, dataSource) val sliceData = slice.queryUsingDriver(driver) CachedValueProvider.Result.create(sliceData, dataSource) diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDBDriver.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDBDriver.kt deleted file mode 100644 index 3ad4ef6e..00000000 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDBDriver.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.mongodb.jbplugin.accessadapter.datagrip.adapter - -import com.intellij.database.dataSource.LocalDataSource -import com.intellij.openapi.project.Project -import com.mongodb.jbplugin.accessadapter.MongoDBDriver -import com.mongodb.jbplugin.accessadapter.Namespace -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.bson.Document -import kotlin.reflect.KClass -import kotlin.time.Duration - -class DataGripMongoDBDriver( - val project: Project, - val dataSource: LocalDataSource -) : MongoDBDriver { - override suspend fun runCommand(command: Document, result: KClass, timeout: Duration): T = withContext(Dispatchers.IO) { - DataSourceQuery(project, dataSource, result).runQuery( - """db.runCommand(${command.toJson()})""", - timeout - )[0] - } - - override suspend fun findOne( - namespace: Namespace, - query: Document, - options: Document, - result: KClass, - timeout: Duration - ): T? = withContext(Dispatchers.IO) { - DataSourceQuery(project, dataSource, result).runQuery( - """db.getSiblingDB("${namespace.database}") - .getCollection("${namespace.collection}") - .findOne(${query.toJson()}, ${options.toJson()}) """.trimMargin(), - timeout - ).getOrNull(0) - } - - override suspend fun findAll( - namespace: Namespace, - query: Document, - result: KClass, - limit: Int, - timeout: Duration - ) = withContext(Dispatchers.IO) { - DataSourceQuery(project, dataSource, result).runQuery( - """db.getSiblingDB("${namespace.database}") - .getCollection("${namespace.collection}") - .find(${query.toJson()}).limit(${limit}) """.trimMargin(), - timeout - ) - } -} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriver.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriver.kt new file mode 100644 index 00000000..84bcd338 --- /dev/null +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriver.kt @@ -0,0 +1,129 @@ +/** + * Represents a MongoDB driver interface that uses a DataGrip + * connection to query MongoDB. + */ + +package com.mongodb.jbplugin.accessadapter.datagrip.adapter + +import com.google.gson.Gson +import com.intellij.database.dataSource.DatabaseConnection +import com.intellij.database.dataSource.DatabaseConnectionManager +import com.intellij.database.dataSource.LocalDataSource +import com.intellij.database.dataSource.connection.ConnectionRequestor +import com.intellij.database.run.ConsoleRunConfiguration +import com.intellij.openapi.project.Project +import com.mongodb.jbplugin.accessadapter.MongoDbDriver +import com.mongodb.jbplugin.accessadapter.Namespace +import org.bson.Document + +import kotlin.reflect.KClass +import kotlin.time.Duration +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeout + +/** + * The driver itself. Shouldn't be used directly, but through the + * DataGripBasedReadModelProvider. + * + * @see com.mongodb.jbplugin.accessadapter.datagrip.DataGripBasedReadModelProvider + * + * @param project + * @param dataSource + */ +internal class DataGripMongoDbDriver( + private val project: Project, + private val dataSource: LocalDataSource +) : MongoDbDriver { + private val gson = Gson() + + override suspend fun runCommand( +command: Document, + result: KClass, + timeout: Duration +): T = withContext( +Dispatchers.IO +) { + runQuery( + """db.runCommand(${command.toJson()})""", + result, + timeout + )[0] + } + + override suspend fun findOne( + namespace: Namespace, + query: Document, + options: Document, + result: KClass, + timeout: Duration + ): T? = withContext(Dispatchers.IO) { + runQuery( + """db.getSiblingDB("${namespace.database}") + .getCollection("${namespace.collection}") + .findOne(${query.toJson()}, ${options.toJson()}) """.trimMargin(), + result, + timeout + ).getOrNull(0) + } + + override suspend fun findAll( + namespace: Namespace, + query: Document, + result: KClass, + limit: Int, + timeout: Duration + ) = withContext(Dispatchers.IO) { + runQuery( + """db.getSiblingDB("${namespace.database}") + .getCollection("${namespace.collection}") + .find(${query.toJson()}).limit($limit) """.trimMargin(), + result, + timeout + ) + } + + suspend fun runQuery( +queryString: String, + resultClass: KClass, + timeout: Duration +): List = + withContext(Dispatchers.IO) { + val connection = getConnection() + val remoteConnection = connection.remoteConnection + val statement = remoteConnection.prepareStatement(queryString.trimIndent()) + + withTimeout(timeout) { + val listOfResults = mutableListOf() + val resultSet = statement.executeQuery() + + if (resultClass.java.isPrimitive || resultClass == String::class.java) { + while (resultSet.next()) { + listOfResults.add(resultSet.getObject(1) as T) + } + } else { + while (resultSet.next()) { + val hashMap = resultSet.getObject(1) as Map + val result = gson.fromJson(gson.toJson(hashMap), resultClass.java) + listOfResults.add(result) + } + } + + listOfResults + } + } + + private suspend fun getConnection(): DatabaseConnection { + val connections = DatabaseConnectionManager.getInstance().activeConnections + return connections.firstOrNull { it.connectionPoint.dataSource == dataSource } + ?: DatabaseConnectionManager.establishConnection( + dataSource, + ConsoleRunConfiguration.newConfiguration(project).apply { + setOptionsFromDataSource(dataSource) + }, + ConnectionRequestor.Anonymous(), + project, + true // if password is not available + )!! + } +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripQueryAdapter.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripQueryAdapter.kt deleted file mode 100644 index 0ff5e3a0..00000000 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripQueryAdapter.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.mongodb.jbplugin.accessadapter.datagrip.adapter - -import com.google.gson.Gson -import com.intellij.database.dataSource.DatabaseConnectionCore -import com.intellij.database.datagrid.DataRequest - -class DataGripQueryAdapter( - private val queryScript: String, - private val resultClass: Class, - private val gson: Gson, - ownerEx: OwnerEx, - private val continuation: (List) -> Unit, -): DataRequest.RawRequest(ownerEx) { - override fun processRaw(p0: Context?, p1: DatabaseConnectionCore?) { - val remoteConnection = p1!!.remoteConnection - val statement = remoteConnection.prepareStatement(queryScript.trimIndent()) - - val listOfResults = mutableListOf() - val resultSet = statement.executeQuery() - - if (resultClass.isPrimitive || resultClass == String::class.java) { - while (resultSet.next()) { - listOfResults.add(resultSet.getObject(1) as T) - } - } else { - while (resultSet.next()) { - val hashMap = resultSet.getObject(1) as Map - val result = gson.fromJson(gson.toJson(hashMap), resultClass) - listOfResults.add(result) - } - } - - continuation(listOfResults) - } -} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataSourceQuery.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataSourceQuery.kt deleted file mode 100644 index becfefa0..00000000 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataSourceQuery.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.mongodb.jbplugin.accessadapter.datagrip.adapter - -import com.google.gson.Gson -import com.intellij.database.console.session.DatabaseSession -import com.intellij.database.console.session.DatabaseSessionManager -import com.intellij.database.dataSource.LocalDataSource -import com.intellij.openapi.project.Project -import kotlinx.coroutines.* -import java.util.concurrent.TimeoutException -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.coroutines.resume -import kotlin.reflect.KClass -import kotlin.time.Duration - -class DataSourceQuery( - private val project: Project, - private val dataSource: LocalDataSource, - private val result: KClass -) { - private val gson = Gson() - - suspend fun runQuery(queryString: String, timeout: Duration): List = withContext(Dispatchers.IO) { - suspendCancellableCoroutine { callback -> - val session = getSession() - val hasFinished = AtomicBoolean(false) - - launch { - val query = DataGripQueryAdapter(queryString, result.java, gson, session) { - if (!hasFinished.compareAndSet(false, true)) { - callback.resume(it) - } - } - - session.messageBus.dataProducer.processRequest(query) - - delay(timeout) - if (!hasFinished.compareAndSet(false, true)) { - callback.cancel(TimeoutException("Timeout running query '$queryString'")) - } - } - } - } - - private fun getSession(): DatabaseSession { - val sessions = DatabaseSessionManager.getSessions(project, dataSource) - if (sessions.isEmpty()) { - return DatabaseSessionManager.openSession(project, dataSource, "mongodb") - } - - return sessions[0] - } -} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt new file mode 100644 index 00000000..05275767 --- /dev/null +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt @@ -0,0 +1,144 @@ +/** + * Test extension that allows us to test with the IntelliJ environment + * without spinning up the whole IDE. Also, sets up a MongoDB instance + * that can be queried. + */ + +package com.mongodb.jbplugin.accessadapter.datagrip + +import com.intellij.database.dataSource.DatabaseDriverManagerImpl +import com.intellij.database.dataSource.LocalDataSource +import com.intellij.database.dataSource.validation.DatabaseDriverValidator.createDownloaderTask +import com.intellij.database.psi.DataSourceManager +import com.intellij.ide.impl.ProjectUtil +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.EDT +import com.intellij.openapi.application.ModalityState +import com.intellij.openapi.progress.EmptyProgressIndicator +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.ProjectManager +import com.intellij.testFramework.junit5.RunInEdt +import com.intellij.testFramework.junit5.TestApplication +import com.intellij.util.ui.EDT +import com.mongodb.jbplugin.accessadapter.MongoDbDriver +import com.mongodb.jbplugin.accessadapter.datagrip.adapter.DataGripMongoDbDriver +import org.junit.jupiter.api.extension.* +import org.testcontainers.containers.MongoDBContainer +import org.testcontainers.junit.jupiter.Testcontainers +import org.testcontainers.lifecycle.Startables + +import java.nio.file.Files +import java.util.* + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking + +/** + * Represents what version of MongoDB we support in the plugin. + */ +enum class MongoDbversion(val versionString: String) { + LATEST("7.0.9"), +; +} + +/** + * Annotation to be used in the test, at the class level. + * + * @see com.mongodb.jbplugin.accessadapter.datagrip.adapter.DataGripMongoDbDriverTest + */ +@TestApplication +@RunInEdt(allMethods = true, writeIntent = true) +@ExtendWith(IntegrationTestExtension::class) +@Testcontainers(parallel = false) +annotation class IntegrationTest(val mongodb: MongoDBVersion = MongoDBVersion.LATEST, val sharded: Boolean = false) + +/** + * Extension implementation. Must not be used directly. + */ +internal class IntegrationTestExtension : BeforeAllCallback, + AfterAllCallback, + ParameterResolver { + private val namespace = ExtensionContext.Namespace.create(IntegrationTestExtension::class.java) + private val containerKey = "CONTAINER" + private val projectKey = "PROJECT" + private val driverKey = "DRIVER" + private val versionKey = "VERSION" + + override fun beforeAll(context: ExtensionContext?) { + val annotation = context!!.requiredTestClass.getAnnotation(IntegrationTest::class.java) + val container = MongoDBContainer("mongo:${annotation.mongodb.versionString}-jammy") + .let { + if (annotation.sharded) { + it.withSharding() + } else { + it + } + } + + Startables.deepStart(container).join() + context.getStore(namespace).put(containerKey, container) + context.getStore(namespace).put(versionKey, annotation.mongodb) + + val project = runBlocking(Dispatchers.EDT) { + val testClassName = context.requiredTestClass.simpleName + ProjectUtil.openOrCreateProject(testClassName, Files.createTempDirectory(testClassName))!! + } + + context.getStore(namespace).put(projectKey, project) + + val dataSource = runBlocking { + val dataSourceManager = DataSourceManager.byDataSource(project, LocalDataSource::class.java)!! + val instance = DatabaseDriverManagerImpl.getInstance() + val jdbcDriver = instance.getDriver("mongo") + + val dataSource = LocalDataSource().apply { + name = UUID.randomUUID().toString() + url = container.connectionString + isConfiguredByUrl = true + username = "" + passwordStorage = LocalDataSource.Storage.PERSIST + databaseDriver = jdbcDriver + } + + dataSourceManager.addDataSource(dataSource) + dataSource + } + + createDownloaderTask(dataSource, null).run(EmptyProgressIndicator()) + + runBlocking(Dispatchers.EDT) { + EDT.dispatchAllInvocationEvents() + } + + val driver = DataGripMongoDbDriver(project, dataSource) + context.getStore(namespace).put(driverKey, driver) + + runBlocking(Dispatchers.EDT) { + EDT.dispatchAllInvocationEvents() + } + } + + override fun afterAll(context: ExtensionContext?) { + val project = context!!.getStore(namespace).get(projectKey) as Project + val mongodb = context.getStore(namespace).get(containerKey) as MongoDBContainer + + ApplicationManager.getApplication().invokeLater({ + ProjectManager.getInstance().closeAndDispose(project) + }, ModalityState.defaultModalityState()) + + mongodb.close() + } + + override fun supportsParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Boolean = + parameterContext?.parameter?.type == Project::class.java || + parameterContext?.parameter?.type == MongoDbDriver::class.java || + parameterContext?.parameter?.type == MongoDBVersion::class.java + + override fun resolveParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Any = + when (parameterContext?.parameter?.type) { + Project::class.java -> extensionContext!!.getStore(namespace).get(projectKey) + MongoDbDriver::class.java -> extensionContext!!.getStore(namespace).get(driverKey) + MongoDBVersion::class.java -> extensionContext!!.getStore(namespace).get(versionKey) + else -> TODO("Parameter of type ${parameterContext?.parameter?.type?.canonicalName} is not supported.") + } +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt new file mode 100644 index 00000000..262bf1c6 --- /dev/null +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt @@ -0,0 +1,33 @@ +package com.mongodb.jbplugin.accessadapter.datagrip.adapter + +import com.mongodb.jbplugin.accessadapter.MongoDbDriver +import com.mongodb.jbplugin.accessadapter.datagrip.IntegrationTest +import com.mongodb.jbplugin.accessadapter.datagrip.MongoDBVersion +import org.bson.Document +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +import kotlinx.coroutines.runBlocking + +@IntegrationTest +class DataGripMongoDbDriverTest { + @Test + fun `can connect and run a command`(version: MongoDBVersion, driver: MongoDbDriver) = runBlocking { + val result = driver.runCommand(Document(mapOf( + "buildInfo" to 1, + )), Map::class) + + assertEquals(result["version"], version.versionString) + } + + @Test + fun `is able to map the result to a class`(version: MongoDBVersion, driver: MongoDbDriver) = runBlocking { + data class MyBuildInfo(val version: String) + + val result = driver.runCommand(Document(mapOf( + "buildInfo" to 1, + )), MyBuildInfo::class) + + assertEquals(result.version, version.versionString) + } +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriver.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriver.kt deleted file mode 100644 index 6f1dbdbb..00000000 --- a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriver.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.mongodb.jbplugin.accessadapter - -import org.bson.Document -import org.owasp.encoder.Encode -import kotlin.reflect.KClass -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds - -data class Namespace(val database: String, val collection: String) { - override fun toString(): String { - return "${database}.${collection}" - } -} - -fun String.toNS(): Namespace { - val (db, coll) = trim().split(".", limit = 2) - return Namespace( - Encode.forJavaScript(db), - Encode.forJavaScript(coll) - ) -} - -interface MongoDBDriver { - suspend fun runCommand(command: Document, result: KClass, timeout: Duration = 1.seconds): T - suspend fun findOne(namespace: Namespace, query: Document, options: Document, result: KClass, timeout: Duration = 1.seconds): T? - suspend fun findAll(namespace: Namespace, query: Document, result: KClass, limit: Int = 10, timeout: Duration = 1.seconds): List -} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBReadModelProvider.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBReadModelProvider.kt deleted file mode 100644 index 66c89004..00000000 --- a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBReadModelProvider.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.mongodb.jbplugin.accessadapter - -interface Slice { - suspend fun queryUsingDriver(from: MongoDBDriver): State -} - -interface MongoDBReadModelProvider { - fun slice(dataSource: DataSource, slice: Slice): T -} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt new file mode 100644 index 00000000..7b0adf3c --- /dev/null +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt @@ -0,0 +1,69 @@ +/** + * Represents the MongoDB Driver facade that we will use internally. + * Usually, we won't use this class directly, only in tests. What we + * will use is the MongoDBReadModelProvider, that provides caching + * and safety mechanisms. + * + * @see com.mongodb.jbplugin.accessadapter.MongoDbReadModelProvider + */ + +package com.mongodb.jbplugin.accessadapter + +import org.bson.Document +import org.owasp.encoder.Encode +import kotlin.reflect.KClass +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +/** + * Represents a MongoDB Namespace (db/coll) + * + * @property database + * @property collection + */ +data class Namespace(val database: String, val collection: String) { + override fun toString(): String = "$database.$collection" +} + +/** + * Represents the MongoDB Driver facade that we will use internally. + * Usually, we won't use this class directly, only in tests. What we + * will use is the MongoDBReadModelProvider, that provides caching + * and safety mechanisms. + * + * @see com.mongodb.jbplugin.accessadapter.MongoDbReadModelProvider + */ +interface MongoDbDriver { + suspend fun runCommand( +command: Document, + result: KClass, + timeout: Duration = 1.seconds +): T + suspend fun findOne( +namespace: Namespace, + query: Document, + options: Document, + result: KClass, + timeout: Duration = 1.seconds +): T? + suspend fun findAll( +namespace: Namespace, + query: Document, + result: KClass, + limit: Int = 10, + timeout: Duration = 1.seconds +): List +} + +/** + * Converts a string in form of `db.coll` to a Namespace object. + * + * @return + */ +fun String.toNs(): Namespace { + val (db, coll) = trim().split(".", limit = 2) + return Namespace( + Encode.forJavaScript(db), + Encode.forJavaScript(coll) + ) +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbReadModelProvider.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbReadModelProvider.kt new file mode 100644 index 00000000..95671aef --- /dev/null +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbReadModelProvider.kt @@ -0,0 +1,28 @@ +/** + * Interface that needs to be implemented to access MongoDB. Implementation + * classes must be thread safe. + */ + +package com.mongodb.jbplugin.accessadapter + +/** + * A slice of data from MongoDB. S is the resulting type of the query. + * + * @see com.mongodb.jbplugin.accessadapter.slice.BuildInfo.Slice + * + * @param S + */ +interface Slice { + suspend fun queryUsingDriver(from: MongoDbDriver): S +} + +/** + * Accessing MongoDB state will be done through the provider, that will ensure + * efficient access or caching if necessary. The type `D` is the type of DataSource + * that will be used by the slice. It's an opaque type. + * + * @param D + */ +interface MongoDbReadModelProvider { + fun slice(dataSource: D, slice: Slice): T +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfo.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfo.kt new file mode 100644 index 00000000..7574aabd --- /dev/null +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfo.kt @@ -0,0 +1,30 @@ +/** + * A slice that represents the build information of the connected cluster. + */ + +package com.mongodb.jbplugin.accessadapter.slice + +import com.mongodb.jbplugin.accessadapter.MongoDbDriver +import org.bson.Document + +/** + * Slice to be used when querying the MongoDbReadModelProvider. + * + * @see com.mongodb.jbplugin.accessadapter.slice.BuildInfo.Slice + * @see com.mongodb.jbplugin.accessadapter.MongoDbReadModelProvider.slice + * @property version + * @property gitVersion + */ +data class BuildInfo( + val version: String, + val gitVersion: String +) { + object Slice : com.mongodb.jbplugin.accessadapter.Slice { + override suspend fun queryUsingDriver(from: MongoDbDriver): BuildInfo = from.runCommand( + Document(mapOf( + "buildInfo" to 1, + )), + BuildInfo::class + ) + } +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSlice.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSlice.kt deleted file mode 100644 index 8cf750b0..00000000 --- a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSlice.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.mongodb.jbplugin.accessadapter.slice - -import com.mongodb.jbplugin.accessadapter.MongoDBDriver -import com.mongodb.jbplugin.accessadapter.Slice -import org.bson.Document - -data class BuildInfo( - val version: String, - val gitVersion: String -) -data object BuildInfoSlice : Slice { - override suspend fun queryUsingDriver(from: MongoDBDriver): BuildInfo { - return from.runCommand( - Document(mapOf( - "buildInfo" to 1, - )), - BuildInfo::class - ) - } -} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriverTest.kt b/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriverTest.kt similarity index 98% rename from packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriverTest.kt rename to packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriverTest.kt index c9514eb3..9b3e8c1b 100644 --- a/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDBDriverTest.kt +++ b/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriverTest.kt @@ -3,7 +3,7 @@ package com.mongodb.jbplugin.accessadapter import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test -class MongoDBDriverTest { +class MongoDbDriverTest { @Test fun `parses a namespace`() { val namespace = "mydb.mycoll".toNS() diff --git a/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSliceTest.kt b/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoTest.kt similarity index 74% rename from packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSliceTest.kt rename to packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoTest.kt index 978aadea..197f2f84 100644 --- a/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoSliceTest.kt +++ b/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfoTest.kt @@ -1,20 +1,21 @@ package com.mongodb.jbplugin.accessadapter.slice -import com.mongodb.jbplugin.accessadapter.MongoDBDriver -import kotlinx.coroutines.runBlocking +import com.mongodb.jbplugin.accessadapter.MongoDbDriver import org.bson.Document import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import org.mockito.Mockito -class BuildInfoSliceTest { +import kotlinx.coroutines.runBlocking + +class BuildInfoTest { @Test fun `returns a valid build info`(): Unit = runBlocking { val command = Document(mapOf("buildInfo" to 1)) - val driver = Mockito.mock() + val driver = Mockito.mock() Mockito.`when`(driver.runCommand(command, BuildInfo::class)).thenReturn(BuildInfo("7.8.0", "1235abc")) - val data = BuildInfoSlice.queryUsingDriver(driver) + val data = BuildInfo.Slice.queryUsingDriver(driver) Assertions.assertEquals("7.8.0", data.version) Assertions.assertEquals("1235abc", data.gitVersion) } From 6aa10b3cc67dc059a8ce7ebf6b328e585bdce21a Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 17:16:50 +0200 Subject: [PATCH 06/16] chore: data access layer --- .../jbplugin/accessadapter/datagrip/IntegrationTest.kt | 4 ++-- .../datagrip/adapter/DataGripMongoDbDriverTest.kt | 6 +++--- .../jbplugin/accessadapter/MongoDbDriverTest.kt | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt index 05275767..48b589a9 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt @@ -36,7 +36,7 @@ import kotlinx.coroutines.runBlocking /** * Represents what version of MongoDB we support in the plugin. */ -enum class MongoDbversion(val versionString: String) { +enum class MongoDbVersion(val versionString: String) { LATEST("7.0.9"), ; } @@ -50,7 +50,7 @@ enum class MongoDbversion(val versionString: String) { @RunInEdt(allMethods = true, writeIntent = true) @ExtendWith(IntegrationTestExtension::class) @Testcontainers(parallel = false) -annotation class IntegrationTest(val mongodb: MongoDBVersion = MongoDBVersion.LATEST, val sharded: Boolean = false) +annotation class IntegrationTest(val mongodb: MongoDbVersion = MongoDbVersion.LATEST, val sharded: Boolean = false) /** * Extension implementation. Must not be used directly. diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt index 262bf1c6..a590519a 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt @@ -2,7 +2,7 @@ package com.mongodb.jbplugin.accessadapter.datagrip.adapter import com.mongodb.jbplugin.accessadapter.MongoDbDriver import com.mongodb.jbplugin.accessadapter.datagrip.IntegrationTest -import com.mongodb.jbplugin.accessadapter.datagrip.MongoDBVersion +import com.mongodb.jbplugin.accessadapter.datagrip.MongoDbVersion import org.bson.Document import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -12,7 +12,7 @@ import kotlinx.coroutines.runBlocking @IntegrationTest class DataGripMongoDbDriverTest { @Test - fun `can connect and run a command`(version: MongoDBVersion, driver: MongoDbDriver) = runBlocking { + fun `can connect and run a command`(version: MongoDbVersion, driver: MongoDbDriver) = runBlocking { val result = driver.runCommand(Document(mapOf( "buildInfo" to 1, )), Map::class) @@ -21,7 +21,7 @@ class DataGripMongoDbDriverTest { } @Test - fun `is able to map the result to a class`(version: MongoDBVersion, driver: MongoDbDriver) = runBlocking { + fun `is able to map the result to a class`(version: MongoDbVersion, driver: MongoDbDriver) = runBlocking { data class MyBuildInfo(val version: String) val result = driver.runCommand(Document(mapOf( diff --git a/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriverTest.kt b/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriverTest.kt index 9b3e8c1b..2d9f8c30 100644 --- a/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriverTest.kt +++ b/packages/mongodb-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriverTest.kt @@ -6,28 +6,28 @@ import org.junit.jupiter.api.Test class MongoDbDriverTest { @Test fun `parses a namespace`() { - val namespace = "mydb.mycoll".toNS() + val namespace = "mydb.mycoll".toNs() assertEquals("mydb", namespace.database) assertEquals("mycoll", namespace.collection) } @Test fun `parses a namespace where collections have dots in a name`() { - val namespace = "mydb.myco.ll".toNS() + val namespace = "mydb.myco.ll".toNs() assertEquals("mydb", namespace.database) assertEquals("myco.ll", namespace.collection) } @Test fun `escapes characters that can be dangerous in javascript`() { - val namespace = """mydb.myco"ll""".toNS() + val namespace = """mydb.myco"ll""".toNs() assertEquals("mydb", namespace.database) assertEquals("myco\\x22ll", namespace.collection) } @Test fun `removes trailing spaces`() { - val namespace = """ mydb.myco"ll """.toNS() + val namespace = """ mydb.myco"ll """.toNs() assertEquals("mydb", namespace.database) assertEquals("myco\\x22ll", namespace.collection) } @@ -41,7 +41,7 @@ class MongoDbDriverTest { @Test fun `can parse back a serialised namespace`() { val namespace = Namespace("mydb", "my.cool.col") - val deserialized = namespace.toString().toNS() + val deserialized = namespace.toString().toNs() assertEquals(namespace, deserialized) } From a85f7cca03238d8953a4eff774ca5ac447aaace9 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 17:20:47 +0200 Subject: [PATCH 07/16] chore: fix formatting and compilation --- .github/PULL_REQUEST_TEMPLATE.md | 4 + .github/workflows/codeql.yml | 76 +++++----- .github/workflows/draft-release.yaml | 2 +- .github/workflows/publish-release.yaml | 2 +- .github/workflows/quality-check.yaml | 4 +- CONTRIBUTING.md | 26 ++-- README.md | 1 + build.gradle.kts | 11 +- gradle/libs.versions.toml | 140 +++++++++--------- packages/jetbrains-plugin/build.gradle.kts | 29 ++-- .../mongodb/jbplugin/meta/BuildInformation.kt | 2 +- .../main/resources/META-INF/pluginIcon.svg | 6 +- .../jbplugin/fixtures/ProjectExtensions.kt | 2 - .../RuntimeInformationServiceTest.kt | 4 +- .../observability/TelemetryServiceTest.kt | 28 ++-- .../datagrip-access-adapter/build.gradle.kts | 22 +-- .../DataGripBasedReadModelProvider.kt | 4 +- .../datagrip/adapter/DataGripMongoDbDriver.kt | 58 ++++---- .../accessadapter/datagrip/IntegrationTest.kt | 26 ++-- .../adapter/DataGripMongoDbDriverTest.kt | 20 ++- .../jbplugin/accessadapter/MongoDbDriver.kt | 34 +++-- .../jbplugin/accessadapter/slice/BuildInfo.kt | 10 +- 22 files changed, 267 insertions(+), 244 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e0d6f867..8820630f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,15 +6,19 @@ eg. fix(type-hint): infer type of a constant for type checking INTELLIJ-1111 --> + ## Description + ### Checklist + - [ ] New tests and/or benchmarks are included. - [ ] Documentation is changed or added. - [ ] Changelog is updated accordingly. - [ ] I have signed the MongoDB Contributor License Agreement (https://www.mongodb.com/legal/contributor-agreement). ## Open Questions + \ No newline at end of file diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 22839fd9..db7c25ae 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -40,48 +40,48 @@ jobs: # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages - matrix: + matrix: include: - - language: java-kotlin - build-mode: autobuild + - language: java-kotlin + build-mode: autobuild steps: - - name: Checkout repository - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - queries: security-extended - config: | - paths: - - 'packages/**/src/**/*.kt' - - 'packages/**/src/**/*.java' + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + queries: security-extended + config: | + paths: + - 'packages/**/src/**/*.kt' + - 'packages/**/src/**/*.java' - # If the analyze step fails for one of the languages you are analyzing with - # "We were unable to automatically build your code", modify the matrix above - # to set the build mode to "manual" for that language. Then modify this step - # to build your code. - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - if: matrix.build-mode == 'manual' - run: | - echo 'If you are using a "manual" build mode for one or more of the' \ - 'languages you are analyzing, replace this with the commands to build' \ - 'your code, for example:' - echo ' make bootstrap' - echo ' make release' - exit 1 + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/draft-release.yaml b/.github/workflows/draft-release.yaml index 3c9c2936..b9eff538 100644 --- a/.github/workflows/draft-release.yaml +++ b/.github/workflows/draft-release.yaml @@ -139,7 +139,7 @@ jobs: ls packages/jetbrains-plugin/build/distributions/jetbrains-plugin.zip CHANGELOG=$(./gradlew --quiet --console=plain :packages:jetbrains-plugin:getChangelog) - + gh release create "${RELEASE_TAG}" \ --title "${RELEASE_TAG}" \ --notes "${CHANGELOG}" \ diff --git a/.github/workflows/publish-release.yaml b/.github/workflows/publish-release.yaml index c5021cc8..ee2512a6 100644 --- a/.github/workflows/publish-release.yaml +++ b/.github/workflows/publish-release.yaml @@ -2,7 +2,7 @@ name: Publish Release on: release: - types: [published] + types: [ published ] jobs: prepare-release: diff --git a/.github/workflows/quality-check.yaml b/.github/workflows/quality-check.yaml index 20ba49fa..2d89c617 100644 --- a/.github/workflows/quality-check.yaml +++ b/.github/workflows/quality-check.yaml @@ -63,7 +63,7 @@ jobs: id: verify-changelog-files with: files: | - CHANGELOG.md + CHANGELOG.md - uses: mheap/github-action-required-labels@v1 if: steps.verify-changed-files.outputs.files_changed == 'false' with: @@ -130,7 +130,7 @@ jobs: with: name: unit-test-coverage path: "**/jacocoTestReport.xml" - + functional-tests: name: 'Functional & UI Tests' runs-on: ubuntu-latest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 803dfb71..7092a959 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,5 @@ # Contributing + ## Getting Started You'll need at least the JDK 17 to work locally on the plugin. While the plugin should @@ -22,7 +23,8 @@ It will take a few moments, and you are ready to go. ## Submitting Changes -MongoDB welcomes community contributions! If you’re interested in making a contribution to MongoDB's plugin for IntelliJ, +MongoDB welcomes community contributions! If you’re interested in making a contribution to MongoDB's plugin for +IntelliJ, please follow the steps below before you start writing any code: - Sign the contributor's agreement. This will allow us to review and accept contributions. @@ -36,8 +38,9 @@ please follow the steps below before you start writing any code: ## Submitting Bugs -You can report new bugs by creating a new issue either in [JIRA](https://jira.mongodb.org/projects/INTELLIJ/issues/) or -[GitHub](https://github.com/mongodb-js/intellij/issues). Please include as much information as possible about your environment +You can report new bugs by creating a new issue either in [JIRA](https://jira.mongodb.org/projects/INTELLIJ/issues/) or +[GitHub](https://github.com/mongodb-js/intellij/issues). Please include as much information as possible about your +environment and include any relevant logs. ## Starting the plugin locally @@ -71,18 +74,19 @@ Will apply the latest changes to the running IDE. UI tests require a working local environment, so before running them, please revisit the `Getting Started` section. -Once the environment is set up, run the follow commandline script to run all the UI tests of +Once the environment is set up, run the follow commandline script to run all the UI tests of the project: ```sh ./gradle/run-ui-test.sh ``` -It will take a while, and Remote Robot will take ownership of your mouse once it starts +It will take a while, and Remote Robot will take ownership of your mouse once it starts a running IntelliJ environment, so please take a seat and watch it run. If a test fails, there will be a video recording in `packages/jetbrains-plugin/video` in AVI format -(you might need VLC Player to view it if you use a Mac) and also a screenshot in `packages/jetbrains-plugin/build/reports` +(you might need VLC Player to view it if you use a Mac) and also a screenshot +in `packages/jetbrains-plugin/build/reports` alongside the hierarchy of the view (the "DOM"). ## Running a single UI Test @@ -115,15 +119,15 @@ add a new dependency: ## Releasing -We don't have an automatic cadence of releases. We plan new releases, implement the +We don't have an automatic cadence of releases. We plan new releases, implement the features and then release when we are done. To release a new plugin version, is as follows: * Go to [GitHub Actions](https://github.com/mongodb-js/intellij/actions) and run the `Release Draft` workflow. - * Choose the type of release that you want to publish, it can be either patch, minor and major. Following semver. + * Choose the type of release that you want to publish, it can be either patch, minor and major. Following semver. * Wait until the workflow is done. - * It will validate that all the tests work and will publish a nightly version in the Marketplace. + * It will validate that all the tests work and will publish a nightly version in the Marketplace. * Go to the [GitHub Releases](https://github.com/mongodb-js/intellij/releases) page and you'll find a new draft release. * Publish the release as a normal GitHub Release, by editing it and publishing. * This will run a workflow _[you can check in GHA](https://github.com/mongodb-js/intellij/actions)_. - * When done it will update the main branch with the updated changelog and plugin version. - * And also will publish the package to the JetBrains Marketplace. \ No newline at end of file + * When done it will update the main branch with the updated changelog and plugin version. + * And also will publish the package to the JetBrains Marketplace. \ No newline at end of file diff --git a/README.md b/README.md index b825e329..aa18a1a1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # mongodb-jetbrains-plugin + [![Quality Check](https://github.com/mongodb-js/intellij/actions/workflows/quality-check.yaml/badge.svg)](https://github.com/mongodb-js/intellij/actions/workflows/quality-check.yaml) ![GitHub Release](https://img.shields.io/github/v/release/mongodb-js/intellij?sort=semver&display_name=release&logo=github) ![GitHub Release](https://img.shields.io/github/v/release/mongodb-js/intellij?sort=semver&display_name=release&logo=jetbrains) diff --git a/build.gradle.kts b/build.gradle.kts index b4f6cd36..8974472e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,9 @@ - import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask group = "com.mongodb" // This should be bumped when releasing a new version using the versionBump task: // ./gradlew versionBump -Pmode={major,minor,patch} -version="0.0.1" +version = "0.0.1" plugins { alias(libs.plugins.versions) @@ -77,9 +76,11 @@ subprojects { isScanForTestClasses = true } - jvmArgs(listOf( - "--add-opens=java.base/java.lang=ALL-UNNAMED" - )) + jvmArgs( + listOf( + "--add-opens=java.base/java.lang=ALL-UNNAMED" + ) + ) } withType { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b05d973f..a63d19ae 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,90 +1,90 @@ [versions] # IntelliJ platform dependencies -intellij-min="2024.1.1" -intellij-type="IU" -intellij-remoteRobot="0.11.22" -intellij-plugin="1.17.3" -intellij-testBuild="241.14494.241" -intellij-changelog-plugin="2.2.0" +intellij-min = "2024.1.1" +intellij-type = "IU" +intellij-remoteRobot = "0.11.22" +intellij-plugin = "1.17.3" +intellij-testBuild = "241.14494.241" +intellij-changelog-plugin = "2.2.0" # Other plugin dependencies -versions-plugin="0.51.0" -spotless-plugin="6.25.0" -jmh-plugin="0.7.2" -diktat-plugin="1.0.1" -jmhreport-plugin="0.9.0" +versions-plugin = "0.51.0" +spotless-plugin = "6.25.0" +jmh-plugin = "0.7.2" +diktat-plugin = "1.0.1" +jmhreport-plugin = "0.9.0" # Library dependencies -kotlin-stdlib="1.9.24" -kotlinx-coroutines="1.8.0" -jupiter="5.10.2" -mockito="5.11.0" -mockito-kotlin="5.3.1" -okHttp="4.12.0" -retrofit="2.11.0" -jmh="1.37" -segment="3.5.1" -jsoup="1.17.2" -video-recorder="2.0" -gson="2.10.1" -mongodb-driver="5.1.0" -owasp-encoder="1.2.3" -testContainers="1.19.8" -intellij-database="241.15989.150" +kotlin-stdlib = "1.9.24" +kotlinx-coroutines = "1.8.0" +jupiter = "5.10.2" +mockito = "5.11.0" +mockito-kotlin = "5.3.1" +okHttp = "4.12.0" +retrofit = "2.11.0" +jmh = "1.37" +segment = "3.5.1" +jsoup = "1.17.2" +video-recorder = "2.0" +gson = "2.10.1" +mongodb-driver = "5.1.0" +owasp-encoder = "1.2.3" +testContainers = "1.19.8" +intellij-database = "241.15989.150" [plugins] -intellij={ id="org.jetbrains.intellij", version.ref="intellij-plugin" } -jmh={ id="me.champeau.jmh", version.ref="jmh-plugin" } -versions={ id="com.github.ben-manes.versions", version.ref="versions-plugin" } -spotless={ id="com.diffplug.spotless", version.ref="spotless-plugin" } -changelog={ id="org.jetbrains.changelog", version.ref="intellij-changelog-plugin" } -jmhreport={ id="io.morethan.jmhreport", version.ref="jmhreport-plugin" } +intellij = { id = "org.jetbrains.intellij", version.ref = "intellij-plugin" } +jmh = { id = "me.champeau.jmh", version.ref = "jmh-plugin" } +versions = { id = "com.github.ben-manes.versions", version.ref = "versions-plugin" } +spotless = { id = "com.diffplug.spotless", version.ref = "spotless-plugin" } +changelog = { id = "org.jetbrains.changelog", version.ref = "intellij-changelog-plugin" } +jmhreport = { id = "io.morethan.jmhreport", version.ref = "jmhreport-plugin" } [libraries] ## Kotlin compileOnly libraries. They must not be bundled because they are already part of the ## JetBrains ecosystem. -kotlin-stdlib={ group="org.jetbrains.kotlin", name="kotlin-stdlib", version.ref="kotlin-stdlib" } -kotlin-reflect={ group="org.jetbrains.kotlin", name="kotlin-reflect", version.ref="kotlin-stdlib" } -kotlin-coroutines-core={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-core", version.ref="kotlinx-coroutines" } -kotlin-coroutines-swing={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-swing", version.ref="kotlinx-coroutines" } -kotlin-coroutines-test={ group="org.jetbrains.kotlinx", name="kotlinx-coroutines-test", version.ref="kotlinx-coroutines" } +kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin-stdlib" } +kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin-stdlib" } +kotlin-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } +kotlin-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } +kotlin-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } ###################################################### ## IntelliJ compileOnly libraries. They must not be bundled because they are already part of the ## JetBrains ecosystem. -intellij-database-sql={ group="com.jetbrains.intellij.database", name="database-sql", version.ref="intellij-database" } -intellij-database-connectivity={ group="com.jetbrains.intellij.database", name="database-connectivity", version.ref="intellij-database" } -intellij-database-jdbc-console={ group="com.jetbrains.intellij.database", name="database-jdbc-console", version.ref="intellij-database" } -intellij-database-core-base={ group="com.jetbrains.intellij.database", name="database", version.ref="intellij-database" } -intellij-database-core-impl={ group="com.jetbrains.intellij.database", name="database-core-impl", version.ref="intellij-database" } +intellij-database-sql = { group = "com.jetbrains.intellij.database", name = "database-sql", version.ref = "intellij-database" } +intellij-database-connectivity = { group = "com.jetbrains.intellij.database", name = "database-connectivity", version.ref = "intellij-database" } +intellij-database-jdbc-console = { group = "com.jetbrains.intellij.database", name = "database-jdbc-console", version.ref = "intellij-database" } +intellij-database-core-base = { group = "com.jetbrains.intellij.database", name = "database", version.ref = "intellij-database" } +intellij-database-core-impl = { group = "com.jetbrains.intellij.database", name = "database-core-impl", version.ref = "intellij-database" } ###################################################### ## Production Libraries. -segment={ group="com.segment.analytics.java", name="analytics", version.ref="segment" } -gson={ group="com.google.code.gson", name="gson", version.ref="gson" } -mongodb-driver={ group="org.mongodb", name="mongodb-driver-kotlin-sync", version.ref="mongodb-driver" } -owasp-encoder={ group="org.owasp.encoder", name="encoder", version.ref="owasp-encoder" } +segment = { group = "com.segment.analytics.java", name = "analytics", version.ref = "segment" } +gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } +mongodb-driver = { group = "org.mongodb", name = "mongodb-driver-kotlin-sync", version.ref = "mongodb-driver" } +owasp-encoder = { group = "org.owasp.encoder", name = "encoder", version.ref = "owasp-encoder" } ###################################################### ## Testing Libraries. -testing-jupiter-engine={ group="org.junit.jupiter", name="junit-jupiter-engine", version.ref="jupiter" } -testing-jupiter-vintage-engine={ group="org.junit.vintage", name="junit-vintage-engine", version.ref="jupiter" } -testing-jsoup= { group="org.jsoup", name="jsoup", version.ref="jsoup" } -testing-mockito-core={ group="org.mockito", name="mockito-core", version.ref="mockito" } -testing-mockito-kotlin={ group="org.mockito.kotlin", name="mockito-kotlin", version.ref="mockito-kotlin" } -testing-video-recorder={ group="com.automation-remarks", name="video-recorder-junit5", version.ref="video-recorder" } -testing-remoteRobot={ group="com.intellij.remoterobot", name="remote-robot", version.ref="intellij-remoteRobot"} -testing-remoteRobotDeps-remoteFixtures={ group="com.intellij.remoterobot", name="remote-fixtures", version.ref="intellij-remoteRobot"} -testing-remoteRobotDeps-ideLauncher={ group="com.intellij.remoterobot", name="ide-launcher", version.ref="intellij-remoteRobot"} -testing-remoteRobotDeps-okHttp={ group="com.squareup.okhttp3", name="okhttp", version.ref="okHttp" } -testing-intellij-ideImpl={ group="com.jetbrains.intellij.platform", name="ide", version.ref="intellij-testBuild" } -testing-intellij-coreUi={ group="com.jetbrains.intellij.platform", name="core-ui", version.ref="intellij-testBuild" } -testing-remoteRobotDeps-retrofit={ group="com.squareup.retrofit2", name="retrofit", version.ref="retrofit" } -testing-remoteRobotDeps-retrofitGson={ group="com.squareup.retrofit2", name="converter-gson", version.ref="retrofit" } -testing-jmh-core={ group="org.openjdk.jmh", name="jmh-core", version.ref="jmh" } -testing-jmh-annotationProcessor={ group="org.openjdk.jmh", name="jmh-generator-annprocess", version.ref="jmh" } -testing-jmh-generatorByteCode={ group="org.openjdk.jmh", name="jmh-generator-bytecode", version.ref="jmh" } -testing-testContainers-core= { group="org.testcontainers", name="testcontainers", version.ref="testContainers" } -testing-testContainers-mongodb= { group="org.testcontainers", name="mongodb", version.ref="testContainers" } -testing-testContainers-jupiter= { group="org.testcontainers", name="junit-jupiter", version.ref="testContainers"} +testing-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "jupiter" } +testing-jupiter-vintage-engine = { group = "org.junit.vintage", name = "junit-vintage-engine", version.ref = "jupiter" } +testing-jsoup = { group = "org.jsoup", name = "jsoup", version.ref = "jsoup" } +testing-mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockito" } +testing-mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" } +testing-video-recorder = { group = "com.automation-remarks", name = "video-recorder-junit5", version.ref = "video-recorder" } +testing-remoteRobot = { group = "com.intellij.remoterobot", name = "remote-robot", version.ref = "intellij-remoteRobot" } +testing-remoteRobotDeps-remoteFixtures = { group = "com.intellij.remoterobot", name = "remote-fixtures", version.ref = "intellij-remoteRobot" } +testing-remoteRobotDeps-ideLauncher = { group = "com.intellij.remoterobot", name = "ide-launcher", version.ref = "intellij-remoteRobot" } +testing-remoteRobotDeps-okHttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okHttp" } +testing-intellij-ideImpl = { group = "com.jetbrains.intellij.platform", name = "ide", version.ref = "intellij-testBuild" } +testing-intellij-coreUi = { group = "com.jetbrains.intellij.platform", name = "core-ui", version.ref = "intellij-testBuild" } +testing-remoteRobotDeps-retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } +testing-remoteRobotDeps-retrofitGson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" } +testing-jmh-core = { group = "org.openjdk.jmh", name = "jmh-core", version.ref = "jmh" } +testing-jmh-annotationProcessor = { group = "org.openjdk.jmh", name = "jmh-generator-annprocess", version.ref = "jmh" } +testing-jmh-generatorByteCode = { group = "org.openjdk.jmh", name = "jmh-generator-bytecode", version.ref = "jmh" } +testing-testContainers-core = { group = "org.testcontainers", name = "testcontainers", version.ref = "testContainers" } +testing-testContainers-mongodb = { group = "org.testcontainers", name = "mongodb", version.ref = "testContainers" } +testing-testContainers-jupiter = { group = "org.testcontainers", name = "junit-jupiter", version.ref = "testContainers" } ###################################################### ## Libraries and plugins only used for the buildScript. -buildScript-plugin-kotlin={ group="org.jetbrains.kotlin", name="kotlin-gradle-plugin", version="1.9.23" } -buildScript-plugin-versions={ group="com.github.ben-manes", name="gradle-versions-plugin", version.ref="versions-plugin" } -buildScript-plugin-spotless={ group="com.diffplug.spotless", name="spotless-plugin-gradle", version="6.25.0" } +buildScript-plugin-kotlin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version = "1.9.23" } +buildScript-plugin-versions = { group = "com.github.ben-manes", name = "gradle-versions-plugin", version.ref = "versions-plugin" } +buildScript-plugin-spotless = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version = "6.25.0" } ###################################################### \ No newline at end of file diff --git a/packages/jetbrains-plugin/build.gradle.kts b/packages/jetbrains-plugin/build.gradle.kts index 3099119c..c30f43a3 100644 --- a/packages/jetbrains-plugin/build.gradle.kts +++ b/packages/jetbrains-plugin/build.gradle.kts @@ -1,4 +1,3 @@ - import org.jetbrains.changelog.Changelog import org.jetbrains.changelog.date import org.jetbrains.intellij.tasks.RunIdeForUiTestTask @@ -104,19 +103,21 @@ tasks { } named("runIdeForUiTests", RunIdeForUiTestTask::class) { - systemProperties(mapOf( - "jb.consents.confirmation.enabled" to false, - "jb.privacy.policy.text" to "", - "eap.require.license" to true, - "ide.mac.message.dialogs.as.sheets" to false, - "ide.mac.file.chooser.native" to false, - "jbScreenMenuBar.enabled" to false, - "apple.laf.useScreenMenuBar" to false, - "idea.trust.all.projects" to true, - "ide.show.tips.on.startup.default.value" to false, - "idea.is.internal" to true, - "robot-server.port" to "8082", - )) + systemProperties( + mapOf( + "jb.consents.confirmation.enabled" to false, + "jb.privacy.policy.text" to "", + "eap.require.license" to true, + "ide.mac.message.dialogs.as.sheets" to false, + "ide.mac.file.chooser.native" to false, + "jbScreenMenuBar.enabled" to false, + "apple.laf.useScreenMenuBar" to false, + "idea.trust.all.projects" to true, + "ide.show.tips.on.startup.default.value" to false, + "idea.is.internal" to true, + "robot-server.port" to "8082", + ) + ) } downloadRobotServerPlugin { diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/meta/BuildInformation.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/meta/BuildInformation.kt index 6aef96a6..a2c8d268 100644 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/meta/BuildInformation.kt +++ b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/meta/BuildInformation.kt @@ -1,6 +1,6 @@ package com.mongodb.jbplugin.meta -import java.util.Properties +import java.util.* /** * This provides access to the build information generated at build time in Gradle. diff --git a/packages/jetbrains-plugin/src/main/resources/META-INF/pluginIcon.svg b/packages/jetbrains-plugin/src/main/resources/META-INF/pluginIcon.svg index 80736ccb..84e84f88 100644 --- a/packages/jetbrains-plugin/src/main/resources/META-INF/pluginIcon.svg +++ b/packages/jetbrains-plugin/src/main/resources/META-INF/pluginIcon.svg @@ -1,7 +1,9 @@ - + - + diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/ProjectExtensions.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/ProjectExtensions.kt index 0a666a70..f7aa3b80 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/ProjectExtensions.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/ProjectExtensions.kt @@ -7,8 +7,6 @@ package com.mongodb.jbplugin.fixtures import com.google.gson.Gson import com.intellij.openapi.project.Project import com.mongodb.jbplugin.observability.* -import com.mongodb.jbplugin.observability.LogMessage -import com.mongodb.jbplugin.observability.TelemetryService import com.mongodb.jbplugin.observability.probe.PluginActivatedProbe import org.mockito.Mockito.`when` import org.mockito.kotlin.any diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/observability/RuntimeInformationServiceTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/observability/RuntimeInformationServiceTest.kt index 88548ec7..c0350902 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/observability/RuntimeInformationServiceTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/observability/RuntimeInformationServiceTest.kt @@ -9,9 +9,7 @@ import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.MockedStatic -import org.mockito.Mockito.`when` -import org.mockito.Mockito.mock -import org.mockito.Mockito.mockStatic +import org.mockito.Mockito.* class RuntimeInformationServiceTest { private lateinit var permanentInstallationId: MockedStatic diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/observability/TelemetryServiceTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/observability/TelemetryServiceTest.kt index 7a48cf7c..3ec082ca 100644 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/observability/TelemetryServiceTest.kt +++ b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/observability/TelemetryServiceTest.kt @@ -14,8 +14,8 @@ internal class TelemetryServiceTest { val mockRuntimeInfo = mockRuntimeInformationService(userId = "654321") val service = TelemetryService( mockProject( - runtimeInformationService = mockRuntimeInfo - ) + runtimeInformationService = mockRuntimeInfo + ) ).apply { analytics = mock() } @@ -37,21 +37,23 @@ internal class TelemetryServiceTest { val mockRuntimeInfo = mockRuntimeInformationService(userId = "654321") val service = TelemetryService( mockProject( - runtimeInformationService = mockRuntimeInfo - ) + runtimeInformationService = mockRuntimeInfo + ) ).apply { analytics = mock() } - service.sendEvent(TelemetryEvent.NewConnection( - isAtlas = true, - isLocalhost = false, - isEnterprise = true, - isGenuine = true, - nonGenuineServerName = null, - serverOsFamily = null, - version = "8.0" - )) + service.sendEvent( + TelemetryEvent.NewConnection( + isAtlas = true, + isLocalhost = false, + isEnterprise = true, + isGenuine = true, + nonGenuineServerName = null, + serverOsFamily = null, + version = "8.0" + ) + ) verify(service.analytics).enqueue( argThat { diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts b/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts index 5d8bf996..d064c4a7 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/build.gradle.kts @@ -1,5 +1,3 @@ - - repositories { maven("https://www.jetbrains.com/intellij-repository/releases/") maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies") @@ -15,15 +13,17 @@ tasks { environment("TESTCONTAINERS_RYUK_DISABLED", "true") val homePath = project.layout.buildDirectory.dir("idea-sandbox/config-test").get().asFile.absolutePath - jvmArgs(listOf( - "--add-opens=java.base/java.lang=ALL-UNNAMED", - "--add-opens=java.desktop/java.awt=ALL-UNNAMED", - "--add-opens=java.desktop/javax.swing=ALL-UNNAMED", - "--add-opens=java.desktop/sun.awt=ALL-UNNAMED", - "-Dpolyglot.engine.WarnInterpreterOnly=false", - "-Dpolyglot.log.level=OFF", - "-Didea.home.path=${homePath}" - )) + jvmArgs( + listOf( + "--add-opens=java.base/java.lang=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt=ALL-UNNAMED", + "--add-opens=java.desktop/javax.swing=ALL-UNNAMED", + "--add-opens=java.desktop/sun.awt=ALL-UNNAMED", + "-Dpolyglot.engine.WarnInterpreterOnly=false", + "-Dpolyglot.log.level=OFF", + "-Didea.home.path=${homePath}" + ) + ) } } diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt index 122419f5..4a83e13a 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProvider.kt @@ -40,8 +40,8 @@ class DataGripBasedReadModelProvider( private val cachedValues: MapOfCachedValues = mutableMapOf() override fun slice(dataSource: LocalDataSource, slice: Slice): T = cachedValues - .computeIfAbsent(slice.javaClass.canonicalName, fromSlice(dataSource, slice)) - .value as T + .computeIfAbsent(slice.javaClass.canonicalName, fromSlice(dataSource, slice)) + .value as T private fun fromSlice( dataSource: LocalDataSource, diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriver.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriver.kt index 84bcd338..c5457674 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriver.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriver.kt @@ -38,12 +38,12 @@ internal class DataGripMongoDbDriver( private val gson = Gson() override suspend fun runCommand( -command: Document, - result: KClass, - timeout: Duration -): T = withContext( -Dispatchers.IO -) { + command: Document, + result: KClass, + timeout: Duration + ): T = withContext( + Dispatchers.IO + ) { runQuery( """db.runCommand(${command.toJson()})""", result, @@ -84,34 +84,34 @@ Dispatchers.IO } suspend fun runQuery( -queryString: String, - resultClass: KClass, - timeout: Duration -): List = - withContext(Dispatchers.IO) { - val connection = getConnection() - val remoteConnection = connection.remoteConnection - val statement = remoteConnection.prepareStatement(queryString.trimIndent()) + queryString: String, + resultClass: KClass, + timeout: Duration + ): List = + withContext(Dispatchers.IO) { + val connection = getConnection() + val remoteConnection = connection.remoteConnection + val statement = remoteConnection.prepareStatement(queryString.trimIndent()) - withTimeout(timeout) { - val listOfResults = mutableListOf() - val resultSet = statement.executeQuery() + withTimeout(timeout) { + val listOfResults = mutableListOf() + val resultSet = statement.executeQuery() - if (resultClass.java.isPrimitive || resultClass == String::class.java) { - while (resultSet.next()) { - listOfResults.add(resultSet.getObject(1) as T) - } - } else { - while (resultSet.next()) { - val hashMap = resultSet.getObject(1) as Map - val result = gson.fromJson(gson.toJson(hashMap), resultClass.java) - listOfResults.add(result) + if (resultClass.java.isPrimitive || resultClass == String::class.java) { + while (resultSet.next()) { + listOfResults.add(resultSet.getObject(1) as T) + } + } else { + while (resultSet.next()) { + val hashMap = resultSet.getObject(1) as Map + val result = gson.fromJson(gson.toJson(hashMap), resultClass.java) + listOfResults.add(result) + } } - } - listOfResults + listOfResults + } } - } private suspend fun getConnection(): DatabaseConnection { val connections = DatabaseConnectionManager.getInstance().activeConnections diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt index 48b589a9..3b3537dc 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt @@ -38,7 +38,7 @@ import kotlinx.coroutines.runBlocking */ enum class MongoDbVersion(val versionString: String) { LATEST("7.0.9"), -; + ; } /** @@ -56,8 +56,8 @@ annotation class IntegrationTest(val mongodb: MongoDbVersion = MongoDbVersion.LA * Extension implementation. Must not be used directly. */ internal class IntegrationTestExtension : BeforeAllCallback, - AfterAllCallback, - ParameterResolver { + AfterAllCallback, + ParameterResolver { private val namespace = ExtensionContext.Namespace.create(IntegrationTestExtension::class.java) private val containerKey = "CONTAINER" private val projectKey = "PROJECT" @@ -68,12 +68,12 @@ internal class IntegrationTestExtension : BeforeAllCallback, val annotation = context!!.requiredTestClass.getAnnotation(IntegrationTest::class.java) val container = MongoDBContainer("mongo:${annotation.mongodb.versionString}-jammy") .let { - if (annotation.sharded) { - it.withSharding() - } else { - it + if (annotation.sharded) { + it.withSharding() + } else { + it + } } - } Startables.deepStart(container).join() context.getStore(namespace).put(containerKey, container) @@ -130,15 +130,15 @@ internal class IntegrationTestExtension : BeforeAllCallback, } override fun supportsParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Boolean = - parameterContext?.parameter?.type == Project::class.java || - parameterContext?.parameter?.type == MongoDbDriver::class.java || - parameterContext?.parameter?.type == MongoDBVersion::class.java + parameterContext?.parameter?.type == Project::class.java || + parameterContext?.parameter?.type == MongoDbDriver::class.java || + parameterContext?.parameter?.type == MongoDbVersion::class.java override fun resolveParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Any = - when (parameterContext?.parameter?.type) { + when (parameterContext?.parameter?.type) { Project::class.java -> extensionContext!!.getStore(namespace).get(projectKey) MongoDbDriver::class.java -> extensionContext!!.getStore(namespace).get(driverKey) - MongoDBVersion::class.java -> extensionContext!!.getStore(namespace).get(versionKey) + MongoDbVersion::class.java -> extensionContext!!.getStore(namespace).get(versionKey) else -> TODO("Parameter of type ${parameterContext?.parameter?.type?.canonicalName} is not supported.") } } \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt index a590519a..690b414e 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/adapter/DataGripMongoDbDriverTest.kt @@ -13,9 +13,13 @@ import kotlinx.coroutines.runBlocking class DataGripMongoDbDriverTest { @Test fun `can connect and run a command`(version: MongoDbVersion, driver: MongoDbDriver) = runBlocking { - val result = driver.runCommand(Document(mapOf( - "buildInfo" to 1, - )), Map::class) + val result = driver.runCommand( + Document( + mapOf( + "buildInfo" to 1, + ) + ), Map::class + ) assertEquals(result["version"], version.versionString) } @@ -24,9 +28,13 @@ class DataGripMongoDbDriverTest { fun `is able to map the result to a class`(version: MongoDbVersion, driver: MongoDbDriver) = runBlocking { data class MyBuildInfo(val version: String) - val result = driver.runCommand(Document(mapOf( - "buildInfo" to 1, - )), MyBuildInfo::class) + val result = driver.runCommand( + Document( + mapOf( + "buildInfo" to 1, + ) + ), MyBuildInfo::class + ) assertEquals(result.version, version.versionString) } diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt index 7b0adf3c..c7dc5d4b 100644 --- a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt @@ -35,24 +35,26 @@ data class Namespace(val database: String, val collection: String) { */ interface MongoDbDriver { suspend fun runCommand( -command: Document, - result: KClass, - timeout: Duration = 1.seconds -): T + command: Document, + result: KClass, + timeout: Duration = 1.seconds + ): T + suspend fun findOne( -namespace: Namespace, - query: Document, - options: Document, - result: KClass, - timeout: Duration = 1.seconds -): T? + namespace: Namespace, + query: Document, + options: Document, + result: KClass, + timeout: Duration = 1.seconds + ): T? + suspend fun findAll( -namespace: Namespace, - query: Document, - result: KClass, - limit: Int = 10, - timeout: Duration = 1.seconds -): List + namespace: Namespace, + query: Document, + result: KClass, + limit: Int = 10, + timeout: Duration = 1.seconds + ): List } /** diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfo.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfo.kt index 7574aabd..7be22006 100644 --- a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfo.kt +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/slice/BuildInfo.kt @@ -21,10 +21,12 @@ data class BuildInfo( ) { object Slice : com.mongodb.jbplugin.accessadapter.Slice { override suspend fun queryUsingDriver(from: MongoDbDriver): BuildInfo = from.runCommand( - Document(mapOf( + Document( + mapOf( "buildInfo" to 1, - )), - BuildInfo::class - ) + ) + ), + BuildInfo::class + ) } } \ No newline at end of file From fa91440247117534b3bb75bab6c201643f7dd880 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 17:31:05 +0200 Subject: [PATCH 08/16] chore: show traces on unit tests --- .github/workflows/quality-check.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/quality-check.yaml b/.github/workflows/quality-check.yaml index 2d89c617..4aa511fb 100644 --- a/.github/workflows/quality-check.yaml +++ b/.github/workflows/quality-check.yaml @@ -116,7 +116,7 @@ jobs: cache: 'gradle' - name: Run Test Suite run: | - ./gradlew --quiet --console=plain "clean" "cleanTest" "unitTest" + ./gradlew --console=plain "clean" "cleanTest" "unitTest" - name: Publish Test Report uses: mikepenz/action-junit-report@v4 if: success() || failure() # always run even if the previous step fails From 27b73d2498954c52d17261fd0eeb7f11de7a71e7 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 17:32:48 +0200 Subject: [PATCH 09/16] chore: setup docker --- .github/workflows/quality-check.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/quality-check.yaml b/.github/workflows/quality-check.yaml index 4aa511fb..24ef6a32 100644 --- a/.github/workflows/quality-check.yaml +++ b/.github/workflows/quality-check.yaml @@ -114,6 +114,10 @@ jobs: distribution: 'adopt' java-version: '17' cache: 'gradle' + - name: Setup Docker (for Test Containers) + run: | + sudo apt update -y + sudo apt install -y docker docker-compose - name: Run Test Suite run: | ./gradlew --console=plain "clean" "cleanTest" "unitTest" From 0c6d4c332b9d444fbc6f5c6929033eca24919bbb Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 17:45:20 +0200 Subject: [PATCH 10/16] chore: avoid leaking the project --- .github/workflows/quality-check.yaml | 2 +- gradle/diktat.yml | 26 ++++++++++--------- .../accessadapter/datagrip/IntegrationTest.kt | 2 ++ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.github/workflows/quality-check.yaml b/.github/workflows/quality-check.yaml index 24ef6a32..35e9b59c 100644 --- a/.github/workflows/quality-check.yaml +++ b/.github/workflows/quality-check.yaml @@ -120,7 +120,7 @@ jobs: sudo apt install -y docker docker-compose - name: Run Test Suite run: | - ./gradlew --console=plain "clean" "cleanTest" "unitTest" + ./gradlew --stacktrace --console=plain "clean" "cleanTest" "unitTest" - name: Publish Test Report uses: mikepenz/action-junit-report@v4 if: success() || failure() # always run even if the previous step fails diff --git a/gradle/diktat.yml b/gradle/diktat.yml index 625c70e9..eca884eb 100644 --- a/gradle/diktat.yml +++ b/gradle/diktat.yml @@ -1,24 +1,26 @@ -- name: MISSING_KDOC_CLASS_ELEMENTS +- name: MISSING_KDOC_CLASS_ELEMENTS # Allow having class where fields don't have kdoc enabled: false -- name: MISSING_KDOC_ON_FUNCTION +- name: MISSING_KDOC_ON_FUNCTION # Allow functions to not have kdoc (too noisy comments) enabled: false -- name: GENERIC_VARIABLE_WRONG_DECLARATION +- name: GENERIC_VARIABLE_WRONG_DECLARATION # Allow generics without boundaries enabled: false -- name: FILE_WILDCARD_IMPORTS +- name: FILE_WILDCARD_IMPORTS # Allow wildcard imports (like java.util.*) enabled: false -- name: TOO_LONG_FUNCTION - enabled: false -- name: KDOC_NO_EMPTY_TAGS +- name: TOO_LONG_FUNCTION # Allow long-ish functions, sometimes they are convenient + enabled: true + configuration: + maxFunctionLength: 50 +- name: KDOC_NO_EMPTY_TAGS # Allow kdocs without specifying obvious parameters. enabled: false -- name: WRONG_INDENTATION +- name: WRONG_INDENTATION # Indentation is managed by intellij enabled: false -- name: MAGIC_NUMBER +- name: MAGIC_NUMBER # Allow magic numbers on array access and ports enabled: false -- name: TOO_MANY_PARAMETERS +- name: TOO_MANY_PARAMETERS # Allow at least 10 parameters (some signatures can be complex when working with intellij) enabled: true configuration: maxParameterListSize: '10' -- name: FILE_NAME_INCORRECT +- name: FILE_NAME_INCORRECT # File name does not need to match class name inside enabled: false -- name: LOCAL_VARIABLE_EARLY_DECLARATION +- name: LOCAL_VARIABLE_EARLY_DECLARATION # Allow declaring variables at the beginning of a function if they are mutable enabled: false \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt index 3b3537dc..f679dec0 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt @@ -17,6 +17,7 @@ import com.intellij.openapi.application.ModalityState import com.intellij.openapi.progress.EmptyProgressIndicator import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectManager +import com.intellij.openapi.util.Disposer import com.intellij.testFramework.junit5.RunInEdt import com.intellij.testFramework.junit5.TestApplication import com.intellij.util.ui.EDT @@ -84,6 +85,7 @@ internal class IntegrationTestExtension : BeforeAllCallback, ProjectUtil.openOrCreateProject(testClassName, Files.createTempDirectory(testClassName))!! } + Disposer.register(ApplicationManager.getApplication(), project) context.getStore(namespace).put(projectKey, project) val dataSource = runBlocking { From 97cf2f3cd71b65839cd5c29b222589021998a4d5 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 17:48:50 +0200 Subject: [PATCH 11/16] chore: ensure namespace is properly escaped --- .../mongodb/jbplugin/accessadapter/MongoDbDriver.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt index c7dc5d4b..d54359dd 100644 --- a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt @@ -21,8 +21,14 @@ import kotlin.time.Duration.Companion.seconds * @property database * @property collection */ -data class Namespace(val database: String, val collection: String) { +class Namespace private constructor(val database: String, val collection: String) { override fun toString(): String = "$database.$collection" + companion object { + operator fun invoke(database: String, collection: String): Namespace = Namespace( + Encode.forJavaScript(database), + Encode.forJavaScript(collection) + ) + } } /** @@ -64,8 +70,5 @@ interface MongoDbDriver { */ fun String.toNs(): Namespace { val (db, coll) = trim().split(".", limit = 2) - return Namespace( - Encode.forJavaScript(db), - Encode.forJavaScript(coll) - ) + return Namespace(db, coll) } \ No newline at end of file From 0973ffa9899f66612a7c828d05c237d63d092b25 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 17:54:48 +0200 Subject: [PATCH 12/16] chore: fix test, we are not using a data class anymore --- .github/workflows/quality-check.yaml | 5 +---- .../com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt | 4 ++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quality-check.yaml b/.github/workflows/quality-check.yaml index 35e9b59c..cca38767 100644 --- a/.github/workflows/quality-check.yaml +++ b/.github/workflows/quality-check.yaml @@ -120,15 +120,12 @@ jobs: sudo apt install -y docker docker-compose - name: Run Test Suite run: | - ./gradlew --stacktrace --console=plain "clean" "cleanTest" "unitTest" + ./gradlew --stacktrace --console=plain "clean" "cleanTest" "unitTest" "jacocoTestReport" -x "packages:jetbrains-plugin:uiTest" - name: Publish Test Report uses: mikepenz/action-junit-report@v4 if: success() || failure() # always run even if the previous step fails with: report_paths: '**/build/test-results/test/TEST-*.xml' - - name: Generate Coverage Report - run: | - ./gradlew --quiet --console=plain "jacocoTestReport" -x "packages:jetbrains-plugin:uiTest" - uses: actions/upload-artifact@v4 name: Upload Unit Test Coverage with: diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt index d54359dd..bb62e689 100644 --- a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt @@ -11,6 +11,7 @@ package com.mongodb.jbplugin.accessadapter import org.bson.Document import org.owasp.encoder.Encode +import java.util.* import kotlin.reflect.KClass import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds @@ -23,6 +24,9 @@ import kotlin.time.Duration.Companion.seconds */ class Namespace private constructor(val database: String, val collection: String) { override fun toString(): String = "$database.$collection" + override fun equals(other: Any?): Boolean = other is Namespace && hashCode() == other.hashCode() + override fun hashCode(): Int = Objects.hash(database, collection) + companion object { operator fun invoke(database: String, collection: String): Namespace = Namespace( Encode.forJavaScript(database), From 502d84934906f6cb1b736ba0703adfe17ab75404 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 18:05:01 +0200 Subject: [PATCH 13/16] chore: remove unused code --- ...ActivatePluginPostStartupActivityUiTest.kt | 21 ---------- .../components/SayHelloMessageBoxFixture.kt | 41 ------------------- 2 files changed, 62 deletions(-) delete mode 100644 packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivityUiTest.kt delete mode 100644 packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/SayHelloMessageBoxFixture.kt diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivityUiTest.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivityUiTest.kt deleted file mode 100644 index 3a251ad9..00000000 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/ActivatePluginPostStartupActivityUiTest.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.mongodb.jbplugin - -import com.intellij.remoterobot.RemoteRobot -import com.mongodb.jbplugin.fixtures.RequiresProject -import com.mongodb.jbplugin.fixtures.UiTest -import com.mongodb.jbplugin.fixtures.components.SayHelloMessageBoxFixture -import com.mongodb.jbplugin.fixtures.findVisible -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -@UiTest -class ActivatePluginPostStartupActivityUiTest { - @Test - @RequiresProject("basic-java-project-with-mongodb") - fun `shows a notification message`(remoteRobot: RemoteRobot) { - val sayHelloMessageBox = remoteRobot.findVisible() - - assertEquals("Build Info", sayHelloMessageBox.title) - sayHelloMessageBox.ok() - } -} diff --git a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/SayHelloMessageBoxFixture.kt b/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/SayHelloMessageBoxFixture.kt deleted file mode 100644 index 2023fd98..00000000 --- a/packages/jetbrains-plugin/src/test/kotlin/com/mongodb/jbplugin/fixtures/components/SayHelloMessageBoxFixture.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.mongodb.jbplugin.fixtures.components - -import com.intellij.remoterobot.RemoteRobot -import com.intellij.remoterobot.data.RemoteComponent -import com.intellij.remoterobot.fixtures.* -import com.intellij.remoterobot.search.locators.byXpath -import com.intellij.remoterobot.stepsProcessing.step -import com.mongodb.jbplugin.fixtures.stripHtml - -/** - * Represents the interactions with the hello message box. - * - * @param remoteRobot - * @param remoteComponent - */ -@DefaultXpath(by = "Name", xpath = "//div[@class='MyDialog' and @title='Build Info']") -@FixtureName(name = "Say Hello Message Box") -class SayHelloMessageBoxFixture(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) : ContainerFixture( - remoteRobot, remoteComponent -) { - val title by lazy { - step("get title of the say hello message box") { - find(ComponentFixture::class.java, byXpath("//div[@visible_text='Build Info']")).callJs( - "component.getText();" - ).stripHtml() - } - } - val body by lazy { - step("get body of the say hello message box") { - find( - ComponentFixture::class.java, byXpath("//div[@visible_text='4.11.0']") - ).callJs("component.getText();").stripHtml() - } - } - - fun ok() { - step("clicking the confirmation button of the message box") { - find(ActionButtonFixture::class.java, byXpath("//div[@visible_text='OK']")).click() - } - } -} \ No newline at end of file From ebd46ac5738b610b622090c824dbd448caae487f Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 18:23:16 +0200 Subject: [PATCH 14/16] chore: add coverage to read model provider --- .../actions/GetMongoDBVersionAction.kt | 50 ------------------- .../src/main/resources/META-INF/plugin.xml | 6 --- .../DataGripBasedReadModelProviderTest.kt | 22 ++++++++ .../accessadapter/datagrip/IntegrationTest.kt | 4 ++ 4 files changed, 26 insertions(+), 56 deletions(-) delete mode 100644 packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/actions/GetMongoDBVersionAction.kt create mode 100644 packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProviderTest.kt diff --git a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/actions/GetMongoDBVersionAction.kt b/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/actions/GetMongoDBVersionAction.kt deleted file mode 100644 index c08b4f91..00000000 --- a/packages/jetbrains-plugin/src/main/kotlin/com/mongodb/jbplugin/actions/GetMongoDBVersionAction.kt +++ /dev/null @@ -1,50 +0,0 @@ -/** - * A Simple, example action, that prints out in a modal popup the version of the - * connected MongoDB Cluster. - */ - -package com.mongodb.jbplugin.actions - -import com.intellij.database.dataSource.localDataSource -import com.intellij.database.psi.DbDataSource -import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.components.Service -import com.intellij.openapi.rd.util.launchChildOnUi -import com.intellij.openapi.ui.Messages -import com.mongodb.jbplugin.accessadapter.datagrip.DataGripBasedReadModelProvider -import com.mongodb.jbplugin.accessadapter.slice.BuildInfo -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch - -/** - * Service that implements the action. - * - * @param coroutineScope - */ -@Service(Service.Level.PROJECT) -class GetMongoDbVersionActionService( - private val coroutineScope: CoroutineScope -) { - fun actionPerformed(event: AnActionEvent) { - coroutineScope.launch { - val readModelProvider = event.project!!.getService(DataGripBasedReadModelProvider::class.java) - val dataSource = event.dataContext.getData(PlatformDataKeys.PSI_ELEMENT) as DbDataSource - val buildInfo = readModelProvider.slice(dataSource.localDataSource!!, BuildInfo.Slice) - - coroutineScope.launchChildOnUi { - Messages.showMessageDialog(buildInfo.version, "Show DB Version", null) - } - } - } -} - -/** - * Action that can be run within the contextual menu of a connection in the data explorer. - */ -class GetMongoDbVersionAction : AnAction() { - override fun actionPerformed(event: AnActionEvent) { - event.project!!.getService(GetMongoDbVersionActionService::class.java).actionPerformed(event) - } -} \ No newline at end of file diff --git a/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml b/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml index 8be472b9..98d97504 100644 --- a/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml +++ b/packages/jetbrains-plugin/src/main/resources/META-INF/plugin.xml @@ -14,10 +14,4 @@ - - - - - \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProviderTest.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProviderTest.kt new file mode 100644 index 00000000..c0437095 --- /dev/null +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProviderTest.kt @@ -0,0 +1,22 @@ +package com.mongodb.jbplugin.accessadapter.datagrip + +import com.intellij.database.dataSource.LocalDataSource +import com.intellij.openapi.project.Project +import com.mongodb.jbplugin.accessadapter.slice.BuildInfo +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +@IntegrationTest +class DataGripBasedReadModelProviderTest { + @Test + fun `can query a slice and returns the result`( +project: Project, + dataSource: LocalDataSource, + version: MongoDbVersion +) { + val service = project.getService(DataGripBasedReadModelProvider::class.java) + val info = service.slice(dataSource, BuildInfo.Slice) + + assertEquals(version.versionString, info.version) + } +} \ No newline at end of file diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt index f679dec0..daedc784 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/IntegrationTest.kt @@ -62,6 +62,7 @@ internal class IntegrationTestExtension : BeforeAllCallback, private val namespace = ExtensionContext.Namespace.create(IntegrationTestExtension::class.java) private val containerKey = "CONTAINER" private val projectKey = "PROJECT" + private val dataSourceKey = "DATASOURCE" private val driverKey = "DRIVER" private val versionKey = "VERSION" @@ -102,6 +103,7 @@ internal class IntegrationTestExtension : BeforeAllCallback, databaseDriver = jdbcDriver } + context.getStore(namespace).put(dataSourceKey, dataSource) dataSourceManager.addDataSource(dataSource) dataSource } @@ -134,12 +136,14 @@ internal class IntegrationTestExtension : BeforeAllCallback, override fun supportsParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Boolean = parameterContext?.parameter?.type == Project::class.java || parameterContext?.parameter?.type == MongoDbDriver::class.java || + parameterContext?.parameter?.type == LocalDataSource::class.java || parameterContext?.parameter?.type == MongoDbVersion::class.java override fun resolveParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Any = when (parameterContext?.parameter?.type) { Project::class.java -> extensionContext!!.getStore(namespace).get(projectKey) MongoDbDriver::class.java -> extensionContext!!.getStore(namespace).get(driverKey) + LocalDataSource::class.java -> extensionContext!!.getStore(namespace).get(dataSourceKey) MongoDbVersion::class.java -> extensionContext!!.getStore(namespace).get(versionKey) else -> TODO("Parameter of type ${parameterContext?.parameter?.type?.canonicalName} is not supported.") } From 206d19cf29db93a87b024cf951a6e206c8e43aef Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 18:24:03 +0200 Subject: [PATCH 15/16] chore: format --- .../datagrip/DataGripBasedReadModelProviderTest.kt | 8 ++++---- .../com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProviderTest.kt b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProviderTest.kt index c0437095..a0af536e 100644 --- a/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProviderTest.kt +++ b/packages/mongodb-access-adapter/datagrip-access-adapter/src/test/kotlin/com/mongodb/jbplugin/accessadapter/datagrip/DataGripBasedReadModelProviderTest.kt @@ -10,10 +10,10 @@ import org.junit.jupiter.api.Test class DataGripBasedReadModelProviderTest { @Test fun `can query a slice and returns the result`( -project: Project, - dataSource: LocalDataSource, - version: MongoDbVersion -) { + project: Project, + dataSource: LocalDataSource, + version: MongoDbVersion + ) { val service = project.getService(DataGripBasedReadModelProvider::class.java) val info = service.slice(dataSource, BuildInfo.Slice) diff --git a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt index bb62e689..9ba6e186 100644 --- a/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt +++ b/packages/mongodb-access-adapter/src/main/kotlin/com/mongodb/jbplugin/accessadapter/MongoDbDriver.kt @@ -29,9 +29,9 @@ class Namespace private constructor(val database: String, val collection: String companion object { operator fun invoke(database: String, collection: String): Namespace = Namespace( - Encode.forJavaScript(database), - Encode.forJavaScript(collection) - ) + Encode.forJavaScript(database), + Encode.forJavaScript(collection) + ) } } From bdf43e11084c855dac15058dbdb5ad9832cdf25c Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 23 May 2024 18:48:17 +0200 Subject: [PATCH 16/16] chore: setup docker for the draft pipeline, as it runs the tests --- .github/workflows/draft-release.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/draft-release.yaml b/.github/workflows/draft-release.yaml index b9eff538..1a6efa5a 100644 --- a/.github/workflows/draft-release.yaml +++ b/.github/workflows/draft-release.yaml @@ -68,7 +68,10 @@ jobs: echo "If this version has already been release consider using a different one." exit 1 fi - + - name: Setup Docker (for Test Containers) + run: | + sudo apt update -y + sudo apt install -y docker docker-compose - name: Run Unit and Integration Tests run: | ./gradlew "unitTest" ":packages:jetbrains-plugin:test"