Skip to content

Commit 8311c41

Browse files
authored
RUST-656 Run tests against serverless in evergreen (#504)
1 parent 0527b05 commit 8311c41

File tree

15 files changed

+275
-78
lines changed

15 files changed

+275
-78
lines changed

.evergreen/config.yml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,33 @@ functions:
377377
MONGODB_API_VERSION=${MONGODB_API_VERSION} \
378378
.evergreen/run-tests.sh
379379
380+
"run serverless tests":
381+
- command: shell.exec
382+
type: test
383+
params:
384+
shell: bash
385+
working_dir: "src"
386+
script: |
387+
${PREPARE_SHELL}
388+
set +o xtrace
389+
# Exported without xtrace to avoid leaking credentials
390+
export SERVERLESS_ATLAS_USER="${SERVERLESS_ATLAS_USER}"
391+
export SERVERLESS_ATLAS_PASSWORD="${SERVERLESS_ATLAS_PASSWORD}"
392+
393+
export MONGODB_URI="${MONGODB_URI}"
394+
export SSL="${SSL}"
395+
export SINGLE_MONGOS_LB_URI="${SINGLE_ATLASPROXY_SERVERLESS_URI}"
396+
export MULTI_MONGOS_LB_URI="${MULTI_ATLASPROXY_SERVERLESS_URI}"
397+
. .evergreen/generate-uri.sh
398+
399+
SNAPPY_COMPRESSION_ENABLED="true" \
400+
ZLIB_COMPRESSION_ENABLED="true" \
401+
ZSTD_COMPRESSION_ENABLED="true" \
402+
SINGLE_THREAD=${SINGLE_THREAD} \
403+
ASYNC_RUNTIME=${ASYNC_RUNTIME} \
404+
MONGODB_API_VERSION=${MONGODB_API_VERSION} \
405+
.evergreen/run-serverless-tests.sh
406+
380407
"run atlas tests":
381408
- command: shell.exec
382409
type: test
@@ -881,6 +908,11 @@ tasks:
881908
commands:
882909
- func: "run connection string tests"
883910

911+
- name: "test-serverless"
912+
tags: ["serverless"]
913+
commands:
914+
- func: "run serverless tests"
915+
884916
- name: "test-atlas-connectivity"
885917
tags: ["atlas-connect"]
886918
commands:
@@ -1387,6 +1419,51 @@ axes:
13871419
REQUIRE_API_VERSION: "1"
13881420
MONGODB_API_VERSION: "1"
13891421

1422+
task_groups:
1423+
- name: serverless_task_group
1424+
setup_group_can_fail_task: true
1425+
setup_group_timeout_secs: 1800 # 30 minutes
1426+
setup_group:
1427+
- func: "fetch source"
1428+
- func: "prepare resources"
1429+
- func: "windows fix"
1430+
- func: "fix absolute paths"
1431+
- func: "init test-results"
1432+
- func: "make files executable"
1433+
- func: "install dependencies"
1434+
- command: shell.exec
1435+
params:
1436+
shell: "bash"
1437+
script: |
1438+
${PREPARE_SHELL}
1439+
set +o xtrace
1440+
SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} \
1441+
SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} \
1442+
SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} \
1443+
LOADBALANCED=ON \
1444+
bash ${DRIVERS_TOOLS}/.evergreen/serverless/create-instance.sh
1445+
- command: expansions.update
1446+
params:
1447+
file: serverless-expansion.yml
1448+
teardown_group:
1449+
- command: shell.exec
1450+
params:
1451+
script: |
1452+
${PREPARE_SHELL}
1453+
set +o xtrace
1454+
SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} \
1455+
SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} \
1456+
SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} \
1457+
SERVERLESS_INSTANCE_NAME=${SERVERLESS_INSTANCE_NAME} \
1458+
bash ${DRIVERS_TOOLS}/.evergreen/serverless/delete-instance.sh
1459+
- func: "upload test results"
1460+
- func: "upload-mo-artifacts"
1461+
- func: "cleanup"
1462+
1463+
tasks:
1464+
- ".serverless"
1465+
1466+
13901467
buildvariants:
13911468
-
13921469
matrix_name: "tests"
@@ -1477,6 +1554,15 @@ buildvariants:
14771554
tasks:
14781555
- "test-plain-auth"
14791556

1557+
- matrix_name: "serverless"
1558+
matrix_spec:
1559+
os:
1560+
- ubuntu-18.04
1561+
async-runtime: "*"
1562+
display_name: "Serverless ${os} with ${async-runtime}"
1563+
tasks:
1564+
- "serverless_task_group"
1565+
14801566
- matrix_name: "atlas-connect"
14811567
matrix_spec:
14821568
os:

.evergreen/generate-uri.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ update_uri() {
2222
else
2323
ORIG_URI="${ORIG_URI}/?"
2424
fi
25-
echo "${ORIG_URI}tls=true&tlsCAFile=${CA_FILE}&tlsCertificateKeyFile=${CERT_FILE}&tlsAllowInvalidCertificates=true"
25+
if [[ "$ORIG_URI" != *"tls=true"* ]]; then
26+
ORIG_URI="${ORIG_URI}tls=true&"
27+
fi
28+
echo "${ORIG_URI}tlsCAFile=${CA_FILE}&tlsCertificateKeyFile=${CERT_FILE}&tlsAllowInvalidCertificates=true"
2629
}
2730

