diff options
author | Håvard Pettersen <havardpe@oath.com> | 2018-10-29 10:04:19 +0000 |
---|---|---|
committer | Håvard Pettersen <havardpe@oath.com> | 2018-11-27 15:11:06 +0000 |
commit | c52bd31c7208d4bab093efb24acb9a3452a0b936 (patch) | |
tree | 1fc9c4b9b03dc1fe305e995a41c413da76df493a /vespalib/src/tests/portal/handle_manager | |
parent | 95323a3a983e3b87f83ea7eaee990ce6070ed699 (diff) |
initial portal code
Diffstat (limited to 'vespalib/src/tests/portal/handle_manager')
-rw-r--r-- | vespalib/src/tests/portal/handle_manager/CMakeLists.txt | 8 | ||||
-rw-r--r-- | vespalib/src/tests/portal/handle_manager/handle_manager_test.cpp | 146 |
2 files changed, 154 insertions, 0 deletions
diff --git a/vespalib/src/tests/portal/handle_manager/CMakeLists.txt b/vespalib/src/tests/portal/handle_manager/CMakeLists.txt new file mode 100644 index 00000000000..b12b72f9ad6 --- /dev/null +++ b/vespalib/src/tests/portal/handle_manager/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespalib_handle_manager_test_app TEST + SOURCES + handle_manager_test.cpp + DEPENDS + vespalib +) +vespa_add_test(NAME vespalib_handle_manager_test_app COMMAND vespalib_handle_manager_test_app) diff --git a/vespalib/src/tests/portal/handle_manager/handle_manager_test.cpp b/vespalib/src/tests/portal/handle_manager/handle_manager_test.cpp new file mode 100644 index 00000000000..4ce25aa0a7a --- /dev/null +++ b/vespalib/src/tests/portal/handle_manager/handle_manager_test.cpp @@ -0,0 +1,146 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/vespalib/testkit/test_kit.h> +#include <vespa/vespalib/portal/handle_manager.h> +#include <vespa/vespalib/util/gate.h> + +#include <thread> +#include <chrono> +#include <atomic> + +using namespace vespalib; +using namespace vespalib::portal; + +TEST_F("require that handles can be created, locked and destroyed", TimeBomb(60)) { + HandleManager manager; + uint64_t handle = manager.create(); + EXPECT_TRUE(handle != manager.null_handle()); + { + HandleGuard guard = manager.lock(handle); + EXPECT_TRUE(guard.valid()); + EXPECT_EQUAL(guard.handle(), handle); + } + EXPECT_TRUE(manager.destroy(handle)); + { + HandleGuard guard = manager.lock(handle); + EXPECT_TRUE(!guard.valid()); + EXPECT_EQUAL(guard.handle(), manager.null_handle()); + } +} + +TEST_F("require that multiple guards can be taken for the same handle", TimeBomb(60)) { + HandleManager manager; + uint64_t handle = manager.create(); + EXPECT_TRUE(handle != manager.null_handle()); + { + HandleGuard guard1 = manager.lock(handle); + HandleGuard guard2 = manager.lock(handle); // <- does not block + EXPECT_TRUE(guard1.valid()); + EXPECT_EQUAL(guard1.handle(), handle); + EXPECT_TRUE(guard2.valid()); + EXPECT_EQUAL(guard2.handle(), handle); + } + EXPECT_TRUE(manager.destroy(handle)); +} + +TEST_F("require that handles are independent", TimeBomb(60)) { + HandleManager manager; + uint64_t handle1 = manager.create(); + uint64_t handle2 = manager.create(); + uint64_t handle3 = manager.create(); + EXPECT_TRUE(handle1 != manager.null_handle()); + EXPECT_TRUE(handle2 != manager.null_handle()); + EXPECT_TRUE(handle3 != manager.null_handle()); + EXPECT_TRUE(handle1 != handle2); + EXPECT_TRUE(handle1 != handle3); + EXPECT_TRUE(handle2 != handle3); + { + HandleGuard guard1 = manager.lock(handle1); + HandleGuard guard2 = manager.lock(handle2); + EXPECT_TRUE(guard1.valid()); + EXPECT_EQUAL(guard1.handle(), handle1); + EXPECT_TRUE(guard2.valid()); + EXPECT_EQUAL(guard2.handle(), handle2); + EXPECT_TRUE(manager.destroy(handle3)); // <- does not block + HandleGuard guard3 = manager.lock(handle3); + EXPECT_TRUE(!guard3.valid()); + EXPECT_EQUAL(guard3.handle(), manager.null_handle()); + } + EXPECT_TRUE(manager.destroy(handle1)); + EXPECT_TRUE(manager.destroy(handle2)); + EXPECT_TRUE(!manager.destroy(handle3)); +} + +struct Fixture { + HandleManager manager; + uint64_t handle; + Gate gate; + std::atomic<size_t> cnt1; + std::atomic<size_t> cnt2; + Fixture() : manager(), handle(manager.create()), gate(), cnt1(0), cnt2(0) {} +}; + +TEST_MT_FF("require that destroy waits for active handle guards", 2, Fixture(), TimeBomb(60)) { + if (thread_id == 0) { + { + auto guard = f1.manager.lock(f1.handle); + TEST_BARRIER(); // #1 + EXPECT_TRUE(!f1.gate.await(20)); + } + EXPECT_TRUE(f1.gate.await(60000)); + } else { + TEST_BARRIER(); // #1 + EXPECT_TRUE(f1.manager.destroy(f1.handle)); + f1.gate.countDown(); + } +} + +TEST_MT_FF("require that destroy disables ability to lock handles", 3, Fixture(), TimeBomb(60)) { + if (thread_id == 0) { + auto guard = f1.manager.lock(f1.handle); + ASSERT_TRUE(guard.valid()); + TEST_BARRIER(); // #1 + while (f1.cnt1 == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + EXPECT_EQUAL(f1.cnt2, 0u); + } else if (thread_id == 1) { + TEST_BARRIER(); // #1 + EXPECT_TRUE(f1.manager.destroy(f1.handle)); + EXPECT_EQUAL(f1.cnt1, 1u); + ++f1.cnt2; + } else { + TEST_BARRIER(); // #1 + while (f1.cnt1 == 0) { + auto guard = f1.manager.lock(f1.handle); + if (guard.valid()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } else { + EXPECT_EQUAL(f1.cnt2, 0u); + ++f1.cnt1; + } + } + } +} + +TEST_MT_FF("require that a single destroy call returns true", 10, Fixture(), TimeBomb(60)) { + if (thread_id == 0) { // 1 thread here + auto guard = f1.manager.lock(f1.handle); + ASSERT_TRUE(guard.valid()); + TEST_BARRIER(); // #1 + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } else { // 'many' threads here + TEST_BARRIER(); // #1 + if (f1.manager.destroy(f1.handle)) { + ++f1.cnt1; + } else { + ++f1.cnt2; + } + } + TEST_BARRIER(); // #2 + EXPECT_EQUAL(f1.cnt1, 1u); + EXPECT_GREATER(num_threads, 5u); + EXPECT_EQUAL(f1.cnt2, (num_threads - 2)); +} + +TEST_MAIN() { TEST_RUN_ALL(); } |