Skip to content

Commit 21065b5

Browse files
authored
Initial driver-kotlin-coroutine implementation
Wraps the driver-reactivestreams to provide a kotlin coroutine API In general a faithful wrapping of the reactivestreams driver but with coroutine support instead of using Publishers. Uses reified overloads to provide synaptic sugar instead of passing resultClass. JAVA-4870
1 parent 9609890 commit 21065b5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+8224
-1
lines changed

.evergreen/run-kotlin-tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ fi
3434
echo "Running Kotlin tests"
3535

3636
./gradlew -version
37-
./gradlew :driver-kotlin-sync:kCheck -Dorg.mongodb.test.uri=${MONGODB_URI} ${MULTI_MONGOS_URI_SYSTEM_PROPERTY}
37+
./gradlew kCheck -Dorg.mongodb.test.uri=${MONGODB_URI} ${MULTI_MONGOS_URI_SYSTEM_PROPERTY}

config/detekt/baseline.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
<CurrentIssues>
55
<ID>IteratorNotThrowingNoSuchElementException:MongoCursor.kt$MongoCursor&lt;T : Any> : IteratorCloseable</ID>
66
<ID>LargeClass:MongoCollectionTest.kt$MongoCollectionTest</ID>
7+
<ID>LongMethod:FindFlowTest.kt$FindFlowTest$@Suppress("DEPRECATION") @Test fun shouldCallTheUnderlyingMethods()</ID>
78
<ID>LongMethod:FindIterableTest.kt$FindIterableTest$@Suppress("DEPRECATION") @Test fun shouldCallTheUnderlyingMethods()</ID>
9+
<ID>MaxLineLength:MapReduceFlow.kt$MapReduceFlow$*</ID>
810
<ID>MaxLineLength:MapReduceIterable.kt$MapReduceIterable$*</ID>
911
<ID>SwallowedException:MockitoHelper.kt$MockitoHelper.DeepReflectionEqMatcher$e: Throwable</ID>
1012
<ID>TooManyFunctions:ClientSession.kt$ClientSession : jClientSession</ID>
13+
<ID>TooManyFunctions:FindFlow.kt$FindFlow&lt;T : Any> : Flow</ID>
1114
<ID>TooManyFunctions:FindIterable.kt$FindIterable&lt;T : Any> : MongoIterable</ID>
1215
<ID>TooManyFunctions:MongoCollection.kt$MongoCollection&lt;T : Any></ID>
1316
<ID>TooManyFunctions:MongoDatabase.kt$MongoDatabase</ID>

config/spotbugs/exclude.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@
175175
<Bug pattern="NM_SAME_SIMPLE_NAME_AS_INTERFACE"/>
176176
</Match>
177177