2831
export MONGODB_URI="$(update_uri ${MONGODB_URI})"

.evergreen/run-serverless-tests.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
3+
set -o errexit
4+
5+
source ./.evergreen/env.sh
6+
7+
FEATURE_FLAGS="zstd-compression,snappy-compression,zlib-compression"
8+
DEFAULT_FEATURES=""
9+
10+
if [ "$ASYNC_RUNTIME" = "async-std" ]; then
11+
FEATURE_FLAGS="${FEATURE_FLAGS},async-std-runtime"
12+
DEFAULT_FEATURES="--no-default-features"
13+
elif [ "$ASYNC_RUNTIME" != "tokio" ]; then
14+
echo "invalid async runtime: ${ASYNC_RUNTIME}" >&2
15+
exit 1
16+
fi
17+
18+
OPTIONS="-- -Z unstable-options --format json --report-time"
19+
20+
if [ "$SINGLE_THREAD" = true ]; then
21+
OPTIONS="$OPTIONS --test-threads=1"
22+
fi
23+
24+
echo "cargo test options: ${DEFAULT_FEATURES} --features $FEATURE_FLAGS ${OPTIONS}"
25+
26+
cargo_test() {
27+
RUST_BACKTRACE=1 \
28+
SERVERLESS="serverless" \
29+
cargo test ${DEFAULT_FEATURES} --features $FEATURE_FLAGS $1 $OPTIONS | cargo2junit
30+
}
31+
32+
cargo_test test::spec::crud > crud.xml
33+
cargo_test test::spec::retryable_reads > retryable_reads.xml
34+
cargo_test test::spec::retryable_writes > retryable_writes.xml
35+
cargo_test test::spec::versioned_api > versioned_api.xml
36+
cargo_test test::spec::sessions > sessions.xml
37+
cargo_test test::spec::transactions > transactions.xml
38+
cargo_test test::spec::load_balancers > load_balancers.xml
39+
cargo_test test::cursor > cursor.xml
40+
41+
junit-report-merger results.xml crud.xml retryable_reads.xml retryable_writes.xml versioned_api.xml sessions.xml transactions.xml load_balancers.xml cursor.xml

