Skip to content

Commit ebc1e15

Browse files
authored
Fix index test failing on server latest (#273)
1 parent ac2adb7 commit ebc1e15

File tree

4 files changed

+255
-134
lines changed

4 files changed

+255
-134
lines changed

Sources/MongoSwift/MongoCollection+Indexes.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public struct IndexModel: Encodable {
3232
}
3333

3434
/// Options to use when creating an index for a collection.
35-
public struct IndexOptions: Encodable {
35+
public struct IndexOptions: Codable {
3636
/// Optionally tells the server to build the index in the background and not block other tasks.
3737
public let background: Bool?
3838

@@ -48,7 +48,7 @@ public struct IndexOptions: Encodable {
4848
*
4949
* - Example: For an index of name: 1, age: -1, the generated name would be "name_1_age_-1".
5050
*/
51-
public let name: String?
51+
public var name: String?
5252

5353
/// Optionally tells the index to only reference documents with the specified field in the index.
5454
public let sparse: Bool?
@@ -61,7 +61,7 @@ public struct IndexOptions: Encodable {
6161
public let unique: Bool?
6262

6363
/// Optionally specifies the index version number, either 0 or 1.
64-
public let indexVersion: Int32?
64+
public var indexVersion: Int32?
6565

6666
/// Optionally specifies the default language for text indexes. Is 'english' if none is provided.
6767
public let defaultLanguage: String?

Tests/LinuxMain.swift

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,6 @@ extension MongoCollectionTests {
148148
("testUpdateMany", testUpdateMany),
149149
("testUpdateManyWithUnacknowledgedWriteConcern", testUpdateManyWithUnacknowledgedWriteConcern),
150150
("testDistinct", testDistinct),
151-
("testCreateIndexFromModel", testCreateIndexFromModel),
152-
("testIndexOptions", testIndexOptions),
153-
("testCreateIndexesFromModels", testCreateIndexesFromModels),
154-
("testCreateIndexFromKeys", testCreateIndexFromKeys),
155-
("testDropIndexByName", testDropIndexByName),
156-
("testDropIndexByModel", testDropIndexByModel),
157-
("testDropIndexByKeys", testDropIndexByKeys),
158-
("testDropAllIndexes", testDropAllIndexes),
159-
("testListIndexes", testListIndexes),
160151
("testGetName", testGetName),
161152
("testCursorIteration", testCursorIteration),
162153
("testCodableCollection", testCodableCollection),
@@ -181,6 +172,20 @@ extension MongoCollection_BulkWriteTests {
181172
]
182173
}
183174

175+
extension MongoCollection_IndexTests {
176+
static var allTests = [
177+
("testCreateIndexFromModel", testCreateIndexFromModel),
178+
("testIndexOptions", testIndexOptions),
179+
("testCreateIndexesFromModels", testCreateIndexesFromModels),
180+
("testCreateIndexFromKeys", testCreateIndexFromKeys),
181+
("testDropIndexByName", testDropIndexByName),
182+
("testDropIndexByModel", testDropIndexByModel),
183+
("testDropIndexByKeys", testDropIndexByKeys),
184+
("testDropAllIndexes", testDropAllIndexes),
185+
("testListIndexes", testListIndexes),
186+
]
187+
}
188+
184189
extension MongoDatabaseTests {
185190
static var allTests = [
186191
("testMongoDatabase", testMongoDatabase),
@@ -231,6 +236,7 @@ XCTMain([
231236
testCase(MongoClientTests.allTests),
232237
testCase(MongoCollectionTests.allTests),
233238
testCase(MongoCollection_BulkWriteTests.allTests),
239+
testCase(MongoCollection_IndexTests.allTests),
234240
testCase(MongoDatabaseTests.allTests),
235241
testCase(ReadPreferenceTests.allTests),
236242
testCase(ReadWriteConcernTests.allTests),
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
@testable import MongoSwift
2+
import Nimble
3+
import XCTest
4+
5+
final class MongoCollection_IndexTests: MongoSwiftTestCase {
6+
var collName: String = ""
7+
var coll: MongoCollection<Document>!
8+
let doc1: Document = ["_id": 1, "cat": "dog"]
9+
let doc2: Document = ["_id": 2, "cat": "cat"]
10+
11+
/// Set up the entire suite - run once before all tests
12+
override class func setUp() {
13+
super.setUp()
14+
do {
15+
_client = try MongoClient()
16+
} catch {
17+
print("Setup failed: \(error)")
18+
}
19+
}
20+
21+
/// Set up a single test - run before each testX function
22+
override func setUp() {
23+
super.setUp()
24+
self.continueAfterFailure = false
25+
self.collName = self.getCollectionName()
26+
27+
do {
28+
guard let client = _client else {
29+
XCTFail("Invalid client")
30+
return
31+
}
32+
coll = try client.db(type(of: self).testDatabase).createCollection(self.collName)
33+
try coll.insertMany([doc1, doc2])
34+
} catch {
35+
XCTFail("Setup failed: \(error)")
36+
}
37+
}
38+
39+
/// Teardown a single test - run after each testX function
40+
override func tearDown() {
41+
super.tearDown()
42+
do {
43+
if coll != nil { try coll.drop() }
44+
} catch {
45+
XCTFail("Dropping test collection \(type(of: self).testDatabase).\(self.collName) failed: \(error)")
46+
}
47+
}
48+
49+
/// Teardown the entire suite - run after all tests complete
50+
override class func tearDown() {
51+
super.tearDown()
52+
do {
53+
guard let client = _client else {
54+
print("Invalid client")
55+
return
56+
}
57+
try client.db(self.testDatabase).drop()
58+
} catch {
59+
print("Dropping test database \(self.testDatabase) failed: \(error)")
60+
}
61+
}
62+
63+
func testCreateIndexFromModel() throws {
64+
let model = IndexModel(keys: ["cat": 1])
65+
expect(try self.coll.createIndex(model)).to(equal("cat_1"))
66+
let indexes = try coll.listIndexes()
67+
expect(indexes.next()?["name"]).to(bsonEqual("_id_"))
68+
expect(indexes.next()?["name"]).to(bsonEqual("cat_1"))
69+
expect(indexes.next()).to(beNil())
70+
}
71+
72+
func testIndexOptions() throws {
73+
let options = IndexOptions(
74+
background: true,
75+
name: "testOptions",
76+
sparse: false,
77+
storageEngine: ["wiredTiger": ["configString": "access_pattern_hint=random"] as Document],
78+
unique: true,
79+
indexVersion: 2,
80+
defaultLanguage: "english",
81+
languageOverride: "cat",
82+
textIndexVersion: 2,
83+
weights: ["cat": 0.5, "_id": 0.5],
84+
sphereIndexVersion: 2,
85+
bits: 32,
86+
max: 30,
87+
min: 0,
88+
bucketSize: 10,
89+
collation: ["locale": "fr"]
90+
)
91+
92+
let model = IndexModel(keys: ["cat": 1, "_id": -1], options: options)
93+
expect(try self.coll.createIndex(model)).to(equal("testOptions"))
94+
95+
let ttlOptions = IndexOptions(expireAfterSeconds: 100, name: "ttl")
96+
let ttlModel = IndexModel(keys: ["cat": 1], options: ttlOptions)
97+
expect(try self.coll.createIndex(ttlModel)).to(equal("ttl"))
98+
99+
var indexes: [IndexOptions] = try self.coll.listIndexes().map { indexDoc in
100+
var decoded = try BSONDecoder().decode(IndexOptions.self, from: indexDoc)
101+
// name is not one of the CodingKeys for IndexOptions so manually pull
102+
// it out of the doc and set it on the options.
103+
decoded.name = indexDoc.name as? String
104+
return decoded
105+
}
106+
107+
indexes.sort { $0.name! < $1.name! }
108+
expect(indexes).to(haveCount(3))
109+
110+
// _id index
111+
expect(indexes[0]).to(equal(IndexOptions(name: "_id_", indexVersion: 2)))
112+
113+
// testOptions index
114+
var expectedTestOptions = options
115+
expectedTestOptions.name = "testOptions"
116+
expect(indexes[1]).to(equal(expectedTestOptions))
117+
118+
// ttl index
119+
var expectedTtlOptions = ttlOptions
120+
expectedTtlOptions.indexVersion = 2
121+
expect(indexes[2]).to(equal(expectedTtlOptions))
122+
}
123+
124+
func testCreateIndexesFromModels() throws {
125+
let model1 = IndexModel(keys: ["cat": 1])
126+
let model2 = IndexModel(keys: ["cat": -1])
127+
expect( try self.coll.createIndexes([model1, model2]) ).to(equal(["cat_1", "cat_-1"]))
128+
let indexes = try coll.listIndexes()
129+
expect(indexes.next()?["name"]).to(bsonEqual("_id_"))
130+
expect(indexes.next()?["name"]).to(bsonEqual("cat_1"))
131+
expect(indexes.next()?["name"]).to(bsonEqual("cat_-1"))
132+
expect(indexes.next()).to(beNil())
133+
}
134+
135+
func testCreateIndexFromKeys() throws {
136+
expect(try self.coll.createIndex(["cat": 1])).to(equal("cat_1"))
137+
138+
let indexOptions = IndexOptions(name: "blah", unique: true)
139+
let model = IndexModel(keys: ["cat": -1], options: indexOptions)
140+
expect(try self.coll.createIndex(model)).to(equal("blah"))
141+
142+
let indexes = try coll.listIndexes()
143+
expect(indexes.next()?["name"]).to(bsonEqual("_id_"))
144+
expect(indexes.next()?["name"]).to(bsonEqual("cat_1"))
145+
146+
let thirdIndex = indexes.next()
147+
expect(thirdIndex?["name"]).to(bsonEqual("blah"))
148+
expect(thirdIndex?["unique"]).to(bsonEqual(true))
149+
150+
expect(indexes.next()).to(beNil())
151+
}
152+
153+
func testDropIndexByName() throws {
154+
let model = IndexModel(keys: ["cat": 1])
155+
expect(try self.coll.createIndex(model)).to(equal("cat_1"))
156+
expect(try self.coll.dropIndex("cat_1")).toNot(throwError())
157+
158+
// now there should only be _id_ left
159+
let indexes = try coll.listIndexes()
160+
expect(indexes.next()?["name"]).to(bsonEqual("_id_"))
161+
expect(indexes.next()).to(beNil())
162+
}
163+
164+
func testDropIndexByModel() throws {
165+
let model = IndexModel(keys: ["cat": 1])
166+
expect(try self.coll.createIndex(model)).to(equal("cat_1"))
167+
168+
let res = try self.coll.dropIndex(model)
169+
expect((res["ok"] as? BSONNumber)?.doubleValue).to(bsonEqual(1.0))
170+
171+
// now there should only be _id_ left
172+
let indexes = try coll.listIndexes()
173+
expect(indexes).toNot(beNil())
174+
expect(indexes.next()?["name"]).to(bsonEqual("_id_"))
175+
expect(indexes.next()).to(beNil())
176+
}
177+
178+
func testDropIndexByKeys() throws {
179+
let model = IndexModel(keys: ["cat": 1])
180+
expect(try self.coll.createIndex(model)).to(equal("cat_1"))
181+
182+
let res = try self.coll.dropIndex(["cat": 1])
183+
expect((res["ok"] as? BSONNumber)?.doubleValue).to(bsonEqual(1.0))
184+
185+
// now there should only be _id_ left
186+
let indexes = try coll.listIndexes()
187+
expect(indexes).toNot(beNil())
188+
expect(indexes.next()?["name"]).to(bsonEqual("_id_"))
189+
expect(indexes.next()).to(beNil())
190+
}
191+
192+
func testDropAllIndexes() throws {
193+
let model = IndexModel(keys: ["cat": 1])
194+
expect(try self.coll.createIndex(model)).to(equal("cat_1"))
195+
196+
let res = try self.coll.dropIndexes()
197+
expect((res["ok"] as? BSONNumber)?.doubleValue).to(bsonEqual(1.0))
198+
199+
// now there should only be _id_ left
200+
let indexes = try coll.listIndexes()
201+
expect(indexes.next()?["name"]).to(bsonEqual("_id_"))
202+
expect(indexes.next()).to(beNil())
203+
}
204+
205+
func testListIndexes() throws {
206+
let indexes = try coll.listIndexes()
207+
// New collection, so expect just the _id_ index to exist.
208+
expect(indexes.next()?["name"]).to(bsonEqual("_id_"))
209+
expect(indexes.next()).to(beNil())
210+
}
211+
}
212+
213+
extension IndexOptions: Equatable {
214+
public static func == (lhs: IndexOptions, rhs: IndexOptions) -> Bool {
215+
return lhs.background == rhs.background &&
216+
lhs.expireAfterSeconds == rhs.expireAfterSeconds &&
217+
lhs.name == rhs.name &&
218+
lhs.sparse == rhs.sparse &&
219+
lhs.storageEngine == rhs.storageEngine &&
220+
lhs.unique == rhs.unique &&
221+
lhs.indexVersion == rhs.indexVersion &&
222+
lhs.defaultLanguage == rhs.defaultLanguage &&
223+
lhs.languageOverride == rhs.languageOverride &&
224+
lhs.textIndexVersion == rhs.textIndexVersion &&
225+
lhs.weights == rhs.weights &&
226+
lhs.sphereIndexVersion == rhs.sphereIndexVersion &&
227+
lhs.bits == rhs.bits &&
228+
lhs.max == rhs.max &&
229+
lhs.min == rhs.min &&
230+
lhs.bucketSize == rhs.bucketSize &&
231+
lhs.partialFilterExpression == rhs.partialFilterExpression &&
232+
lhs.collation?["locale"] as? String == rhs.collation?["locale"] as? String
233+
// ^ server adds a bunch of extra fields and a version number
234+
// to collations. rather than deal with those, just verify the
235+
// locale matches.
236+
}
237+
}

0 commit comments

Comments
 (0)