178+
<Match>
179+
<Class name="~com.mongodb.kotlin.client.coroutine.ClientSession.*"/>
180+
<Bug pattern="NM_SAME_SIMPLE_NAME_AS_INTERFACE"/>
181+
</Match>
182+
178183
<Match>
179184
<Class name="~com.mongodb.internal.async.client.ClientSession.*"/>
180185
<Bug pattern="NM_SAME_SIMPLE_NAME_AS_INTERFACE"/>
@@ -252,4 +257,20 @@
252257
<Method name="~.*validateAnnotations.*"/>
253258
<Bug pattern="UC_USELESS_OBJECT"/>
254259
</Match>
260+
261+
262+
<!-- Spotbugs reports false positives for suspendable operations with default params
263+
see: https://github.com/Kotlin/kotlinx.coroutines/issues/3099
264+
-->
265+
<Match>
266+
<Class name="com.mongodb.kotlin.client.coroutine.MongoClient"/>
267+
<Method name="startSession"/>
268+
<Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"/>
269+
</Match>
270+
<Match>
271+
<Class name="~com.mongodb.kotlin.client.coroutine.*"/>
272+
<Bug pattern="NP_NONNULL_PARAM_VIOLATION"/>
273+
</Match>
274+
275+
255276
</FindBugsFilter>
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import io.gitlab.arturbosch.detekt.Detekt
17+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
18+
19+
plugins {
20+
id("org.jetbrains.kotlin.jvm") version "1.8.10"
21+
`java-library`
22+
23+
// Test based plugins
24+
id("com.diffplug.spotless")
25+
id("org.jetbrains.dokka") version "1.7.20"
26+
id("io.gitlab.arturbosch.detekt") version "1.21.0"
27+
}
28+
29+
repositories {
30+
mavenCentral()
31+
google()
32+
}
33+
34+
base.archivesName.set("mongodb-driver-kotlin-coroutine")
35+
36+
description = "The MongoDB Kotlin Coroutine Driver"
37+
38+
ext.set("pomName", "MongoDB Kotlin Coroutine Driver")
39+
40+
sourceSets {
41+
create("integrationTest") {
42+
kotlin.srcDir("$projectDir/src/integration/kotlin")
43+
compileClasspath += sourceSets.main.get().output
44+
runtimeClasspath += sourceSets.main.get().output
45+
compileClasspath += project(":driver-sync").sourceSets.test.get().output
46+
runtimeClasspath += project(":driver-sync").sourceSets.test.get().output
47+
compileClasspath += project(":driver-core").sourceSets.test.get().output
48+
runtimeClasspath += project(":driver-core").sourceSets.test.get().output
49+
compileClasspath += project(":bson").sourceSets.test.get().output
50+
runtimeClasspath += project(":bson").sourceSets.test.get().output
51+
}
52+
}
53+
54+
val integrationTestImplementation: Configuration by
55+
configurations.getting { extendsFrom(configurations.testImplementation.get()) }
56+
57+
dependencies {
58+
// Align versions of all Kotlin components
59+
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
60+
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
61+
62+
implementation(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4"))
63+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
64+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactive")
65+
66+
api(project(path = ":bson", configuration = "default"))
67+
api(project(path = ":driver-reactive-streams", configuration = "default"))
68+
69+
testImplementation("org.jetbrains.kotlin:kotlin-reflect")
70+
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
71+
testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0")
72+
testImplementation("org.mockito:mockito-junit-jupiter:4.11.0")
73+
testImplementation("org.assertj:assertj-core:3.24.2")
74+
testImplementation("io.github.classgraph:classgraph:4.8.154")
75+
76+
integrationTestImplementation("org.jetbrains.kotlin:kotlin-test-junit")
77+
integrationTestImplementation(project(path = ":driver-sync"))
78+
integrationTestImplementation(project(path = ":driver-core"))
79+
integrationTestImplementation(project(path = ":bson"))
80+
}
81+
82+
kotlin { explicitApi() }
83+
84+
tasks.withType<KotlinCompile> { kotlinOptions.jvmTarget = "1.8" }
85+
86+
// ===========================
87+
// Code Quality checks
88+
// ===========================
89+
spotless {
90+
kotlinGradle {
91+
ktfmt("0.39").dropboxStyle().configure { it.setMaxWidth(120) }
92+
trimTrailingWhitespace()
93+
indentWithSpaces()
94+
endWithNewline()
95+
licenseHeaderFile(rootProject.file("config/mongodb.license"), "(group|plugins|import|buildscript|rootProject)")
96+
}
97+
98+
kotlin {
99+
target("**/*.kt")
100+
ktfmt().dropboxStyle().configure { it.setMaxWidth(120) }
101+
trimTrailingWhitespace()
102+
indentWithSpaces()
103+
endWithNewline()
104+
licenseHeaderFile(rootProject.file("config/mongodb.license"))
105+
}
106+
107+
format("extraneous") {
108+
target("*.xml", "*.yml", "*.md")
109+
trimTrailingWhitespace()
110+
indentWithSpaces()
111+
endWithNewline()
112+
}
113+
}
114+
115+
tasks.named("check") { dependsOn("spotlessApply") }
116+
117+
detekt {
118+
allRules = true // fail build on any finding
119+
buildUponDefaultConfig = true // preconfigure defaults
120+
config = rootProject.files("config/detekt/detekt.yml") // point to your custom config defining rules to run,
121+
// overwriting default behavior
122+
baseline = rootProject.file("config/detekt/baseline.xml") // a way of suppressing issues before introducing detekt
123+
source =
124+
files(
125+
file("src/main/kotlin"),
126+
file("src/test/kotlin"),
127+
file("src/integrationTest/kotlin"),
128+
)
129+
}
130+
131+
tasks.withType<Detekt>().configureEach {
132+
reports {
133+
html.required.set(true) // observe findings in your browser with structure and code snippets
134+
xml.required.set(true) // checkstyle like format mainly for integrations like Jenkins
135+
txt.required.set(false) // similar to the console output, contains issue signature to manually edit
136+
}
137+
}
138+
139+
spotbugs {
140+
showProgress.set(true)
141+
142+
tasks.getByName("spotbugsIntegrationTest") { enabled = false }
143+
}
144+
145+
// ===========================
146+
// Test Configuration
147+
// ===========================
148+
val integrationTest =
149+
tasks.create("integrationTest", Test::class) {
150+
description = "Runs the integration tests."
151+
group = "verification"
152+
153+
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
154+
classpath = sourceSets["integrationTest"].runtimeClasspath
155+
}
156+
157+
tasks.create("kCheck") {
158+
description = "Runs all the kotlin checks"
159+
group = "verification"
160+
161+
dependsOn("clean", "check", integrationTest)
162+
tasks.findByName("check")?.mustRunAfter("clean")
163+
tasks.findByName("integrationTest")?.mustRunAfter("check")
164+
}
165+
166+
tasks.test { useJUnitPlatform() }
167+
168+
// ===========================
169+
// Dokka Configuration
170+
// ===========================
171+
val dokkaOutputDir = "${rootProject.buildDir}/docs/${base.archivesName.get()}"
172+
173+
tasks.dokkaHtml.configure {
174+
outputDirectory.set(file(dokkaOutputDir))
175+
moduleName.set(base.archivesName.get())
176+
}
177+
178+
val cleanDokka by tasks.register<Delete>("cleanDokka") { delete(dokkaOutputDir) }
179+
180+
project.parent?.tasks?.named("docs") {
181+
dependsOn(tasks.dokkaHtml)
182+
mustRunAfter(cleanDokka)
183+
}
184+
185+
tasks.javadocJar.configure {
186+
dependsOn(cleanDokka, tasks.dokkaHtml)
187+
archiveClassifier.set("javadoc")
188+
from(dokkaOutputDir)
189+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mongodb.kotlin.client.coroutine
17+
18+
import com.mongodb.client.AbstractCrudTest
19+
import com.mongodb.client.Fixture
20+
import com.mongodb.client.MongoDatabase
21+
import com.mongodb.event.CommandListener
22+
import com.mongodb.kotlin.client.coroutine.syncadapter.SyncMongoClient
23+
import org.bson.BsonArray
24+
import org.bson.BsonDocument
25+
26+
data class CrudTest(
27+
val filename: String,
28+
val description: String,
29+
val databaseName: String,
30+
val collectionName: String,
31+
val data: BsonArray,
32+
val definition: BsonDocument,
33+
val skipTest: Boolean
34+
) : AbstractCrudTest(filename, description, databaseName, collectionName, data, definition, skipTest) {
35+
36+
private var mongoClient: SyncMongoClient? = null
37+
38+
override fun createMongoClient(commandListener: CommandListener) {
39+
mongoClient =
40+
SyncMongoClient(
41+
MongoClient.create(Fixture.getMongoClientSettingsBuilder().addCommandListener(commandListener).build()))
42+
}
43+
44+
override fun getDatabase(databaseName: String): MongoDatabase = mongoClient!!.getDatabase(databaseName)
45+
46+
override fun cleanUp() {
47+
mongoClient?.close()
48+
}
49+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mongodb.kotlin.client.coroutine
17+
18+
import java.io.IOException
19+
import java.net.URISyntaxException
20+
import org.bson.BsonArray
21+
import org.bson.BsonDocument
22+
import org.junit.Assume.assumeFalse
23+
import org.junit.runners.Parameterized
24+
25+
internal class UnifiedCrudTest(
26+
fileDescription: String?,
27+
testDescription: String,
28+
schemaVersion: String,
29+
runOnRequirements: BsonArray?,
30+
entitiesArray: BsonArray,
31+
initialData: BsonArray,
32+
definition: BsonDocument
33+
) : UnifiedTest(fileDescription, schemaVersion, runOnRequirements, entitiesArray, initialData, definition) {
34+
35+
init {
36+
assumeFalse(testDescription == "Unacknowledged findOneAndReplace with hint string on 4.4+ server")
37+
assumeFalse(testDescription == "Unacknowledged findOneAndReplace with hint document on 4.4+ server")
38+
assumeFalse(testDescription == "Unacknowledged findOneAndUpdate with hint string on 4.4+ server")
39+
assumeFalse(testDescription == "Unacknowledged findOneAndUpdate with hint document on 4.4+ server")
40+
assumeFalse(testDescription == "Unacknowledged findOneAndDelete with hint string on 4.4+ server")
41+
assumeFalse(testDescription == "Unacknowledged findOneAndDelete with hint document on 4.4+ server")
42+
}
43+
44+
companion object {
45+
@JvmStatic
46+
@Parameterized.Parameters(name = "{0}: {1}")
47+
@Throws(URISyntaxException::class, IOException::class)
48+
fun data(): Collection<Array<Any?>?>? {
49+
return getTestData("unified-test-format/crud")
50+
}
51+
}
52+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mongodb.kotlin.client.coroutine
17+
18+
import com.mongodb.ClientEncryptionSettings
19+
import com.mongodb.MongoClientSettings
20+
import com.mongodb.client.MongoClient as JMongoClient
21+
import com.mongodb.client.MongoDatabase as JMongoDatabase
22+
import com.mongodb.client.gridfs.GridFSBucket
23+
import com.mongodb.client.unified.UnifiedTest as JUnifiedTest
24+
import com.mongodb.client.vault.ClientEncryption
25+
import com.mongodb.kotlin.client.coroutine.syncadapter.SyncMongoClient
26+
import org.bson.BsonArray
27+
import org.bson.BsonDocument
28+
29+
internal abstract class UnifiedTest(
30+
fileDescription: String?,
31+
schemaVersion: String,
32+
runOnRequirements: BsonArray?,
33+
entitiesArray: BsonArray,
34+
initialData: BsonArray,
35+
definition: BsonDocument
36+
) : JUnifiedTest(fileDescription, schemaVersion, runOnRequirements, entitiesArray, initialData, definition) {
37+
38+
override fun createMongoClient(settings: MongoClientSettings): JMongoClient =
39+
SyncMongoClient(MongoClient.create(settings))
40+
41+
override fun createGridFSBucket(database: JMongoDatabase?): GridFSBucket {
42+
TODO("Not yet implemented - JAVA-4893")
43+
}
44+
45+
override fun createClientEncryption(
46+
keyVaultClient: JMongoClient?,
47+
clientEncryptionSettings: ClientEncryptionSettings?
48+
): ClientEncryption {
49+
TODO("Not yet implemented - JAVA-4896")
50+
}
51+
}

0 commit comments

Comments
 (0)