Skip to content

Commit 260f02a

Browse files
authored
SWIFT-1383 Test that driver only creates implicit session after connection checkout (#734)
1 parent b6fda97 commit 260f02a

File tree

4 files changed

+64
-13
lines changed

4 files changed

+64
-13
lines changed

.evergreen/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1399,7 +1399,7 @@ buildvariants:
13991399
display_name: "${sanitize} ${os-fully-featured} ${ssl-auth}"
14001400
matrix_spec:
14011401
os-fully-featured: "ubuntu-18.04"
1402-
swift-version: "5.5"
1402+
swift-version: "5.4" # TODO SWIFT-1499: update to Swift 5.5
14031403
ssl-auth: "*"
14041404
sanitize: "tsan"
14051405
tasks:

Tests/MongoSwiftSyncTests/ClientSessionTests.swift

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ final class SyncClientSessionTests: MongoSwiftTestCase {
320320
}
321321
}
322322

323+
/// Sessions spec test 13 was easier to write with concurrency and lives in MongoSwiftTests/AsyncAwaitTests.swift.
324+
323325
/// Test that causal consistency guarantees are met on deployments that support cluster time.
324326
func testCausalConsistency() throws {
325327
guard MongoSwiftTestCase.topologyType != .single else {
@@ -512,17 +514,6 @@ final class SyncClientSessionTests: MongoSwiftTestCase {
512514
expect(startedEvents).to(haveCount(1))
513515
expect(startedEvents[0].command["readConcern"]?.documentValue?["afterClusterTime"]).to(beNil())
514516
}
515-
516-
// Causal consistency spec test 10: When an unacknowledged write is executed in a causally consistent
517-
// ClientSession the operationTime property of the ClientSession is not updated
518-
try client.withSession(options: ClientSessionOptions(causalConsistency: true)) { session in
519-
let collection1 = db.collection(
520-
self.getCollectionName(),
521-
options: MongoCollectionOptions(writeConcern: try WriteConcern(w: .number(0)))
522-
)
523-
try collection1.insertOne(["x": 3])
524-
expect(session.operationTime).to(beNil())
525-
}
526517
}
527518

528519
func testSessionsUnified() throws {

Tests/MongoSwiftTests/AsyncAwaitTestUtils.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,15 @@ extension MongoSwiftTestCase {
7070
// see: https://github.com/realm/SwiftLint/issues/3753
7171
internal func withTestNamespace<T>(
7272
ns: MongoNamespace? = nil,
73+
clientOptions: MongoClientOptions? = nil,
7374
collectionOptions: CreateCollectionOptions? = nil,
7475
_ f: (MongoClient, MongoDatabase, MongoCollection<BSONDocument>) async throws -> T
7576
) async throws -> T {
7677
let ns = ns ?? self.getNamespace()
7778
guard let collName = ns.collection else {
7879
throw TestError(message: "missing collection")
7980
}
80-
return try await self.withTestClient { client in
81+
return try await self.withTestClient(options: clientOptions) { client in
8182
let database = client.db(ns.db)
8283
let collection: MongoCollection<BSONDocument>
8384
do {
@@ -147,4 +148,14 @@ extension MongoClient {
147148
}
148149
}
149150

151+
@available(macOS 12, *)
152+
extension TestCommandMonitor {
153+
/// Capture events that occur while the the provided closure executes.
154+
public func captureEvents<T>(_ f: () async throws -> T) async rethrows -> T {
155+
self.enable()
156+
defer { self.disable() }
157+
return try await f()
158+
}
159+
}
160+
150161
#endif

Tests/MongoSwiftTests/AsyncAwaitTests.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,55 @@ final class AsyncAwaitTests: MongoSwiftTestCase {
144144
}
145145
}
146146
}
147+
148+
/// Sessions prose test 13: Test that implicit sessions only allocate their server session after a successful
149+
/// connection checkout.
150+
func testImplicitSessionsCreatedAfterConnectionCheckout() throws {
151+
testAsync {
152+
let clientOptions = MongoClientOptions(maxPoolSize: 1)
153+
try await self.withTestNamespace(clientOptions: clientOptions) { client, _, coll in
154+
let monitor = client.addCommandMonitor()
155+
try await monitor.captureEvents {
156+
async let insert = try coll.insertOne(["x": 1])
157+
async let delete = try coll.deleteOne(["x": 2])
158+
async let update = try coll.updateOne(filter: ["x": 3], update: ["$set": ["y": 1]])
159+
async let bulk = try coll.bulkWrite([.updateOne(filter: ["x": 4], update: ["$set": ["y": 1]])])
160+
async let findOneAndDelete = try coll.findOneAndDelete(["x": 5])
161+
async let findOneAndUpdate = try coll.findOneAndUpdate(
162+
filter: ["x": 6],
163+
update: ["$set": ["y": 1]]
164+
)
165+
async let findOneAndReplace = try coll.findOneAndReplace(filter: ["x": 7], replacement: ["x": 8])
166+
async let cursor = try coll.find()
167+
// the cursor will hold onto its connection until its done being iterated, so we need to iterate to
168+
// allow the other operations to make progress.
169+
for try await _ in try await cursor {}
170+
_ = try await [
171+
insert,
172+
delete,
173+
update,
174+
bulk,
175+
findOneAndDelete,
176+
findOneAndUpdate,
177+
findOneAndReplace
178+
] as [Any?]
179+
}
180+
let events = monitor.events(withEventTypes: [.commandStartedEvent])
181+
guard events.count == 8 else {
182+
XCTFail("Expected 8 command started events, but only found \(events.count)")
183+
return
184+
}
185+
let lsids = events.compactMap { $0.commandStartedValue!.command["lsid"] }
186+
guard lsids.count == 8 else {
187+
XCTFail("Expected 8 command started events to contain lsids, but only found \(lsids.count)")
188+
return
189+
}
190+
for i in 1...7 {
191+
expect(lsids[i]).to(equal(lsids[0]))
192+
}
193+
}
194+
}
195+
}
147196
}
148197

149198
@available(macOS 12, *)

0 commit comments

Comments
 (0)