From cff75712fd31a7322e53f2849c3145cc536ec5e9 Mon Sep 17 00:00:00 2001
From: Ben Caimano <bcaimano@gmail.com>
Date: Tue, 8 Jan 2019 17:43:36 -0500
Subject: [PATCH] TIG-1334 Fix segfault in test_gennylib_with_server (#103)

---
 evergreen.yml                              | 43 +++--------------
 scripts/run-resmoke.sh                     | 55 ++++++++++++++++++++++
 src/gennylib/test/MongoTestFixture.cpp     | 18 ++++---
 src/gennylib/test/MongoTestFixture.hpp     |  6 ++-
 src/gennylib/test/RunCommandActor_test.cpp |  5 +-
 5 files changed, 76 insertions(+), 51 deletions(-)
 create mode 100755 scripts/run-resmoke.sh

diff --git a/evergreen.yml b/evergreen.yml
index d40b2648d3..b862a9b1d7 100644
--- a/evergreen.yml
+++ b/evergreen.yml
@@ -244,46 +244,15 @@ functions:
   # Requires f_compile to have been run first.
   ##
   f_resmoke_test:
-  - command: shell.exec
+  - command: subprocess.exec
     params:
       continue_on_err: true
       working_dir: src
-      script: |
-        set -o errexit
-        set -o pipefail
-        # set -o nounset # the "activate" script has an unbound variable
-
-        source build/venv/bin/activate
-
-        # We rely on catch2 to report test failures, but it doesn't always do so.
-        # See https://github.com/catchorg/Catch2/issues/1210
-        # As a workaround, we generate a dummy report with a failed test that is deleted if resmoke
-        # succeeds.
-
-        cat << EOF >> "build/sentinel.junit.xml"
-        <?xml version="1.0" encoding="UTF-8"?>
-        <testsuites>
-         <testsuite name="resmoke_failure_sentinel" errors="0" failures="1" tests="1" hostname="tbd" time="1.0" timestamp="2019-01-01T00:00:00Z">
-          <testcase classname="resmoke_failure_sentinel" name="Dummy testcase to signal that resmoke failed because a report may not be generated" time="1.0">
-           <failure message="resmoke did not exit cleanly, see task log for detail" type="">
-           </failure>
-          </testcase>
-          <system-out/>
-          <system-err/>
-         </testsuite>
-        </testsuites>
-        EOF
-
-        # The tests themselves do the reporting instead of using resmoke.
-        python build/mongo/buildscripts/resmoke.py \
-               --suite src/resmokeconfig/${resmoke_suite} \
-               --mongod mongod \
-               --mongo mongo \
-               --mongos mongos
-
-        # Remove the sentinel report if resmoke succeeds. This line won't be executed if
-        # resmoke fails because we've set errexit on this shell.
-        rm build/sentinel.junit.xml
+      binary: /bin/bash
+      args:
+      - ${workdir}/src/scripts/run-resmoke.sh
+      env:
+        RESMOKE_SUITE: ${resmoke_suite}
 
   ##
   # Runs python nosetests.
diff --git a/scripts/run-resmoke.sh b/scripts/run-resmoke.sh
new file mode 100755
index 0000000000..3f643fae71
--- /dev/null
+++ b/scripts/run-resmoke.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+set -o errexit
+set -o pipefail
+# set -o nounset # the "activate" script has an unbound variable
+
+SCRIPTS_DIR="$(dirname "${BASH_SOURCE[0]}")"
+ROOT_DIR="$(cd "${SCRIPTS_DIR}/.." && pwd)"
+BUILD_DIR="${ROOT_DIR}/build"
+
+VENV_DIR="${VENV_DIR:-${BUILD_DIR}/venv}"
+MONGO_DIR="${MONGO_DIR:-${BUILD_DIR}/mongo}"
+RESMOKE_SUITE="${RESMOKE_SUITE:-genny_standalone.yml}"
+SENTINEL_XML="${BUILD_DIR}/sentinel.junit.xml"
+
+if [[ -z $VIRTUAL_ENV ]]; then
+    # shellcheck disable=SC1090
+    . "${VENV_DIR}/bin/activate"
+fi
+
+# Move to the root dir because of how resmoke paths
+cd "${ROOT_DIR}"
+
+# We rely on catch2 to report test failures, but it doesn't always do so.
+# See https://github.com/catchorg/Catch2/issues/1210
+# As a workaround, we generate a dummy report with a failed test that is deleted if resmoke
+# succeeds.
+
+cat << EOF >> "${SENTINEL_XML}"
+<?xml version="1.0" encoding="UTF-8"?>
+<testsuites>
+ <testsuite name="resmoke_failure_sentinel" errors="0" failures="1" tests="1" hostname="tbd" time="1.0" timestamp="2019-01-01T00:00:00Z">
+  <testcase classname="resmoke_failure_sentinel" name="Dummy testcase to signal that resmoke failed because a report may not be generated" time="1.0">
+   <failure message="resmoke did not exit cleanly, see task log for detail" type="">
+   </failure>
+  </testcase>
+  <system-out/>
+  <system-err/>
+ </testsuite>
+</testsuites>
+EOF
+
+# Add the mongo dir to the end of the path so we can find mongo executables
+export PATH="${PATH}:${MONGO_DIR}"
+
+# The tests themselves do the reporting instead of using resmoke.
+python2 "${MONGO_DIR}/buildscripts/resmoke.py" \
+       --suite "${ROOT_DIR}/src/resmokeconfig/${RESMOKE_SUITE}" \
+       --mongod mongod \
+       --mongo mongo \
+       --mongos mongos
+
+# Remove the sentinel report if resmoke succeeds. This line won't be executed if
+# resmoke fails because we've set errexit on this shell.
+rm "${SENTINEL_XML}"
diff --git a/src/gennylib/test/MongoTestFixture.cpp b/src/gennylib/test/MongoTestFixture.cpp
index ac75363f49..a660414314 100644
--- a/src/gennylib/test/MongoTestFixture.cpp
+++ b/src/gennylib/test/MongoTestFixture.cpp
@@ -9,20 +9,17 @@
 
 namespace genny::testing {
 
-const mongocxx::uri MongoTestFixture::kConnectionString = []() {
+mongocxx::uri MongoTestFixture::connectionUri() {
     const char* connChar = getenv("MONGO_CONNECTION_STRING");
-    std::string connStr;
-
-    if (!connChar) {
-        connStr = mongocxx::uri::k_default_uri;
-        BOOST_LOG_TRIVIAL(info) << "MONGO_CONNECTION_STRING not set, using default value: "
-                                << connStr;
-    } else {
-        connStr = connChar;
+
+    if (connChar != nullptr) {
+        return mongocxx::uri(connChar);
     }
 
+    auto& connStr = mongocxx::uri::k_default_uri;
+    BOOST_LOG_TRIVIAL(info) << "MONGO_CONNECTION_STRING not set, using default value: " << connStr;
     return mongocxx::uri(connStr);
-}();
+};
 
 void MongoTestFixture::dropAllDatabases() {
     for (auto&& dbDoc : client.list_databases()) {
@@ -33,4 +30,5 @@ void MongoTestFixture::dropAllDatabases() {
         }
     }
 }
+
 }  // namespace genny::testing
diff --git a/src/gennylib/test/MongoTestFixture.hpp b/src/gennylib/test/MongoTestFixture.hpp
index 58975a97c0..5ccb149ae1 100644
--- a/src/gennylib/test/MongoTestFixture.hpp
+++ b/src/gennylib/test/MongoTestFixture.hpp
@@ -2,19 +2,21 @@
 #define HEADER_D9091084_CB09_4108_A553_5D0EC18C132F_INCLUDED
 
 #include <mongocxx/client.hpp>
+#include <mongocxx/instance.hpp>
 
 namespace genny::testing {
 
 class MongoTestFixture {
 public:
-    MongoTestFixture() : client(kConnectionString) {}
+    MongoTestFixture() : instance(mongocxx::instance::current()), client(connectionUri()) {}
 
 protected:
     void dropAllDatabases();
 
+    mongocxx::instance & instance;
     mongocxx::client client;
 
-    static const mongocxx::uri kConnectionString;
+    static mongocxx::uri connectionUri();
 };
 }  // namespace genny::testing
 
diff --git a/src/gennylib/test/RunCommandActor_test.cpp b/src/gennylib/test/RunCommandActor_test.cpp
index 9e2ce747f2..3eb315bc71 100644
--- a/src/gennylib/test/RunCommandActor_test.cpp
+++ b/src/gennylib/test/RunCommandActor_test.cpp
@@ -6,10 +6,11 @@
 #include <bsoncxx/builder/stream/document.hpp>
 #include <bsoncxx/json.hpp>
 
-#include <MongoTestFixture.hpp>
 #include <cast_core/actors/RunCommand.hpp>
 #include <gennylib/MongoException.hpp>
 
+#include "MongoTestFixture.hpp"
+
 namespace genny {
 namespace {
 
@@ -35,7 +36,7 @@ TEST_CASE_METHOD(MongoTestFixture,
               OperationCommand: {someKey: 1}
     )");
 
-    ActorHelper ah(config, 1, MongoTestFixture::kConnectionString.to_string());
+    ActorHelper ah(config, 1, MongoTestFixture::connectionUri().to_string());
 
     SECTION("throws error with full context on operation_exception") {
         bool has_exception = true;