Skip to content

Commit 72dd717

Browse files
author
Trisha Gee
committed
Added tests for FindAndUpdate. We still need to add validation to make sure users don't do a replace operation accidentally.
1 parent 01c4114 commit 72dd717

10 files changed

Lines changed: 279 additions & 27 deletions

File tree

driver/src/main/org/mongodb/operation/DocumentHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ final class DocumentHelper {
2222

2323
private DocumentHelper() { }
2424

25-
static void putIfTrue(final Document command, final boolean condition, final String key, final boolean value) {
25+
static void putIfTrue(final Document command, final String key, final boolean condition) {
2626
if (condition) {
27-
command.put(key, value);
27+
command.put(key, condition);
2828
}
2929
}
3030

driver/src/main/org/mongodb/operation/FindAndReplace.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ public Document toDocument() {
6767
putIfNotNull(command, "query", getFilter());
6868
putIfNotNull(command, "fields", getSelector());
6969
putIfNotNull(command, "sort", getSortCriteria());
70-
putIfTrue(command, isReturnNew(), "new", true);
71-
putIfTrue(command, isUpsert(), "upsert", true);
70+
putIfTrue(command, "new", isReturnNew());
71+
putIfTrue(command, "upsert", isUpsert());
7272

7373
// TODO: I don't think this will work, as we don't have a Class<T> to make sure that serialization works properly
7474
command.put("update", replacement);

driver/src/main/org/mongodb/operation/FindAndUpdate.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ public Document toDocument() {
7171
putIfNotNull(command, "query", getFilter());
7272
putIfNotNull(command, "fields", getSelector());
7373
putIfNotNull(command, "sort", getSortCriteria());
74-
putIfTrue(command, isReturnNew(), "new", true);
75-
putIfTrue(command, isUpsert(), "upsert", true);
74+
putIfTrue(command, "new", isReturnNew());
75+
putIfTrue(command, "upsert", isUpsert());
7676

7777
command.put("update", updateOperations);
7878
return command;

driver/src/test/acceptance/org/mongodb/acceptancetest/crud/FindAndReplaceAcceptanceTest.java

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,37 @@ public void shouldReplaceDocumentAndReturnOriginal() {
5555
}
5656

5757
@Test
58-
public void shouldFindAndReplaceWithDocumentRequiringACustomEncoder() {
59-
Worker pat = new Worker(new ObjectId(), "Pat", "Sales", new Date());
58+
public void shouldReplaceAndReturnOriginalItemWithDocumentRequiringACustomEncoder() {
59+
Worker pat = new Worker(new ObjectId(), "Pat", "Sales", new Date(), 0);
6060
final MongoCollection<Worker> collection = database.getCollection(getCollectionName(), new WorkerCodec());
6161
collection.insert(pat);
6262

6363
assertThat(collection.find().count(), is(1L));
6464

65-
final Worker jordan = new Worker(pat.getId(), "Jordan", "Engineer", new Date());
65+
final Worker jordan = new Worker(pat.getId(), "Jordan", "Engineer", new Date(), 1);
6666
final Worker returnedDocument = collection.find(new Document("name", "Pat"))
6767
.getOneAndReplace(jordan);
6868

6969
assertThat("Document, retrieved from getOneAndReplace, should match the document inserted before",
7070
returnedDocument, equalTo(pat));
7171
}
7272

73+
@Test
74+
public void shouldReplaceAndReturnNewItemWithDocumentRequiringACustomEncoder() {
75+
Worker pat = new Worker(new ObjectId(), "Pat", "Sales", new Date(), 3);
76+
final MongoCollection<Worker> collection = database.getCollection(getCollectionName(), new WorkerCodec());
77+
collection.insert(pat);
78+
79+
assertThat(collection.find().count(), is(1L));
80+
81+
final Worker jordan = new Worker(pat.getId(), "Jordan", "Engineer", new Date(), 7);
82+
final Worker returnedDocument = collection.find(new Document("name", "Pat"))
83+
.replaceOneAndGet(jordan);
84+
85+
assertThat("Worker retrieved from replaceOneAndGet should match the updated Worker",
86+
returnedDocument, equalTo(jordan));
87+
}
88+
7389
@Test
7490
public void shouldReturnNewDocumentAfterReplaceWhenUsingReplaceOneAndGet() {
7591
final ObjectId id = new ObjectId();
@@ -86,9 +102,8 @@ public void shouldReturnNewDocumentAfterReplaceWhenUsingReplaceOneAndGet() {
86102
document, equalTo(documentReplacement));
87103
}
88104

89-
90105
@Test
91-
public void shouldReturnNullWhenNothingToReplace() {
106+
public void shouldReturnNullWhenNothingToReplaceForGetOneAndReplace() {
92107
final Document documentInserted = new Document(KEY, VALUE_TO_CARE_ABOUT);
93108
collection.insert(documentInserted);
94109

@@ -97,12 +112,24 @@ public void shouldReturnNullWhenNothingToReplace() {
97112
final Document document = collection.find(new Document(KEY, "bar"))
98113
.getOneAndReplace(new Document("foo", "bar"));
99114

100-
assertNull("Document retrieved from replaceAndGet should be null", document);
115+
assertNull("Document retrieved from getOneAndReplace should be null when no matching document found", document);
101116
}
102117

118+
@Test
119+
public void shouldReturnNullWhenNothingToReplaceForReplaceOneAndGet() {
120+
final Document documentInserted = new Document(KEY, VALUE_TO_CARE_ABOUT);
121+
collection.insert(documentInserted);
122+
123+
assertThat(collection.find().count(), is(1L));
124+
125+
final Document document = collection.find(new Document(KEY, "bar"))
126+
.replaceOneAndGet(new Document("foo", "bar"));
127+
128+
assertNull("Document retrieved from replaceOneAndGet should be null when no matching document found", document);
129+
}
103130

104131
@Test
105-
public void shouldInsertDocumentWhenFilterDoesNotMatchAnyDocuments() {
132+
public void shouldInsertDocumentWhenFilterDoesNotMatchAnyDocumentsAndUpsertFlagIsSet() {
106133
final Document originalDocument = new Document(KEY, VALUE_TO_CARE_ABOUT);
107134
collection.insert(originalDocument);
108135

@@ -115,7 +142,7 @@ public void shouldInsertDocumentWhenFilterDoesNotMatchAnyDocuments() {
115142
.replaceOneAndGet(replacementDocument);
116143

117144
assertThat(collection.find().count(), is(2L));
118-
assertThat("Document retrieved from replaceOrInsertAndGet with filter that doesn't match should match the replacement document",
145+
assertThat("Document retrieved from replaceOneAndGet with filter that doesn't match should match the replacement document",
119146
document, equalTo(replacementDocument));
120147
}
121148

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright (c) 2008 - 2013 10gen, Inc. <http://10gen.com>
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+
17+
package org.mongodb.acceptancetest.crud;
18+
19+
import org.bson.types.ObjectId;
20+
import org.junit.Test;
21+
import org.mongodb.DatabaseTestCase;
22+
import org.mongodb.Document;
23+
import org.mongodb.MongoCollection;
24+
import org.mongodb.test.Worker;
25+
import org.mongodb.test.WorkerCodec;
26+
27+
import java.util.Date;
28+
29+
import static org.hamcrest.core.Is.is;
30+
import static org.hamcrest.core.IsEqual.equalTo;
31+
import static org.junit.Assert.assertNull;
32+
import static org.junit.Assert.assertThat;
33+
34+
public class FindAndUpdateAcceptanceTest extends DatabaseTestCase {
35+
private static final String KEY = "searchKey";
36+
private static final String VALUE_TO_CARE_ABOUT = "Value to match";
37+
38+
@Test
39+
public void shouldUpdateDocumentAndReturnOriginal() {
40+
final Document documentInserted = new Document(KEY, VALUE_TO_CARE_ABOUT).append("someNumber", 11);
41+
collection.insert(documentInserted);
42+
43+
assertThat(collection.find().count(), is(1L));
44+
45+
final Document updateOperation = new Document("$inc", new Document("someNumber", 1));
46+
final Document documentBeforeChange = collection.find(new Document(KEY, VALUE_TO_CARE_ABOUT))
47+
.getOneAndUpdate(updateOperation);
48+
49+
assertThat("Document returned from getOneAndUpdate should be the original document",
50+
(Integer) documentBeforeChange.get("someNumber"), equalTo(11));
51+
}
52+
53+
@Test
54+
public void shouldUpdateDocumentAndReturnNew() {
55+
final Document documentInserted = new Document(KEY, VALUE_TO_CARE_ABOUT).append("someNumber", 11);
56+
collection.insert(documentInserted);
57+
58+
assertThat(collection.find().count(), is(1L));
59+
60+
final Document updateOperation = new Document("$inc", new Document("someNumber", 1));
61+
final Document updatedDocument = collection.find(new Document(KEY, VALUE_TO_CARE_ABOUT))
62+
.updateOneAndGet(updateOperation);
63+
64+
assertThat("Document returned from updateOneAndGet should be the updated document",
65+
(Integer) updatedDocument.get("someNumber"), equalTo(12));
66+
}
67+
68+
@Test
69+
public void shouldFindAndReplaceWithDocumentRequiringACustomEncoder() {
70+
Worker pat = new Worker(new ObjectId(), "Pat", "Sales", new Date(), 7);
71+
final MongoCollection<Worker> collection = database.getCollection(getCollectionName(), new WorkerCodec());
72+
collection.insert(pat);
73+
74+
assertThat(collection.find().count(), is(1L));
75+
76+
final Document updateOperation = new Document("$inc", new Document("numberOfJobs", 1));
77+
final Worker updatedDocument = collection.find(new Document("name", "Pat"))
78+
.updateOneAndGet(updateOperation);
79+
80+
assertThat("Worker returned from updateOneAndGet should have the",
81+
updatedDocument.getNumberOfJobs(), equalTo(8));
82+
}
83+
84+
@Test
85+
public void shouldReturnNullWhenNothingToUpdate() {
86+
final Document documentInserted = new Document(KEY, VALUE_TO_CARE_ABOUT).append("someNumber", 11);
87+
collection.insert(documentInserted);
88+
89+
assertThat(collection.find().count(), is(1L));
90+
91+
final Document updateOperation = new Document("$inc", new Document("someNumber", 1));
92+
final Document document = collection.find(new Document(KEY, "someValueThatDoesNotExist"))
93+
.getOneAndUpdate(updateOperation);
94+
95+
assertNull("Document retrieved from getOneAndUpdate should be null", document);
96+
}
97+
98+
99+
@Test
100+
public void shouldInsertDocumentWhenFilterDoesNotMatchAnyDocumentsAndUpsertSelected() {
101+
final Document originalDocument = new Document(KEY, VALUE_TO_CARE_ABOUT).append("someNumber", 11);
102+
collection.insert(originalDocument);
103+
104+
assertThat(collection.find().count(), is(1L));
105+
106+
final String newValueThatDoesNotMatchAnythingInDatabase = "valueThatDoesNotMatch";
107+
final Document updateOperation = new Document("$inc", new Document("someNumber", 1));
108+
final Document document = collection.find(new Document(KEY, newValueThatDoesNotMatchAnythingInDatabase))
109+
.upsert()
110+
.updateOneAndGet(updateOperation);
111+
112+
assertThat(collection.find().count(), is(2L));
113+
assertThat("Document retrieved from updateOneAndGet and upsert true should have the new values",
114+
(Integer) document.get("someNumber"), equalTo(1));
115+
assertThat("Document retrieved from updateOneAndGet and upsert true should have the new values",
116+
document.get(KEY).toString(), equalTo(newValueThatDoesNotMatchAnythingInDatabase));
117+
}
118+
119+
// @Test(expected = IllegalArgumentException.class)
120+
// public void shouldThrowAnExceptionIfReplacementContainsUpdateOperators() {
121+
// final Document documentInserted = new Document(KEY, VALUE_TO_CARE_ABOUT);
122+
// collection.insert(documentInserted);
123+
//
124+
// assertThat(collection.count(), is(1L));
125+
//
126+
// collection.filter(new Document(KEY, VALUE_TO_CARE_ABOUT))
127+
// .replaceAndGet(new Document("$set", new Document("foo", "bar")), Get.AfterChangeApplied);
128+
// }
129+
130+
//TODO: should not be able to change the ID of a document
131+
//TODO: Should reject an update that doesn't have a $ operator
132+
133+
}

driver/src/test/functional/org/mongodb/operation/FindAndRemoveOperationSpecification.groovy

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import org.mongodb.Document
44
import org.mongodb.FunctionalSpecification
55
import org.mongodb.MongoClientOptions
66
import org.mongodb.codecs.DocumentCodec
7-
import org.mongodb.codecs.PrimitiveCodecs
87
import org.mongodb.connection.Cluster
98
import org.mongodb.connection.ClusterableServerFactory
109
import org.mongodb.connection.ConnectionFactory
@@ -22,7 +21,6 @@ import static org.mongodb.Fixture.getSSLSettings
2221

2322
class FindAndRemoveOperationSpecification extends FunctionalSpecification {
2423
private final DocumentCodec documentDecoder = new DocumentCodec()
25-
private final PrimitiveCodecs primitiveCodecs = PrimitiveCodecs.createDefault()
2624

2725
private final MongoClientOptions options = MongoClientOptions.builder().build();
2826
private final ConnectionFactory connectionFactory = new DefaultConnectionFactory(options.connectionSettings,

driver/src/test/functional/org/mongodb/operation/FindAndReplaceOperationCustomCodecsSpecification.groovy

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ class FindAndReplaceOperationCustomCodecsSpecification extends FunctionalSpecifi
5757

5858
def 'should be able to specify a custom encoder for the replacement object'() {
5959
given:
60-
Worker pete = new Worker('Pete', 'handyman', new Date())
61-
Worker sam = new Worker('Sam', 'plumber', new Date())
62-
Worker jordan = new Worker(pete.id, 'Jordan', 'sparky', new Date())
60+
Worker pete = new Worker('Pete', 'handyman', new Date(), 3)
61+
Worker sam = new Worker('Sam', 'plumber', new Date(), 5)
62+
Worker jordan = new Worker(pete.id, 'Jordan', 'sparky', new Date(), 7)
6363

6464
workerCollection.insert(pete);
6565
workerCollection.insert(sam);
@@ -69,15 +69,15 @@ class FindAndReplaceOperationCustomCodecsSpecification extends FunctionalSpecifi
6969
.returnNew(false);
7070

7171
FindAndReplaceOperation<Worker> operation = new FindAndReplaceOperation<Worker>(getBufferProvider(), session, false,
72-
workerCollection.namespace, findAndReplace
73-
, new WorkerCodec(),
74-
new WorkerCodec())
72+
workerCollection.namespace, findAndReplace,
73+
new WorkerCodec(), new WorkerCodec())
7574
Worker returnedValue = operation.execute()
7675

7776
then:
7877
returnedValue == pete
7978
}
8079

8180
//TODO: what about custom Date formats?
81+
//TODO: test null returns
8282

8383
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright (c) 2008 - 2013 10gen, Inc. <http://10gen.com>
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+
17+
package org.mongodb.operation
18+
19+
import org.mongodb.Document
20+
import org.mongodb.FunctionalSpecification
21+
import org.mongodb.MongoClientOptions
22+
import org.mongodb.MongoCollection
23+
import org.mongodb.connection.Cluster
24+
import org.mongodb.connection.ClusterableServerFactory
25+
import org.mongodb.connection.ConnectionFactory
26+
import org.mongodb.connection.ServerAddress
27+
import org.mongodb.connection.impl.DefaultClusterFactory
28+
import org.mongodb.connection.impl.DefaultClusterableServerFactory
29+
import org.mongodb.connection.impl.DefaultConnectionFactory
30+
import org.mongodb.connection.impl.DefaultConnectionProviderFactory
31+
import org.mongodb.session.ClusterSession
32+
import org.mongodb.session.Session
33+
import org.mongodb.test.Worker
34+
import org.mongodb.test.WorkerCodec
35+
36+
import static java.util.concurrent.Executors.newScheduledThreadPool
37+
import static org.mongodb.Fixture.getBufferProvider
38+
import static org.mongodb.Fixture.getSSLSettings
39+
40+
class FindAndUpdateOperationSpecification extends FunctionalSpecification {
41+
private final MongoClientOptions options = MongoClientOptions.builder().build();
42+
private final ConnectionFactory connectionFactory = new DefaultConnectionFactory(options.connectionSettings,
43+
getSSLSettings(), getBufferProvider(), [])
44+
45+
private final ClusterableServerFactory clusterableServerFactory = new DefaultClusterableServerFactory(
46+
options.serverSettings, new DefaultConnectionProviderFactory(options.connectionProviderSettings, connectionFactory),
47+
null, connectionFactory, newScheduledThreadPool(3), getBufferProvider())
48+
49+
private final Cluster cluster = new DefaultClusterFactory().create(new ServerAddress(), clusterableServerFactory)
50+
private final Session session = new ClusterSession(cluster)
51+
52+
private MongoCollection<Worker> workerCollection
53+
54+
def setup() {
55+
//setup with a collection designed to store Workers not Documents
56+
workerCollection = database.getCollection(getCollectionName(), new WorkerCodec())
57+
}
58+
59+
def 'should be able to specify a custom encoder and have the found value return in that type'() {
60+
given:
61+
Worker pete = new Worker('Pete', 'handyman', new Date(), 3)
62+
Worker sam = new Worker('Sam', 'plumber', new Date(), 7)
63+
64+
workerCollection.insert(pete);
65+
workerCollection.insert(sam);
66+
67+
when:
68+
FindAndUpdate findAndUpdate = new FindAndUpdate<Worker>(getCollectionName()).where(new Document('name', 'Pete'))
69+
.updateWith(new Document('$inc', new Document('numberOfJobs', 1)))
70+
.returnNew(true);
71+
72+
FindAndUpdateOperation<Worker> operation = new FindAndUpdateOperation<Worker>(getBufferProvider(), session, false,
73+
workerCollection.namespace, findAndUpdate,
74+
new WorkerCodec())
75+
Worker returnedValue = operation.execute()
76+
77+
then:
78+
Worker updatedPete = new Worker(pete.id, pete.name, pete.jobTitle, pete.dateStarted, 4)
79+
returnedValue == updatedPete
80+
}
81+
82+
}

0 commit comments

Comments
 (0)