// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "journal/FutureImpl.h" #include "common/Cond.h" #include "common/Mutex.h" #include "gtest/gtest.h" #include "test/journal/RadosTestFixture.h" class TestFutureImpl : public RadosTestFixture { public: struct FlushHandler : public journal::FutureImpl::FlushHandler { uint64_t refs; uint64_t flushes; FlushHandler() : refs(0), flushes(0) {} void get() override { ++refs; } void put() override { assert(refs > 0); --refs; } void flush(const journal::FutureImplPtr &future) override { ++flushes; } }; journal::FutureImplPtr create_future(uint64_t tag_tid, uint64_t entry_tid, uint64_t commit_tid, const journal::FutureImplPtr &prev = journal::FutureImplPtr()) { journal::FutureImplPtr future(new journal::FutureImpl(tag_tid, entry_tid, commit_tid)); future->init(prev); return future; } void flush(const journal::FutureImplPtr &future) { } FlushHandler m_flush_handler; }; TEST_F(TestFutureImpl, Getters) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future = create_future(234, 123, 456); ASSERT_EQ(234U, future->get_tag_tid()); ASSERT_EQ(123U, future->get_entry_tid()); ASSERT_EQ(456U, future->get_commit_tid()); } TEST_F(TestFutureImpl, Attach) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future = create_future(234, 123, 456); ASSERT_FALSE(future->attach(&m_flush_handler)); ASSERT_EQ(1U, m_flush_handler.refs); } TEST_F(TestFutureImpl, AttachWithPendingFlush) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future = create_future(234, 123, 456); future->flush(NULL); ASSERT_TRUE(future->attach(&m_flush_handler)); ASSERT_EQ(1U, m_flush_handler.refs); } TEST_F(TestFutureImpl, Detach) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future = create_future(234, 123, 456); ASSERT_FALSE(future->attach(&m_flush_handler)); future->detach(); ASSERT_EQ(0U, m_flush_handler.refs); } TEST_F(TestFutureImpl, DetachImplicit) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future = create_future(234, 123, 456); ASSERT_FALSE(future->attach(&m_flush_handler)); future.reset(); ASSERT_EQ(0U, m_flush_handler.refs); } TEST_F(TestFutureImpl, Flush) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future = create_future(234, 123, 456); ASSERT_FALSE(future->attach(&m_flush_handler)); C_SaferCond cond; future->flush(&cond); ASSERT_EQ(1U, m_flush_handler.flushes); future->safe(-EIO); ASSERT_EQ(-EIO, cond.wait()); } TEST_F(TestFutureImpl, FlushWithoutContext) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future = create_future(234, 123, 456); ASSERT_FALSE(future->attach(&m_flush_handler)); future->flush(NULL); ASSERT_EQ(1U, m_flush_handler.flushes); future->safe(-EIO); ASSERT_TRUE(future->is_complete()); ASSERT_EQ(-EIO, future->get_return_value()); } TEST_F(TestFutureImpl, FlushChain) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future1 = create_future(234, 123, 456); journal::FutureImplPtr future2 = create_future(234, 124, 457, future1); journal::FutureImplPtr future3 = create_future(235, 1, 458, future2); FlushHandler flush_handler; ASSERT_FALSE(future1->attach(&m_flush_handler)); ASSERT_FALSE(future2->attach(&flush_handler)); ASSERT_FALSE(future3->attach(&m_flush_handler)); C_SaferCond cond; future3->flush(&cond); ASSERT_EQ(1U, m_flush_handler.flushes); ASSERT_EQ(1U, flush_handler.flushes); future3->safe(0); ASSERT_FALSE(future3->is_complete()); future1->safe(0); ASSERT_FALSE(future3->is_complete()); future2->safe(-EIO); ASSERT_TRUE(future3->is_complete()); ASSERT_EQ(-EIO, future3->get_return_value()); ASSERT_EQ(-EIO, cond.wait()); ASSERT_EQ(0, future1->get_return_value()); } TEST_F(TestFutureImpl, FlushInProgress) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future1 = create_future(234, 123, 456); journal::FutureImplPtr future2 = create_future(234, 124, 457, future1); ASSERT_FALSE(future1->attach(&m_flush_handler)); ASSERT_FALSE(future2->attach(&m_flush_handler)); future1->set_flush_in_progress(); ASSERT_TRUE(future1->is_flush_in_progress()); future1->flush(NULL); ASSERT_EQ(0U, m_flush_handler.flushes); future1->safe(0); } TEST_F(TestFutureImpl, FlushAlreadyComplete) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future = create_future(234, 123, 456); future->safe(-EIO); C_SaferCond cond; future->flush(&cond); ASSERT_EQ(-EIO, cond.wait()); } TEST_F(TestFutureImpl, Wait) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future = create_future(234, 1, 456); C_SaferCond cond; future->wait(&cond); future->safe(-EEXIST); ASSERT_EQ(-EEXIST, cond.wait()); } TEST_F(TestFutureImpl, WaitAlreadyComplete) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future = create_future(234, 1, 456); future->safe(-EEXIST); C_SaferCond cond; future->wait(&cond); ASSERT_EQ(-EEXIST, cond.wait()); } TEST_F(TestFutureImpl, SafePreservesError) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future1 = create_future(234, 123, 456); journal::FutureImplPtr future2 = create_future(234, 124, 457, future1); future1->safe(-EIO); future2->safe(-EEXIST); ASSERT_TRUE(future2->is_complete()); ASSERT_EQ(-EIO, future2->get_return_value()); } TEST_F(TestFutureImpl, ConsistentPreservesError) { std::string oid = get_temp_oid(); ASSERT_EQ(0, create(oid)); ASSERT_EQ(0, client_register(oid)); journal::JournalMetadataPtr metadata = create_metadata(oid); ASSERT_EQ(0, init_metadata(metadata)); journal::FutureImplPtr future1 = create_future(234, 123, 456); journal::FutureImplPtr future2 = create_future(234, 124, 457, future1); future2->safe(-EEXIST); future1->safe(-EIO); ASSERT_TRUE(future2->is_complete()); ASSERT_EQ(-EEXIST, future2->get_return_value()); }