You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by jb...@apache.org on 2018/03/29 05:24:49 UTC

[geode-native] branch develop updated: GEODE-4921: Initial revision of new testing framework. (#249)

This is an automated email from the ASF dual-hosted git repository.

jbarrett pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode-native.git


The following commit(s) were added to refs/heads/develop by this push:
     new 09744d5  GEODE-4921: Initial revision of new testing framework. (#249)
09744d5 is described below

commit 09744d59dc599972f8a7c6f95aa92dc03e489542
Author: Jacob Barrett <jb...@pivotal.io>
AuthorDate: Wed Mar 28 22:24:48 2018 -0700

    GEODE-4921: Initial revision of new testing framework. (#249)
    
    - Single process.
    - Easy to debug from IDE.
    - No environment variables required to run.
    - Uses GTest as base framework.
---
 CMakeLists.txt                                     |   2 +-
 cppcache/CMakeLists.txt                            |   8 +-
 cppcache/integration-test-2/CMakeLists.txt         |  67 ++++++
 cppcache/integration-test-2/ExampleTest.cpp        | 130 +++++++++++
 .../integration-test-2/RegionPutGetAllTest.cpp     | 185 +++++++++++++++
 cppcache/integration-test-2/framework/Cluster.cpp  | 124 ++++++++++
 cppcache/integration-test-2/framework/Cluster.h    | 244 ++++++++++++++++++++
 .../integration-test-2/framework/Framework.cpp     |  18 ++
 cppcache/integration-test-2/framework/Framework.h  |  49 ++++
 cppcache/integration-test-2/framework/Gfsh.cpp     |  18 ++
 cppcache/integration-test-2/framework/Gfsh.h       | 255 +++++++++++++++++++++
 .../integration-test-2/framework/GfshExecute.cpp   |  18 ++
 .../integration-test-2/framework/GfshExecute.h     | 120 ++++++++++
 cppcache/integration-test-2/framework/config.h.in  |  25 ++
 cppcache/test/CMakeLists.txt                       |   6 +-
 dependencies/boost/CMakeLists.txt                  |  56 ++++-
 dependencies/gtest/CMakeLists.txt                  |  47 ++--
 tests/cpp/testobject/CMakeLists.txt                |   4 +-
 18 files changed, 1343 insertions(+), 33 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 37b3a77..b3fd8e1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -210,7 +210,7 @@ if (WIN32 OR ${CMAKE_GENERATOR} STREQUAL "Xcode")
   set ( _DEBUG_OR_RELEASE $<$<CONFIG:Debug>:Debug>$<$<NOT:$<CONFIG:Debug>>:Release>)
 else()
   set(CMAKE_USES_BUILDTYPE FALSE)
-  set ( _DEBUG_OR_RELEASE )
+  set ( _DEBUG_OR_RELEASE .)
 endif()
 
 # Default to only showing output on failure for unit tests but allow
diff --git a/cppcache/CMakeLists.txt b/cppcache/CMakeLists.txt
index ff464c9..6be25d5 100644
--- a/cppcache/CMakeLists.txt
+++ b/cppcache/CMakeLists.txt
@@ -70,11 +70,14 @@ if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
     demangle
     kstat
   )
-endif()
-if (${WIN32})
+elseif (WIN32)
   target_link_libraries(_apache-geode INTERFACE
     Dbghelp
   )
+  target_compile_definitions(_apache-geode INTERFACE
+    # Required for Boost.WinAPI
+    _WIN32_WINNT=0x06020000
+  )
 endif()
 
 target_link_libraries(_apache-geode INTERFACE
@@ -98,3 +101,4 @@ add_subdirectory(shared)
 add_subdirectory(static)
 add_subdirectory(test)
 add_subdirectory(integration-test)
+add_subdirectory(integration-test-2)
diff --git a/cppcache/integration-test-2/CMakeLists.txt b/cppcache/integration-test-2/CMakeLists.txt
new file mode 100644
index 0000000..17331c2
--- /dev/null
+++ b/cppcache/integration-test-2/CMakeLists.txt
@@ -0,0 +1,67 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+configure_file(framework/config.h.in config.h)
+
+add_executable(integration-test-2
+  ExampleTest.cpp
+  framework/Gfsh.cpp
+  framework/Gfsh.h
+  framework/Framework.cpp
+  framework/Framework.h
+  framework/Cluster.cpp
+  framework/Cluster.h
+  framework/GfshExecute.cpp
+  framework/GfshExecute.h
+  RegionPutGetAllTest.cpp
+  )
+
+target_compile_definitions(integration-test-2
+  PUBLIC
+    BOOST_ASIO_HAS_MOVE
+)
+
+target_include_directories(integration-test-2
+  PUBLIC
+    ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+target_link_libraries(integration-test-2
+  PUBLIC
+    apache-geode
+    testobject
+    GTest::GTest
+    GTest::Main
+    Boost::boost
+    Boost::system
+    Boost::log
+)
+
+if(WIN32)
+  target_compile_definitions(integration-test-2
+    PUBLIC
+      # Required for Boost.WinAPI
+      _WIN32_WINNT=0x06020000
+  )
+
+  foreach (_target apache-geode testobject)
+    add_custom_command(TARGET integration-test-2 POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different
+        "$<TARGET_FILE:${_target}>" "$<TARGET_FILE_DIR:integration-test-2>")
+  endforeach()
+endif()
+
+enable_testing()
+include(GoogleTest)
+gtest_discover_tests(integration-test-2)
diff --git a/cppcache/integration-test-2/ExampleTest.cpp b/cppcache/integration-test-2/ExampleTest.cpp
new file mode 100644
index 0000000..4c25d68
--- /dev/null
+++ b/cppcache/integration-test-2/ExampleTest.cpp
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <random>
+#include <thread>
+#include <future>
+
+#include <gtest/gtest.h>
+
+#include <geode/Cache.hpp>
+#include <geode/PoolManager.hpp>
+
+#include "framework/Framework.h"
+#include "framework/Gfsh.h"
+#include "framework/Cluster.h"
+
+namespace {
+
+using namespace apache::geode::client;
+using namespace std::chrono;
+
+std::shared_ptr<Region> setupRegion(Cache& cache) {
+  auto region = cache.createRegionFactory(RegionShortcut::PROXY)
+                    .setPoolName("default")
+                    .create("region");
+
+  return region;
+}
+
+/**
+ * Example test using 2 servers and waiting for async tasks to synchronize using
+ * furtures.
+ */
+TEST(ExampleTest, DISABLED_putAndGetWith2Servers) {
+  Cluster cluster{LocatorCount{1}, ServerCount{2}};
+  cluster.getGfsh()
+      .create()
+      .region()
+      .withName("region")
+      .withType("REPLICATE")
+      .execute();
+
+  auto task1 = std::async(std::launch::async, [&] {
+    auto cache = cluster.createCache();
+    auto region = setupRegion(cache);
+
+    region->put(1, "one");
+  });
+
+  auto task2 = std::async(std::launch::async, [&] {
+    auto cache = cluster.createCache();
+    auto region = setupRegion(cache);
+
+    auto status = task1.wait_for(debug_safe(minutes(1)));
+    ASSERT_EQ(std::future_status::ready, status);
+
+    auto v1 = std::dynamic_pointer_cast<CacheableString>(region->get(1));
+
+    EXPECT_EQ("one", v1->value());
+  });
+  ASSERT_EQ(std::future_status::ready, task2.wait_for(debug_safe(minutes(1))));
+}
+
+/**
+ * Example test using single server and waiting for async put and update
+ * operations to synchronize using promises.
+ */
+TEST(ExampleTest, DISABLED_putGetAndUpdateWith1Server) {
+  Cluster cluster{LocatorCount{1}, ServerCount{1}};
+  cluster.getGfsh()
+      .create()
+      .region()
+      .withName("region")
+      .withType("REPLICATE")
+      .execute();
+
+  std::promise<void> putPromise;
+  std::promise<void> updatePromise;
+
+  auto task1 = std::async(std::launch::async, [&] {
+    SCOPED_TRACE("task1");
+
+    auto cache = cluster.createCache();
+    auto region = setupRegion(cache);
+
+    region->put(1, "one");
+    putPromise.set_value();
+
+    ASSERT_EQ(std::future_status::ready,
+              updatePromise.get_future().wait_for(debug_safe(minutes(1))));
+
+    auto v1 = std::dynamic_pointer_cast<CacheableString>(region->get(1));
+    EXPECT_EQ("two", v1->value());
+  });
+
+  auto task2 = std::async(std::launch::async, [&] {
+    SCOPED_TRACE("task2");
+
+    auto cache = cluster.createCache();
+    auto region = setupRegion(cache);
+
+    ASSERT_EQ(std::future_status::ready,
+              putPromise.get_future().wait_for(debug_safe(minutes(1))));
+
+    auto v1 = std::dynamic_pointer_cast<CacheableString>(region->get(1));
+    EXPECT_EQ("one", v1->value());
+
+    region->put(1, "two");
+    updatePromise.set_value();
+
+  });
+  ASSERT_EQ(std::future_status::ready, task2.wait_for(debug_safe(minutes(1))));
+}
+
+}  // namespace
\ No newline at end of file
diff --git a/cppcache/integration-test-2/RegionPutGetAllTest.cpp b/cppcache/integration-test-2/RegionPutGetAllTest.cpp
new file mode 100644
index 0000000..cadd635
--- /dev/null
+++ b/cppcache/integration-test-2/RegionPutGetAllTest.cpp
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <future>
+#include <initializer_list>
+#include <iostream>
+#include <memory>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include <geode/Cache.hpp>
+#include <geode/PoolManager.hpp>
+
+#include <VariousPdxTypes.hpp>
+
+#include "framework/Cluster.h"
+#include "framework/Gfsh.h"
+
+namespace {
+
+using namespace apache::geode::client;
+using namespace std::chrono;
+using namespace PdxTests;
+
+template <int32_t Index, class PdxType>
+struct PdxTypesHelper {
+  static constexpr int32_t index = Index;
+  using type = PdxType;
+};
+
+using PdxTypesHelper1 = PdxTypesHelper<1, PdxTypes1>;
+using PdxTypesHelper2 = PdxTypesHelper<2, PdxTypes2>;
+using PdxTypesHelper3 = PdxTypesHelper<3, PdxTypes3>;
+using PdxTypesHelper4 = PdxTypesHelper<4, PdxTypes4>;
+using PdxTypesHelper5 = PdxTypesHelper<5, PdxTypes5>;
+using PdxTypesHelper6 = PdxTypesHelper<6, PdxTypes6>;
+using PdxTypesHelper7 = PdxTypesHelper<7, PdxTypes7>;
+using PdxTypesHelper8 = PdxTypesHelper<8, PdxTypes8>;
+using PdxTypesHelper9 = PdxTypesHelper<9, PdxTypes9>;
+using PdxTypesHelper10 = PdxTypesHelper<10, PdxTypes10>;
+
+std::shared_ptr<Region> setupRegion(Cache &cache) {
+  auto region = cache.createRegionFactory(RegionShortcut::PROXY)
+                    .setPoolName("default")
+                    .create("region");
+
+  return region;
+}
+
+void registerPdxTypes(Cache &cache,
+                      const std::initializer_list<TypeFactoryMethodPdx>
+                          &typeFactoryMethodPdxList) {
+  auto &pdxTypeRegistry = cache.getTypeRegistry();
+
+  for (const auto &typeFactoryMethodPdx : typeFactoryMethodPdxList) {
+    pdxTypeRegistry.registerPdxType(typeFactoryMethodPdx);
+  }
+}
+
+void setupPdxTypes(Cache &cache) {
+  registerPdxTypes(
+      cache,
+      {PdxTypes1::createDeserializable, PdxTypes2::createDeserializable,
+       PdxTypes3::createDeserializable, PdxTypes4::createDeserializable,
+       PdxTypes5::createDeserializable, PdxTypes6::createDeserializable,
+       PdxTypes7::createDeserializable, PdxTypes8::createDeserializable,
+       PdxTypes9::createDeserializable, PdxTypes10::createDeserializable});
+}
+
+HashMapOfCacheable setupMap() {
+  HashMapOfCacheable map;
+  map.emplace(CacheableInt32::create(PdxTypesHelper1::index),
+              std::make_shared<PdxTypesHelper1::type>());
+  map.emplace(CacheableInt32::create(PdxTypesHelper2::index),
+              std::make_shared<PdxTypesHelper2::type>());
+  map.emplace(CacheableInt32::create(PdxTypesHelper3::index),
+              std::make_shared<PdxTypesHelper3::type>());
+  map.emplace(CacheableInt32::create(PdxTypesHelper4::index),
+              std::make_shared<PdxTypesHelper4::type>());
+  map.emplace(CacheableInt32::create(PdxTypesHelper5::index),
+              std::make_shared<PdxTypesHelper5::type>());
+  map.emplace(CacheableInt32::create(PdxTypesHelper6::index),
+              std::make_shared<PdxTypesHelper6::type>());
+  map.emplace(CacheableInt32::create(PdxTypesHelper7::index),
+              std::make_shared<PdxTypesHelper7::type>());
+  map.emplace(CacheableInt32::create(PdxTypesHelper8::index),
+              std::make_shared<PdxTypesHelper8::type>());
+  map.emplace(CacheableInt32::create(PdxTypesHelper9::index),
+              std::make_shared<PdxTypesHelper9::type>());
+  map.emplace(CacheableInt32::create(PdxTypesHelper10::index),
+              std::make_shared<PdxTypesHelper10::type>());
+  return map;
+}
+
+template <class T>
+void assert_eq(HashMapOfCacheable &expected, HashMapOfCacheable &actual) {
+  const auto key = CacheableInt32::create(T::index);
+  ASSERT_TRUE(
+      std::dynamic_pointer_cast<typename T::type>(expected[key])
+          ->equals(std::dynamic_pointer_cast<typename T::type>(expected[key])))
+      << "Expected key " << key->value() << " with value of type "
+      << typeid(typename T::type).name() << " to be equal.";
+}
+
+void assert_eq(HashMapOfCacheable &expected, HashMapOfCacheable &actual) {
+  ASSERT_EQ(expected.size(), actual.size());
+
+  assert_eq<PdxTypesHelper1>(expected, actual);
+  assert_eq<PdxTypesHelper2>(expected, actual);
+  assert_eq<PdxTypesHelper3>(expected, actual);
+  assert_eq<PdxTypesHelper4>(expected, actual);
+  assert_eq<PdxTypesHelper5>(expected, actual);
+  assert_eq<PdxTypesHelper6>(expected, actual);
+  assert_eq<PdxTypesHelper7>(expected, actual);
+  assert_eq<PdxTypesHelper8>(expected, actual);
+  assert_eq<PdxTypesHelper9>(expected, actual);
+  assert_eq<PdxTypesHelper10>(expected, actual);
+}
+
+template <class Key, class... Tail>
+std::vector<Key> to_keys(std::unordered_map<Key, Tail...> map) {
+  std::vector<Key> keys;
+  keys.reserve(map.size());
+  for (const auto &entry : map) {
+    keys.push_back(entry.first);
+  }
+  return keys;
+};
+
+template <class Container>
+void localDestroy(Region &region, const Container keys) {
+  for (const auto &key : keys) {
+    region.localDestroy(key);
+  }
+}
+
+/**
+ * Port of testThinClientPutGetAll
+ */
+TEST(RegionPutGetAllTest, variousPdxTypes) {
+  Cluster cluster{LocatorCount{1}, ServerCount{2}};
+  cluster.getGfsh()
+      .create()
+      .region()
+      .withName("region")
+      .withType("REPLICATE")
+      .execute();
+
+  auto cache = cluster.createCache();
+  auto region = setupRegion(cache);
+
+  setupPdxTypes(cache);
+
+  auto putAllMap = setupMap();
+  auto keys = to_keys(putAllMap);
+
+  // TODO - Understand: Put one tests putAll doesn't fail for existing entry?
+  region->put(putAllMap.cbegin()->first, putAllMap.cbegin()->second);
+
+  region->putAll(putAllMap);
+
+  // TODO - Understand: Clear local cache to force fetch from server?
+  localDestroy(*region, keys);
+
+  auto getAllMap = region->getAll(keys);
+
+  assert_eq(putAllMap, getAllMap);
+}
+
+}  // namespace
diff --git a/cppcache/integration-test-2/framework/Cluster.cpp b/cppcache/integration-test-2/framework/Cluster.cpp
new file mode 100644
index 0000000..0771274
--- /dev/null
+++ b/cppcache/integration-test-2/framework/Cluster.cpp
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Cluster.h"
+
+void Locator::start() {
+  if (started_) return;
+
+  cluster_.getGfsh()
+      .start()
+      .locator()
+      .withDir(name_)
+      .withBindAddress(locatorAddress_.address)
+      .withPort(locatorAddress_.port)
+      .withJmxManagerPort(jmxManagerPort_)
+      .withHttpServicePort(0)
+      .execute();
+
+  //    std::cout << "locator: " << locatorAddress_.port << ": started"
+  //              << std::endl;
+  started_ = true;
+}
+
+void Locator::stop() {
+  cluster_.getGfsh().stop().locator().withDir(name_).execute();
+
+  //    std::cout << "locator: " << locatorAddress_.port << ": stopped"
+  //              << std::endl;
+  started_ = false;
+}
+
+void Server::start() {
+  cluster_.getGfsh()
+      .start()
+      .server()
+      .withDir(name_)
+      .withBindAddress(serverAddress_.address)
+      .withPort(serverAddress_.port)
+      .withLocators(locators_.front().getAdddress().address + "[" +
+                    std::to_string(locators_.front().getAdddress().port) + "]")
+      .execute();
+
+  //    std::cout << "server: " << serverAddress_.port << ": started" <<
+  //    std::endl;
+  started_ = true;
+}
+
+void Server::stop() {
+  cluster_.getGfsh().stop().server().withDir(name_).execute();
+
+  //    std::cout << "server: " << serverAddress_.port << ": stopped" <<
+  //    std::endl;
+  started_ = false;
+}
+
+void Cluster::start() {
+  locators_.reserve(initialLocators_);
+  for (size_t i = 0; i < initialLocators_; i++) {
+    locators_.push_back({*this, locators_,
+                         name_ + "/locator/" + std::to_string(i),
+                         jmxManagerPort_});
+  }
+
+  servers_.reserve(initialServers_);
+  for (size_t i = 0; i < initialServers_; i++) {
+    servers_.push_back(
+        {*this, locators_, name_ + "/server/" + std::to_string(i)});
+  }
+
+  std::vector<std::future<void>> futures;
+
+  for (auto &locator : locators_) {
+    futures.push_back(std::async(std::launch::async, [&] { locator.start(); }));
+  }
+
+  // TODO hack until there is a way to either tell servers to retry or wait
+  // for single future.
+  for (auto &future : futures) {
+    future.wait();
+  }
+
+  for (auto &server : servers_) {
+    futures.push_back(std::async(std::launch::async, [&] { server.start(); }));
+  }
+
+  for (auto &future : futures) {
+    future.wait();
+  }
+
+  //    std::cout << "cluster: " << jmxManagerPort_ << ": started" << std::endl;
+  started_ = true;
+}
+
+void Cluster::stop() {
+  std::vector<std::future<void>> futures;
+  for (auto &server : servers_) {
+    futures.push_back(std::async(std::launch::async, [&] { server.stop(); }));
+  }
+
+  for (auto &locator : locators_) {
+    futures.push_back(std::async(std::launch::async, [&] { locator.stop(); }));
+  }
+
+  for (auto &future : futures) {
+    future.wait();
+  }
+
+  //    std::cout << "cluster: " << jmxManagerPort_ << ": stopped" << std::endl;
+  started_ = false;
+}
diff --git a/cppcache/integration-test-2/framework/Cluster.h b/cppcache/integration-test-2/framework/Cluster.h
new file mode 100644
index 0000000..d73899a
--- /dev/null
+++ b/cppcache/integration-test-2/framework/Cluster.h
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef INTEGRATION_TEST_FRAMEWORK_CLUSTER_H
+#define INTEGRATION_TEST_FRAMEWORK_CLUSTER_H
+
+#include <cstdint>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <geode/Cache.hpp>
+#include <geode/PoolManager.hpp>
+
+#include "Framework.h"
+#include "GfshExecute.h"
+
+template <typename T, typename Parameter>
+class NamedType {
+ public:
+  explicit NamedType(T const &value) : value_(value) {}
+  explicit NamedType(T &&value) : value_(std::move(value)) {}
+  T &get() { return value_; }
+  T const &get() const { return value_; }
+
+ private:
+  T value_;
+};
+
+class Cluster;
+
+struct LocatorAddress {
+  std::string address;
+  uint16_t port;
+};
+
+class Locator {
+ public:
+  Locator(Cluster &cluster, std::vector<Locator> &locators, std::string name,
+          uint16_t jmxManagerPort)
+      : cluster_(cluster),
+        locators_(locators),
+        name_(std::move(name)),
+        jmxManagerPort_(jmxManagerPort) {
+    auto hostname = "localhost";
+    auto port = Framework::getAvailablePort();
+
+    locatorAddress_ = LocatorAddress{hostname, port};
+
+    // start();
+  }
+
+  ~Locator() noexcept {
+    try {
+      if (started_) {
+        stop();
+      }
+    } catch (...) {
+    }
+  }
+
+  Locator(const Locator &copy) = delete;
+  Locator &operator=(const Locator &copy) = delete;
+  Locator(Locator &&move)
+      : cluster_(move.cluster_),
+        locators_(move.locators_),
+        locatorAddress_(move.locatorAddress_),
+        jmxManagerPort_(move.jmxManagerPort_),
+        started_(move.started_),
+        name_(move.name_) {
+    move.started_ = false;
+  };
+  //  Locator &operator=(Locator &&move) = default;
+
+  const LocatorAddress &getAdddress() const { return locatorAddress_; }
+
+  void start();
+
+  void stop();
+
+ private:
+  Cluster &cluster_;
+  std::vector<Locator> &locators_;
+
+  LocatorAddress locatorAddress_;
+
+  uint16_t jmxManagerPort_;
+
+  std::string name_;
+
+  bool started_ = false;
+};
+
+struct ServerAddress {
+  std::string address;
+  uint16_t port;
+};
+
+class Server {
+ public:
+  Server(Cluster &cluster, std::vector<Locator> &locators, std::string name)
+      : cluster_(cluster), locators_(locators), name_(std::move(name)) {
+    auto hostname = "localhost";
+    auto port = Framework::getAvailablePort();
+    serverAddress_ = ServerAddress{hostname, port};
+
+    // start();
+  }
+
+  ~Server() noexcept {
+    try {
+      if (started_) {
+        stop();
+      }
+    } catch (...) {
+    }
+  }
+
+  Server(const Server &copy) = delete;
+  Server &operator=(const Server &other) = delete;
+  Server(Server &&move)
+      : cluster_(move.cluster_),
+        locators_(move.locators_),
+        serverAddress_(move.serverAddress_),
+        started_(move.started_),
+        name_(move.name_) {
+    move.started_ = false;
+  };
+  //  Server &operator=(Server &&other) = default;
+
+  void start();
+
+  void stop();
+
+ private:
+  Cluster &cluster_;
+  std::vector<Locator> &locators_;
+
+  ServerAddress serverAddress_;
+
+  bool started_ = false;
+
+  std::string name_;
+};
+
+using LocatorCount = NamedType<size_t, struct LocatorCountParameter>;
+using ServerCount = NamedType<size_t, struct ServerCountParameter>;
+using Name = NamedType<std::string, struct NameParameter>;
+
+class Cluster {
+ public:
+  Cluster(LocatorCount initialLocators, ServerCount initialServers)
+      : Cluster(Name(std::string(::testing::UnitTest::GetInstance()
+                                     ->current_test_info()
+                                     ->test_case_name()) +
+                     "/" +
+                     ::testing::UnitTest::GetInstance()
+                         ->current_test_info()
+                         ->name()),
+                initialLocators, initialServers){};
+
+  Cluster(Name name, LocatorCount initialLocators, ServerCount initialServers)
+      : name_(name.get()),
+        initialLocators_(initialLocators.get()),
+        initialServers_(initialServers.get()) {
+    jmxManagerPort_ = Framework::getAvailablePort();
+
+    start();
+  }
+
+  ~Cluster() noexcept {
+    try {
+      if (started_) {
+        stop();
+      }
+    } catch (...) {
+    }
+  }
+
+  Cluster(const Cluster &copy) = delete;
+  Cluster &operator=(const Cluster &other) = delete;
+  Cluster(Cluster &&copy) = default;
+  Cluster &operator=(Cluster &&other) = default;
+
+  std::string getJmxManager() {
+    return locators_.begin()->getAdddress().address + "[" +
+           std::to_string(jmxManagerPort_) + "]";
+  }
+
+  void start();
+
+  void stop();
+
+  apache::geode::client::Cache createCache() {
+    using namespace apache::geode::client;
+    auto cache = CacheFactory()
+                     .set("log-level", "none")
+                     .set("statistic-sampling-enabled", "false")
+                     .create();
+
+    auto poolFactory = cache.getPoolManager().createFactory();
+    for (const auto &locator : locators_) {
+      poolFactory.addLocator(locator.getAdddress().address,
+                             locator.getAdddress().port);
+      poolFactory.create("default");
+    }
+
+    return cache;
+  }
+
+  Gfsh &getGfsh() noexcept { return gfsh_; }
+
+ private:
+  std::string name_;
+
+  size_t initialLocators_;
+  std::vector<Locator> locators_;
+
+  size_t initialServers_;
+  std::vector<Server> servers_;
+
+  bool started_ = false;
+  uint16_t jmxManagerPort_;
+
+  GfshExecute gfsh_;
+};
+
+#endif  // INTEGRATION_TEST_FRAMEWORK_CLUSTER_H
diff --git a/cppcache/integration-test-2/framework/Framework.cpp b/cppcache/integration-test-2/framework/Framework.cpp
new file mode 100644
index 0000000..fe6942a
--- /dev/null
+++ b/cppcache/integration-test-2/framework/Framework.cpp
@@ -0,0 +1,18 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Framework.h"
diff --git a/cppcache/integration-test-2/framework/Framework.h b/cppcache/integration-test-2/framework/Framework.h
new file mode 100644
index 0000000..4b9d197
--- /dev/null
+++ b/cppcache/integration-test-2/framework/Framework.h
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef INTEGRATION_TEST_FRAMEWORK_FRAMEWORK_H
+#define INTEGRATION_TEST_FRAMEWORK_FRAMEWORK_H
+
+#include <cstdint>
+#include <random>
+#include <chrono>
+
+class Framework {
+ public:
+  static uint16_t getAvailablePort() {
+    // TODO boost open ephemeral port.
+    std::random_device randomDevice;
+    std::default_random_engine randomEngine(randomDevice());
+    std::uniform_int_distribution<uint16_t> uniformDist;
+    auto port = uniformDist(randomEngine);
+    return port;
+  }
+};
+
+template <class _Rep, class _Period>
+constexpr std::chrono::duration<_Rep, _Period> debug_safe(
+    std::chrono::duration<_Rep, _Period> duration) {
+#ifndef __OPTIMIZE__
+  return duration + std::chrono::hours(1);
+#else
+  return duration;
+#endif
+};
+
+#endif  // INTEGRATION_TEST_FRAMEWORK_FRAMEWORK_H
diff --git a/cppcache/integration-test-2/framework/Gfsh.cpp b/cppcache/integration-test-2/framework/Gfsh.cpp
new file mode 100644
index 0000000..d10798d
--- /dev/null
+++ b/cppcache/integration-test-2/framework/Gfsh.cpp
@@ -0,0 +1,18 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Gfsh.h"
diff --git a/cppcache/integration-test-2/framework/Gfsh.h b/cppcache/integration-test-2/framework/Gfsh.h
new file mode 100644
index 0000000..b56c7e9
--- /dev/null
+++ b/cppcache/integration-test-2/framework/Gfsh.h
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef INTEGRATION_TEST_FRAMEWORK_GFSH_H
+#define INTEGRATION_TEST_FRAMEWORK_GFSH_H
+
+#include <string>
+#include <iostream>
+
+#include <boost/process.hpp>
+#include <boost/log/trivial.hpp>
+
+class Gfsh {
+ public:
+  Gfsh() = default;
+  virtual ~Gfsh() = default;
+
+  class Start;
+  Start start() { return Start{*this}; }
+
+  class Stop;
+  Stop stop() { return Stop{*this}; }
+
+  class Create;
+  Create create() { return Create{*this}; }
+
+  class Connect;
+  Connect connect() { return Connect{*this}; }
+
+  class Shutdown;
+  Shutdown shutdown() { return Shutdown{*this}; }
+
+  class Verb {
+   public:
+   protected:
+    Verb(Gfsh &gfsh) : gfsh_(gfsh) {}
+    Gfsh &gfsh_;
+  };
+
+  template <class Result>
+  class Command {
+   public:
+    virtual Result execute() { Result{gfsh_}.parse(gfsh_.execute(command_)); }
+
+   protected:
+    Command(Gfsh &gfsh, std::string command)
+        : gfsh_(gfsh), command_(std::move(command)) {}
+    Gfsh &gfsh_;
+    std::string command_;
+  };
+
+  class Start {
+   public:
+    Start(Gfsh &gfsh) : gfsh_(gfsh) {}
+
+    class Server;
+    Server server() { return Server{gfsh_}; };
+
+    class Locator;
+    Locator locator() { return Locator{gfsh_}; };
+
+    class Locator : public Command<void> {
+     public:
+      Locator(Gfsh &gfsh) : Command(gfsh, "start locator") {}
+
+      Locator &withName(const std::string &name) {
+        command_ += " --name=" + name;
+        return *this;
+      };
+
+      Locator &withDir(const std::string &dir) {
+        command_ += " --dir=" + dir;
+        return *this;
+      };
+
+      Locator &withBindAddress(const std::string &bindAddress) {
+        command_ += " --bind-address=" + bindAddress;
+        return *this;
+      };
+
+      Locator &withPort(uint16_t port) {
+        command_ += " --port=" + std::to_string(port);
+        return *this;
+      };
+
+      Locator &withJmxManagerPort(uint16_t jmxManagerPort) {
+        command_ +=
+            " --J=-Dgemfire.jmx-manager-port=" + std::to_string(jmxManagerPort);
+        return *this;
+      };
+
+      Locator &withHttpServicePort(uint16_t httpServicePort) {
+        command_ += " --http-service-port=" + std::to_string(httpServicePort);
+        return *this;
+      };
+
+      Locator &withLogLevel(const std::string logLevel) {
+        command_ += " --log-level=" + logLevel;
+        return *this;
+      };
+    };
+
+    class Server : public Command<void> {
+     public:
+      Server(Gfsh &gfsh) : Command(gfsh, "start server") {}
+
+      Server &withName(const std::string &name) {
+        command_ += " --name=" + name;
+        return *this;
+      };
+
+      Server &withDir(const std::string &dir) {
+        command_ += " --dir=" + dir;
+        return *this;
+      };
+
+      Server &withBindAddress(const std::string &bindAddress) {
+        command_ += " --bind-address=" + bindAddress;
+        return *this;
+      };
+
+      Server &withPort(uint16_t serverPort) {
+        command_ += " --server-port=" + std::to_string(serverPort);
+        return *this;
+      };
+
+      Server &withLocators(const std::string locators) {
+        command_ += " --locators=" + locators;
+        return *this;
+      };
+
+      Server &withLogLevel(const std::string logLevel) {
+        command_ += " --log-level=" + logLevel;
+        return *this;
+      };
+    };
+
+   private:
+    Gfsh &gfsh_;
+  };
+
+  class Stop {
+   public:
+    Stop(Gfsh &gfsh) : gfsh_(gfsh) {}
+
+    class Server;
+    Server server() { return Server{gfsh_}; };
+
+    class Locator;
+    Locator locator() { return Locator{gfsh_}; };
+
+    class Locator : public Command<void> {
+     public:
+      Locator(Gfsh &gfsh) : Command(gfsh, "stop locator") {}
+
+      Locator &withName(const std::string &name) {
+        command_ += " --name=" + name;
+        return *this;
+      };
+
+      Locator &withDir(const std::string &dir) {
+        command_ += " --dir=" + dir;
+        return *this;
+      };
+    };
+
+    class Server : public Command<void> {
+     public:
+      Server(Gfsh &gfsh) : Command(gfsh, "stop server") {}
+
+      Server &withName(const std::string &name) {
+        command_ += " --name=" + name;
+        return *this;
+      };
+
+      Server &withDir(const std::string &dir) {
+        command_ += " --dir=" + dir;
+        return *this;
+      };
+    };
+
+   private:
+    Gfsh &gfsh_;
+  };
+
+  class Create : public Verb {
+   public:
+    Create(Gfsh &gfsh) : Verb{gfsh} {}
+
+    class Region;
+    Region region() { return Region{gfsh_}; };
+
+    class Region : public Command<void> {
+     public:
+      Region(Gfsh &gfsh) : Command(gfsh, "create region") {}
+
+      Region &withName(const std::string &name) {
+        command_ += " --name=" + name;
+        return *this;
+      };
+
+      Region &withType(const std::string &type) {
+        command_ += " --type=" + type;
+        return *this;
+      };
+    };
+  };
+
+  class Connect : public Command<void> {
+   public:
+    Connect(Gfsh &gfsh) : Command{gfsh, "connect"} {}
+
+    Connect &withJmxManager(const std::string &jmxManager) {
+      command_ += " --jmx-manager=" + jmxManager;
+      return *this;
+    };
+  };
+
+  class Shutdown : public Command<void> {
+   public:
+    Shutdown(Gfsh &gfsh) : Command{gfsh, "shutdown"} {}
+
+    Shutdown &withIncludeLocators(bool includeLocators) {
+      command_ += " --include-locators=" +
+                  std::string(includeLocators ? "true" : "false");
+      return *this;
+    };
+  };
+
+ protected:
+  virtual void execute(const std::string &command) = 0;
+};
+
+template <>
+inline void Gfsh::Command<void>::execute() {
+  gfsh_.execute(command_);
+}
+
+#endif  // INTEGRATION_TEST_FRAMEWORK_GFSH_H
diff --git a/cppcache/integration-test-2/framework/GfshExecute.cpp b/cppcache/integration-test-2/framework/GfshExecute.cpp
new file mode 100644
index 0000000..b7114ba
--- /dev/null
+++ b/cppcache/integration-test-2/framework/GfshExecute.cpp
@@ -0,0 +1,18 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GfshExecute.h"
diff --git a/cppcache/integration-test-2/framework/GfshExecute.h b/cppcache/integration-test-2/framework/GfshExecute.h
new file mode 100644
index 0000000..014adac
--- /dev/null
+++ b/cppcache/integration-test-2/framework/GfshExecute.h
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef INTEGRATION_TEST_FRAMEWORK_GFSHEXECUTE_H
+#define INTEGRATION_TEST_FRAMEWORK_GFSHEXECUTE_H
+
+#include <string>
+#include <iostream>
+#include <algorithm>
+#include <regex>
+
+#include <boost/process.hpp>
+#include <boost/log/trivial.hpp>
+
+#include "Gfsh.h"
+#include "config.h"
+
+template <class _T>
+bool starts_with(const _T &input, const _T &match) {
+  return input.size() >= match.size() &&
+         std::equal(std::begin(match), std::end(match), std::begin(input));
+}
+
+class GfshExecute : public Gfsh {
+ public:
+  GfshExecute() = default;
+  virtual ~GfshExecute() = default;
+
+  class Connect : public Command<void> {
+   public:
+    Connect(Gfsh &gfsh) : Command{gfsh, "connect"} {}
+
+    Connect &withJmxManager(const std::string &jmxManager) {
+      command_ += " --jmx-manager=" + jmxManager;
+      return *this;
+    };
+  };
+
+ protected:
+  void execute(const std::string &command) override {
+    BOOST_LOG_TRIVIAL(info) << "Gfsh::execute: " << command;
+
+    using namespace boost::process;
+
+    std::vector<std::string> commands;
+    if (!connection_.empty()) {
+      commands.push_back("-e");
+      commands.push_back(connection_);
+    }
+    commands.push_back("-e");
+    commands.push_back(command);
+
+    auto env = boost::this_process::environment();
+    // broken on windows env["JAVA_ARGS"] = "-Xmx1g -client";
+
+    ipstream outStream;
+    ipstream errStream;
+    child gfsh(GFSH_EXECUTABLE, args = commands, env, std_out > outStream,
+               std_err > errStream);
+
+    std::string line;
+
+    while (outStream && std::getline(outStream, line) && !line.empty())
+      BOOST_LOG_TRIVIAL(debug) << "Gfsh::execute: " << line;
+
+    while (errStream && std::getline(errStream, line) && !line.empty())
+      BOOST_LOG_TRIVIAL(error) << "Gfsh::execute: " << line;
+
+    gfsh.wait();
+
+    extractConnectionCommand(command);
+  }
+
+  void extractConnectionCommand(const std::string &command) {
+    if (starts_with(command, std::string("connect"))) {
+      connection_ = command;
+    } else if (starts_with(command, std::string("start locator"))) {
+      auto jmxManagerHost = std::string("localhost");
+      auto jmxManagerPort = std::string("1099");
+
+      std::regex jmxManagerHostRegex("bind-address=([^\\s]+)");
+      std::smatch jmxManagerHostMatch;
+      if (std::regex_search(command, jmxManagerHostMatch,
+                            jmxManagerHostRegex)) {
+        jmxManagerHost = jmxManagerHostMatch[1];
+      }
+
+      std::regex jmxManagerPortRegex("jmx-manager-port=(\\d+)");
+      std::smatch jmxManagerPortMatch;
+      if (std::regex_search(command, jmxManagerPortMatch,
+                            jmxManagerPortRegex)) {
+        jmxManagerPort = jmxManagerPortMatch[1];
+      }
+
+      connection_ = "connect --jmx-manager=" + jmxManagerHost + "[" +
+                    jmxManagerPort + "]";
+    }
+  }
+
+ private:
+  std::string connection_;
+};
+
+#endif  // INTEGRATION_TEST_FRAMEWORK_GFSHEXECUTE_H
diff --git a/cppcache/integration-test-2/framework/config.h.in b/cppcache/integration-test-2/framework/config.h.in
new file mode 100644
index 0000000..935175f
--- /dev/null
+++ b/cppcache/integration-test-2/framework/config.h.in
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef INTEGRATION_TEST_FRAMEWORK_CONFIG_H
+#define INTEGRATION_TEST_FRAMEWORK_CONFIG_H
+
+#define GFSH_EXECUTABLE "@Geode_gfsh_EXECUTABLE@"
+
+#endif  // INTEGRATION_TEST_FRAMEWORK_CONFIG_H
diff --git a/cppcache/test/CMakeLists.txt b/cppcache/test/CMakeLists.txt
index 459c1d0..91b1e3d 100644
--- a/cppcache/test/CMakeLists.txt
+++ b/cppcache/test/CMakeLists.txt
@@ -51,9 +51,9 @@ endif()
 target_link_libraries(${PROJECT_NAME}
   PRIVATE
     apache-geode-static
-    gtest
-    gtest_main
-    boost
+    GTest::GTest
+    GTest::Main
+    Boost::boost
 )
 
 target_include_directories(${PROJECT_NAME}
diff --git a/dependencies/boost/CMakeLists.txt b/dependencies/boost/CMakeLists.txt
index a85d768..150a0da 100644
--- a/dependencies/boost/CMakeLists.txt
+++ b/dependencies/boost/CMakeLists.txt
@@ -15,8 +15,8 @@
 
 project( boost LANGUAGES NONE )
 
-set( ${PROJECT_NAME}_VERSION 1.65.1 )
-set( ${PROJECT_NAME}_SHA265 a13de2c8fbad635e6ba9c8f8714a0e6b4264b60a29b964b940a22554705b6b60 )
+set( ${PROJECT_NAME}_VERSION 1.66.0 )
+set( ${PROJECT_NAME}_SHA265 bd0df411efd9a585e5a2212275f8762079fed8842264954675a4fddc46cfcf60 )
 string(REPLACE "." "_" _VERSION_UNDERSCORE ${${PROJECT_NAME}_VERSION})
 set( ${PROJECT_NAME}_URL "https://dl.bintray.com/boostorg/release/${${PROJECT_NAME}_VERSION}/source/boost_${_VERSION_UNDERSCORE}.tar.gz" )
 set( ${PROJECT_NAME}_EXTERN ${PROJECT_NAME}-extern )
@@ -26,7 +26,17 @@ ProcessorCount(_NPROCS)
 
 include(ExternalProject)
 
-set( _B2_FLAGS -d0 --prefix=<INSTALL_DIR> --with-system address-model=${BUILD_BITS} link=static )
+set(_B2_FLAGS
+  -d0
+  --prefix=<INSTALL_DIR>
+  --with-system
+  --with-log
+  --layout=system
+  address-model=${BUILD_BITS}
+  link=static
+  threading=multi
+  variant=$<LOWER_CASE:$<CONFIG>>
+)
 
 if (${_NPROCS})
   set ( _B2_FLAGS ${_B2_FLAGS} -j${_NPROCS} )
@@ -43,6 +53,9 @@ endif()
 
 if ("SunOS" STREQUAL ${CMAKE_SYSTEM_NAME})
   set ( _BOOTSTRAP_COMMAND ${_BOOTSTRAP_COMMAND} --with-toolset=sun )
+  set ( _B2_FLAGS ${_B2_FLAGS} define=BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES)
+elseif ("Windows" STREQUAL ${CMAKE_SYSTEM_NAME})
+  set ( CMAKE_STATIC_LIBRARY_PREFIX lib )
 endif()
 
 ExternalProject_Add( ${${PROJECT_NAME}_EXTERN}
@@ -83,14 +96,49 @@ if ("SunOS" STREQUAL ${CMAKE_SYSTEM_NAME})
   )
 endif()
 
+
+function(ADD_BOOST_LIBRARY)
+  set(options)
+  set(oneValueArgs)
+  set(multiValueArgs LIBRARIES DEPENDENCIES)
+  cmake_parse_arguments(PARSE_ARGV 1 args "${options}" "${oneValueArgs}" "${multiValueArgs}")
+
+  set(args_NAME ${ARGV0})
+
+  if (NOT DEFINED args_LIBRARIES OR args_LIBRARIES STREQUAL "")
+    set(args_LIBRARIES ${args_NAME})
+  endif()
+
+  set(linkLibraries)
+  foreach(library ${args_LIBRARIES})
+    list(APPEND linkLibraries "${${PROJECT_NAME}_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}boost_${args_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}")
+  endforeach()
+
+  add_library(boost_${args_NAME} INTERFACE)
+  target_link_libraries(boost_${args_NAME} INTERFACE
+    ${linkLibraries}
+    ${args_DEPENDENCIES}
+  )
+  add_library(Boost::${args_NAME} ALIAS boost_${args_NAME})
+endfunction()
+
+
 add_library(${PROJECT_NAME} INTERFACE)
 target_include_directories(${PROJECT_NAME} INTERFACE
   $<BUILD_INTERFACE:${${PROJECT_NAME}_INSTALL_DIR}/include>
   $<BUILD_INTERFACE:${${PROJECT_NAME}_INSTALL_DIR}/src>
 )
 target_compile_definitions(${PROJECT_NAME} INTERFACE
+  BOOST_ALL_NO_LIB
 )
 target_link_libraries(${PROJECT_NAME} INTERFACE
 )
-
+add_library(Boost::boost ALIAS boost)
 add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXTERN})
+
+add_boost_library(system DEPENDENCIES Boost::boost)
+add_boost_library(atomic DEPENDENCIES Boost::boost)
+add_boost_library(thread DEPENDENCIES Boost::atomic Boost::boost)
+add_boost_library(filesystem DEPENDENCIES Boost::boost)
+add_boost_library(log DEPENDENCIES Boost::thread Boost::filesystem Boost::boost)
+add_boost_library(log_setup DEPENDENCIES Boost::log)
diff --git a/dependencies/gtest/CMakeLists.txt b/dependencies/gtest/CMakeLists.txt
index f1ca84b..5b8c454 100644
--- a/dependencies/gtest/CMakeLists.txt
+++ b/dependencies/gtest/CMakeLists.txt
@@ -35,38 +35,41 @@ ExternalProject_Add( ${${PROJECT_NAME}_EXTERN}
 )
 
 ExternalProject_Get_Property( ${${PROJECT_NAME}_EXTERN} SOURCE_DIR )
-set( ${PROJECT_NAME}_SOURCE_DIR ${SOURCE_DIR}/googletest )
-set( gmock_SOURCE_DIR ${SOURCE_DIR}/googlemock )
+set( ${PROJECT_NAME}_gtest_SOURCE_DIR ${SOURCE_DIR}/googletest )
+set( ${PROJECT_NAME}_gmock_SOURCE_DIR ${SOURCE_DIR}/googlemock )
 ExternalProject_Get_Property( ${${PROJECT_NAME}_EXTERN} INSTALL_DIR )
 set( ${PROJECT_NAME}_INSTALL_DIR ${INSTALL_DIR} )
 ExternalProject_Get_Property( ${${PROJECT_NAME}_EXTERN} BINARY_DIR )
-set( ${PROJECT_NAME}_BINARY_DIR ${BINARY_DIR}/googlemock/gtest//${_DEBUG_OR_RELEASE} )
-set( gmock_BINARY_DIR ${BINARY_DIR}/googlemock//${_DEBUG_OR_RELEASE} )
+set( ${PROJECT_NAME}_gtest_BINARY_DIR ${BINARY_DIR}/googlemock/gtest/${_DEBUG_OR_RELEASE} )
+set( ${PROJECT_NAME}_gmock_BINARY_DIR ${BINARY_DIR}/googlemock/${_DEBUG_OR_RELEASE} )
 set( DEPENDENCIES_${PROJECT_NAME}_DIR ${${PROJECT_NAME}_BINARY_DIR} PARENT_SCOPE)
 
 set( ${PROJECT_NAME}_STATIC_LIB
-${${PROJECT_NAME}_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${PROJECT_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}
-${${PROJECT_NAME}_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${PROJECT_NAME}_main${CMAKE_STATIC_LIBRARY_SUFFIX}
-${gmock_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}
-${gmock_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}
+${${PROJECT_NAME}_gtest_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}
+${${PROJECT_NAME}_gtest_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}
+${${PROJECT_NAME}_gmock_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}
+${${PROJECT_NAME}_gmock_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}
 PARENT_SCOPE)
 
-add_library(${PROJECT_NAME} INTERFACE)
-target_include_directories(${PROJECT_NAME} INTERFACE
-  $<BUILD_INTERFACE:${${PROJECT_NAME}_SOURCE_DIR}/include>
-  $<BUILD_INTERFACE:${gmock_SOURCE_DIR}/include>
+add_library(${PROJECT_NAME}_gtest INTERFACE)
+target_include_directories(${PROJECT_NAME}_gtest INTERFACE
+  $<BUILD_INTERFACE:${${PROJECT_NAME}_gtest_SOURCE_DIR}/include>
+  $<BUILD_INTERFACE:${${PROJECT_NAME}_gmock_SOURCE_DIR}/include>
 )
-target_link_libraries(${PROJECT_NAME} INTERFACE
-  ${${PROJECT_NAME}_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${PROJECT_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}
+target_link_libraries(${PROJECT_NAME}_gtest INTERFACE
+  ${${PROJECT_NAME}_gtest_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}
 )
-add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXTERN})
+add_dependencies(${PROJECT_NAME}_gtest ${${PROJECT_NAME}_EXTERN})
 
-add_library(${PROJECT_NAME}_main INTERFACE)
-target_include_directories(${PROJECT_NAME}_main INTERFACE
-  $<BUILD_INTERFACE:${${PROJECT_NAME}_SOURCE_DIR}/include>
-  $<BUILD_INTERFACE:${gmock_SOURCE_DIR}/include>
+add_library(${PROJECT_NAME}_gtest_main INTERFACE)
+target_include_directories(${PROJECT_NAME}_gtest_main INTERFACE
+  $<BUILD_INTERFACE:${${PROJECT_NAME}_gtest_SOURCE_DIR}/include>
+  $<BUILD_INTERFACE:${${PROJECT_NAME}_gmock_SOURCE_DIR}/include>
 )
-target_link_libraries(${PROJECT_NAME}_main INTERFACE
-  ${${PROJECT_NAME}_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${PROJECT_NAME}_main${CMAKE_STATIC_LIBRARY_SUFFIX}
+target_link_libraries(${PROJECT_NAME}_gtest_main INTERFACE
+  ${${PROJECT_NAME}_gtest_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}
 )
-add_dependencies(${PROJECT_NAME}_main ${${PROJECT_NAME}_EXTERN})
+add_dependencies(${PROJECT_NAME}_gtest_main ${${PROJECT_NAME}_EXTERN})
+
+add_library(GTest::GTest ALIAS ${PROJECT_NAME}_gtest)
+add_library(GTest::Main ALIAS ${PROJECT_NAME}_gtest_main)
diff --git a/tests/cpp/testobject/CMakeLists.txt b/tests/cpp/testobject/CMakeLists.txt
index f2cbd9b..f548149 100644
--- a/tests/cpp/testobject/CMakeLists.txt
+++ b/tests/cpp/testobject/CMakeLists.txt
@@ -74,8 +74,10 @@ target_compile_definitions(${PROJECT_NAME}
 )
 
 target_include_directories(${PROJECT_NAME}
+	PUBLIC
+	  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
   PRIVATE
-	$<TARGET_PROPERTY:apache-geode,SOURCE_DIR>/../src
+	  $<TARGET_PROPERTY:apache-geode,SOURCE_DIR>/../src
 )
 
 target_link_libraries(${PROJECT_NAME}

-- 
To stop receiving notification emails like this one, please contact
jbarrett@apache.org.