memgraph/tests/unit/utils_sync_ptr.cpp
andrejtonev e8850549d2
Add multi-tenancy v1 (#952)
* Decouple BoltSession and communication::bolt::Session
* Add CREATE/USE/DROP DATABASE
* Add SHOW DATABASES
* Cover WebSocket session
* Simple session safety implemented via RWLock
* Storage symlinks for backward. compatibility
* Extend the audit log with the DB info
* Add auth part
* Add tenant recovery
2023-08-01 18:49:11 +02:00

297 lines
6.9 KiB
C++

// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include <gtest/gtest.h>
#include <atomic>
#include <chrono>
#include <thread>
#include <utils/sync_ptr.hpp>
#include "utils/exceptions.hpp"
using namespace std::chrono_literals;
TEST(SyncPtr, Basic) {
std::atomic_bool alive{false};
struct Test {
Test(std::atomic_bool &alive) : alive_(alive) { alive_ = true; }
~Test() { alive_ = false; }
std::atomic_bool &alive_;
};
ASSERT_FALSE(alive);
memgraph::utils::SyncPtr<Test> sp(alive);
ASSERT_TRUE(alive);
auto sp_copy1 = sp.get();
auto sp_copy2 = sp.get();
sp_copy1.reset();
ASSERT_TRUE(alive);
sp_copy2.reset();
ASSERT_TRUE(alive);
sp.DestroyAndSync();
ASSERT_FALSE(alive);
}
TEST(SyncPtr, BasicWConfig) {
std::atomic_bool alive{false};
struct Test {
Test(std::atomic_bool &alive) : alive_(alive) { alive_ = true; }
~Test() { alive_ = false; }
std::atomic_bool &alive_;
};
struct TestConf {
TestConf(int i) : conf_(i) {}
int conf_;
};
ASSERT_FALSE(alive);
memgraph::utils::SyncPtr<Test, TestConf> sp(123, alive);
ASSERT_TRUE(alive);
ASSERT_EQ(sp.config().conf_, 123);
auto sp_copy1 = sp.get();
auto sp_copy2 = sp.get();
sp_copy1.reset();
ASSERT_TRUE(alive);
sp_copy2.reset();
ASSERT_TRUE(alive);
sp.DestroyAndSync();
ASSERT_FALSE(alive);
}
TEST(SyncPtr, Sync) {
std::atomic_bool alive{false};
struct Test {
Test(std::atomic_bool &alive) : alive_(alive) { alive_ = true; }
~Test() { alive_ = false; }
std::atomic_bool &alive_;
};
std::thread th;
ASSERT_FALSE(alive);
memgraph::utils::SyncPtr<Test> sp(alive);
{
using namespace std::chrono_literals;
sp.timeout(10000ms); // 10sec
ASSERT_TRUE(alive);
auto sp_copy1 = sp.get();
auto sp_copy2 = sp.get();
th = std::thread([&alive, p = sp.get()]() mutable {
// Wait for a second and then release the pointer
// SyncPtr will be destroyed in the mean time (and block)
std::this_thread::sleep_for(std::chrono::milliseconds(200));
ASSERT_TRUE(alive);
p.reset();
ASSERT_FALSE(alive);
});
}
ASSERT_TRUE(alive);
sp.DestroyAndSync();
th.join();
ASSERT_FALSE(alive);
}
TEST(SyncPtr, SyncWConfig) {
std::atomic_bool alive{false};
struct Test {
Test(std::atomic_bool &alive) : alive_(alive) { alive_ = true; }
~Test() { alive_ = false; }
std::atomic_bool &alive_;
};
struct TestConf {
TestConf(int i) : conf_(i) {}
int conf_;
};
std::thread th;
ASSERT_FALSE(alive);
memgraph::utils::SyncPtr<Test, TestConf> sp(456, alive);
{
using namespace std::chrono_literals;
sp.timeout(10000ms); // 10sec
ASSERT_TRUE(alive);
ASSERT_EQ(sp.config().conf_, 456);
auto sp_copy1 = sp.get();
auto sp_copy2 = sp.get();
th = std::thread([&alive, p = sp.get()]() mutable {
// Wait for a second and then release the pointer
// SyncPtr will be destroyed in the mean time (and block)
std::this_thread::sleep_for(std::chrono::milliseconds(200));
ASSERT_TRUE(alive);
p.reset();
ASSERT_FALSE(alive);
});
}
ASSERT_TRUE(alive);
sp.DestroyAndSync();
th.join();
ASSERT_FALSE(alive);
}
TEST(SyncPtr, Timeout100ms) {
std::atomic_bool alive{false};
struct Test {
Test(std::atomic_bool &alive) : alive_(alive) { alive_ = true; }
~Test() { alive_ = false; }
std::atomic_bool &alive_;
};
std::thread th;
ASSERT_FALSE(alive);
memgraph::utils::SyncPtr<Test> sp(alive);
using namespace std::chrono_literals;
sp.timeout(100ms);
ASSERT_TRUE(alive);
auto p = sp.get();
ASSERT_TRUE(alive);
auto start_100ms = std::chrono::system_clock::now();
ASSERT_THROW(sp.DestroyAndSync(), memgraph::utils::BasicException);
auto end_100ms = std::chrono::system_clock::now();
auto delta_100ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_100ms - start_100ms).count();
ASSERT_NEAR(delta_100ms, 100, 100);
p.reset();
ASSERT_FALSE(alive);
}
TEST(SyncPtr, Timeout567ms) {
std::atomic_bool alive{false};
struct Test {
Test(std::atomic_bool &alive) : alive_(alive) { alive_ = true; }
~Test() { alive_ = false; }
std::atomic_bool &alive_;
};
std::thread th;
ASSERT_FALSE(alive);
memgraph::utils::SyncPtr<Test> sp(alive);
using namespace std::chrono_literals;
sp.timeout(567ms);
ASSERT_TRUE(alive);
auto p = sp.get();
ASSERT_TRUE(alive);
auto start = std::chrono::system_clock::now();
ASSERT_THROW(sp.DestroyAndSync(), memgraph::utils::BasicException);
auto end = std::chrono::system_clock::now();
auto delta_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
ASSERT_NEAR(delta_ms, 567, 100);
p.reset();
ASSERT_FALSE(alive);
}
TEST(SyncPtr, Timeout100msWConfig) {
std::atomic_bool alive{false};
struct Test {
Test(std::atomic_bool &alive) : alive_(alive) { alive_ = true; }
~Test() { alive_ = false; }
std::atomic_bool &alive_;
};
struct TestConf {
TestConf(int i) : conf_(i) {}
int conf_;
};
std::thread th;
ASSERT_FALSE(alive);
memgraph::utils::SyncPtr<Test, TestConf> sp(0, alive);
using namespace std::chrono_literals;
sp.timeout(100ms);
ASSERT_TRUE(alive);
auto p = sp.get();
ASSERT_TRUE(alive);
auto start_100ms = std::chrono::system_clock::now();
ASSERT_THROW(sp.DestroyAndSync(), memgraph::utils::BasicException);
auto end_100ms = std::chrono::system_clock::now();
auto delta_100ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_100ms - start_100ms).count();
ASSERT_NEAR(delta_100ms, 100, 100);
p.reset();
ASSERT_FALSE(alive);
}
TEST(SyncPtr, Timeout567msWConfig) {
std::atomic_bool alive{false};
struct Test {
Test(std::atomic_bool &alive) : alive_(alive) { alive_ = true; }
~Test() { alive_ = false; }
std::atomic_bool &alive_;
};
struct TestConf {
TestConf(int i) : conf_(i) {}
int conf_;
};
std::thread th;
ASSERT_FALSE(alive);
memgraph::utils::SyncPtr<Test, TestConf> sp(2, alive);
using namespace std::chrono_literals;
sp.timeout(567ms);
ASSERT_TRUE(alive);
auto p = sp.get();
ASSERT_TRUE(alive);
auto start = std::chrono::system_clock::now();
ASSERT_THROW(sp.DestroyAndSync(), memgraph::utils::BasicException);
auto end = std::chrono::system_clock::now();
auto delta_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
ASSERT_NEAR(delta_ms, 567, 100);
p.reset();
ASSERT_FALSE(alive);
}