blob: 799b81d421d9938539a01b51a838a8a48504b089 [file] [log] [blame]
/*
* 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/Cluster.h>
#include <framework/Framework.h>
#include <framework/Gfsh.h>
#include <gmock/gmock.h>
#include <future>
#include <iostream>
#include <random>
#include <thread>
#include <boost/log/core.hpp>
#include <gtest/gtest.h>
#include <geode/AttributesMutator.hpp>
#include <geode/Cache.hpp>
#include <geode/CacheListener.hpp>
#include <geode/EntryEvent.hpp>
#include <geode/PoolManager.hpp>
#include <geode/RegionEvent.hpp>
#include <geode/RegionFactory.hpp>
#include <geode/RegionShortcut.hpp>
#include "mock/CacheListenerMock.hpp"
#include "utility/make_unique.hpp"
namespace {
class HARegionCacheListenerARLEPDTest : public ::testing::Test {
protected:
static ::std::unique_ptr<::Cluster> cluster_;
/* Cache listener mocks make a circular reference to the region, and the
* region retains a circular reference back to the cache. The reference is
* established when a callback is called and is resolved when the mock is
* verified and cleared. The circular reference prevents the cache from
* falling out of scope and shutting down, and it prevents the mock instance
* from verifying and clearing itself. You have to manually verify and clear
* the mock at the end of every test. */
static ::std::shared_ptr<::apache::geode::client::Nice_MockListener>
listener_;
static ::std::unique_ptr<::apache::geode::client::Cache> cache_;
static ::std::shared_ptr<::apache::geode::client::Region> region_;
/* Surprise! There are different code paths for event callbacks. Some are
sequential, the result of a server response; Some of them are concurrent - the
result of a server message.
TODO: Build out both sequential and concurrent listener events. */
::std::mutex cv_m_;
::std::condition_variable cv_;
bool verified_;
std::function<void(const apache::geode::client::RegionEvent &)>
verify_the_regionevent_callback;
std::function<void(const apache::geode::client::EntryEvent &)>
verify_the_entryevent_callback;
std::function<bool()> the_verification_condition;
/* SetUp and TearDown happen after test fixture construction and before test
* fixture destruction to avoid superious noise in the mock. */
void SetUp() override {
::apache::geode::client::AttributesMutator(region_).setCacheListener(
listener_);
}
void TearDown() override {
::apache::geode::client::AttributesMutator(region_).setCacheListener({});
::testing::Mock::VerifyAndClearExpectations(
listener_.get()); // Just to make sure it's clean for the next test.
}
HARegionCacheListenerARLEPDTest()
: verified_{false},
verify_the_regionevent_callback{::testing::Invoke(
this,
&HARegionCacheListenerARLEPDTest::verify_regionevent_callback)},
verify_the_entryevent_callback{::testing::Invoke(
this,
&HARegionCacheListenerARLEPDTest::verify_entryevent_callback)},
the_verification_condition{
std::bind(&HARegionCacheListenerARLEPDTest::is_verified, this)} {
create_the_test_region();
// Assure we've already received an afterRegionLive event by creating the
// region. Then destroy it for the test.
cluster_->getGfsh().destroy().region().withName("region").execute();
// Cycle the endpoint to flush the client-internal process marker.
// We should be able to get a second afterRegionLive after this.
clear_marker_processed_flag();
}
~HARegionCacheListenerARLEPDTest() override { destroy_any_test_region(); }
void clear_marker_processed_flag() {
/* As of this writing, you typically only get afterRegionLive once. This
* means, if almost any any prior test runs, you'll likely have already
* processed this event. But there is an exception: the state is reset if
* the endpoint disconnects.
*/
cluster_->getServers()[0].stop();
cluster_->getServers()[0].start();
}
void create_the_test_region() {
cluster_->getGfsh()
.create()
.region()
.withName(get_the_test_region_name())
.withType("PARTITION")
.execute();
}
void destroy_any_test_region() {
cluster_->getGfsh()
.destroy()
.region()
.ifExists()
.withName(get_the_test_region_name())
.execute();
}
static const std::string &get_the_test_region_name() {
static const std::string test_region_name{"region"};
return test_region_name;
}
void verify_regionevent_callback(
const ::apache::geode::client::RegionEvent &) {
auto lk = std::unique_lock<std::mutex>(cv_m_);
verified_ = true;
cv_.notify_one();
}
void verify_entryevent_callback(const ::apache::geode::client::EntryEvent &) {
auto lk = std::unique_lock<std::mutex>(cv_m_);
verified_ = true;
cv_.notify_one();
}
bool is_verified() { return verified_; }
public:
static void SetUpTestSuite() {
listener_ =
::std::make_shared<::apache::geode::client::Nice_MockListener>();
cluster_ = ::make_unique<::Cluster>(Name{"HARegionCacheListenerARLEPDTest"},
LocatorCount{1}, ServerCount{1});
cluster_->start();
cache_ = ::make_unique<::apache::geode::client::Cache>(
cluster_->createCache({}, ::Cluster::SubscriptionState::Enabled));
region_ = cache_
->createRegionFactory(
::apache::geode::client::RegionShortcut::PROXY)
.setPoolName("default")
.create(get_the_test_region_name());
}
static void TearDownTestSuite() {
region_.reset();
cache_.reset();
cluster_.reset();
listener_.reset();
}
};
::std::unique_ptr<::Cluster> HARegionCacheListenerARLEPDTest::cluster_{};
::std::shared_ptr<::apache::geode::client::Nice_MockListener>
HARegionCacheListenerARLEPDTest::listener_{};
::std::unique_ptr<::apache::geode::client::Cache>
HARegionCacheListenerARLEPDTest::cache_{};
::std::shared_ptr<::apache::geode::client::Region>
HARegionCacheListenerARLEPDTest::region_{};
} // namespace
using ::testing::AllOf;
using ::testing::Eq;
using ::testing::Property;
using ::apache::geode::client::CacheableString;
using ::apache::geode::client::EntryEvent;
using ::apache::geode::client::RegionEvent;
TEST_F(HARegionCacheListenerARLEPDTest,
DISABLED_afterRegionLiveAfterEPDisconnect) {
auto with_these_properties = Property(&RegionEvent::getRegion, Eq(region_));
EXPECT_CALL(*listener_, afterRegionLive(with_these_properties))
.WillOnce(verify_the_regionevent_callback);
auto lk = std::unique_lock<std::mutex>(cv_m_);
create_the_test_region();
cv_.wait_for(lk, ::std::chrono::seconds{5}, the_verification_condition);
::testing::Mock::VerifyAndClearExpectations(listener_.get());
}