/* * Copyright (c) 2012 by Matthias Noack, Zuse Institute Berlin * * Licensed under the BSD License, see LICENSE file for details. * */ #include #include #include #include "common/test_environment.h" #include "common/test_rpc_server_dir.h" #include "common/test_rpc_server_mrc.h" #include "common/test_rpc_server_osd.h" #include "libxtreemfs/client.h" #include "libxtreemfs/file_handle.h" #include "libxtreemfs/options.h" #include "libxtreemfs/volume.h" #include "libxtreemfs/xtreemfs_exception.h" #include "rpc/client.h" #include "xtreemfs/OSDServiceConstants.h" using namespace std; using namespace xtreemfs::pbrpc; using namespace xtreemfs::util; namespace xtreemfs { namespace rpc { class AsyncWriteHandlerTest : public ::testing::Test { protected: static const int kBlockSize = 1024 * 128; virtual void SetUp() { initialize_logger(LEVEL_WARN); test_env.options.connect_timeout_s = 3; test_env.options.request_timeout_s = 3; test_env.options.retry_delay_s = 3; test_env.options.enable_async_writes = true; test_env.options.async_writes_max_request_size_kb = 128; test_env.options.async_writes_max_requests = 8; test_env.options.periodic_xcap_renewal_interval_s = 2; ASSERT_TRUE(test_env.Start()); // Open a volume volume = test_env.client->OpenVolume( test_env.volume_name_, NULL, // No SSL options. test_env.options); // Open a file. file = volume->OpenFile( test_env.user_credentials, "/test_file", static_cast( xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_CREAT | xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_TRUNC | xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_RDWR)); } virtual void TearDown() { //volume->Close(); test_env.Stop(); } TestEnvironment test_env; Volume* volume; FileHandle* file; }; /** A normal async write with nothing special */ TEST_F(AsyncWriteHandlerTest, NormalWrite) { size_t blocks = 5; size_t buffer_size = kBlockSize * blocks; boost::scoped_array write_buf(new char[buffer_size]()); vector expected(blocks); for (size_t i = 0; i < blocks; ++i) { expected[i] = WriteEntry(i, 0, kBlockSize); } ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0)); ASSERT_NO_THROW(file->Flush()); EXPECT_TRUE(equal(expected.begin(), expected.end(), test_env.osds[0]->GetReceivedWrites().end() - blocks)); ASSERT_NO_THROW(file->Close()); } /** Let the first write request fail. The write should be retried and finally * succeed. */ TEST_F(AsyncWriteHandlerTest, FirstWriteFail) { size_t blocks = 5; size_t buffer_size = kBlockSize * blocks; boost::scoped_array write_buf(new char[buffer_size]()); vector expected_tail(blocks); for (size_t i = 0; i < blocks; ++i) { expected_tail[i] = WriteEntry(i, 0, kBlockSize); } test_env.osds[0]->AddDropRule( new ProcIDFilterRule(xtreemfs::pbrpc::PROC_ID_WRITE, new DropNRule(1))); ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0)); ASSERT_NO_THROW(file->Flush()); EXPECT_TRUE(equal(expected_tail.begin(), expected_tail.end(), test_env.osds[0]->GetReceivedWrites().end() - expected_tail.size())); ASSERT_NO_THROW(file->Close()); } /** Let the last write request fail. The write should be retried and finally * succeed. */ TEST_F(AsyncWriteHandlerTest, LastWriteFail) { size_t blocks = 5; size_t buffer_size = kBlockSize * blocks; boost::scoped_array write_buf(new char[buffer_size]()); vector expected_front(blocks - 1); vector expected_tail(1); for (size_t i = 0; i < blocks - 1; ++i) { expected_front[i] = WriteEntry(i, 0, kBlockSize); } expected_tail[0] = WriteEntry(blocks - 1, 0, kBlockSize); test_env.osds[0]->AddDropRule( new ProcIDFilterRule(xtreemfs::pbrpc::PROC_ID_WRITE, new SkipMDropNRule(blocks - 1, 1))); ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0)); ASSERT_NO_THROW(file->Flush()); EXPECT_TRUE(equal(expected_front.begin(), expected_front.end(), test_env.osds[0]->GetReceivedWrites().begin())); EXPECT_TRUE(equal(expected_tail.begin(), expected_tail.end(), test_env.osds[0]->GetReceivedWrites().end() - expected_tail.size())); ASSERT_NO_THROW(file->Close()); } /** Let the intermediate write request fail. The write should be retried and * finally succeed. */ TEST_F(AsyncWriteHandlerTest, IntermediateWriteFail) { size_t blocks = 5; size_t buffer_size = kBlockSize * blocks; size_t middle = blocks / 2; boost::scoped_array write_buf(new char[buffer_size]()); vector expected_front(middle); vector expected_tail(blocks - middle); for (size_t i = 0; i < middle; ++i) { expected_front[i] = WriteEntry(i, 0, kBlockSize); } for (size_t i = middle; i < blocks; ++i) { expected_tail[i - middle] = WriteEntry(i, 0, kBlockSize); } test_env.osds[0]->AddDropRule( new ProcIDFilterRule(xtreemfs::pbrpc::PROC_ID_WRITE, new SkipMDropNRule(middle, 1))); ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0)); ASSERT_NO_THROW(file->Flush()); EXPECT_TRUE(equal(expected_front.begin(), expected_front.end(), test_env.osds[0]->GetReceivedWrites().begin())); EXPECT_TRUE(equal(expected_tail.begin(), expected_tail.end(), test_env.osds[0]->GetReceivedWrites().end() - expected_tail.size())); ASSERT_NO_THROW(file->Close()); } /** Let the all writes request fail. The write should be retried and finally * succeed. */ TEST_F(AsyncWriteHandlerTest, AllWritesFail) { size_t blocks = 5; size_t buffer_size = kBlockSize * blocks; boost::scoped_array write_buf(new char[buffer_size]()); vector expected_tail(blocks); for (size_t i = 0; i < blocks; ++i) { expected_tail[i] = WriteEntry(i, 0, kBlockSize); } test_env.osds[0]->AddDropRule( new ProcIDFilterRule(xtreemfs::pbrpc::PROC_ID_WRITE, new DropNRule(blocks))); ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0)); ASSERT_NO_THROW(file->Flush()); EXPECT_TRUE(equal(expected_tail.begin(), expected_tail.end(), test_env.osds[0]->GetReceivedWrites().end() - expected_tail.size())); ASSERT_NO_THROW(file->Close()); } /** Let the first write request fail when there are more writes than * writeahead allows. The write should be retried and finally succeed. */ TEST_F(AsyncWriteHandlerTest, FirstWriteFailLong) { size_t blocks = 2 * test_env.options.async_writes_max_requests; size_t buffer_size = kBlockSize * blocks; boost::scoped_array write_buf(new char[buffer_size]()); vector expected_tail(blocks); for (size_t i = 0; i < blocks; ++i) { expected_tail[i] = WriteEntry(i, 0, kBlockSize); } test_env.osds[0]->AddDropRule( new ProcIDFilterRule(xtreemfs::pbrpc::PROC_ID_WRITE, new DropNRule(1))); ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0)); ASSERT_NO_THROW(file->Flush()); EXPECT_TRUE(equal(expected_tail.begin(), expected_tail.end(), test_env.osds[0]->GetReceivedWrites().end() - expected_tail.size())); ASSERT_NO_THROW(file->Close()); } /** TODO(mno): Maybe let all future requests fail to test the retry count. */ } // namespace rpc } // namespace xtreemfs