Skip to content

Commit d5194a1

Browse files
authored
Fix Evergreen failures on replica sets and against serverless (#743)
1 parent b1e8f4b commit d5194a1

File tree

3 files changed

+211
-191
lines changed

3 files changed

+211
-191
lines changed

Tests/MongoSwiftSyncTests/MongoCursorTests.swift

Lines changed: 108 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,113 @@ final class MongoCursorTests: MongoSwiftTestCase {
5656
}
5757
}
5858

59+
func testNext() throws {
60+
try self.withTestNamespace { _, _, coll in
61+
// query empty collection
62+
var cursor = try coll.find()
63+
expect(cursor.next()).to(beNil())
64+
65+
// insert a doc so something matches initial query
66+
try coll.insertOne(doc1)
67+
cursor = try coll.find()
68+
69+
// next() returns a Result<Document, Error>?
70+
let result = cursor.next()
71+
expect(result).toNot(beNil())
72+
expect(try result?.get()).to(equal(doc1))
73+
74+
expect(cursor.next()).to(beNil())
75+
expect(cursor.isAlive()).to(beFalse())
76+
77+
expect(try cursor.next()?.get()).to(throwError(errorType: MongoError.LogicError.self))
78+
}
79+
}
80+
81+
func testKill() throws {
82+
try self.withTestNamespace { _, _, coll in
83+
_ = try coll.insertMany([[:], [:], [:]])
84+
let cursor = try coll.find()
85+
expect(cursor.isAlive()).to(beTrue())
86+
87+
expect(cursor.next()).toNot(beNil())
88+
expect(cursor.isAlive()).to(beTrue())
89+
90+
cursor.kill()
91+
expect(cursor.isAlive()).to(beFalse())
92+
expect(try cursor.next()?.get()).to(throwError(errorType: MongoError.LogicError.self))
93+
}
94+
}
95+
96+
func testLazySequence() throws {
97+
// Verify that the sequence behavior of normal cursors is as expected.
98+
try self.withTestNamespace { _, _, coll in
99+
try coll.insertMany([["_id": 1], ["_id": 2], ["_id": 3]])
100+
101+
var cursor = try coll.find()
102+
expect(Array(cursor).count).to(equal(3))
103+
expect(cursor.isAlive()).to(beFalse())
104+
105+
cursor = try coll.find()
106+
let mapped = Array(cursor.map { _ in 1 })
107+
expect(mapped).to(equal([1, 1, 1]))
108+
expect(cursor.isAlive()).to(beFalse())
109+
110+
cursor = try coll.find()
111+
let filteredMapped = cursor.filter {
112+
$0.isSuccess
113+
}.map { result -> Int? in
114+
let document = try! result.get() // always succeeds due to filter stage
115+
return document["_id"]?.toInt()
116+
}
117+
expect(Array(filteredMapped)).to(equal([1, 2, 3]))
118+
}
119+
}
120+
121+
func testCursorTerminatesOnError() throws {
122+
try self.withTestNamespace { client, _, coll in
123+
guard try client.supportsFailCommand() else {
124+
printSkipMessage(testName: self.name, reason: "failCommand not supported")
125+
return
126+
}
127+
128+
try coll.insertOne([:])
129+
try coll.insertOne([:])
130+
131+
let cursor = try coll.find([:], options: FindOptions(batchSize: 1))
132+
133+
let fp = FailPoint.failCommand(failCommands: ["getMore"], mode: .times(1), errorCode: 10)
134+
try fp.enable()
135+
defer { fp.disable() }
136+
137+
var count = 0
138+
for result in cursor {
139+
expect(count).to(beLessThan(2))
140+
if count >= 2 {
141+
break
142+
}
143+
// getmore should return error
144+
if count == 1 {
145+
expect(try result.get()).to(throwError())
146+
if result.isSuccess { break }
147+
}
148+
count += 1
149+
}
150+
}
151+
}
152+
153+
func testCursorClosedError() throws {
154+
try self.withTestNamespace { _, _, coll in
155+
let cursor = try coll.find([:], options: FindOptions(batchSize: 1))
156+
157+
for _ in cursor {}
158+
expect(try cursor.next()?.get()).to(throwError(errorType: MongoError.LogicError.self))
159+
}
160+
}
161+
}
162+
163+
/// These are in their own test class to make it easier to skip running them against serverless, which does not support
164+
/// capped collections. (CLOUDP-106443)
165+
final class TailableCursorTests: MongoSwiftTestCase {
59166
func testTailableCursor() throws {
60167
let collOptions = CreateCollectionOptions(capped: true, max: 3, size: 1000)
61168
try self.withTestNamespace(collectionOptions: collOptions) { _, _, coll in
@@ -113,43 +220,6 @@ final class MongoCursorTests: MongoSwiftTestCase {
113220
}
114221
}
115222

116-
func testNext() throws {
117-
try self.withTestNamespace { _, _, coll in
118-
// query empty collection
119-
var cursor = try coll.find()
120-
expect(cursor.next()).to(beNil())
121-
122-
// insert a doc so something matches initial query
123-
try coll.insertOne(doc1)
124-
cursor = try coll.find()
125-
126-
// next() returns a Result<Document, Error>?
127-
let result = cursor.next()
128-
expect(result).toNot(beNil())
129-
expect(try result?.get()).to(equal(doc1))
130-
131-
expect(cursor.next()).to(beNil())
132-
expect(cursor.isAlive()).to(beFalse())
133-
134-
expect(try cursor.next()?.get()).to(throwError(errorType: MongoError.LogicError.self))
135-
}
136-
}
137-
138-
func testKill() throws {
139-
try self.withTestNamespace { _, _, coll in
140-
_ = try coll.insertMany([[:], [:], [:]])
141-
let cursor = try coll.find()
142-
expect(cursor.isAlive()).to(beTrue())
143-
144-
expect(cursor.next()).toNot(beNil())
145-
expect(cursor.isAlive()).to(beTrue())
146-
147-
cursor.kill()
148-
expect(cursor.isAlive()).to(beFalse())
149-
expect(try cursor.next()?.get()).to(throwError(errorType: MongoError.LogicError.self))
150-
}
151-
}
152-
153223
func testKillTailable() throws {
154224
let options = CreateCollectionOptions(capped: true, max: 3, size: 1000)
155225
try self.withTestNamespace(ns: self.getNamespace(suffix: "tail"), collectionOptions: options) { _, _, coll in
@@ -188,30 +258,7 @@ final class MongoCursorTests: MongoSwiftTestCase {
188258
}
189259
}
190260

191-
func testLazySequence() throws {
192-
// Verify that the sequence behavior of normal cursors is as expected.
193-
try self.withTestNamespace { _, _, coll in
194-
try coll.insertMany([["_id": 1], ["_id": 2], ["_id": 3]])
195-
196-
var cursor = try coll.find()
197-
expect(Array(cursor).count).to(equal(3))
198-
expect(cursor.isAlive()).to(beFalse())
199-
200-
cursor = try coll.find()
201-
let mapped = Array(cursor.map { _ in 1 })
202-
expect(mapped).to(equal([1, 1, 1]))
203-
expect(cursor.isAlive()).to(beFalse())
204-
205-
cursor = try coll.find()
206-
let filteredMapped = cursor.filter {
207-
$0.isSuccess
208-
}.map { result -> Int? in
209-
let document = try! result.get() // always succeeds due to filter stage
210-
return document["_id"]?.toInt()
211-
}
212-
expect(Array(filteredMapped)).to(equal([1, 2, 3]))
213-
}
214-
261+
func testLazySequenceTailableCursor() throws {
215262
// Verify that map/filter are lazy by using a tailable cursor.
216263
let options = CreateCollectionOptions(capped: true, max: 3, size: 10000)
217264
try self.withTestNamespace(collectionOptions: options) { _, _, coll in
@@ -239,45 +286,4 @@ final class MongoCursorTests: MongoSwiftTestCase {
239286
expect(cursor.isAlive()).to(beFalse())
240287
}
241288
}
242-
243-
func testCursorTerminatesOnError() throws {
244-
try self.withTestNamespace { client, _, coll in
245-
guard try client.supportsFailCommand() else {
246-
printSkipMessage(testName: self.name, reason: "failCommand not supported")
247-
return
248-
}
249-
250-
try coll.insertOne([:])
251-
try coll.insertOne([:])
252-
253-
let cursor = try coll.find([:], options: FindOptions(batchSize: 1))
254-
255-
let fp = FailPoint.failCommand(failCommands: ["getMore"], mode: .times(1), errorCode: 10)
256-
try fp.enable()
257-
defer { fp.disable() }
258-
259-
var count = 0
260-
for result in cursor {
261-
expect(count).to(beLessThan(2))
262-
if count >= 2 {
263-
break
264-
}
265-
// getmore should return error
266-
if count == 1 {
267-
expect(try result.get()).to(throwError())
268-
if result.isSuccess { break }
269-
}
270-
count += 1
271-
}
272-
}
273-
}
274-
275-
func testCursorClosedError() throws {
276-
try self.withTestNamespace { _, _, coll in
277-
let cursor = try coll.find([:], options: FindOptions(batchSize: 1))
278-
279-
for _ in cursor {}
280-
expect(try cursor.next()?.get()).to(throwError(errorType: MongoError.LogicError.self))
281-
}
282-
}
283289
}

Tests/MongoSwiftSyncTests/SDAMTests.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,9 @@ final class SDAMTests: MongoSwiftTestCase {
236236
} + // true in URI
237237
hostURIs.map { try MongoClient.makeTestClient($0, options: optsTrue) } // true in options struct
238238

239-
// 4 of 6 attempts to perform writes should fail assuming these are 3-node replica sets, since in 2 cases we
240-
// will directly connect to the primary, and in the other 4 we will directly connect to a secondary.
239+
// we test against 3-node replica sets with one primary, one secondary, and one arbiter. 4 of 6 attempts to
240+
// perform writes here should fail, since in 2 cases we directly connect to the primary, and in the other 4 we
241+
// will directly connect to the secondary or arbiter.
241242

242243
var failures = 0
243244
for client in testClientsShouldMostlyFail {
@@ -246,14 +247,17 @@ final class SDAMTests: MongoSwiftTestCase {
246247
try collection.insertOne(["x": 1])
247248
}
248249
} catch {
249-
expect(error).to(beAnInstanceOf(MongoError.CommandError.self))
250+
// the error type here can vary. when the deployment does not use auth, the error should be a
251+
// CommandError. when the deployment does use auth, a write against a secondary will throw a
252+
// CommandError but a write against the arbiter will throw an AuthenticationError as arbiters do not
253+
// support auth.
250254
failures += 1
251255
}
252256
}
253257

254258
expect(failures).to(
255259
equal(4),
256-
description: "Writes should fail when connecting to secondaries with directConnection=true"
260+
description: "Writes should fail when connecting to secondaries and arbiters with directConnection=true"
257261
)
258262
}
259263
}

0 commit comments

Comments
 (0)