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

bbender 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 9870644  GEODE-5626: Fix crash in register all keys (#351)
9870644 is described below

commit 9870644656ef61239244a43e65aaadc922a858c2
Author: Blake Bender <[email protected]>
AuthorDate: Mon Sep 17 07:48:15 2018 -0700

    GEODE-5626: Fix crash in register all keys (#351)
    
    * GEODE-5626: Reject getInitialValues=true in registerAllKeys when region 
is not caching.
    
        - Refactor Cluster class so we can apply locators separately.
        - Clean up server directories at test startup.
        - Add test cases for caching proxy and proxy regions with 
getInitialValues set to true
        - remove extraneous comment and empty doc comments
        - throw exception if gfsh exits non-zero
        - use relative path when deleting server directory
    
    Co-authored-by: Ivan Godwin <[email protected]>
---
 cppcache/integration-test-2/CMakeLists.txt         |   1 +
 cppcache/integration-test-2/RegisterKeysTest.cpp   | 191 +++++++++++++++++++++
 cppcache/integration-test-2/framework/Cluster.h    |  30 ++--
 .../integration-test-2/framework/GfshExecute.cpp   |   3 +
 .../integration-test-2/framework/GfshExecute.h     |  23 ++-
 cppcache/src/ThinClientRegion.cpp                  |  19 +-
 6 files changed, 252 insertions(+), 15 deletions(-)

diff --git a/cppcache/integration-test-2/CMakeLists.txt 
b/cppcache/integration-test-2/CMakeLists.txt
index 198c704..8e0233c 100644
--- a/cppcache/integration-test-2/CMakeLists.txt
+++ b/cppcache/integration-test-2/CMakeLists.txt
@@ -27,6 +27,7 @@ add_executable(integration-test-2
   framework/GfshExecute.h
   RegionPutGetAllTest.cpp
   PdxInstanceTest.cpp
+  RegisterKeysTest.cpp
   StructTest.cpp
   EnableChunkHandlerThreadTest.cpp
   )
diff --git a/cppcache/integration-test-2/RegisterKeysTest.cpp 
b/cppcache/integration-test-2/RegisterKeysTest.cpp
new file mode 100644
index 0000000..1dc3333
--- /dev/null
+++ b/cppcache/integration-test-2/RegisterKeysTest.cpp
@@ -0,0 +1,191 @@
+/* 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 <gtest/gtest.h>
+
+#include <geode/CacheFactory.hpp>
+#include <geode/Cache.hpp>
+#include <geode/PoolManager.hpp>
+#include <geode/RegionFactory.hpp>
+#include <geode/RegionShortcut.hpp>
+
+#include "framework/Framework.h"
+#include "framework/Gfsh.h"
+#include "framework/Cluster.h"
+
+namespace {
+
+using namespace apache::geode::client;
+
+apache::geode::client::Cache createTestCache() {
+  CacheFactory cacheFactory;
+  return cacheFactory.set("log-level", "none")
+      .set("statistic-sampling-enabled", "false")
+      .create();
+}
+
+std::shared_ptr<Region> setupCachingProxyRegion(Cache& cache) {
+  auto region = cache.createRegionFactory(RegionShortcut::CACHING_PROXY)
+                    .setPoolName("default")
+                    .create("region");
+
+  return region;
+}
+
+std::shared_ptr<Region> setupProxyRegion(Cache& cache) {
+  auto region = cache.createRegionFactory(RegionShortcut::PROXY)
+                    .setPoolName("default")
+                    .create("region");
+
+  return region;
+}
+
+TEST(RegisterKeysTest, RegisterAllWithCachingRegion) {
+  Cluster cluster{LocatorCount{1}, ServerCount{1}};
+  cluster.getGfsh()
+      .create()
+      .region()
+      .withName("region")
+      .withType("PARTITION")
+      .execute();
+
+  {
+    auto cache = createTestCache();
+    auto poolFactory =
+        cache.getPoolManager().createFactory().setSubscriptionEnabled(true);
+    cluster.applyLocators(poolFactory);
+    poolFactory.create("default");
+    auto region = setupCachingProxyRegion(cache);
+
+    region->put("one", std::make_shared<CacheableInt16>(1));
+    region->put("two", std::make_shared<CacheableInt16>(2));
+    region->put("three", std::make_shared<CacheableInt16>(3));
+  }
+
+  {
+    auto cache2 = createTestCache();
+    auto poolFactory =
+        cache2.getPoolManager().createFactory().setSubscriptionEnabled(true);
+    cluster.applyLocators(poolFactory);
+    poolFactory.create("default");
+    auto region2 = setupCachingProxyRegion(cache2);
+
+    auto&& entryBefore = region2->getEntry("one");
+    ASSERT_EQ(entryBefore, nullptr);
+
+    // 2nd parameter is getInitialValues, default is false, which leads to the
+    // first update notification being passed in with a NULL "oldValue".  Set 
it
+    // to true here, and verify the entry retrieved is valid, i.e. the initial
+    // value was retrieved.
+    region2->registerAllKeys(false, true);
+
+    auto&& uncastedEntry = region2->getEntry("one");
+    auto&& entryAfter =
+        std::dynamic_pointer_cast<CacheableInt16>(uncastedEntry->getValue());
+    ASSERT_NE(entryAfter, nullptr);
+    ASSERT_EQ(entryAfter->value(), 1);
+  }
+}
+
+TEST(RegisterKeysTest, RegisterAnyWithCachingRegion) {
+  Cluster cluster{LocatorCount{1}, ServerCount{1}};
+  cluster.getGfsh()
+      .create()
+      .region()
+      .withName("region")
+      .withType("PARTITION")
+      .execute();
+
+  {
+    auto cache = createTestCache();
+    auto poolFactory =
+        cache.getPoolManager().createFactory().setSubscriptionEnabled(true);
+    cluster.applyLocators(poolFactory);
+    poolFactory.create("default");
+    auto region = setupCachingProxyRegion(cache);
+
+    region->put("one", std::make_shared<CacheableInt16>(1));
+    region->put("two", std::make_shared<CacheableInt16>(2));
+    region->put("three", std::make_shared<CacheableInt16>(3));
+
+    cache.close();
+  }
+
+  {
+    auto cache2 = createTestCache();
+    auto poolFactory =
+        cache2.getPoolManager().createFactory().setSubscriptionEnabled(true);
+    cluster.applyLocators(poolFactory);
+    poolFactory.create("default");
+    auto region2 = setupCachingProxyRegion(cache2);
+    std::vector<std::shared_ptr<CacheableKey> > keys;
+    keys.push_back(std::make_shared<CacheableString>("one"));
+
+    auto&& entryBefore = region2->getEntry("one");
+    ASSERT_EQ(entryBefore, nullptr);
+
+    region2->registerKeys(keys, false, true);
+
+    auto&& entryAfterGet = std::dynamic_pointer_cast<CacheableInt16>(
+        region2->getEntry("one")->getValue());
+    ASSERT_NE(entryAfterGet, nullptr);
+    ASSERT_EQ(entryAfterGet->value(), 1);
+  }
+}
+
+TEST(RegisterKeysTest, RegisterAllWithProxyRegion) {
+  Cluster cluster{LocatorCount{1}, ServerCount{1}};
+  cluster.getGfsh()
+      .create()
+      .region()
+      .withName("region")
+      .withType("PARTITION")
+      .execute();
+  auto cache = createTestCache();
+  auto poolFactory =
+      cache.getPoolManager().createFactory().setSubscriptionEnabled(true);
+  cluster.applyLocators(poolFactory);
+  poolFactory.create("default");
+  auto region = setupProxyRegion(cache);
+
+  EXPECT_THROW(region->registerAllKeys(false, true), IllegalStateException);
+  cache.close();
+}
+
+TEST(RegisterKeysTest, RegisterAnyWithProxyRegion) {
+  Cluster cluster{LocatorCount{1}, ServerCount{1}};
+  cluster.getGfsh()
+      .create()
+      .region()
+      .withName("region")
+      .withType("PARTITION")
+      .execute();
+  auto cache = createTestCache();
+  auto poolFactory =
+      cache.getPoolManager().createFactory().setSubscriptionEnabled(true);
+  cluster.applyLocators(poolFactory);
+  poolFactory.create("default");
+  auto region = setupProxyRegion(cache);
+  std::vector<std::shared_ptr<CacheableKey> > keys;
+  keys.push_back(std::make_shared<CacheableInt16>(2));
+
+  EXPECT_THROW(region->registerKeys(keys, false, true), IllegalStateException);
+  cache.close();
+}
+
+}  // namespace
diff --git a/cppcache/integration-test-2/framework/Cluster.h 
b/cppcache/integration-test-2/framework/Cluster.h
index fb5871e..37be2e6 100644
--- a/cppcache/integration-test-2/framework/Cluster.h
+++ b/cppcache/integration-test-2/framework/Cluster.h
@@ -182,6 +182,7 @@ class Cluster {
         initialServers_(initialServers.get()) {
     jmxManagerPort_ = Framework::getAvailablePort();
 
+    removeServerDirectory();
     start();
   }
 
@@ -208,33 +209,38 @@ class Cluster {
 
   void stop();
 
+  void removeServerDirectory() {
+    boost::filesystem::path serverDir = boost::filesystem::relative(name_);
+    boost::filesystem::remove_all(serverDir);
+  }
+
+  apache::geode::client::Cache createCache() { return createCache({}); }
 
   apache::geode::client::Cache createCache(const 
std::unordered_map<std::string, std::string>& properties) {
     using apache::geode::client::CacheFactory;
 
     CacheFactory cacheFactory;
 
-    for (auto&& property : properties) {
+    for (auto &&property : properties) {
       cacheFactory.set(property.first, property.second);
     }
 
-    auto cache = cacheFactory
-            .set("log-level", "none")
-            .set("statistic-sampling-enabled", "false")
-            .create();
+    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");
-    }
+    applyLocators(poolFactory);
+    poolFactory.create("default");
 
     return cache;
   }
 
-  apache::geode::client::Cache createCache() {
-    return createCache({});
+  void applyLocators(apache::geode::client::PoolFactory &poolFactory) {
+   for (const auto &locator : locators_) {
+     poolFactory.addLocator(locator.getAdddress().address,
+                            locator.getAdddress().port);
+   }
   }
 
   Gfsh &getGfsh() noexcept { return gfsh_; }
diff --git a/cppcache/integration-test-2/framework/GfshExecute.cpp 
b/cppcache/integration-test-2/framework/GfshExecute.cpp
index 8a569e9..b9d8f69 100644
--- a/cppcache/integration-test-2/framework/GfshExecute.cpp
+++ b/cppcache/integration-test-2/framework/GfshExecute.cpp
@@ -67,6 +67,9 @@ void GfshExecute::execute(const std::string &command) {
   auto exit_code = gfsh.exit_code();
   BOOST_LOG_TRIVIAL(debug) << "Gfsh::execute: exit:" << exit_code;
 
+  if (exit_code) {
+    throw new GfshExecuteException("gfsh error", exit_code);
+  }
   extractConnectionCommand(command);
 }
 
diff --git a/cppcache/integration-test-2/framework/GfshExecute.h 
b/cppcache/integration-test-2/framework/GfshExecute.h
index d44cccc..d812c41 100644
--- a/cppcache/integration-test-2/framework/GfshExecute.h
+++ b/cppcache/integration-test-2/framework/GfshExecute.h
@@ -20,10 +20,12 @@
 #ifndef INTEGRATION_TEST_FRAMEWORK_GFSHEXECUTE_H
 #define INTEGRATION_TEST_FRAMEWORK_GFSHEXECUTE_H
 
-#include <string>
-#include <iostream>
 #include <algorithm>
+#include <iostream>
 #include <regex>
+#include <string>
+
+#include <geode/Exception.hpp>
 
 #pragma error_messages(off, oklambdaretmulti, wvarhidemem, \
                        w_constexprnonlitret, explctspectypename)
@@ -40,6 +42,23 @@ bool starts_with(const _T &input, const _T &match) {
          std::equal(std::begin(match), std::end(match), std::begin(input));
 }
 
+
+ class GfshExecuteException : public apache::geode::client::Exception {
+public:
+  GfshExecuteException(std::string message, int returnCode) :
+      apache::geode::client::Exception(message),
+      returnCode_(returnCode) {}
+  ~GfshExecuteException() noexcept override {}
+  std::string getName() const override {
+    return "GfshExecuteException";
+  }
+  int getGfshReturnCode() {
+    return returnCode_;
+  }
+private:
+  int returnCode_;
+};
+
 class GfshExecute : public Gfsh {
  public:
   GfshExecute() = default;
diff --git a/cppcache/src/ThinClientRegion.cpp 
b/cppcache/src/ThinClientRegion.cpp
index 74c467a..2629685 100644
--- a/cppcache/src/ThinClientRegion.cpp
+++ b/cppcache/src/ThinClientRegion.cpp
@@ -417,9 +417,18 @@ void ThinClientRegion::registerKeys(
         "Durable flag only applicable for "
         "durable clients");
   }
+  if (getInitialValues && !m_regionAttributes.getCachingEnabled()) {
+    LOGERROR(
+          "Register keys getInitialValues flag is only applicable for caching"
+          "clients");
+    throw IllegalStateException(
+        "getInitialValues flag only applicable for caching clients");
+  }
 
   InterestResultPolicy interestPolicy = InterestResultPolicy::NONE;
-  if (getInitialValues) interestPolicy = InterestResultPolicy::KEYS_VALUES;
+  if (getInitialValues) {
+    interestPolicy = InterestResultPolicy::KEYS_VALUES;
+  }
 
   LOGDEBUG("ThinClientRegion::registerKeys : interestpolicy is %d",
            interestPolicy.ordinal);
@@ -489,6 +498,14 @@ void ThinClientRegion::registerAllKeys(bool isDurable, 
bool getInitialValues,
         "Durable flag only applicable for durable clients");
   }
 
+  if (getInitialValues && !m_regionAttributes.getCachingEnabled()) {
+    LOGERROR(
+          "Register all keys getInitialValues flag is only applicable for 
caching"
+          "clients");
+    throw IllegalStateException(
+        "getInitialValues flag only applicable for caching clients");
+  }
+
   InterestResultPolicy interestPolicy = InterestResultPolicy::NONE;
   if (getInitialValues) {
     interestPolicy = InterestResultPolicy::KEYS_VALUES;

Reply via email to