src/client/options/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,9 @@ impl ClientOptions {
12051205
/// Applies the options in other to these options if a value is not already present
12061206
#[cfg(test)]
12071207
pub(crate) fn merge(&mut self, other: ClientOptions) {
1208+
if self.hosts.is_empty() {
1209+
self.hosts = other.hosts;
1210+
}
12081211
merge_options!(
12091212
other,
12101213
self,
@@ -1218,6 +1221,7 @@ impl ClientOptions {
12181221
direct_connection,
12191222
driver_info,
12201223
heartbeat_freq,
1224+
load_balanced,
12211225
local_threshold,
12221226
max_idle_time,
12231227
max_pool_size,
@@ -1230,6 +1234,7 @@ impl ClientOptions {
12301234
server_api,
12311235
server_selection_timeout,
12321236
socket_timeout,
1237+
test_options,
12331238
tls,
12341239
write_concern,
12351240
original_srv_info,

src/coll/mod.rs

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,46 +1078,51 @@ where
10781078

10791079
n_attempted += current_batch_size;
10801080
}
1081-
Err(e) => match *e.kind {
1082-
ErrorKind::BulkWrite(bw) => {
1083-
// for ordered inserts this size will be incorrect, but knowing the batch
1084-
// size isn't needed for ordered failures since we
1085-
// return immediately from them anyways.
1086-
let current_batch_size = bw.inserted_ids.len()
1087-
+ bw.write_errors.as_ref().map(|we| we.len()).unwrap_or(0);
1088-
1089-
let failure_ref =
1090-
cumulative_failure.get_or_insert_with(BulkWriteFailure::new);
1091-
if let Some(write_errors) = bw.write_errors {
1092-
for err in write_errors {
1093-
let index = n_attempted + err.index;
1094-
1095-
failure_ref
1096-
.write_errors
1097-
.get_or_insert_with(Default::default)
1098-
.push(BulkWriteError { index, ..err });
1081+
Err(e) => {
1082+
let labels = e.labels().clone();
1083+
match *e.kind {
1084+
ErrorKind::BulkWrite(bw) => {
1085+
// for ordered inserts this size will be incorrect, but knowing the
1086+
// batch size isn't needed for ordered
1087+
// failures since we return immediately from
1088+
// them anyways.
1089+
let current_batch_size = bw.inserted_ids.len()
1090+
+ bw.write_errors.as_ref().map(|we| we.len()).unwrap_or(0);
1091+
1092+
let failure_ref =
1093+
cumulative_failure.get_or_insert_with(BulkWriteFailure::new);
1094+
if let Some(write_errors) = bw.write_errors {
1095+
for err in write_errors {
1096+
let index = n_attempted + err.index;
1097+
1098+
failure_ref
1099+
.write_errors
1100+
.get_or_insert_with(Default::default)
1101+
.push(BulkWriteError { index, ..err });
1102+
}
10991103
}
1100-
}
1101-
1102-
if let Some(wc_error) = bw.write_concern_error {
1103-
failure_ref.write_concern_error = Some(wc_error);
1104-
}
11051104

1106-
error_labels.extend(e.labels);
1105+
if let Some(wc_error) = bw.write_concern_error {
1106+
failure_ref.write_concern_error = Some(wc_error);
1107+
}
11071108

1108-
if ordered {
1109-
// this will always be true since we invoked get_or_insert_with above.
1110-
if let Some(failure) = cumulative_failure {
1111-
return Err(Error {
1112-
kind: Box::new(ErrorKind::BulkWrite(failure)),
1113-
labels: error_labels,
1114-
});
1109+
error_labels.extend(labels);
1110+
1111+
if ordered {
1112+
// this will always be true since we invoked get_or_insert_with
1113+
// above.
1114+
if let Some(failure) = cumulative_failure {
1115+
return Err(Error::new(
1116+
ErrorKind::BulkWrite(failure),
1117+
Some(error_labels),
1118+
));
1119+
}
11151120
}
1121+
n_attempted += current_batch_size;
11161122
}
1117-
n_attempted += current_batch_size;
1123+
_ => return Err(e),
11181124
}
1119-
_ => return Err(e),
1120-
},
1125+
}
11211126
}
11221127
}
11231128

src/error.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,20 @@ pub type Result<T> = std::result::Result<T, Error>;
4545
pub struct Error {
4646
/// The type of error that occurred.
4747
pub kind: Box<ErrorKind>,
48-
pub(crate) labels: HashSet<String>,
48+
labels: HashSet<String>,
4949
}
5050

5151
impl Error {
5252
pub(crate) fn new(kind: ErrorKind, labels: Option<impl IntoIterator<Item = String>>) -> Self {
53+
let mut labels: HashSet<String> = labels
54+
.map(|labels| labels.into_iter().collect())
55+
.unwrap_or_default();
56+
if let Some(wc) = kind.get_write_concern_error() {
57+
labels.extend(wc.labels.clone());
58+
}
5359
Self {
5460
kind: Box::new(kind),
55-
labels: labels
56-
.map(|labels| labels.into_iter().collect())
57-
.unwrap_or_default(),
61+
labels,
5862
}
5963
}
6064

@@ -318,10 +322,7 @@ where
318322
ErrorKind: From<E>,
319323
{
320324
fn from(err: E) -> Self {
321-
Self {
322-
kind: Box::new(err.into()),
323-
labels: Default::default(),
324-
}
325+
Error::new(err.into(), None::<Option<String>>)
325326
}
326327
}
327328

@@ -433,6 +434,22 @@ pub enum ErrorKind {
433434
IncompatibleServer { message: String },
434435
}
435436

437+
impl ErrorKind {
438+
// This is only used as part of a workaround to Atlas Proxy not returning
439+
// toplevel error labels.
440+
// TODO CLOUDP-105256 Remove this when Atlas Proxy error label behavior is fixed.
441+
fn get_write_concern_error(&self) -> Option<&WriteConcernError> {
442+
match self {
443+
ErrorKind::BulkWrite(BulkWriteFailure {
444+
write_concern_error,
445+
..
446+
}) => write_concern_error.as_ref(),
447+
ErrorKind::Write(WriteFailure::WriteConcernError(err)) => Some(err),
448+
_ => None,
449+
}
450+
}
451+
}
452+
436453
/// An error that occurred due to a database command failing.
437454
#[derive(Clone, Debug, Deserialize)]
438455
#[non_exhaustive]
@@ -473,6 +490,12 @@ pub struct WriteConcernError {
473490
/// A document identifying the write concern setting related to the error.
474491
#[serde(rename = "errInfo")]
475492
pub details: Option<Document>,
493+
494+
/// Labels categorizing the error.
495+
// TODO CLOUDP-105256 Remove this when the Atlas Proxy properly returns
496+
// error labels at the top level.
497+
#[serde(rename = "errorLabels", default)]
498+
pub(crate) labels: Vec<String>,
476499
}
477500

478501
/// An error that occurred during a write operation that wasn't due to being unable to satisfy a

src/operation/delete/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ async fn handle_write_concern_failure() {
193193
"wtimeout": 0,
194194
"provenance": "clientSupplied"
195195
} }),
196+
labels: vec![],
196197
};
197198
assert_eq!(wc_error, &expected_wc_err);
198199
}

src/operation/insert/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ async fn handle_write_failure() {
356356
"wtimeout": 0,
357357
"provenance": "clientSupplied"
358358
} }),
359+
labels: vec![],
359360
};
360361
assert_eq!(write_concern_error, expected_wc_err);
361362

src/operation/update/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ async fn handle_write_concern_failure() {
258258
"wtimeout": 0,
259259
"provenance": "clientSupplied"
260260
} }),
261+
labels: vec![],
261262
};
262263
assert_eq!(wc_error, &expected_wc_err);
263264
}

0 commit comments

Comments
 (0)