blob: 2a6f79c20625a61f1d6a39103f977578d950f2eb [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 <atomic>
#include <mutex>
#include <unordered_map>
#include <gtest/gtest.h>
#include "TestableRecursiveMutex.hpp"
#include "util/synchronized_map.hpp"
using apache::geode::client::synchronized_map;
TEST(synchronized_mapTest, emplaceLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
auto result = map.emplace("a", "A");
ASSERT_EQ(true, result.second);
EXPECT_EQ("a", result.first->first);
EXPECT_EQ("A", result.first->second);
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
result = map.emplace("b", "B");
ASSERT_EQ(true, result.second);
EXPECT_EQ("b", result.first->first);
EXPECT_EQ("B", result.first->second);
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(2, map.mutex().lock_count_);
EXPECT_EQ(2, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, eraseKeyLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.mutex().resetCounters();
auto result = map.erase("a");
ASSERT_EQ(1, result);
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, beginLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.mutex().resetCounters();
const auto& begin = map.begin();
ASSERT_EQ("a", begin->first);
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(0, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, beginConstLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.mutex().resetCounters();
const auto& constMap = map;
const auto& begin = constMap.begin();
ASSERT_EQ("a", begin->first);
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(0, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, cbeginLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.mutex().resetCounters();
const auto& begin = map.cbegin();
ASSERT_EQ("a", begin->first);
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(0, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, endLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.mutex().resetCounters();
const auto& begin = map.begin();
const auto& end = map.end();
ASSERT_NE(begin, end);
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(0, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, endConsLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.mutex().resetCounters();
const auto& constMap = map;
const auto& begin = constMap.begin();
const auto& end = constMap.end();
ASSERT_NE(begin, end);
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(0, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, cendLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.mutex().resetCounters();
const auto& begin = map.cbegin();
const auto& end = map.cend();
ASSERT_NE(begin, end);
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(0, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, emptyLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
ASSERT_TRUE(map.empty());
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
map.emplace("a", "A");
map.mutex().resetCounters();
ASSERT_FALSE(map.empty());
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, sizeLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
ASSERT_EQ(0, map.size());
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
map.emplace("a", "A");
map.mutex().resetCounters();
ASSERT_EQ(1, map.size());
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, clearLocks) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.mutex().resetCounters();
map.clear();
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
EXPECT_TRUE(map.empty());
}
TEST(synchronized_mapTest, findNotLocked) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.mutex().resetCounters();
{
std::lock_guard<decltype(map)::mutex_type> lock(map.mutex());
const auto& entry = map.find("a");
EXPECT_EQ(1, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
EXPECT_EQ("a", entry->first);
}
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, findConstNotLocked) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.mutex().resetCounters();
{
auto&& lock = map.make_lock();
const auto& constMap = map;
const auto& entry = constMap.find("a");
EXPECT_EQ(1, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
EXPECT_EQ("a", entry->first);
}
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, iteratorNotLocked) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.emplace("a", "A");
map.emplace("b", "B");
map.mutex().resetCounters();
auto& mutex = map.mutex();
EXPECT_EQ(0, mutex.recursive_depth_);
EXPECT_EQ(0, mutex.recursive_depth_);
EXPECT_EQ(0, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
{
for (const auto& entry : map) {
EXPECT_EQ(0, mutex.recursive_depth_);
EXPECT_EQ(0, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
}
EXPECT_EQ(0, mutex.recursive_depth_);
EXPECT_EQ(0, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
{
std::lock_guard<decltype(map)::mutex_type> lock(mutex);
for (const auto& entry : map) {
EXPECT_EQ(1, mutex.recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
}
EXPECT_EQ(0, mutex.recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, make_lockDefault) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
{
auto&& lock = map.make_lock();
EXPECT_EQ(1, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, make_lock_WithUniqueLock) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
{
auto&& lock = map.make_lock<std::unique_lock>();
EXPECT_EQ(1, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, make_lock_WithUniqueLockDefered) {
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
{
auto&& lock = map.make_lock<std::unique_lock>(std::defer_lock);
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(0, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
lock.lock();
EXPECT_EQ(1, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(0, map.mutex().unlock_count_);
}
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
}
TEST(synchronized_mapTest, insertIteratorIteratorLocks) {
std::unordered_map<std::string, std::string> source = {{"a", "A"},
{"b", "B"}};
synchronized_map<std::unordered_map<std::string, std::string>,
TestableRecursiveMutex>
map;
map.insert(source.begin(), source.end());
EXPECT_EQ(0, map.mutex().recursive_depth_);
EXPECT_EQ(1, map.mutex().lock_count_);
EXPECT_EQ(1, map.mutex().unlock_count_);
EXPECT_EQ(2, map.size());
}