Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions Sources/MongoSwift/MongoClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,10 @@ public struct ClientOptions: CodingStrategyProvider, Decodable {
/// Specifies a ReadPreference to use for the client.
public var readPreference: ReadPreference? = nil

/// Determines whether the client should retry supported read operations.
// TODO: SWIFT-587 make this public.
internal var retryReads: Bool?
/// Determines whether the client should retry supported read operations (on by default).
public var retryReads: Bool?

/// Determines whether the client should retry supported write operations.
/// Determines whether the client should retry supported write operations (on by default).
public var retryWrites: Bool?

/**
Expand Down Expand Up @@ -67,7 +66,7 @@ public struct ClientOptions: CodingStrategyProvider, Decodable {
public var writeConcern: WriteConcern?

private enum CodingKeys: CodingKey {
case retryWrites, readConcern, writeConcern
case retryWrites, retryReads, readConcern, writeConcern
}

/// Convenience initializer allowing any/all to be omitted or optional.
Expand All @@ -78,6 +77,7 @@ public struct ClientOptions: CodingStrategyProvider, Decodable {
notificationCenter: NotificationCenter? = nil,
readConcern: ReadConcern? = nil,
readPreference: ReadPreference? = nil,
retryReads: Bool? = nil,
retryWrites: Bool? = nil,
serverMonitoring: Bool = false,
tlsOptions: TLSOptions? = nil,
Expand All @@ -91,6 +91,7 @@ public struct ClientOptions: CodingStrategyProvider, Decodable {
self.readConcern = readConcern
self.readPreference = readPreference
self.retryWrites = retryWrites
self.retryReads = retryReads
self.serverMonitoring = serverMonitoring
self.tlsOptions = tlsOptions
self.uuidCodingStrategy = uuidCodingStrategy
Expand Down
2 changes: 1 addition & 1 deletion Sources/MongoSwift/MongoCollection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public struct SyncMongoCollection<T: Codable> {
internal let _client: SyncMongoClient

/// The namespace for this collection.
private let namespace: MongoNamespace
internal let namespace: MongoNamespace

/// Encoder used by this collection for BSON conversions. (e.g. converting `CollectionType`s, indexes, and options
/// to documents).
Expand Down
7 changes: 7 additions & 0 deletions Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ extension ReadWriteConcernTests {
]
}

extension RetryableReadsTests {
static var allTests = [
("testRetryableReads", testRetryableReads),
]
}

extension RetryableWritesTests {
static var allTests = [
("testRetryableWrites", testRetryableWrites),
Expand Down Expand Up @@ -310,6 +316,7 @@ XCTMain([
testCase(OptionsTests.allTests),
testCase(ReadPreferenceTests.allTests),
testCase(ReadWriteConcernTests.allTests),
testCase(RetryableReadsTests.allTests),
testCase(RetryableWritesTests.allTests),
testCase(SDAMTests.allTests),
])
2 changes: 1 addition & 1 deletion Tests/MongoSwiftTests/ChangeStreamTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ internal struct ChangeStreamTestOperation: Decodable {
internal func execute(using client: SyncMongoClient) throws -> TestOperationResult? {
let db = client.db(self.database)
let coll = db.collection(self.collection)
return try self.operation.op.execute(client: client, database: db, collection: coll, session: nil)
return try self.operation.execute(on: .collection(coll), session: nil)
}
}

Expand Down
72 changes: 72 additions & 0 deletions Tests/MongoSwiftTests/RetryableReadsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Foundation
import MongoSwift
import Nimble
import XCTest

/// Struct representing a single test within a spec test JSON file.
private struct RetryableReadsTest: SpecTest {
let description: String

let operations: [TestOperationDescription]

let clientOptions: ClientOptions?

let useMultipleMongoses: Bool?

let skipReason: String?

let failPoint: FailPoint?

let expectations: [TestCommandStartedEvent]?
}

/// Struct representing a single retryable-writes spec test JSON file.
private struct RetryableReadsTestFile: Decodable, SpecTestFile {
private enum CodingKeys: String, CodingKey {
case name, runOn, databaseName = "database_name", collectionName = "collection_name", data, tests
}

let name: String

let runOn: [TestRequirement]?

let databaseName: String

let collectionName: String?

let data: TestData

let tests: [RetryableReadsTest]
}

final class RetryableReadsTests: MongoSwiftTestCase, FailPointConfigured {
var activeFailPoint: FailPoint?

override func tearDown() {
self.disableActiveFailPoint()
}

override func setUp() {
self.continueAfterFailure = false
}

func testRetryableReads() throws {
let skippedTestKeywords = [
"findOne", // TODO: SWIFT-643: Unskip this test
"changeStream", // TODO: SWIFT-648: Unskip this test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so does libmongoc skip this test or how did they not catch this before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they run the test and apparently it passes. From talking with Kevin, it seems that maybe they're just not verifying all the results.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤷‍♀

"gridfs",
"count.",
"count-",
"mapReduce"
]

let tests = try retrieveSpecTestFiles(specName: "retryable-reads", asType: RetryableReadsTestFile.self)
for (_, testFile) in tests {
guard skippedTestKeywords.allSatisfy({ !testFile.name.contains($0) }) else {
fileLevelLog("Skipping tests from file \(testFile.name)...")
continue
}
try testFile.runTests(parent: self)
}
}
}
43 changes: 38 additions & 5 deletions Tests/MongoSwiftTests/RetryableWritesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import Foundation
import Nimble
import XCTest

/// Struct representing a single test within a spec test JSON file.
private struct RetryableWritesTest: Decodable, SpecTest {
/// Struct representing a single test within a retryable-writes spec test JSON file.
private struct RetryableWritesTest: Decodable {
/// Description of the test.
let description: String

/// The expected outcome of executing the operation.
let outcome: TestOutcome

/// The operation to execute as part of this test case.
let operation: AnyTestOperation

/// Options used to configure the `SyncMongoClient` used for this test.
Expand Down Expand Up @@ -67,12 +72,12 @@ final class RetryableWritesTests: MongoSwiftTestCase, FailPointConfigured {

if let requirements = testFile.runOn {
guard requirements.contains(where: { $0.isMet(by: version, MongoSwiftTestCase.topologyType) }) else {
print("Skipping tests from file \(fileName), deployment requirements not met.")
fileLevelLog("Skipping tests from file \(fileName), deployment requirements not met.")
continue
}
}

print("\n------------\nExecuting tests from file \(fileName)...\n")
fileLevelLog("Executing tests from file \(fileName)...\n")
for test in testFile.tests {
print("Executing test: \(test.description)")

Expand All @@ -90,7 +95,35 @@ final class RetryableWritesTests: MongoSwiftTestCase, FailPointConfigured {
}
defer { self.disableActiveFailPoint() }

try test.run(client: client, db: db, collection: collection, session: nil)
var result: TestOperationResult?
var seenError: Error?

do {
result = try test.operation.execute(on: .collection(collection), session: nil)
} catch {
if case let ServerError.bulkWriteError(_, _, _, bulkResult, _) = error {
result = TestOperationResult(from: bulkResult)
}
seenError = error
}

if test.outcome.error ?? false {
expect(seenError).toNot(beNil(), description: test.description)
} else {
expect(seenError).to(beNil(), description: test.description)
}

if let expectedResult = test.outcome.result {
expect(result).toNot(beNil())
expect(result).to(equal(expectedResult))
}

let verifyColl = db.collection(test.outcome.collection.name ?? collection.name)
let foundDocs = try Array(verifyColl.find())
expect(foundDocs.count).to(equal(test.outcome.collection.data.count))
zip(foundDocs, test.outcome.collection.data).forEach {
expect($0).to(sortedEqual($1), description: test.description)
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions Tests/MongoSwiftTests/SpecTestRunner/Match.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ extension BSON: Matchable {
case let (.array(actual), .array(expected)):
return actual.matches(expected: expected)
default:
if let selfInt = self.asInt(), let expectedInt = expected.asInt() {
return selfInt == expectedInt
}
return self == expected
}
}
Expand Down
Loading