Skip to content

Commit 2044149

Browse files
committed
Ensure write error is included in exception message (#724)
Implement new CRUD specification prose test for write error details JAVA-3993
1 parent 7677bc9 commit 2044149

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed

driver-core/src/main/com/mongodb/MongoWriteException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class MongoWriteException extends MongoServerException {
3333
* @param serverAddress the server address
3434
*/
3535
public MongoWriteException(final WriteError error, final ServerAddress serverAddress) {
36-
super(error.getCode(), error.getMessage(), serverAddress);
36+
super("Write operation error on server " + serverAddress + ". Write error: " + error + ". ", serverAddress);
3737
this.error = error;
3838
}
3939

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
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 com.mongodb.client;
18+
19+
import com.mongodb.MongoBulkWriteException;
20+
import com.mongodb.MongoWriteConcernException;
21+
import com.mongodb.MongoWriteException;
22+
import com.mongodb.client.model.CreateCollectionOptions;
23+
import com.mongodb.client.model.Filters;
24+
import com.mongodb.client.model.ValidationOptions;
25+
import org.bson.BsonArray;
26+
import org.bson.BsonDocument;
27+
import org.bson.BsonInt32;
28+
import org.bson.BsonString;
29+
import org.bson.Document;
30+
import org.junit.Before;
31+
import org.junit.Test;
32+
33+
import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet;
34+
import static com.mongodb.ClusterFixture.serverVersionAtLeast;
35+
import static java.lang.String.format;
36+
import static java.util.Arrays.asList;
37+
import static org.junit.Assert.assertEquals;
38+
import static org.junit.Assert.assertFalse;
39+
import static org.junit.Assert.assertNotNull;
40+
import static org.junit.Assert.assertTrue;
41+
import static org.junit.Assert.fail;
42+
import static org.junit.Assume.assumeTrue;
43+
44+
/**
45+
* See https://github.com/mongodb/specifications/blob/master/source/crud/tests/README.rst#prose-tests
46+
*/
47+
public class CrudProseTest extends DatabaseTestCase {
48+
private BsonDocument failPointDocument;
49+
50+
@Before
51+
@Override
52+
public void setUp() {
53+
super.setUp();
54+
}
55+
56+
/**
57+
* 1. WriteConcernError.details exposes writeConcernError.errInfo
58+
*/
59+
@Test
60+
public void testWriteConcernErrInfoIsPropagated() {
61+
assumeTrue(isDiscoverableReplicaSet() && serverVersionAtLeast(4, 0));
62+
63+
try {
64+
setFailPoint();
65+
collection.insertOne(Document.parse("{ x: 1 }"));
66+
} catch (MongoWriteConcernException e) {
67+
assertEquals(e.getWriteConcernError().getCode(), 100);
68+
assertEquals("UnsatisfiableWriteConcern", e.getWriteConcernError().getCodeName());
69+
assertEquals(e.getWriteConcernError().getDetails(), new BsonDocument("writeConcern",
70+
new BsonDocument("w", new BsonInt32(2))
71+
.append("wtimeout", new BsonInt32(0))
72+
.append("provenance", new BsonString("clientSupplied"))));
73+
} catch (Exception ex) {
74+
fail(format("Incorrect exception thrown in test: %s", ex.getClass()));
75+
} finally {
76+
disableFailPoint();
77+
}
78+
}
79+
80+
/**
81+
* 2. WriteError.details exposes writeErrors[].errInfo
82+
*/
83+
@Test
84+
public void testWriteErrorDetailsIsPropagated() {
85+
assumeTrue(serverVersionAtLeast(3, 2));
86+
87+
getCollectionHelper().create(getCollectionName(),
88+
new CreateCollectionOptions()
89+
.validationOptions(new ValidationOptions()
90+
.validator(Filters.type("x", "string"))));
91+
92+
try {
93+
collection.insertOne(new Document("x", 1));
94+
fail("Should throw, as document doesn't match schema");
95+
} catch (MongoWriteException e) {
96+
// These assertions doesn't do exactly what's required by the specification, but it's simpler to implement and nearly as
97+
// effective
98+
assertTrue(e.getMessage().contains("Write error"));
99+
assertNotNull(e.getError().getDetails());
100+
if (serverVersionAtLeast(5, 0)) {
101+
assertFalse(e.getError().getDetails().isEmpty());
102+
}
103+
}
104+
105+
try {
106+
collection.insertMany(asList(new Document("x", 1)));
107+
fail("Should throw, as document doesn't match schema");
108+
} catch (MongoBulkWriteException e) {
109+
// These assertions doesn't do exactly what's required by the specification, but it's simpler to implement and nearly as
110+
// effective
111+
assertTrue(e.getMessage().contains("Write errors"));
112+
assertEquals(1, e.getWriteErrors().size());
113+
if (serverVersionAtLeast(5, 0)) {
114+
assertFalse(e.getWriteErrors().get(0).getDetails().isEmpty());
115+
}
116+
}
117+
}
118+
119+
private void setFailPoint() {
120+
failPointDocument = new BsonDocument("configureFailPoint", new BsonString("failCommand"))
121+
.append("mode", new BsonDocument("times", new BsonInt32(1)))
122+
.append("data", new BsonDocument("failCommands", new BsonArray(asList(new BsonString("insert"))))
123+
.append("writeConcernError", new BsonDocument("code", new BsonInt32(100))
124+
.append("codeName", new BsonString("UnsatisfiableWriteConcern"))
125+
.append("errmsg", new BsonString("Not enough data-bearing nodes"))
126+
.append("errInfo", new BsonDocument("writeConcern", new BsonDocument("w", new BsonInt32(2))
127+
.append("wtimeout", new BsonInt32(0))
128+
.append("provenance", new BsonString("clientSupplied"))))));
129+
getCollectionHelper().runAdminCommand(failPointDocument);
130+
}
131+
132+
private void disableFailPoint() {
133+
getCollectionHelper().runAdminCommand(failPointDocument.append("mode", new BsonString("off")));
134+
}
135+
}

0 commit comments

Comments
 (0)