Imported Upstream version 1.5.1
This commit is contained in:
131
cpp/test/common/drop_rules.h
Normal file
131
cpp/test/common/drop_rules.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Matthias Noack, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPP_TEST_COMMON_DROP_RULES_H_
|
||||
#define CPP_TEST_COMMON_DROP_RULES_H_
|
||||
|
||||
namespace xtreemfs {
|
||||
namespace rpc {
|
||||
|
||||
/** This interface is used for arbitrary implementations of drop rules
|
||||
* for RPC requests processed by TestRPCServer.
|
||||
*/
|
||||
class DropRule {
|
||||
public:
|
||||
/** This method is called for every received process */
|
||||
virtual bool DropRequest(uint32_t proc_id) = 0;
|
||||
|
||||
/** This method is used to determine whether or not a rule can be deleted */
|
||||
virtual bool IsPointless() const = 0;
|
||||
|
||||
/** Helper predicate function for std::algorithm */
|
||||
static bool IsPointlessPred(const DropRule* rule) {
|
||||
return rule->IsPointless();
|
||||
}
|
||||
|
||||
virtual ~DropRule() {};
|
||||
};
|
||||
|
||||
/** This rule skips m requests before dropping n requests. Afterwards, the rule
|
||||
* becomes pointless. The proc_id is not checked.
|
||||
*/
|
||||
class SkipMDropNRule : public DropRule {
|
||||
public:
|
||||
SkipMDropNRule(size_t skip, size_t drop) : skip_count_(skip), drop_count_(drop) {}
|
||||
|
||||
virtual bool DropRequest(uint32_t proc_id) {
|
||||
if (skip_count_ == 0 && drop_count_ > 0) {
|
||||
--drop_count_;
|
||||
return true;
|
||||
} else if (skip_count_ > 0) {
|
||||
--skip_count_;
|
||||
}
|
||||
return false;
|
||||
// or just:
|
||||
// return skip_count_-- > 0 ? ++skip_count_ : drop_count_-- > 0 ? true : ++drop_count_;
|
||||
}
|
||||
|
||||
virtual bool IsPointless() const {
|
||||
return (drop_count_ == 0) && (skip_count_ == 0);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t skip_count_;
|
||||
size_t drop_count_;
|
||||
};
|
||||
|
||||
/** This rule is used in combination with another rule which will be only
|
||||
* called when the proc_id passed to DropRequest matches the one passed
|
||||
* to the ctor.
|
||||
*/
|
||||
class ProcIDFilterRule : public DropRule {
|
||||
public:
|
||||
/** Construct a proc_id filtered rule from an existing rule.
|
||||
* The ownership of rule's pointee is transfered to the created instance.
|
||||
*/
|
||||
ProcIDFilterRule(uint32_t proc_id, DropRule* rule)
|
||||
: proc_id_(proc_id), rule_(rule) {}
|
||||
|
||||
virtual bool DropRequest(uint32_t proc_id) {
|
||||
return proc_id == proc_id_ ? rule_->DropRequest(proc_id) : false;
|
||||
}
|
||||
|
||||
virtual bool IsPointless() const {
|
||||
return rule_->IsPointless();
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t proc_id_;
|
||||
boost::scoped_ptr<DropRule> rule_;
|
||||
};
|
||||
|
||||
/** This rule drops n requests without checking the proc_id. */
|
||||
class DropNRule : public DropRule {
|
||||
public:
|
||||
DropNRule(size_t count) : count_(count) {}
|
||||
|
||||
virtual bool DropRequest(uint32_t proc_id) {
|
||||
if (count_ > 0) {
|
||||
--count_;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool IsPointless() const {
|
||||
return count_ == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
/** This rule drops all rules with a certain proc_id. This rule will never
|
||||
* become pointless.
|
||||
*/
|
||||
class DropByProcIDRule : public DropRule {
|
||||
public:
|
||||
DropByProcIDRule(uint32_t proc_id)
|
||||
: proc_id_(proc_id) {}
|
||||
|
||||
virtual bool DropRequest(uint32_t proc_id) {
|
||||
return proc_id_ == proc_id;
|
||||
}
|
||||
|
||||
virtual bool IsPointless() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t proc_id_;
|
||||
};
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace xtreemfs
|
||||
|
||||
#endif
|
||||
108
cpp/test/common/test_environment.cpp
Normal file
108
cpp/test/common/test_environment.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#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 "util/logging.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::rpc;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
namespace xtreemfs {
|
||||
|
||||
TestEnvironment::TestEnvironment()
|
||||
: options(), user_credentials() {
|
||||
user_credentials.set_username("ClientTest");
|
||||
user_credentials.add_groups("ClientTest");
|
||||
|
||||
dir.reset(new TestRPCServerDIR());
|
||||
mrc.reset(new TestRPCServerMRC());
|
||||
osds.push_back(new TestRPCServerOSD());
|
||||
|
||||
volume_name_ = "test";
|
||||
}
|
||||
|
||||
TestEnvironment::~TestEnvironment() {
|
||||
for (size_t i = 0; i < osds.size(); i++) {
|
||||
delete osds[i];
|
||||
}
|
||||
}
|
||||
|
||||
void TestEnvironment::AddOSDs(int num_of_osds) {
|
||||
for (int i = 1; i < num_of_osds; i++) {
|
||||
osds.push_back(new TestRPCServerOSD());
|
||||
}
|
||||
}
|
||||
|
||||
bool TestEnvironment::Start() {
|
||||
if (!dir->Start()) {
|
||||
return false;
|
||||
}
|
||||
if (Logging::log->loggingActive(LEVEL_INFO)) {
|
||||
Logging::log->getLog(LEVEL_INFO)
|
||||
<< "DIR running at: " << dir->GetAddress() << endl;
|
||||
}
|
||||
if (!mrc->Start()) {
|
||||
return false;
|
||||
}
|
||||
if (Logging::log->loggingActive(LEVEL_INFO)) {
|
||||
Logging::log->getLog(LEVEL_INFO)
|
||||
<< "MRC running at: " << mrc->GetAddress() << endl;
|
||||
}
|
||||
dir->RegisterVolume(volume_name_, mrc->GetAddress());
|
||||
for (size_t i = 0; i < osds.size(); i++) {
|
||||
if (!osds[i]->Start()) {
|
||||
return false;
|
||||
}
|
||||
if (Logging::log->loggingActive(LEVEL_INFO)) {
|
||||
Logging::log->getLog(LEVEL_INFO)
|
||||
<< "OSD running at: " << osds[i]->GetAddress() << endl;
|
||||
}
|
||||
mrc->RegisterOSD(osds[i]->GetAddress());
|
||||
}
|
||||
// TODO(mberlin): Register OSDs at MRC.
|
||||
|
||||
// If the DIR server address was not explicitly overridden, set it to the
|
||||
// started test DIR server.
|
||||
if (options.service_addresses.empty()) {
|
||||
options.service_addresses.Add(dir->GetAddress());
|
||||
}
|
||||
|
||||
client.reset(Client::CreateClient(
|
||||
options.service_addresses,
|
||||
user_credentials,
|
||||
NULL, // No SSL options.
|
||||
options));
|
||||
|
||||
// Start the client (a connection to the DIR service will be setup).
|
||||
client->Start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestEnvironment::Stop() {
|
||||
if (client.get()) {
|
||||
client->Shutdown();
|
||||
}
|
||||
|
||||
if (dir.get()) {
|
||||
dir->Stop();
|
||||
}
|
||||
if (mrc.get()) {
|
||||
mrc->Stop();
|
||||
}
|
||||
for (size_t i = 0; i < osds.size(); i++) {
|
||||
osds[i]->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xtreemfs
|
||||
59
cpp/test/common/test_environment.h
Normal file
59
cpp/test/common/test_environment.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPP_TEST_COMMON_TEST_ENVIRONMENT_H_
|
||||
#define CPP_TEST_COMMON_TEST_ENVIRONMENT_H_
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "libxtreemfs/options.h"
|
||||
#include "pbrpc/RPC.pb.h" // xtreemfs::pbrpc::UserCredentials
|
||||
|
||||
namespace xtreemfs {
|
||||
|
||||
namespace rpc {
|
||||
class TestRPCServerMRC;
|
||||
class TestRPCServerDIR;
|
||||
class TestRPCServerOSD;
|
||||
} // namespace rpc
|
||||
|
||||
class Client;
|
||||
|
||||
/** Aggregator class which bundles Client and TestRPCServer objects to
|
||||
* run unit tests.
|
||||
*
|
||||
* Modify options accordingly before executing Start() to influence
|
||||
* the client.
|
||||
*/
|
||||
class TestEnvironment {
|
||||
public:
|
||||
explicit TestEnvironment();
|
||||
~TestEnvironment();
|
||||
|
||||
bool Start();
|
||||
void Stop();
|
||||
|
||||
/** Add num_of_osds additional OSDs before executing Start(). */
|
||||
void AddOSDs(int num_of_osds);
|
||||
|
||||
boost::scoped_ptr<Client> client;
|
||||
Options options;
|
||||
xtreemfs::pbrpc::UserCredentials user_credentials;
|
||||
|
||||
/** Volume name under which the MRC will be registered. */
|
||||
std::string volume_name_;
|
||||
|
||||
boost::scoped_ptr<xtreemfs::rpc::TestRPCServerDIR> dir;
|
||||
boost::scoped_ptr<xtreemfs::rpc::TestRPCServerMRC> mrc;
|
||||
std::vector<xtreemfs::rpc::TestRPCServerOSD*> osds;
|
||||
};
|
||||
|
||||
} // namespace xtreemfs
|
||||
|
||||
#endif // CPP_TEST_COMMON_TEST_ENVIRONMENT_H_
|
||||
590
cpp/test/common/test_rpc_server.h
Normal file
590
cpp/test/common/test_rpc_server.h
Normal file
@@ -0,0 +1,590 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPP_TEST_COMMON_TEST_RPC_SERVER_H_
|
||||
#define CPP_TEST_COMMON_TEST_RPC_SERVER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef WIN32
|
||||
#include <csignal>
|
||||
#include <pthread.h>
|
||||
#endif // !WIN32
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/smart_ptr.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "include/Common.pb.h"
|
||||
#include "pbrpc/RPC.pb.h"
|
||||
#include "rpc/record_marker.h"
|
||||
#include "util/logging.h"
|
||||
#include "xtreemfs/DIR.pb.h"
|
||||
#include "xtreemfs/get_request_message.h"
|
||||
#include "drop_rules.h"
|
||||
|
||||
namespace xtreemfs {
|
||||
namespace rpc {
|
||||
|
||||
/** Base class which allows to implement a test XtreemFS server.
|
||||
*
|
||||
* Implementations have to set interface_id_ accordingly and add
|
||||
* implemented operations to operations_.
|
||||
*/
|
||||
template <class Derived> class TestRPCServer {
|
||||
public:
|
||||
TestRPCServer()
|
||||
: interface_id_(0),
|
||||
drop_connection_(false) {}
|
||||
|
||||
virtual ~TestRPCServer() {}
|
||||
|
||||
/** Starts the RPC Server at free, random port. False if not successful. */
|
||||
bool Start() {
|
||||
using boost::asio::ip::tcp;
|
||||
using xtreemfs::util::Logging;
|
||||
|
||||
xtreemfs::util::initialize_logger(xtreemfs::util::LEVEL_WARN);
|
||||
|
||||
if (interface_id_ == 0) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
|
||||
<< "You forgot to set interface_id_ in"
|
||||
" your TestRPCServer implementation."<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (operations_.size() == 0) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
|
||||
<< "You have not registered any implemented operations." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
tcp::endpoint localhost(
|
||||
boost::asio::ip::address::from_string("127.0.0.1"), 0);
|
||||
acceptor_.reset(
|
||||
new tcp::acceptor(io_service, localhost));
|
||||
daemon_.reset(new boost::thread(boost::bind(&TestRPCServer<Derived>::Run,
|
||||
this)));
|
||||
} catch (const std::exception& e) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
|
||||
<< "Failed to start the server: " << e.what() << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Stops the server again. */
|
||||
void Stop() {
|
||||
using xtreemfs::util::Logging;
|
||||
|
||||
// Stop running Session() threads.
|
||||
std::map< boost::thread::id,
|
||||
boost::shared_ptr<boost::thread> > active_sessions_copy;
|
||||
{
|
||||
boost::mutex::scoped_lock lock(active_sessions_mutex_);
|
||||
active_sessions_copy = active_sessions_;
|
||||
|
||||
// Close active sessions.
|
||||
for (std::map< boost::thread::id,
|
||||
boost::shared_ptr<boost::asio::ip::tcp::socket> >::iterator iter
|
||||
= active_sessions_socks_.begin();
|
||||
iter != active_sessions_socks_.end();
|
||||
iter++) {
|
||||
iter->second->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
|
||||
}
|
||||
}
|
||||
// Wait for all closed sessions to exit.
|
||||
for (std::map< boost::thread::id,
|
||||
boost::shared_ptr<boost::thread> >::iterator iter
|
||||
= active_sessions_copy.begin();
|
||||
iter != active_sessions_copy.end();
|
||||
iter++) {
|
||||
iter->second->join();
|
||||
}
|
||||
{
|
||||
boost::mutex::scoped_lock lock(active_sessions_mutex_);
|
||||
if (active_sessions_.size() > 0) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
|
||||
<< "There are open sessions left ("
|
||||
<< active_sessions_.size() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(drop_rules_mutex_);
|
||||
for (std::list<DropRule*>::iterator it = drop_rules_.begin();
|
||||
it != drop_rules_.end();
|
||||
++it) {
|
||||
delete *it;
|
||||
}
|
||||
drop_rules_.clear();
|
||||
}
|
||||
|
||||
// Unfortunately, boost::asio does not allow to abort synchronous operations
|
||||
// See: https://svn.boost.org/trac/boost/ticket/2832
|
||||
// Randomly acceptor_->close(ec); succeeds, but not guaranteed. Even things
|
||||
// like shutdown(acceptor_->native(), SHUT_RDWR); did not work.
|
||||
// During debugging in Eclipse, I noticed that the daemon_ thread exits from
|
||||
// the blocking acceptor_->accept() if it was interrupted by the debugger.
|
||||
// Therefore, we call a no-op signal handler in the thread now and accept()
|
||||
// becomes unblocked, effectively allowing to stop the daemon_ thread.
|
||||
if (daemon_.get()) {
|
||||
daemon_->interrupt();
|
||||
// Ignore errors.
|
||||
boost::system::error_code ec;
|
||||
acceptor_->close(ec);
|
||||
if (!daemon_->timed_join(boost::posix_time::milliseconds(10))) {
|
||||
#ifdef WIN32
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
|
||||
<< "Failed to stop the server, daemon thread won't unblock. "
|
||||
"Abort manually with Ctrl + C." << std::endl;
|
||||
#else
|
||||
pthread_kill(daemon_->native_handle(), SIGUSR2);
|
||||
daemon_->join();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the address of the service in the format "ip-address:port". */
|
||||
std::string GetAddress() {
|
||||
return acceptor_->local_endpoint().address().to_string() + ":"
|
||||
+ boost::lexical_cast<std::string>(acceptor_->local_endpoint().port());
|
||||
}
|
||||
|
||||
/** Add a DropRule, ownership is transferred to the callee. */
|
||||
void AddDropRule(DropRule* rule) {
|
||||
boost::mutex::scoped_lock lock(drop_rules_mutex_);
|
||||
drop_rules_.push_back(rule);
|
||||
RemovePointlessDropRules(lock);
|
||||
}
|
||||
|
||||
/** The connection will be shut down once after this call. */
|
||||
void DropConnection() {
|
||||
boost::mutex::scoped_lock lock(drop_connection_mutex_);
|
||||
drop_connection_ = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Function pointer an implemented server operation. */
|
||||
typedef google::protobuf::Message* (Derived::*Operation)(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
struct Op {
|
||||
Op() {}
|
||||
|
||||
Op(Derived* server, Operation op)
|
||||
: server(server), op(op) {}
|
||||
|
||||
/** Pointer to the implementation of TestRPCServer. */
|
||||
Derived* server;
|
||||
/** Function pointer to the implemented operation. */
|
||||
Operation op;
|
||||
};
|
||||
|
||||
/** Interface ID of the implemented XtreemFS service. */
|
||||
uint32_t interface_id_;
|
||||
|
||||
/** Implementations have to register implemented operations with the
|
||||
* corresponding proc_id here. */
|
||||
std::map<uint32_t, Op> operations_;
|
||||
|
||||
private:
|
||||
/** Delete old rules, should be called from a locked context */
|
||||
void RemovePointlessDropRules(const boost::mutex::scoped_lock& lock) {
|
||||
std::remove_if(drop_rules_.begin(), drop_rules_.end(), &DropRule::IsPointlessPred);
|
||||
}
|
||||
|
||||
/** Returns true if the request shall be dropped. */
|
||||
bool CheckIfRequestShallBeDropped(uint32_t proc_id) {
|
||||
using xtreemfs::util::Logging;
|
||||
boost::mutex::scoped_lock lock(drop_rules_mutex_);
|
||||
|
||||
bool drop_request = false;
|
||||
// NOTE: all drop rules must be asked even if drop_request is already
|
||||
// true. This is important for counting rules or other side effects.
|
||||
for (std::list<DropRule*>::iterator it = drop_rules_.begin();
|
||||
it != drop_rules_.end();
|
||||
++it) {
|
||||
drop_request = drop_request || (*it)->DropRequest(proc_id);
|
||||
}
|
||||
|
||||
if (drop_request) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
|
||||
<< "Dropping request (proc_id = " << proc_id << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return drop_request;
|
||||
}
|
||||
|
||||
static void DummySignalHandler(int signal) {
|
||||
// See comment at TestRPCServer::Stop() why this is needed.
|
||||
}
|
||||
|
||||
/** Processes the "request" and returns a response.
|
||||
*
|
||||
* @remarks Ownership of return value is transferred to caller.
|
||||
*/
|
||||
google::protobuf::Message* ExecuteOperation(
|
||||
uint32_t proc_id,
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
typename std::map<uint32_t, Op>::iterator iter
|
||||
= operations_.find(proc_id);
|
||||
if (iter == operations_.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Op& entry = iter->second;
|
||||
return (entry.server->*(entry.op))
|
||||
(auth, user_credentials, request, data, data_len,
|
||||
response_data, response_data_len);
|
||||
}
|
||||
|
||||
/** Daemon function which accepts new connections. */
|
||||
void Run() {
|
||||
using boost::asio::ip::tcp;
|
||||
using xtreemfs::util::Logging;
|
||||
|
||||
#ifndef WIN32
|
||||
signal(SIGUSR2, DummySignalHandler);
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
if (boost::this_thread::interruption_requested()) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
|
||||
<< "Received interrupt, aborting server listener." << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
boost::shared_ptr<tcp::socket> sock(new tcp::socket(io_service));
|
||||
try {
|
||||
acceptor_->accept(*sock);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(drop_connection_mutex_);
|
||||
if (drop_connection_) {
|
||||
drop_connection_ = false;
|
||||
sock->shutdown(tcp::socket::shutdown_both);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
boost::shared_ptr<boost::thread> new_thread(new boost::thread(
|
||||
boost::bind(&TestRPCServer<Derived>::Session, this, sock)));
|
||||
{
|
||||
boost::mutex::scoped_lock lock(active_sessions_mutex_);
|
||||
active_sessions_[new_thread->get_id()] = new_thread;
|
||||
active_sessions_socks_[new_thread->get_id()] = sock;
|
||||
}
|
||||
} catch (const boost::system::system_error&) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Connection handler. */
|
||||
void Session(boost::shared_ptr<boost::asio::ip::tcp::socket> sock) {
|
||||
using xtreemfs::util::Logging;
|
||||
|
||||
try {
|
||||
std::string remote_address =
|
||||
sock->remote_endpoint().address().to_string() + ":"
|
||||
+ boost::lexical_cast<std::string>(sock->remote_endpoint().port());
|
||||
boost::scoped_array<char> record_marker_buffer(
|
||||
new char[xtreemfs::rpc::RecordMarker::get_size()]);
|
||||
boost::scoped_array<char> header_buffer;
|
||||
boost::scoped_array<char> message_buffer;
|
||||
boost::scoped_array<char> data_buffer;
|
||||
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
|
||||
<< "New client connection from: " << remote_address << std::endl;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (boost::this_thread::interruption_requested()) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
|
||||
<< "Received interrupt, aborting test server connection to: "
|
||||
<< remote_address << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
size_t length = 0;
|
||||
boost::scoped_ptr<xtreemfs::rpc::RecordMarker> request_rm;
|
||||
try {
|
||||
// Read record marker.
|
||||
length = boost::asio::read(
|
||||
*sock,
|
||||
boost::asio::buffer(record_marker_buffer.get(),
|
||||
xtreemfs::rpc::RecordMarker::get_size()));
|
||||
if (length < xtreemfs::rpc::RecordMarker::get_size()) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
|
||||
<< "Read invalid record marker from: "
|
||||
<< remote_address << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
request_rm.reset(
|
||||
new xtreemfs::rpc::RecordMarker(record_marker_buffer.get()));
|
||||
|
||||
// Read header, message and data.
|
||||
std::vector<boost::asio::mutable_buffer> bufs;
|
||||
header_buffer.reset(new char[request_rm->header_len()]);
|
||||
bufs.push_back(
|
||||
boost::asio::buffer(reinterpret_cast<void*>(header_buffer.get()),
|
||||
request_rm->header_len()));
|
||||
if (request_rm->message_len() > 0) {
|
||||
message_buffer.reset(new char[request_rm->message_len()]);
|
||||
bufs.push_back(
|
||||
boost::asio::buffer(
|
||||
reinterpret_cast<void*>(message_buffer.get()),
|
||||
request_rm->message_len()));
|
||||
} else {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
|
||||
<< "Received a request with an empty message from: "
|
||||
<< remote_address << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (request_rm->data_len() > 0) {
|
||||
data_buffer.reset(new char[request_rm->data_len()]);
|
||||
bufs.push_back(
|
||||
boost::asio::buffer(reinterpret_cast<void*>(data_buffer.get()),
|
||||
request_rm->data_len()));
|
||||
} else {
|
||||
data_buffer.reset(NULL);
|
||||
}
|
||||
|
||||
length = boost::asio::read(*sock, bufs);
|
||||
|
||||
if (length != (request_rm->header_len()
|
||||
+ request_rm->message_len()
|
||||
+ request_rm->data_len())) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
|
||||
<< "Failed to read a complete request from: "
|
||||
<< remote_address << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (const boost::system::error_code& error) {
|
||||
if (error == boost::asio::error::eof) {
|
||||
break; // Connection closed cleanly by peer.
|
||||
} else {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse header and message.
|
||||
xtreemfs::pbrpc::RPCHeader request_rpc_header;
|
||||
if (!request_rpc_header.ParseFromArray(
|
||||
reinterpret_cast<void*>(header_buffer.get()),
|
||||
request_rm->header_len())) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
|
||||
<< "Failed to parse request header received from: "
|
||||
<< remote_address << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t interface_id
|
||||
= request_rpc_header.request_header().interface_id();
|
||||
uint32_t proc_id = request_rpc_header.request_header().proc_id();
|
||||
if (interface_id != interface_id_) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
|
||||
<< "Received a message which was not intended for this service"
|
||||
" with interface id: " << interface_id_ << " (Message from"
|
||||
" = " << remote_address
|
||||
<< " (interface id = " << interface_id << ", proc id = "
|
||||
<< proc_id << ")" << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
boost::scoped_ptr<google::protobuf::Message> request_message(
|
||||
xtreemfs::pbrpc::GetMessageForProcID(interface_id, proc_id));
|
||||
if (!request_message.get()) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
|
||||
<< "Failed to find a suitable request message type for message"
|
||||
" received from: " << remote_address << " (interface id = "
|
||||
<< interface_id
|
||||
<< ", proc id = " << proc_id << ")" << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!request_message->ParseFromArray(
|
||||
reinterpret_cast<void*>(message_buffer.get()),
|
||||
request_rm->message_len())) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
|
||||
<< "Failed to parse request message received from: "
|
||||
<< remote_address << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the request should be dropped.
|
||||
if (CheckIfRequestShallBeDropped(proc_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process request.
|
||||
boost::scoped_array<char> response_data;
|
||||
uint32_t response_data_len = 0;
|
||||
boost::scoped_ptr<google::protobuf::Message> response_message(
|
||||
ExecuteOperation(proc_id,
|
||||
request_rpc_header.request_header().auth_data(),
|
||||
request_rpc_header.request_header().user_creds(),
|
||||
*request_message,
|
||||
data_buffer.get(),
|
||||
request_rm->data_len(),
|
||||
&response_data,
|
||||
&response_data_len));
|
||||
if (!response_message.get()) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
|
||||
<< "No response was generated. Operation with proc id = "
|
||||
<< proc_id << " is probably not implemented? (interface_id = "
|
||||
<< interface_id_ << ")" << std::endl;
|
||||
break;
|
||||
}
|
||||
if (!response_message->IsInitialized()) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
|
||||
<< "Response message is not valid."
|
||||
" Not all required fields have been initialized: "
|
||||
<< response_message->InitializationErrorString() << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Send response.
|
||||
xtreemfs::pbrpc::RPCHeader response_header(request_rpc_header);
|
||||
xtreemfs::rpc::RecordMarker response_rm(
|
||||
response_header.ByteSize(),
|
||||
response_message->ByteSize(),
|
||||
response_data_len);
|
||||
|
||||
size_t response_bytes_size = xtreemfs::rpc::RecordMarker::get_size()
|
||||
+ response_rm.header_len()
|
||||
+ response_rm.message_len()
|
||||
+ response_rm.data_len();
|
||||
boost::scoped_array<char> response_bytes(new char[response_bytes_size]);
|
||||
char* response = response_bytes.get();
|
||||
response_rm.serialize(response);
|
||||
response += xtreemfs::rpc::RecordMarker::get_size();
|
||||
|
||||
response_header.CheckInitialized();
|
||||
if (!response_header.SerializeToArray(response, response_rm.header_len())) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
|
||||
<< "Failed to serialize header" << std::endl;
|
||||
break;
|
||||
}
|
||||
response += response_rm.header_len();
|
||||
|
||||
response_message->CheckInitialized();
|
||||
if (!response_message->SerializeToArray(response, response_rm.message_len())) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
|
||||
<< "Failed to serialize message" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
response += response_rm.message_len();
|
||||
|
||||
if (response_data.get() != NULL) {
|
||||
memcpy(response, response_data.get(), response_data_len);
|
||||
}
|
||||
|
||||
std::vector<boost::asio::mutable_buffer> write_bufs;
|
||||
write_bufs.push_back(
|
||||
boost::asio::buffer(reinterpret_cast<void*>(response_bytes.get()),
|
||||
response_bytes_size));
|
||||
|
||||
boost::asio::write(*sock, write_bufs);
|
||||
}
|
||||
} catch (const boost::system::system_error& e) {
|
||||
if (e.code() != boost::asio::error::eof) {
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
|
||||
<< "Exception in thread: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
boost::mutex::scoped_lock lock(active_sessions_mutex_);
|
||||
active_sessions_.erase(boost::this_thread::get_id());
|
||||
active_sessions_socks_.erase(boost::this_thread::get_id());
|
||||
}
|
||||
}
|
||||
|
||||
/** Guards access to active_sessions_ and active_sessions_socks_. */
|
||||
boost::mutex active_sessions_mutex_;
|
||||
|
||||
/** Active client connections (thread id -> thread). */
|
||||
std::map< boost::thread::id,
|
||||
boost::shared_ptr<boost::thread> > active_sessions_;
|
||||
|
||||
/** Socket of active client connections. Needed to cleanly shut them down. */
|
||||
std::map< boost::thread::id,
|
||||
boost::shared_ptr<boost::asio::ip::tcp::socket> >
|
||||
active_sessions_socks_;
|
||||
|
||||
/** Thread which listens on the server socket and accepts new connections. */
|
||||
boost::scoped_ptr<boost::thread> daemon_;
|
||||
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
boost::scoped_ptr<boost::asio::ip::tcp::acceptor> acceptor_;
|
||||
|
||||
/** Drop rules for incoming requests. */
|
||||
std::list<DropRule*> drop_rules_;
|
||||
|
||||
/** Guards access drop_rules_. */
|
||||
boost::mutex drop_rules_mutex_;
|
||||
|
||||
/** Used to drop the next connection. */
|
||||
bool drop_connection_;
|
||||
|
||||
/** Guards access drop_connection_. */
|
||||
boost::mutex drop_connection_mutex_;
|
||||
};
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace xtreemfs
|
||||
|
||||
#endif // CPP_TEST_COMMON_TEST_RPC_SERVER_H_
|
||||
144
cpp/test/common/test_rpc_server_dir.cpp
Normal file
144
cpp/test/common/test_rpc_server_dir.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/test_rpc_server_dir.h"
|
||||
|
||||
#include "libxtreemfs/pbrpc_url.h"
|
||||
#include "xtreemfs/DIR.pb.h"
|
||||
#include "xtreemfs/DIRServiceConstants.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::pbrpc;
|
||||
|
||||
namespace xtreemfs {
|
||||
namespace rpc {
|
||||
|
||||
TestRPCServerDIR::TestRPCServerDIR() {
|
||||
interface_id_ = INTERFACE_ID_DIR;
|
||||
// Register available operations.
|
||||
|
||||
operations_[PROC_ID_XTREEMFS_SERVICE_GET_BY_NAME]
|
||||
= Op(this, &TestRPCServerDIR::GetServiceByNameOperation);
|
||||
operations_[PROC_ID_XTREEMFS_SERVICE_GET_BY_UUID]
|
||||
= Op(this, &TestRPCServerDIR::GetServiceByUUIDOperation);
|
||||
operations_[PROC_ID_XTREEMFS_ADDRESS_MAPPINGS_GET]
|
||||
= Op(this, &TestRPCServerDIR::GetAddressMappingOperation);
|
||||
|
||||
}
|
||||
|
||||
void TestRPCServerDIR::RegisterVolume(const std::string& volume_name,
|
||||
const std::string& mrc_uuid) {
|
||||
boost::mutex::scoped_lock lock(mutex_);
|
||||
known_volumes_[volume_name] = mrc_uuid;
|
||||
}
|
||||
|
||||
google::protobuf::Message* TestRPCServerDIR::GetServiceByNameOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
const serviceGetByNameRequest* rq
|
||||
= reinterpret_cast<const serviceGetByNameRequest*>(&request);
|
||||
|
||||
string mrc_uuid;
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex_);
|
||||
map<string, string>::iterator iter = known_volumes_.find(rq->name());
|
||||
if (iter != known_volumes_.end()) {
|
||||
mrc_uuid = iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
ServiceSet* response = new ServiceSet();
|
||||
if (!mrc_uuid.empty()) {
|
||||
Service* new_entry = response->add_services();
|
||||
new_entry->set_type(SERVICE_TYPE_VOLUME);
|
||||
new_entry->set_uuid(mrc_uuid);
|
||||
new_entry->set_version(0);
|
||||
new_entry->set_name(rq->name());
|
||||
new_entry->set_last_updated_s(0);
|
||||
KeyValuePair* new_data = new_entry->mutable_data()->add_data();
|
||||
new_data->set_key("mrc");
|
||||
new_data->set_value(mrc_uuid);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
google::protobuf::Message* TestRPCServerDIR::GetServiceByUUIDOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
const serviceGetByUUIDRequest* rq
|
||||
= reinterpret_cast<const serviceGetByUUIDRequest*>(&request);
|
||||
|
||||
string mrc_uuid = rq->name();
|
||||
string name;
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex_);
|
||||
map<string, string>::iterator iter;
|
||||
|
||||
for (iter = known_volumes_.begin(); iter != known_volumes_.end(); ++iter) {
|
||||
if (iter->second == mrc_uuid) {
|
||||
name = iter->first;
|
||||
mrc_uuid = iter->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ServiceSet* response = new ServiceSet();
|
||||
if (!name.empty()) {
|
||||
Service* new_entry = response->add_services();
|
||||
new_entry->set_type(SERVICE_TYPE_VOLUME);
|
||||
new_entry->set_uuid(mrc_uuid);
|
||||
new_entry->set_version(0);
|
||||
new_entry->set_name(name);
|
||||
new_entry->set_last_updated_s(0);
|
||||
KeyValuePair* new_data = new_entry->mutable_data()->add_data();
|
||||
new_data->set_key("mrc");
|
||||
new_data->set_value(mrc_uuid);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
google::protobuf::Message* TestRPCServerDIR::GetAddressMappingOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
const addressMappingGetRequest* rq
|
||||
= reinterpret_cast<const addressMappingGetRequest*>(&request);
|
||||
|
||||
AddressMappingSet* response = new AddressMappingSet();
|
||||
|
||||
AddressMapping* mapping = response->add_mappings();
|
||||
size_t uuid_split_pos = rq->uuid().find_last_of(":");
|
||||
mapping->set_uuid(rq->uuid());
|
||||
mapping->set_version(0);
|
||||
mapping->set_protocol(PBRPCURL::GetSchemePBRPC());
|
||||
mapping->set_address(rq->uuid().substr(0, uuid_split_pos));
|
||||
mapping->set_port(atoi(rq->uuid().substr(uuid_split_pos+1).c_str()));
|
||||
mapping->set_match_network("*");
|
||||
mapping->set_ttl_s(3600);
|
||||
mapping->set_uri("");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace xtreemfs
|
||||
72
cpp/test/common/test_rpc_server_dir.h
Normal file
72
cpp/test/common/test_rpc_server_dir.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2014 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPP_TEST_COMMON_TEST_RPC_SERVER_DIR_CPP_
|
||||
#define CPP_TEST_COMMON_TEST_RPC_SERVER_DIR_CPP_
|
||||
|
||||
#include "common/test_rpc_server.h"
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
class Message;
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
namespace xtreemfs {
|
||||
namespace rpc {
|
||||
|
||||
class TestRPCServerDIR : public TestRPCServer<TestRPCServerDIR> {
|
||||
public:
|
||||
TestRPCServerDIR();
|
||||
|
||||
void RegisterVolume(const std::string& volume_name,
|
||||
const std::string& mrc_uuid);
|
||||
|
||||
protected:
|
||||
/** Mock-up version returns the given UUID (hostname:port) as address. */
|
||||
virtual google::protobuf::Message* GetAddressMappingOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
private:
|
||||
google::protobuf::Message* GetServiceByNameOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
google::protobuf::Message* GetServiceByUUIDOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
/** Guards access to known_volumes_. */
|
||||
boost::mutex mutex_;
|
||||
|
||||
std::map<std::string, std::string> known_volumes_;
|
||||
};
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace xtreemfs
|
||||
|
||||
#endif // CPP_TEST_COMMON_TEST_RPC_SERVER_DIR_CPP_
|
||||
146
cpp/test/common/test_rpc_server_mrc.cpp
Normal file
146
cpp/test/common/test_rpc_server_mrc.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/test_rpc_server_mrc.h"
|
||||
|
||||
#include "xtreemfs/MRC.pb.h"
|
||||
#include "xtreemfs/MRCServiceConstants.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::pbrpc;
|
||||
|
||||
namespace xtreemfs {
|
||||
namespace rpc {
|
||||
|
||||
TestRPCServerMRC::TestRPCServerMRC() : file_size_(1024 * 1024) {
|
||||
interface_id_ = INTERFACE_ID_MRC;
|
||||
// Register available operations.
|
||||
operations_[PROC_ID_OPEN] = Op(this, &TestRPCServerMRC::OpenOperation);
|
||||
operations_[PROC_ID_XTREEMFS_RENEW_CAPABILITY] =
|
||||
Op(this, &TestRPCServerMRC::RenewCapabilityOperation);
|
||||
operations_[PROC_ID_XTREEMFS_UPDATE_FILE_SIZE] =
|
||||
Op(this, &TestRPCServerMRC::UpdateFileSizeOperation);
|
||||
operations_[PROC_ID_FTRUNCATE] =
|
||||
Op(this, &TestRPCServerMRC::FTruncate);
|
||||
}
|
||||
|
||||
google::protobuf::Message* TestRPCServerMRC::OpenOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
const openRequest* rq = reinterpret_cast<const openRequest*>(&request);
|
||||
|
||||
openResponse* response = new openResponse();
|
||||
|
||||
XCap* xcap = response->mutable_creds()->mutable_xcap();
|
||||
xcap->set_access_mode(rq->flags());
|
||||
xcap->set_client_identity("client_identity");
|
||||
xcap->set_expire_time_s(3600);
|
||||
xcap->set_expire_timeout_s(static_cast<uint32_t>(time(0)) + 3600);
|
||||
xcap->set_file_id(rq->volume_name() + ":0");
|
||||
xcap->set_replicate_on_close(false);
|
||||
xcap->set_server_signature("signature");
|
||||
xcap->set_snap_config(SNAP_CONFIG_SNAPS_DISABLED);
|
||||
xcap->set_snap_timestamp(0);
|
||||
xcap->set_truncate_epoch(0);
|
||||
|
||||
XLocSet* xlocset = response->mutable_creds()->mutable_xlocs();
|
||||
xlocset->set_read_only_file_size(file_size_);
|
||||
xlocset->set_replica_update_policy(""); // "" = REPL_UPDATE_PC_NONE;
|
||||
xlocset->set_version(0);
|
||||
xlocset->add_replicas();
|
||||
|
||||
Replica* replica = xlocset->mutable_replicas(0);
|
||||
replica->set_replication_flags(0);
|
||||
|
||||
for (std::vector<std::string>::iterator it = osd_uuids_.begin();
|
||||
it != osd_uuids_.end();
|
||||
++it) {
|
||||
replica->add_osd_uuids(*it);
|
||||
}
|
||||
|
||||
replica->mutable_striping_policy()->set_type(STRIPING_POLICY_RAID0);
|
||||
replica->mutable_striping_policy()->set_stripe_size(128);
|
||||
replica->mutable_striping_policy()->set_width(1);
|
||||
|
||||
response->set_timestamp_s(static_cast<uint32_t>(time(0)));
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
google::protobuf::Message* TestRPCServerMRC::RenewCapabilityOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
const XCap* rq = reinterpret_cast<const XCap*>(&request);
|
||||
|
||||
XCap* response = new XCap(*rq);
|
||||
|
||||
response->set_expire_time_s(time(0) + 3600);
|
||||
response->set_expire_timeout_s(3600);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
google::protobuf::Message* TestRPCServerMRC::UpdateFileSizeOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
//const xtreemfs_update_file_sizeRequest* rq =
|
||||
// reinterpret_cast<const xtreemfs_update_file_sizeRequest*>(&request);
|
||||
|
||||
timestampResponse* response = new timestampResponse();
|
||||
|
||||
response->set_timestamp_s(static_cast<uint32_t>(time(0)));
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
google::protobuf::Message* TestRPCServerMRC::FTruncate(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
const XCap* rq = reinterpret_cast<const XCap*>(&request);
|
||||
|
||||
XCap* response = new XCap(*rq);
|
||||
response->set_expire_time_s(time(0) + 3600);
|
||||
response->set_expire_timeout_s(3600);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
void TestRPCServerMRC::SetFileSize(uint64_t size) {
|
||||
boost::mutex::scoped_lock lock(mutex_);
|
||||
file_size_ = size;
|
||||
}
|
||||
|
||||
void TestRPCServerMRC::RegisterOSD(std::string uuid) {
|
||||
boost::mutex::scoped_lock lock(mutex_);
|
||||
osd_uuids_.push_back(uuid);
|
||||
}
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace xtreemfs
|
||||
82
cpp/test/common/test_rpc_server_mrc.h
Normal file
82
cpp/test/common/test_rpc_server_mrc.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPP_TEST_COMMON_TEST_RPC_SERVER_MRC_CPP_
|
||||
#define CPP_TEST_COMMON_TEST_RPC_SERVER_MRC_CPP_
|
||||
|
||||
#include "common/test_rpc_server.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
class Message;
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
namespace xtreemfs {
|
||||
namespace rpc {
|
||||
|
||||
class TestRPCServerMRC : public TestRPCServer<TestRPCServerMRC> {
|
||||
public:
|
||||
TestRPCServerMRC();
|
||||
|
||||
void SetFileSize(uint64_t size);
|
||||
void RegisterOSD(std::string uuid);
|
||||
|
||||
private:
|
||||
google::protobuf::Message* OpenOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
google::protobuf::Message* UpdateFileSizeOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
google::protobuf::Message* RenewCapabilityOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
google::protobuf::Message* FTruncate(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
/** Mutex used to protect all member variables from concurrent access. */
|
||||
boost::mutex mutex_;
|
||||
|
||||
/** Default file size reported by the MRC for every file requested. */
|
||||
uint64_t file_size_;
|
||||
|
||||
std::vector<std::string> osd_uuids_;
|
||||
};
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace xtreemfs
|
||||
|
||||
#endif // CPP_TEST_COMMON_TEST_RPC_SERVER_MRC_CPP_
|
||||
146
cpp/test/common/test_rpc_server_osd.cpp
Normal file
146
cpp/test/common/test_rpc_server_osd.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/test_rpc_server_osd.h"
|
||||
|
||||
#include "util/logging.h"
|
||||
#include "xtreemfs/OSD.pb.h"
|
||||
#include "xtreemfs/OSDServiceConstants.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::pbrpc;
|
||||
using xtreemfs::util::Logging;
|
||||
|
||||
namespace xtreemfs {
|
||||
namespace rpc {
|
||||
|
||||
const int kMaxFileSize = 10 * 1024 * 1024;
|
||||
|
||||
TestRPCServerOSD::TestRPCServerOSD() : file_size_(0) {
|
||||
interface_id_ = INTERFACE_ID_OSD;
|
||||
// Register available operations.
|
||||
operations_[PROC_ID_TRUNCATE]
|
||||
= Op(this, &TestRPCServerOSD::TruncateOperation);
|
||||
operations_[PROC_ID_WRITE]
|
||||
= Op(this, &TestRPCServerOSD::WriteOperation);
|
||||
operations_[PROC_ID_READ]
|
||||
= Op(this, &TestRPCServerOSD::ReadOperation);
|
||||
data_.reset(new char[kMaxFileSize]);
|
||||
}
|
||||
|
||||
const std::vector<WriteEntry> TestRPCServerOSD::GetReceivedWrites() const {
|
||||
boost::mutex::scoped_lock lock(mutex_);
|
||||
return received_writes_;
|
||||
}
|
||||
|
||||
google::protobuf::Message* TestRPCServerOSD::TruncateOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
boost::mutex::scoped_lock lock(mutex_);
|
||||
const truncateRequest* rq
|
||||
= static_cast<const truncateRequest*>(&request);
|
||||
|
||||
file_size_ = rq->new_file_size();
|
||||
assert(file_size_ <= kMaxFileSize);
|
||||
|
||||
OSDWriteResponse* response = new OSDWriteResponse();
|
||||
response->set_size_in_bytes(rq->new_file_size());
|
||||
response->set_truncate_epoch(0);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
google::protobuf::Message* TestRPCServerOSD::ReadOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
boost::mutex::scoped_lock lock(mutex_);
|
||||
const readRequest* rq
|
||||
= static_cast<const readRequest*>(&request);
|
||||
|
||||
const int64_t object_size =
|
||||
rq->file_credentials().xlocs().replicas(0).
|
||||
striping_policy().stripe_size() * 1024;
|
||||
const int64_t offset = rq->object_number() * object_size +
|
||||
rq->offset();
|
||||
const int64_t bytes_to_read =
|
||||
std::min(static_cast<int64_t>(rq->length()), file_size_ - offset);
|
||||
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
|
||||
<< "Received read: object_number: " << rq->object_number()
|
||||
<< ", offset: " << offset
|
||||
<< ", read length: " << rq->length()
|
||||
<< ", object_size: " << object_size
|
||||
<< ", file_size: " << file_size_
|
||||
<< ", sending: " << bytes_to_read << " bytes"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
if (bytes_to_read > 0) {
|
||||
response_data->reset(new char[bytes_to_read]);
|
||||
*response_data_len = bytes_to_read;
|
||||
memcpy(response_data->get(), &data_[offset], bytes_to_read);
|
||||
}
|
||||
|
||||
ObjectData* response = new ObjectData();
|
||||
response->set_zero_padding(0);
|
||||
response->set_invalid_checksum_on_osd(false);
|
||||
response->set_checksum(0);
|
||||
return response;
|
||||
}
|
||||
|
||||
google::protobuf::Message* TestRPCServerOSD::WriteOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
boost::mutex::scoped_lock lock(mutex_);
|
||||
const writeRequest* rq
|
||||
= static_cast<const writeRequest*>(&request);
|
||||
|
||||
received_writes_.push_back(
|
||||
WriteEntry(rq->object_number(), rq->offset(), data_len));
|
||||
|
||||
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
|
||||
<< "Received write: object_number: " << rq->object_number()
|
||||
<< ", offset: " << rq->offset()
|
||||
<< ", data_len: " << data_len << std::endl;
|
||||
}
|
||||
|
||||
const uint64_t object_size =
|
||||
rq->file_credentials().xlocs().replicas(0).
|
||||
striping_policy().stripe_size() * 1024;
|
||||
const uint64_t offset = rq->object_number() * object_size + rq->offset();
|
||||
|
||||
file_size_ = offset + data_len;
|
||||
assert(file_size_ <= kMaxFileSize);
|
||||
|
||||
memcpy(&data_[offset], data, data_len);
|
||||
|
||||
OSDWriteResponse* response = new OSDWriteResponse();
|
||||
response->set_size_in_bytes(file_size_);
|
||||
response->set_truncate_epoch(0);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace xtreemfs
|
||||
97
cpp/test/common/test_rpc_server_osd.h
Normal file
97
cpp/test/common/test_rpc_server_osd.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPP_TEST_COMMON_TEST_RPC_SERVER_OSD_CPP_
|
||||
#define CPP_TEST_COMMON_TEST_RPC_SERVER_OSD_CPP_
|
||||
|
||||
#include "common/test_rpc_server.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
class Message;
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
namespace xtreemfs {
|
||||
namespace rpc {
|
||||
|
||||
class WriteEntry {
|
||||
public:
|
||||
WriteEntry()
|
||||
: object_number_(0), offset_(0), data_len_(0) { }
|
||||
|
||||
WriteEntry(uint64_t objectNumber, uint32_t offset, uint32_t data_len)
|
||||
: object_number_(objectNumber), offset_(offset), data_len_(data_len) { }
|
||||
|
||||
bool operator==(const WriteEntry& other) const {
|
||||
return (other.object_number_ == this->object_number_)
|
||||
&& (other.offset_ == this->offset_)
|
||||
&& (other.data_len_ == this->data_len_);
|
||||
}
|
||||
|
||||
uint64_t object_number_;
|
||||
uint32_t offset_;
|
||||
uint32_t data_len_;
|
||||
};
|
||||
|
||||
class TestRPCServerOSD : public TestRPCServer<TestRPCServerOSD> {
|
||||
public:
|
||||
TestRPCServerOSD();
|
||||
const std::vector<WriteEntry> GetReceivedWrites() const;
|
||||
|
||||
private:
|
||||
google::protobuf::Message* TruncateOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
google::protobuf::Message* ReadOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
google::protobuf::Message* WriteOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len);
|
||||
|
||||
/** Mutex used to protect all member variables from concurrent access. */
|
||||
mutable boost::mutex mutex_;
|
||||
|
||||
/** A single file size is remembered between requests. */
|
||||
int64_t file_size_;
|
||||
|
||||
/** The file data. */
|
||||
boost::scoped_array<char> data_;
|
||||
|
||||
/** A list of received write requests that can be used to check against an
|
||||
* expected result.
|
||||
*/
|
||||
std::vector<WriteEntry> received_writes_;
|
||||
};
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace xtreemfs
|
||||
|
||||
#endif // CPP_TEST_COMMON_TEST_RPC_SERVER_OSD_CPP_
|
||||
84
cpp/test/fuse/fuse_options_test.cpp
Normal file
84
cpp/test/fuse/fuse_options_test.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "fuse/fuse_options.h"
|
||||
#include "libxtreemfs/xtreemfs_exception.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
namespace xtreemfs {
|
||||
|
||||
class FuseOptionsTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
shutdown_logger();
|
||||
atexit(google::protobuf::ShutdownProtobufLibrary);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(FuseOptionsTest, TestCommandLineMultipleOptionsPerFuseOptionAndMinusoOption) {
|
||||
int argc = 7;
|
||||
char** argv = new char*[argc];
|
||||
argv[0] = strdup("mount.xtreemfs");
|
||||
argv[1] = strdup("--fuse_option");
|
||||
argv[2] = strdup("allow_other,bogus");
|
||||
argv[3] = strdup("--fuse_option");
|
||||
argv[4] = strdup("bogus2");
|
||||
argv[5] = strdup("localhost/test");
|
||||
argv[6] = strdup("/mnt/xtreemfs");
|
||||
|
||||
xtreemfs::FuseOptions options;
|
||||
|
||||
ASSERT_NO_THROW({
|
||||
options.ParseCommandLine(argc, argv);
|
||||
});
|
||||
ASSERT_TRUE(!options.show_help && !options.empty_arguments_list
|
||||
&& !options.show_version);
|
||||
|
||||
ASSERT_EQ(3, options.fuse_options.size());
|
||||
EXPECT_EQ("bogus2", options.fuse_options[0]);
|
||||
// Split options are added to the end of fuse_options.
|
||||
EXPECT_EQ("allow_other", options.fuse_options[1]);
|
||||
EXPECT_EQ("bogus", options.fuse_options[2]);
|
||||
|
||||
// when using -o, split options are ordered because they are processed in
|
||||
// Options::ParseCommandLine.
|
||||
free(argv[1]);
|
||||
argv[1] = strdup("-o");
|
||||
free(argv[3]);
|
||||
argv[3] = strdup("-o");
|
||||
|
||||
ASSERT_NO_THROW({
|
||||
options.ParseCommandLine(argc, argv);
|
||||
});
|
||||
ASSERT_TRUE(!options.show_help && !options.empty_arguments_list
|
||||
&& !options.show_version);
|
||||
|
||||
ASSERT_EQ(3, options.fuse_options.size());
|
||||
EXPECT_EQ("allow_other", options.fuse_options[0]);
|
||||
EXPECT_EQ("bogus", options.fuse_options[1]);
|
||||
EXPECT_EQ("bogus2", options.fuse_options[2]);
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
free(argv[i]);
|
||||
}
|
||||
delete[] argv;
|
||||
}
|
||||
|
||||
} // namespace xtreemfs
|
||||
4
cpp/test/ld_preload/cp.sh
Executable file
4
cpp/test/ld_preload/cp.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
BUILD_DIR="../../build"
|
||||
#LD_DEBUG=all
|
||||
XTREEMFS_PRELOAD_OPTIONS="--log-level DEBUG demo.xtreemfs.org/demo /xtreemfs" LD_PRELOAD=$BUILD_DIR"/libxtreemfs_preload.so" cp $1 $2
|
||||
71
cpp/test/ld_preload/preload_test.cpp
Normal file
71
cpp/test/ld_preload/preload_test.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2014 by Matthias Noack, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
const char default_path[] = "/xtreemfs/temp_b.file";
|
||||
const char* path = default_path;
|
||||
|
||||
// take path from command line if specified
|
||||
if (argc > 1) {
|
||||
path = argv[1];
|
||||
}
|
||||
|
||||
// open() file
|
||||
std::cout << "TEST: open()" << std::endl;
|
||||
//FILE* file_a = std::fopen("/xtreemfs/demo/temp_a.file", "w");
|
||||
int file_b = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0777);
|
||||
//int file_b = open("/xtreemfs/demo/temp.file", O_WRONLY | O_CREAT); // this is wrong by open specification, mode is not set, but O_CREAT is
|
||||
|
||||
const char data_to_write[] = "Hello World!";
|
||||
char data_to_read[256] = "";
|
||||
|
||||
ssize_t write_ret = write(file_b, (void*)data_to_write, sizeof(data_to_write));
|
||||
|
||||
lseek(file_b, 0, SEEK_SET);
|
||||
|
||||
// close() file
|
||||
close(file_b);
|
||||
|
||||
// open() same file for reading
|
||||
file_b = open(path, O_RDONLY, 0);
|
||||
|
||||
ssize_t read_ret = read(file_b, (void*)data_to_read, sizeof(data_to_write));
|
||||
|
||||
// close() file
|
||||
std::cout << "TEST: close()" << std::endl;
|
||||
//std::fclose(file_a);
|
||||
close(file_b);
|
||||
|
||||
// compare written and read
|
||||
if (0 == std::strcmp(data_to_write, data_to_read))
|
||||
std::cout << "PASS" << std::endl;
|
||||
else
|
||||
std::cout << "FAIL" << std::endl;
|
||||
|
||||
// stat(), fstat()
|
||||
|
||||
// access()
|
||||
|
||||
// ftruncate()
|
||||
|
||||
// getcwd()
|
||||
|
||||
std::cout << "TEST: done()" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
4
cpp/test/ld_preload/preload_test.sh
Executable file
4
cpp/test/ld_preload/preload_test.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
BUILD_DIR="../../build"
|
||||
#LD_DEBUG=all
|
||||
XTREEMFS_PRELOAD_OPTIONS="--log-level ERR demo.xtreemfs.org/demo /xtreemfs" LD_PRELOAD=$BUILD_DIR"/libxtreemfs_preload.so" $BUILD_DIR/preload_test $1
|
||||
4
cpp/test/ld_preload/setfattr.sh
Executable file
4
cpp/test/ld_preload/setfattr.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
BUILD_DIR="../../build"
|
||||
#LD_DEBUG=all
|
||||
XTREEMFS_PRELOAD_OPTIONS="--log-level DEBUG demo.xtreemfs.org/demo /xtreemfs" LD_PRELOAD=$BUILD_DIR"/libxtreemfs_preload.so" setfattr "$@"
|
||||
249
cpp/test/libxtreemfs/async_write_handler_test.cpp
Normal file
249
cpp/test/libxtreemfs/async_write_handler_test.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Matthias Noack, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#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>(
|
||||
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<char> write_buf(new char[buffer_size]());
|
||||
|
||||
vector<WriteEntry> 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<char> write_buf(new char[buffer_size]());
|
||||
|
||||
vector<WriteEntry> 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<char> write_buf(new char[buffer_size]());
|
||||
|
||||
vector<WriteEntry> expected_front(blocks - 1);
|
||||
vector<WriteEntry> 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<char> write_buf(new char[buffer_size]());
|
||||
|
||||
vector<WriteEntry> expected_front(middle);
|
||||
vector<WriteEntry> 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<char> write_buf(new char[buffer_size]());
|
||||
|
||||
vector<WriteEntry> 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<char> write_buf(new char[buffer_size]());
|
||||
|
||||
vector<WriteEntry> 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
|
||||
180
cpp/test/libxtreemfs/client_implementation_test.cpp
Normal file
180
cpp/test/libxtreemfs/client_implementation_test.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2014 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <map>
|
||||
|
||||
#include "common/test_rpc_server_dir.h"
|
||||
#include "libxtreemfs/client.h"
|
||||
#include "libxtreemfs/helper.h"
|
||||
#include "libxtreemfs/options.h"
|
||||
#include "libxtreemfs/pbrpc_url.h"
|
||||
#include "libxtreemfs/xtreemfs_exception.h"
|
||||
#include "xtreemfs/DIR.pb.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::pbrpc;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
namespace xtreemfs {
|
||||
|
||||
class ClientImplementationTest : public ::testing::Test {
|
||||
protected:
|
||||
/** Mock-up DIR server where custom address mappings can be registered. */
|
||||
class TestRPCServerDIRCustomMapping : public xtreemfs::rpc::TestRPCServerDIR {
|
||||
public:
|
||||
void AddMapping(const string& uuid, const AddressMapping& mapping) {
|
||||
mappings_.insert(pair<string, AddressMapping>(uuid, mapping));
|
||||
}
|
||||
|
||||
private:
|
||||
/** Map from UUID to AddressMapping(s). */
|
||||
std::multimap<string, AddressMapping> mappings_;
|
||||
|
||||
virtual google::protobuf::Message* GetAddressMappingOperation(
|
||||
const pbrpc::Auth& auth,
|
||||
const pbrpc::UserCredentials& user_credentials,
|
||||
const google::protobuf::Message& request,
|
||||
const char* data,
|
||||
uint32_t data_len,
|
||||
boost::scoped_array<char>* response_data,
|
||||
uint32_t* response_data_len) {
|
||||
const addressMappingGetRequest* rq
|
||||
= reinterpret_cast<const addressMappingGetRequest*>(&request);
|
||||
|
||||
AddressMappingSet* response = new AddressMappingSet();
|
||||
|
||||
pair<multimap<string,AddressMapping>::iterator,
|
||||
multimap<string,AddressMapping>::iterator> ret;
|
||||
ret = mappings_.equal_range(rq->uuid());
|
||||
for (multimap<string,AddressMapping>::iterator it = ret.first;
|
||||
it != ret.second;
|
||||
++it) {
|
||||
AddressMapping* mapping = response->add_mappings();
|
||||
mapping->CopyFrom(it->second);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
};
|
||||
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
|
||||
kTestUUID_ = "uuid";
|
||||
kTestPort_ = 12345;
|
||||
|
||||
user_credentials_.set_username("ClientImplementationTest");
|
||||
user_credentials_.add_groups("ClientImplementationTest");
|
||||
|
||||
|
||||
dir_.reset(new TestRPCServerDIRCustomMapping());
|
||||
ASSERT_TRUE(dir_->Start());
|
||||
|
||||
client_.reset(Client::CreateClient(
|
||||
dir_->GetAddress(),
|
||||
user_credentials_,
|
||||
NULL, // No SSL options.
|
||||
options_));
|
||||
|
||||
// Start the client (a connection to the DIR service will be setup).
|
||||
client_->Start();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
if (dir_.get()) {
|
||||
client_->Shutdown();
|
||||
}
|
||||
if (dir_.get()) {
|
||||
dir_->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
void AddAddressMapping(const std::string& match_network,
|
||||
const std::string& hostname) {
|
||||
AddressMapping mapping;
|
||||
mapping.set_uuid(kTestUUID_);
|
||||
mapping.set_version(0);
|
||||
mapping.set_protocol(PBRPCURL::GetSchemePBRPC());
|
||||
mapping.set_address(hostname);
|
||||
mapping.set_port(kTestPort_);
|
||||
mapping.set_match_network(match_network);
|
||||
mapping.set_ttl_s(3600);
|
||||
mapping.set_uri("");
|
||||
|
||||
dir_->AddMapping(kTestUUID_, mapping);
|
||||
}
|
||||
|
||||
std::string ExpectedAddress(const std::string& hostname) {
|
||||
return hostname + ":" + boost::lexical_cast<string>(kTestPort_);
|
||||
}
|
||||
|
||||
boost::scoped_ptr<TestRPCServerDIRCustomMapping> dir_;
|
||||
|
||||
boost::scoped_ptr<Client> client_;
|
||||
|
||||
Options options_;
|
||||
UserCredentials user_credentials_;
|
||||
|
||||
/** Test constant used for all operations. */
|
||||
std::string kTestUUID_;
|
||||
int kTestPort_;
|
||||
};
|
||||
|
||||
|
||||
/** For the requested UUID is exactly one default entry available. */
|
||||
TEST_F(ClientImplementationTest, UUIDToAddressDefaultOnly) {
|
||||
AddAddressMapping("*", "default");
|
||||
|
||||
EXPECT_EQ(ExpectedAddress("default"), client_->UUIDToAddress(kTestUUID_));
|
||||
}
|
||||
|
||||
/** For the requested UUID is no address known. */
|
||||
TEST_F(ClientImplementationTest, UUIDToAddressNoService) {
|
||||
AddAddressMapping("*", "default");
|
||||
|
||||
ASSERT_THROW(client_->UUIDToAddress("unknown-UUID"),
|
||||
AddressToUUIDNotFoundException);
|
||||
}
|
||||
|
||||
/** For the requested UUID is a local network and a default one available. */
|
||||
#ifdef __linux__
|
||||
TEST_F(ClientImplementationTest, UUIDToAddressLocalNetworkAndDefault) {
|
||||
boost::unordered_set<string> local_networks = GetNetworks();
|
||||
// TODO(mberlin): This effectively requires to run the unit test with at
|
||||
// least one network interface. Put an if around this if this
|
||||
// results into flaky tests.
|
||||
ASSERT_GE(local_networks.size(), 1);
|
||||
|
||||
AddAddressMapping(*local_networks.begin(), "local-network");
|
||||
AddAddressMapping("*", "default");
|
||||
|
||||
EXPECT_EQ(ExpectedAddress("local-network"),
|
||||
client_->UUIDToAddress(kTestUUID_));
|
||||
}
|
||||
#endif // __linux__
|
||||
|
||||
/** Same as "UUIDToAddressLocalNetworkAndDefault", but reverse list order. */
|
||||
#ifdef __linux__
|
||||
TEST_F(ClientImplementationTest, UUIDToAddressDefaultAndLocalNetwork) {
|
||||
boost::unordered_set<string> local_networks = GetNetworks();
|
||||
// TODO(mberlin): This effectively requires to run the unit test with at
|
||||
// least one network interface. Put an if around this if this
|
||||
// results into flaky tests.
|
||||
ASSERT_GE(local_networks.size(), 1);
|
||||
|
||||
AddAddressMapping("*", "default");
|
||||
AddAddressMapping(*local_networks.begin(), "local-network");
|
||||
|
||||
EXPECT_EQ(ExpectedAddress("local-network"),
|
||||
client_->UUIDToAddress(kTestUUID_));
|
||||
}
|
||||
#endif // __linux__
|
||||
|
||||
} // namespace xtreemfs
|
||||
92
cpp/test/libxtreemfs/helper_test.cpp
Normal file
92
cpp/test/libxtreemfs/helper_test.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2014 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include "libxtreemfs/helper.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
namespace xtreemfs {
|
||||
|
||||
/** Tests for various helper methods. */
|
||||
class HelperTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
shutdown_logger();
|
||||
atexit(google::protobuf::ShutdownProtobufLibrary);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
TEST_F(HelperTest, GetNetworkStringUnixIPv4) {
|
||||
// Linux's "getifaddrs" returns for each network interface a "struct ifaddrs".
|
||||
// Check that the network is correctly determined based on such a struct.
|
||||
struct ifaddrs ifaddr = {};
|
||||
struct addrinfo hints = {};
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
|
||||
struct addrinfo* ai_addr;
|
||||
ASSERT_EQ(0, getaddrinfo("127.0.0.1", NULL, &hints, &ai_addr));
|
||||
|
||||
struct addrinfo* ai_netmask;
|
||||
ASSERT_EQ(0, getaddrinfo("255.0.0.0", NULL, &hints, &ai_netmask));
|
||||
|
||||
ifaddr.ifa_next = NULL;
|
||||
ifaddr.ifa_name = (char*) "eth0";
|
||||
ifaddr.ifa_addr = ai_addr->ai_addr;
|
||||
ifaddr.ifa_netmask = ai_netmask->ai_addr;
|
||||
|
||||
EXPECT_EQ("127.0.0.0/8", GetNetworkStringUnix(&ifaddr));
|
||||
|
||||
freeaddrinfo(ai_addr);
|
||||
freeaddrinfo(ai_netmask);
|
||||
}
|
||||
#endif // __linux__
|
||||
|
||||
#ifdef __linux__
|
||||
TEST_F(HelperTest, GetNetworkStringUnixIPv6) {
|
||||
// Linux's "getifaddrs" returns for each network interface a "struct ifaddrs".
|
||||
// Check that the network is correctly determined based on such a struct.
|
||||
struct ifaddrs ifaddr = {};
|
||||
struct addrinfo hints = {};
|
||||
hints.ai_family = AF_INET6;
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
|
||||
struct addrinfo* ai_addr;
|
||||
ASSERT_EQ(0, getaddrinfo("fe80::b4ff:fe58:a410", NULL, &hints, &ai_addr));
|
||||
|
||||
struct addrinfo* ai_netmask;
|
||||
ASSERT_EQ(0, getaddrinfo("ffff:ffff:ffff:ffff::", NULL, &hints, &ai_netmask));
|
||||
|
||||
ifaddr.ifa_next = NULL;
|
||||
ifaddr.ifa_name = (char*) "eth0";
|
||||
ifaddr.ifa_addr = ai_addr->ai_addr;
|
||||
ifaddr.ifa_netmask = ai_netmask->ai_addr;
|
||||
|
||||
EXPECT_EQ("fe80::/64", GetNetworkStringUnix(&ifaddr));
|
||||
|
||||
freeaddrinfo(ai_addr);
|
||||
freeaddrinfo(ai_netmask);
|
||||
}
|
||||
#endif // __linux__
|
||||
|
||||
} // namespace xtreemfs
|
||||
335
cpp/test/libxtreemfs/metadata_cache_test.cpp
Normal file
335
cpp/test/libxtreemfs/metadata_cache_test.cpp
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "libxtreemfs/metadata_cache.h"
|
||||
#include "libxtreemfs/helper.h"
|
||||
#include "util/logging.h"
|
||||
#include "xtreemfs/MRC.pb.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs;
|
||||
using namespace xtreemfs::pbrpc;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
class MetadataCacheTestSize2 : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
|
||||
metadata_cache_ = new MetadataCache(2, 3600); // Max 2 entries, 1 hour.
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
delete metadata_cache_;
|
||||
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
|
||||
shutdown_logger();
|
||||
}
|
||||
|
||||
MetadataCache* metadata_cache_;
|
||||
};
|
||||
|
||||
class MetadataCacheTestSize1024 : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
|
||||
metadata_cache_ = new MetadataCache(1024, 3600); // Max 1k entries, 1 hour.
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
delete metadata_cache_;
|
||||
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
|
||||
shutdown_logger();
|
||||
}
|
||||
|
||||
MetadataCache* metadata_cache_;
|
||||
};
|
||||
|
||||
/** If a Stat entry gets updated through UpdateStatTime(), the new timeout must
|
||||
* be respected in case of an eviction. */
|
||||
TEST_F(MetadataCacheTestSize2, UpdateStatTimeKeepsSequentialTimeoutOrder) {
|
||||
Stat a, b, c;
|
||||
InitializeStat(&a);
|
||||
InitializeStat(&b);
|
||||
InitializeStat(&c);
|
||||
a.set_ino(0);
|
||||
b.set_ino(1);
|
||||
c.set_ino(2);
|
||||
|
||||
metadata_cache_->UpdateStat("/a", a);
|
||||
metadata_cache_->UpdateStat("/b", b);
|
||||
// Cache is full now. a would be first item to get evicted.
|
||||
metadata_cache_->UpdateStatTime("/a", 0, SETATTR_MTIME);
|
||||
// "b" should be the oldest Stat element now and get evicted.
|
||||
metadata_cache_->UpdateStat("/c", c);
|
||||
// Was "a" found or did "b" survive?
|
||||
EXPECT_EQ(MetadataCache::kStatCached, metadata_cache_->GetStat("/a", &a));
|
||||
EXPECT_EQ(0, a.ino());
|
||||
// "c" is also still there.
|
||||
EXPECT_EQ(MetadataCache::kStatCached, metadata_cache_->GetStat("/c", &c));
|
||||
EXPECT_EQ(2, c.ino());
|
||||
}
|
||||
|
||||
/** If a Stat entry gets updated through UpdateStat(), the new timeout must be
|
||||
* respected in case of an eviction. */
|
||||
TEST_F(MetadataCacheTestSize2, UpdateStatKeepsSequentialTimeoutOrder) {
|
||||
Stat a, b, c;
|
||||
InitializeStat(&a);
|
||||
InitializeStat(&b);
|
||||
InitializeStat(&c);
|
||||
a.set_ino(0);
|
||||
b.set_ino(1);
|
||||
c.set_ino(2);
|
||||
|
||||
metadata_cache_->UpdateStat("/a", a);
|
||||
metadata_cache_->UpdateStat("/b", b);
|
||||
// Cache is full now. a would be first item to get evicted.
|
||||
metadata_cache_->UpdateStat("/a", a);
|
||||
// "b" should be the oldest Stat element now and get evicted.
|
||||
metadata_cache_->UpdateStat("/c", c);
|
||||
// Was "a" found or did "b" survive?
|
||||
EXPECT_EQ(MetadataCache::kStatCached, metadata_cache_->GetStat("/a", &a));
|
||||
EXPECT_EQ(0, a.ino());
|
||||
// "c" is also still there.
|
||||
EXPECT_EQ(MetadataCache::kStatCached, metadata_cache_->GetStat("/c", &c));
|
||||
EXPECT_EQ(2, c.ino());
|
||||
}
|
||||
|
||||
/** Test if Size is updated correctly after UpdateStat() or Invalidate(). */
|
||||
TEST_F(MetadataCacheTestSize2, CheckSizeAfterUpdateAndInvalidate) {
|
||||
Stat a, b, c;
|
||||
InitializeStat(&a);
|
||||
InitializeStat(&b);
|
||||
InitializeStat(&c);
|
||||
EXPECT_EQ(0, metadata_cache_->Size());
|
||||
metadata_cache_->UpdateStat("/a", a);
|
||||
EXPECT_EQ(1, metadata_cache_->Size());
|
||||
metadata_cache_->UpdateStat("/b", b);
|
||||
EXPECT_EQ(2, metadata_cache_->Size());
|
||||
metadata_cache_->UpdateStat("/c", b);
|
||||
// Cache has only room for two entries.
|
||||
EXPECT_EQ(2, metadata_cache_->Size());
|
||||
|
||||
metadata_cache_->Invalidate("/b");
|
||||
EXPECT_EQ(1, metadata_cache_->Size());
|
||||
metadata_cache_->Invalidate("/c");
|
||||
EXPECT_EQ(0, metadata_cache_->Size());
|
||||
}
|
||||
|
||||
/** Test (Get|Update)DirEntries methods. */
|
||||
TEST_F(MetadataCacheTestSize2, UpdateAndGetDirEntries) {
|
||||
DirectoryEntries dir_entries;
|
||||
int chunk_size = 1024;
|
||||
int entry_count = chunk_size;
|
||||
string dir = "/";
|
||||
|
||||
// Fill dir_entries;
|
||||
for (int i = 0; i < entry_count; i++) {
|
||||
Stat a;
|
||||
a.set_ino(i);
|
||||
dir_entries.add_entries();
|
||||
dir_entries.mutable_entries(dir_entries.entries_size()-1)
|
||||
->mutable_stbuf()->CopyFrom(a);
|
||||
string path_to_stat = dir + boost::lexical_cast<std::string>(i);
|
||||
dir_entries.mutable_entries(dir_entries.entries_size()-1)
|
||||
->set_name(path_to_stat);
|
||||
}
|
||||
metadata_cache_->UpdateDirEntries(dir, dir_entries);
|
||||
|
||||
boost::scoped_ptr<DirectoryEntries> dir_entries_read;
|
||||
|
||||
// Read all entries.
|
||||
dir_entries_read.reset(metadata_cache_->GetDirEntries(dir, 0, entry_count));
|
||||
EXPECT_EQ(entry_count, dir_entries_read->entries_size());
|
||||
for (int i = 0; i < dir_entries_read->entries_size(); i++) {
|
||||
string path_to_stat = dir + boost::lexical_cast<std::string>(i);
|
||||
EXPECT_EQ(i, dir_entries_read->entries(i).stbuf().ino());
|
||||
EXPECT_EQ(path_to_stat, dir_entries_read->entries(i).name());
|
||||
}
|
||||
|
||||
// Read a subset.
|
||||
dir_entries_read.reset(metadata_cache_
|
||||
->GetDirEntries(dir, entry_count/2, entry_count/2-1));
|
||||
EXPECT_EQ(entry_count/2-1, dir_entries_read->entries_size());
|
||||
int offset = entry_count/2;
|
||||
for (int i = 0; i < dir_entries_read->entries_size(); i++) {
|
||||
string path_to_stat = dir + boost::lexical_cast<std::string>(offset);
|
||||
EXPECT_EQ(path_to_stat, dir_entries_read->entries(i).name());
|
||||
EXPECT_EQ(offset, dir_entries_read->entries(i).stbuf().ino());
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
/** If a Stat entry gets updated through UpdateStat(), the new timeout must be
|
||||
* respected in case of an eviction. */
|
||||
TEST_F(MetadataCacheTestSize1024, InvalidatePrefix) {
|
||||
Stat a, b, c, d;
|
||||
InitializeStat(&a);
|
||||
InitializeStat(&b);
|
||||
InitializeStat(&c);
|
||||
InitializeStat(&d);
|
||||
a.set_ino(0);
|
||||
b.set_ino(1);
|
||||
c.set_ino(2);
|
||||
d.set_ino(3);
|
||||
|
||||
metadata_cache_->UpdateStat("/dir", a);
|
||||
metadata_cache_->UpdateStat("/dir/file1", b);
|
||||
metadata_cache_->UpdateStat("/dir.file1", c);
|
||||
metadata_cache_->UpdateStat("/dirZfile1", d);
|
||||
|
||||
metadata_cache_->InvalidatePrefix("/dir");
|
||||
|
||||
// Invalidate of all matching entries successful?
|
||||
EXPECT_EQ(MetadataCache::kStatNotCached,
|
||||
metadata_cache_->GetStat("/dir", &a));
|
||||
EXPECT_EQ(MetadataCache::kStatNotCached,
|
||||
metadata_cache_->GetStat("/dir/file1", &b));
|
||||
|
||||
// Similiar entries which do not match the prefix "/dir/" have not been
|
||||
// invalidated.
|
||||
EXPECT_EQ(MetadataCache::kStatCached,
|
||||
metadata_cache_->GetStat("/dir.file1", &c));
|
||||
EXPECT_EQ(2, c.ino());
|
||||
EXPECT_EQ(MetadataCache::kStatCached,
|
||||
metadata_cache_->GetStat("/dirZfile1", &d));
|
||||
EXPECT_EQ(3, d.ino());
|
||||
}
|
||||
|
||||
/** If a Stat entry gets updated through UpdateStat(), the new timeout must be
|
||||
* respected in case of an eviction. */
|
||||
TEST_F(MetadataCacheTestSize1024, RenamePrefix) {
|
||||
Stat a, b, c, d;
|
||||
InitializeStat(&a);
|
||||
InitializeStat(&b);
|
||||
InitializeStat(&c);
|
||||
InitializeStat(&d);
|
||||
a.set_ino(0);
|
||||
b.set_ino(1);
|
||||
c.set_ino(2);
|
||||
d.set_ino(3);
|
||||
|
||||
metadata_cache_->UpdateStat("/dir", a);
|
||||
metadata_cache_->UpdateStat("/dir/file1", b);
|
||||
metadata_cache_->UpdateStat("/dir.file1", c);
|
||||
metadata_cache_->UpdateStat("/dirZfile1", d);
|
||||
EXPECT_EQ(4, metadata_cache_->Size());
|
||||
|
||||
metadata_cache_->RenamePrefix("/dir", "/newdir");
|
||||
EXPECT_EQ(4, metadata_cache_->Size());
|
||||
|
||||
// Rename of all matching entries successful?
|
||||
EXPECT_EQ(MetadataCache::kStatCached,
|
||||
metadata_cache_->GetStat("/newdir", &a));
|
||||
EXPECT_EQ(0, a.ino());
|
||||
EXPECT_EQ(MetadataCache::kStatCached,
|
||||
metadata_cache_->GetStat("/newdir/file1", &b));
|
||||
EXPECT_EQ(1, b.ino());
|
||||
|
||||
// Similiar entries which do not match the prefix "/dir/" have not been
|
||||
// renamed.
|
||||
EXPECT_EQ(MetadataCache::kStatCached,
|
||||
metadata_cache_->GetStat("/dir.file1", &c));
|
||||
EXPECT_EQ(2, c.ino());
|
||||
EXPECT_EQ(MetadataCache::kStatCached,
|
||||
metadata_cache_->GetStat("/dirZfile1", &d));
|
||||
EXPECT_EQ(3, d.ino());
|
||||
}
|
||||
|
||||
/** Are large nanoseconds values correctly updated by
|
||||
* UpdateStatAttributes? */
|
||||
TEST_F(MetadataCacheTestSize1024, UpdateStatAttributes) {
|
||||
string path = "/file";
|
||||
Stat stat, update_stat;
|
||||
InitializeStat(&stat);
|
||||
InitializeStat(&update_stat);
|
||||
stat.set_ino(0);
|
||||
update_stat.set_ino(1);
|
||||
|
||||
metadata_cache_->UpdateStat(path, stat);
|
||||
EXPECT_EQ(1, metadata_cache_->Size());
|
||||
EXPECT_EQ(MetadataCache::kStatCached, metadata_cache_->GetStat(path, &stat));
|
||||
EXPECT_EQ(0, stat.ino());
|
||||
EXPECT_EQ(0, stat.mtime_ns());
|
||||
|
||||
uint64_t time = 1234567890;
|
||||
time *= 1000000000;
|
||||
update_stat.set_atime_ns(time);
|
||||
update_stat.set_mtime_ns(time);
|
||||
metadata_cache_->UpdateStatAttributes(
|
||||
path,
|
||||
update_stat,
|
||||
static_cast<Setattrs>(SETATTR_ATIME | SETATTR_MTIME));
|
||||
EXPECT_EQ(1, metadata_cache_->Size());
|
||||
EXPECT_EQ(MetadataCache::kStatCached, metadata_cache_->GetStat(path, &stat));
|
||||
EXPECT_EQ(0, stat.ino());
|
||||
EXPECT_EQ(time, stat.atime_ns());
|
||||
EXPECT_EQ(time, stat.mtime_ns());
|
||||
}
|
||||
|
||||
/** Changing the file access mode may only modify the last 12 bits (3 bits for
|
||||
* sticky bit, set GID and set UID and 3 * 3 bits for the file access mode). */
|
||||
TEST_F(MetadataCacheTestSize1024, UpdateStatAttributesPreservesModeBits) {
|
||||
string path = "/file";
|
||||
Stat stat, cached_stat;
|
||||
InitializeStat(&stat);
|
||||
stat.set_ino(0);
|
||||
stat.set_mode(33188); // Octal: 100644 (regular file + 644).
|
||||
|
||||
metadata_cache_->UpdateStat(path, stat);
|
||||
EXPECT_EQ(1, metadata_cache_->Size());
|
||||
EXPECT_EQ(MetadataCache::kStatCached,
|
||||
metadata_cache_->GetStat(path, &cached_stat));
|
||||
EXPECT_EQ(0, cached_stat.ino());
|
||||
EXPECT_EQ(33188, cached_stat.mode());
|
||||
|
||||
stat.set_mode(420); // Octal: 644.
|
||||
metadata_cache_->UpdateStatAttributes(path, stat, SETATTR_MODE);
|
||||
EXPECT_EQ(1, metadata_cache_->Size());
|
||||
EXPECT_EQ(MetadataCache::kStatCached,
|
||||
metadata_cache_->GetStat(path, &cached_stat));
|
||||
EXPECT_EQ(0, cached_stat.ino());
|
||||
EXPECT_EQ(33188, cached_stat.mode());
|
||||
|
||||
stat.set_mode(263076); // Octal: 1001644 (regular file + sticky bit + 644).
|
||||
|
||||
metadata_cache_->UpdateStat(path, stat);
|
||||
EXPECT_EQ(1, metadata_cache_->Size());
|
||||
EXPECT_EQ(MetadataCache::kStatCached,
|
||||
metadata_cache_->GetStat(path, &cached_stat));
|
||||
EXPECT_EQ(0, cached_stat.ino());
|
||||
EXPECT_EQ(263076, cached_stat.mode());
|
||||
|
||||
stat.set_mode(511); // Octal: 0777 (no sticky bit + 777).
|
||||
metadata_cache_->UpdateStatAttributes(path, stat, SETATTR_MODE);
|
||||
EXPECT_EQ(1, metadata_cache_->Size());
|
||||
EXPECT_EQ(MetadataCache::kStatCached,
|
||||
metadata_cache_->GetStat(path, &cached_stat));
|
||||
EXPECT_EQ(0, cached_stat.ino());
|
||||
EXPECT_EQ(262655, cached_stat.mode()); // Octal: 1000777.
|
||||
}
|
||||
|
||||
/** Ideas:
|
||||
*
|
||||
* test TTL expiration.
|
||||
* test invalidateprefix.
|
||||
*
|
||||
* test correct setting of maximum ttl for every operation
|
||||
*
|
||||
*/
|
||||
292
cpp/test/libxtreemfs/object_cache_test.cpp
Normal file
292
cpp/test/libxtreemfs/object_cache_test.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (c) 2013 by Felix Hupfeld.
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
#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/helper.h"
|
||||
#include "libxtreemfs/object_cache.h"
|
||||
#include "libxtreemfs/options.h"
|
||||
#include "libxtreemfs/volume.h"
|
||||
#include "libxtreemfs/xtreemfs_exception.h"
|
||||
#include "rpc/client.h"
|
||||
#include "rpc/sync_callback.h"
|
||||
#include "util/logging.h"
|
||||
#include "xtreemfs/OSDServiceConstants.h"
|
||||
|
||||
namespace xtreemfs {
|
||||
|
||||
const int kObjectSize = 10;
|
||||
|
||||
class FakeOsdFile {
|
||||
public:
|
||||
FakeOsdFile() : size_(0), reads_(0), writes_(0) {
|
||||
data_.reset(new char[500]);
|
||||
}
|
||||
int Read(int object_no, char* buffer) {
|
||||
reads_++;
|
||||
const int offset = object_no * kObjectSize;
|
||||
const int bytes_to_read = std::min(kObjectSize, size_ - offset);
|
||||
if (bytes_to_read <= 0) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(buffer, &data_[offset], bytes_to_read);
|
||||
return bytes_to_read;
|
||||
}
|
||||
void Write(int object_no, const char* data, int bytes_to_write) {
|
||||
writes_++;
|
||||
const int offset = object_no * kObjectSize;
|
||||
memcpy(&data_[offset], data, bytes_to_write);
|
||||
size_ = std::max(size_, offset + bytes_to_write);
|
||||
}
|
||||
void Truncate(int new_size) {
|
||||
size_ = new_size;
|
||||
}
|
||||
boost::scoped_array<char> data_;
|
||||
int size_;
|
||||
int reads_;
|
||||
int writes_;
|
||||
};
|
||||
|
||||
class ObjectCacheTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
util::initialize_logger(util::LEVEL_WARN);
|
||||
cache_.reset(new ObjectCache(2, kObjectSize));
|
||||
reader_ = boost::bind(&FakeOsdFile::Read, &osd_file_, _1, _2);
|
||||
writer_ = boost::bind(&FakeOsdFile::Write, &osd_file_, _1, _2, _3);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
util::shutdown_logger();
|
||||
}
|
||||
|
||||
FakeOsdFile osd_file_;
|
||||
boost::scoped_ptr<ObjectCache> cache_;
|
||||
ObjectReaderFunction reader_;
|
||||
ObjectWriterFunction writer_;
|
||||
};
|
||||
|
||||
TEST_F(ObjectCacheTest, BasicUse) {
|
||||
cache_->Write(0, 0, "TestData", 9, reader_, writer_);
|
||||
EXPECT_EQ(1, osd_file_.reads_);
|
||||
EXPECT_EQ(0, osd_file_.writes_);
|
||||
EXPECT_EQ(0, osd_file_.size_);
|
||||
|
||||
char buffer[10];
|
||||
EXPECT_EQ(9, cache_->Read(0, 0, buffer, 10, reader_, writer_));
|
||||
EXPECT_EQ(0, strcmp(buffer, "TestData"));
|
||||
EXPECT_EQ(1, osd_file_.reads_);
|
||||
EXPECT_EQ(0, osd_file_.writes_);
|
||||
EXPECT_EQ(0, osd_file_.size_);
|
||||
|
||||
cache_->Flush(writer_);
|
||||
EXPECT_EQ(1, osd_file_.reads_);
|
||||
EXPECT_EQ(1, osd_file_.writes_);
|
||||
EXPECT_EQ(9, osd_file_.size_);
|
||||
|
||||
cache_->Flush(writer_);
|
||||
EXPECT_EQ(1, osd_file_.reads_);
|
||||
EXPECT_EQ(1, osd_file_.writes_);
|
||||
EXPECT_EQ(9, osd_file_.size_);
|
||||
}
|
||||
|
||||
TEST_F(ObjectCacheTest, Truncate) {
|
||||
cache_->Write(0, 0, "TestDataTe", 10, reader_, writer_);
|
||||
cache_->Write(1, 0, "stData", 6, reader_, writer_);
|
||||
EXPECT_EQ(2, osd_file_.reads_);
|
||||
EXPECT_EQ(0, osd_file_.writes_);
|
||||
EXPECT_EQ(0, osd_file_.size_);
|
||||
|
||||
// Shrink
|
||||
cache_->Truncate(12);
|
||||
osd_file_.Truncate(12);
|
||||
EXPECT_EQ(2, osd_file_.reads_);
|
||||
EXPECT_EQ(0, osd_file_.writes_);
|
||||
EXPECT_EQ(12, osd_file_.size_);
|
||||
|
||||
char buffer[17];
|
||||
EXPECT_EQ(2, cache_->Read(1, 0, buffer, 10, reader_, writer_));
|
||||
EXPECT_EQ(0, strncmp(buffer, "st", 2));
|
||||
EXPECT_EQ(2, osd_file_.reads_);
|
||||
EXPECT_EQ(0, osd_file_.writes_);
|
||||
EXPECT_EQ(12, osd_file_.size_);
|
||||
|
||||
cache_->Flush(writer_);
|
||||
EXPECT_EQ(2, osd_file_.reads_);
|
||||
EXPECT_EQ(2, osd_file_.writes_);
|
||||
EXPECT_EQ(12, osd_file_.size_);
|
||||
|
||||
// Extend
|
||||
cache_->Truncate(20);
|
||||
osd_file_.Truncate(20);
|
||||
EXPECT_EQ(2, osd_file_.reads_);
|
||||
EXPECT_EQ(2, osd_file_.writes_);
|
||||
EXPECT_EQ(20, osd_file_.size_);
|
||||
|
||||
char buffer2[10];
|
||||
EXPECT_EQ(10, cache_->Read(1, 0, buffer2, 10, reader_, writer_));
|
||||
EXPECT_EQ(0, strncmp(buffer2, "st\0\0\0\0\0\0", 10));
|
||||
EXPECT_EQ(2, osd_file_.reads_);
|
||||
EXPECT_EQ(2, osd_file_.writes_);
|
||||
EXPECT_EQ(20, osd_file_.size_);
|
||||
|
||||
cache_->Flush(writer_);
|
||||
EXPECT_EQ(2, osd_file_.reads_);
|
||||
// We need not to flush out shrunk objects as the layer above us will
|
||||
// take care of it by sending a truncate to the OSD.
|
||||
EXPECT_EQ(2, osd_file_.writes_);
|
||||
EXPECT_EQ(20, osd_file_.size_);
|
||||
}
|
||||
|
||||
TEST_F(ObjectCacheTest, WriteBack) {
|
||||
cache_->Write(0, 0, "TestData", 9, reader_, writer_);
|
||||
EXPECT_EQ(1, osd_file_.reads_);
|
||||
EXPECT_EQ(0, osd_file_.writes_);
|
||||
EXPECT_EQ(0, osd_file_.size_);
|
||||
|
||||
cache_->Write(1, 0, "TestData", 9, reader_, writer_);
|
||||
EXPECT_EQ(2, osd_file_.reads_);
|
||||
EXPECT_EQ(0, osd_file_.writes_);
|
||||
EXPECT_EQ(0, osd_file_.size_);
|
||||
|
||||
cache_->Write(2, 0, "TestData", 9, reader_, writer_);
|
||||
EXPECT_EQ(3, osd_file_.reads_);
|
||||
EXPECT_EQ(1, osd_file_.writes_);
|
||||
EXPECT_EQ(9, osd_file_.size_);
|
||||
|
||||
cache_->Flush(writer_);
|
||||
EXPECT_EQ(3, osd_file_.reads_);
|
||||
EXPECT_EQ(3, osd_file_.writes_);
|
||||
EXPECT_EQ(29, osd_file_.size_);
|
||||
|
||||
// Read back in
|
||||
char buffer[10];
|
||||
EXPECT_EQ(10, cache_->Read(0, 0, buffer, 10, reader_, writer_));
|
||||
EXPECT_EQ(0, strncmp(buffer, "TestData\0\0", 10));
|
||||
EXPECT_EQ(4, osd_file_.reads_);
|
||||
EXPECT_EQ(3, osd_file_.writes_);
|
||||
EXPECT_EQ(29, osd_file_.size_);
|
||||
}
|
||||
|
||||
class ObjectCacheEndToEndTest : public ::testing::Test {
|
||||
protected:
|
||||
static const int kBlockSize = 1024 * 128;
|
||||
|
||||
virtual void SetUp() {
|
||||
util::initialize_logger(util::LEVEL_WARN);
|
||||
test_env.options.connect_timeout_s = 15;
|
||||
test_env.options.request_timeout_s = 5;
|
||||
test_env.options.retry_delay_s = 5;
|
||||
test_env.options.object_cache_size = 2;
|
||||
|
||||
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>(
|
||||
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();
|
||||
}
|
||||
|
||||
void CheckData(char* data, int buffer_size) {
|
||||
for (int i = 0; i < buffer_size; ++i) {
|
||||
ASSERT_EQ('0' + (i % 3), data[i]);
|
||||
}
|
||||
}
|
||||
void CheckDataIsNull(char* data, int buffer_size) {
|
||||
for (int i = 0; i < buffer_size; ++i) {
|
||||
ASSERT_EQ(0, data[i]);
|
||||
}
|
||||
}
|
||||
void FillData(char* data, int buffer_size) {
|
||||
for (int i = 0; i < buffer_size; ++i) {
|
||||
data[i] = '0' + (i % 3);
|
||||
}
|
||||
}
|
||||
TestEnvironment test_env;
|
||||
Volume* volume;
|
||||
FileHandle* file;
|
||||
};
|
||||
|
||||
TEST_F(ObjectCacheEndToEndTest, Persistence) {
|
||||
const size_t blocks = 5;
|
||||
const size_t buffer_size = kBlockSize * blocks;
|
||||
boost::scoped_array<char> write_buf(new char[buffer_size]);
|
||||
FillData(write_buf.get(), buffer_size);
|
||||
|
||||
EXPECT_EQ(buffer_size, file->Write(write_buf.get(), buffer_size, 0));
|
||||
ASSERT_NO_THROW(file->Close());
|
||||
|
||||
file = volume->OpenFile(
|
||||
test_env.user_credentials,
|
||||
"/test_file",
|
||||
static_cast<xtreemfs::pbrpc::SYSTEM_V_FCNTL>(
|
||||
xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_CREAT |
|
||||
xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_RDONLY));
|
||||
memset(write_buf.get(), 0, buffer_size);
|
||||
EXPECT_EQ(buffer_size, file->Read(write_buf.get(), buffer_size, 0));
|
||||
CheckData(write_buf.get(), buffer_size);
|
||||
ASSERT_NO_THROW(file->Close());
|
||||
}
|
||||
|
||||
TEST_F(ObjectCacheEndToEndTest, NormalWrite) {
|
||||
const size_t blocks = 5;
|
||||
const size_t buffer_size = kBlockSize * blocks;
|
||||
boost::scoped_array<char> write_buf(new char[buffer_size]);
|
||||
FillData(write_buf.get(), buffer_size);
|
||||
|
||||
EXPECT_EQ(0, file->Read(write_buf.get(), buffer_size, 0));
|
||||
|
||||
EXPECT_EQ(buffer_size, file->Write(write_buf.get(), buffer_size, 0));
|
||||
|
||||
EXPECT_EQ(buffer_size, file->Read(write_buf.get(), buffer_size + 5, 0));
|
||||
CheckData(write_buf.get(), buffer_size);
|
||||
|
||||
ASSERT_NO_THROW(file->Flush());
|
||||
|
||||
ASSERT_NO_THROW(file->Truncate(test_env.user_credentials, 0));
|
||||
EXPECT_EQ(0, file->Read(write_buf.get(), buffer_size, 0));
|
||||
|
||||
ASSERT_NO_THROW(file->Truncate(test_env.user_credentials, buffer_size));
|
||||
EXPECT_EQ(buffer_size, file->Read(write_buf.get(), buffer_size, 0));
|
||||
CheckDataIsNull(write_buf.get(), buffer_size);
|
||||
|
||||
file->Write(write_buf.get(), buffer_size, 0);
|
||||
ASSERT_NO_THROW(file->Close());
|
||||
|
||||
EXPECT_EQ(5 + 5, test_env.osds[0]->GetReceivedWrites().size());
|
||||
}
|
||||
|
||||
} // namespace xtreemfs
|
||||
91
cpp/test/libxtreemfs/options_test.cpp
Normal file
91
cpp/test/libxtreemfs/options_test.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2014 by Robert Schmidtke, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "libxtreemfs/options.h"
|
||||
#include "libxtreemfs/xtreemfs_exception.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
namespace xtreemfs {
|
||||
|
||||
class OptionsTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
shutdown_logger();
|
||||
}
|
||||
|
||||
xtreemfs::Options options_;
|
||||
};
|
||||
|
||||
TEST_F(OptionsTest, TestFailOnMultipleLogLevelOptions) {
|
||||
const char* n_argv[] = { "executable", "--log-level=DEBUG", "-dINFO" };
|
||||
ASSERT_THROW(
|
||||
options_.ParseCommandLine(3, const_cast<char**>(n_argv)),
|
||||
InvalidCommandLineParametersException
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(OptionsTest, TestExplicitSpecificationOverride) {
|
||||
const char* n_argv[] = {
|
||||
"executable",
|
||||
"--log-level=DEBUG",
|
||||
"-o", "-d=INFO"
|
||||
};
|
||||
options_.ParseCommandLine(4, const_cast<char**>(n_argv));
|
||||
ASSERT_EQ("DEBUG", options_.log_level_string);
|
||||
}
|
||||
|
||||
TEST_F(OptionsTest, TestExplicitAndAlternativeCombination) {
|
||||
const char* n_argv[] = {
|
||||
"executable",
|
||||
"--log-file-path=/tmp/test.log",
|
||||
"-o", "-d=INFO"
|
||||
};
|
||||
options_.ParseCommandLine(4, const_cast<char**>(n_argv));
|
||||
ASSERT_EQ("/tmp/test.log", options_.log_file_path);
|
||||
ASSERT_EQ("INFO", options_.log_level_string);
|
||||
}
|
||||
|
||||
TEST_F(OptionsTest, TestMultipleLongAlternativeOptions) {
|
||||
const char* n_argv[] = {
|
||||
"executable",
|
||||
"-o", "log-file-path=/tmp/test.log",
|
||||
"-o", "log-level=INFO"
|
||||
};
|
||||
options_.ParseCommandLine(5, const_cast<char**>(n_argv));
|
||||
ASSERT_EQ("/tmp/test.log", options_.log_file_path);
|
||||
ASSERT_EQ("INFO", options_.log_level_string);
|
||||
}
|
||||
|
||||
TEST_F(OptionsTest, TestCommaSeparatedAlternativeOptions) {
|
||||
const char* n_argv[] = {
|
||||
"executable",
|
||||
"-o", "log-file-path=/tmp/test.log,-d=INFO"
|
||||
};
|
||||
options_.ParseCommandLine(3, const_cast<char**>(n_argv));
|
||||
ASSERT_EQ("/tmp/test.log", options_.log_file_path);
|
||||
ASSERT_EQ("INFO", options_.log_level_string);
|
||||
}
|
||||
|
||||
TEST_F(OptionsTest, TestFstabExample) {
|
||||
const char* n_argv[] = {
|
||||
"executable",
|
||||
"-o", "_netdev,pkcs12-file-path=/tmp/pkcs12.p12,log-level=DEBUG"
|
||||
};
|
||||
options_.ParseCommandLine(3, const_cast<char**>(n_argv));
|
||||
ASSERT_EQ("/tmp/pkcs12.p12", options_.ssl_pkcs12_path);
|
||||
ASSERT_EQ("DEBUG", options_.log_level_string);
|
||||
}
|
||||
|
||||
} // namespace xtreemfs
|
||||
222
cpp/test/libxtreemfs/pbprpc_url_test.cpp
Normal file
222
cpp/test/libxtreemfs/pbprpc_url_test.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "libxtreemfs/pbrpc_url.h"
|
||||
#include "libxtreemfs/xtreemfs_exception.h"
|
||||
#include "util/logging.h"
|
||||
#include "xtreemfs/GlobalTypes.pb.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::pbrpc;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
namespace xtreemfs {
|
||||
|
||||
class PBRPCURLTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
|
||||
volume_name = "test";
|
||||
default_scheme = PBRPCURL::GetSchemePBRPC();
|
||||
default_port = DIR_PBRPC_PORT_DEFAULT;
|
||||
|
||||
servers.push_back("localhost");
|
||||
servers.push_back("127.0.0.1");
|
||||
servers.push_back("somehost");
|
||||
|
||||
ports.push_back(1234);
|
||||
ports.push_back(4242);
|
||||
ports.push_back(31337);
|
||||
|
||||
pbrpc_url_.reset(new PBRPCURL());
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
shutdown_logger();
|
||||
}
|
||||
|
||||
typedef list<string> ServerList;
|
||||
typedef list<uint16_t> PortList;
|
||||
|
||||
ServerList servers;
|
||||
PortList ports;
|
||||
string volume_name;
|
||||
string default_scheme;
|
||||
uint16_t default_port;
|
||||
|
||||
boost::scoped_ptr<PBRPCURL> pbrpc_url_;
|
||||
};
|
||||
|
||||
TEST_F(PBRPCURLTest, URLWithOneAddressAndVolume) {
|
||||
stringstream url_to_parse;
|
||||
url_to_parse << servers.front() << '/' << volume_name;
|
||||
pbrpc_url_->ParseURL(url_to_parse.str(), default_scheme, default_port);
|
||||
|
||||
ServiceAddresses addresses = pbrpc_url_->GetAddresses();
|
||||
|
||||
EXPECT_FALSE(addresses.empty());
|
||||
EXPECT_EQ(volume_name, pbrpc_url_->volume());
|
||||
EXPECT_EQ(PBRPCURL::GetSchemePBRPC(), pbrpc_url_->scheme());
|
||||
|
||||
stringstream expected_address;
|
||||
expected_address << "localhost:" << DIR_PBRPC_PORT_DEFAULT;
|
||||
EXPECT_EQ(expected_address.str(), addresses.GetAddresses().front());
|
||||
}
|
||||
|
||||
TEST_F(PBRPCURLTest, URLWithMultipleAddressesAndVolume) {
|
||||
// Build an URL to parse
|
||||
stringstream url_to_parse;
|
||||
ServerList::const_iterator servers_it = servers.begin();
|
||||
|
||||
for (; servers_it != servers.end(); ++servers_it) {
|
||||
if(servers_it != servers.begin()) {
|
||||
url_to_parse << ',';
|
||||
}
|
||||
url_to_parse << *servers_it;
|
||||
}
|
||||
url_to_parse << '/' << volume_name;
|
||||
|
||||
// Parse URL and get addresses
|
||||
pbrpc_url_->ParseURL(url_to_parse.str(), default_scheme, default_port);
|
||||
ServiceAddresses addresses = pbrpc_url_->GetAddresses();
|
||||
|
||||
// Check expectations
|
||||
EXPECT_EQ(servers.size(), addresses.size());
|
||||
EXPECT_EQ(volume_name, pbrpc_url_->volume());
|
||||
EXPECT_EQ(default_scheme, pbrpc_url_->scheme());
|
||||
|
||||
servers_it = servers.begin();
|
||||
stringstream expected_address;
|
||||
ServiceAddresses::Addresses services = addresses.GetAddresses();
|
||||
for(ServiceAddresses::Addresses::iterator it = services.begin();
|
||||
it != services.end();
|
||||
++it, ++servers_it) {
|
||||
expected_address.str("");
|
||||
expected_address << *servers_it << ':' << default_port;
|
||||
EXPECT_EQ(expected_address.str(), *it);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PBRPCURLTest, URLWithMultipleAddressesPortsAndVolume) {
|
||||
// Build an URL to parse
|
||||
stringstream url_to_parse;
|
||||
ServerList::const_iterator servers_it = servers.begin();
|
||||
PortList::const_iterator ports_it = ports.begin();
|
||||
|
||||
for (; servers_it != servers.end(); ++servers_it, ++ports_it) {
|
||||
if(servers_it != servers.begin()) {
|
||||
url_to_parse << ',';
|
||||
}
|
||||
url_to_parse << *servers_it << ':' << *ports_it;
|
||||
}
|
||||
url_to_parse << '/' << volume_name;
|
||||
|
||||
// Parse URL and get addresses
|
||||
pbrpc_url_->ParseURL(url_to_parse.str(), default_scheme, default_port);
|
||||
ServiceAddresses addresses = pbrpc_url_->GetAddresses();
|
||||
|
||||
// Check expectations
|
||||
EXPECT_EQ(servers.size(), addresses.size());
|
||||
EXPECT_EQ(volume_name, pbrpc_url_->volume());
|
||||
EXPECT_EQ(default_scheme, pbrpc_url_->scheme());
|
||||
|
||||
servers_it = servers.begin();
|
||||
ports_it = ports.begin();
|
||||
stringstream expected_address;
|
||||
ServiceAddresses::Addresses services = addresses.GetAddresses();
|
||||
for(ServiceAddresses::Addresses::iterator it = services.begin();
|
||||
it != services.end();
|
||||
++it, ++servers_it, ++ports_it) {
|
||||
expected_address.str("");
|
||||
expected_address << *servers_it << ':' << *ports_it;
|
||||
EXPECT_EQ(expected_address.str(), *it);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PBRPCURLTest, URLWithMultipleAddressesProtocolsPortsAndVolume) {
|
||||
// Build an URL to parse
|
||||
stringstream url_to_parse;
|
||||
ServerList::const_iterator servers_it = servers.begin();
|
||||
PortList::const_iterator ports_it = ports.begin();
|
||||
|
||||
for (; servers_it != servers.end(); ++servers_it, ++ports_it) {
|
||||
if(servers_it != servers.begin()) {
|
||||
url_to_parse << ',';
|
||||
}
|
||||
url_to_parse << default_scheme << "://" << *servers_it << ':' << *ports_it;
|
||||
}
|
||||
url_to_parse << '/' << volume_name;
|
||||
// Parse URL and get addresses
|
||||
pbrpc_url_->ParseURL(url_to_parse.str(), default_scheme, default_port);
|
||||
ServiceAddresses addresses = pbrpc_url_->GetAddresses();
|
||||
|
||||
// Check expectations
|
||||
EXPECT_EQ(servers.size(), addresses.size());
|
||||
EXPECT_EQ(volume_name, pbrpc_url_->volume());
|
||||
EXPECT_EQ(default_scheme, pbrpc_url_->scheme());
|
||||
|
||||
servers_it = servers.begin();
|
||||
ports_it = ports.begin();
|
||||
stringstream expected_address;
|
||||
ServiceAddresses::Addresses services = addresses.GetAddresses();
|
||||
for(ServiceAddresses::Addresses::iterator it = services.begin();
|
||||
it != services.end();
|
||||
++it, ++servers_it, ++ports_it) {
|
||||
expected_address.str("");
|
||||
expected_address << *servers_it << ':' << *ports_it;
|
||||
EXPECT_EQ(expected_address.str(), *it);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PBRPCURLTest, URLWithMultipleAddressesProtocolsAndVolume) {
|
||||
// Build an URL to parse
|
||||
stringstream url_to_parse;
|
||||
ServerList::const_iterator servers_it = servers.begin();
|
||||
|
||||
for (; servers_it != servers.end(); ++servers_it) {
|
||||
if(servers_it != servers.begin()) {
|
||||
url_to_parse << ',';
|
||||
}
|
||||
url_to_parse << default_scheme << "://" << *servers_it;
|
||||
}
|
||||
url_to_parse << '/' << volume_name;
|
||||
// Parse URL and get addresses
|
||||
pbrpc_url_->ParseURL(url_to_parse.str(), default_scheme, default_port);
|
||||
ServiceAddresses addresses = pbrpc_url_->GetAddresses();
|
||||
|
||||
// Check expectations
|
||||
EXPECT_EQ(servers.size(), addresses.size());
|
||||
EXPECT_EQ(volume_name, pbrpc_url_->volume());
|
||||
EXPECT_EQ(default_scheme, pbrpc_url_->scheme());
|
||||
|
||||
servers_it = servers.begin();
|
||||
stringstream expected_address;
|
||||
ServiceAddresses::Addresses services = addresses.GetAddresses();
|
||||
for(ServiceAddresses::Addresses::iterator it = services.begin();
|
||||
it != services.end();
|
||||
++it, ++servers_it) {
|
||||
expected_address.str("");
|
||||
expected_address << *servers_it << ':' << default_port;
|
||||
EXPECT_EQ(expected_address.str(), *it);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PBRPCURLTest, URLAddressesWithDifferentProtocols) {
|
||||
EXPECT_THROW({
|
||||
pbrpc_url_->ParseURL("pbrpc://localhost,pbrpcg://remote/" + volume_name,
|
||||
PBRPCURL::GetSchemePBRPC(),
|
||||
DIR_PBRPC_PORT_DEFAULT);
|
||||
}, InvalidURLException);
|
||||
}
|
||||
|
||||
} // namespace xtreemfs
|
||||
206
cpp/test/libxtreemfs/system_user_mapping_unix_test.cpp
Normal file
206
cpp/test/libxtreemfs/system_user_mapping_unix_test.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libxtreemfs/system_user_mapping_unix.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
class UserMappingUnixTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
shutdown_logger();
|
||||
}
|
||||
|
||||
SystemUserMappingUnix user_mapping_;
|
||||
};
|
||||
|
||||
// Test user functions.
|
||||
TEST_F(UserMappingUnixTest, UsernameRootIs0) {
|
||||
// Assuming the entry "root" exists.
|
||||
EXPECT_EQ(0, user_mapping_.UsernameToUID("root"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, Username1Is1) {
|
||||
// Assuming there's no user with name "1111", the number itself should be
|
||||
// returned.
|
||||
EXPECT_EQ(1111, user_mapping_.UsernameToUID("1111"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, Username2Pow32Minus1IsSame) {
|
||||
// 2^32-2 would overflow in case of int32_t but remains 2^32-1 with uint32_t.
|
||||
// 2^32-1 is the reserved -1.
|
||||
EXPECT_EQ(4294967294, user_mapping_.UsernameToUID("4294967294"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, UsernameMinus1isNobody) {
|
||||
// -1 is used by chown to tell that uid or gid should not change. However,
|
||||
// the reverse mapping is not possible and should map to nobody.
|
||||
// (uid_t)-1 = 4294967295.
|
||||
EXPECT_EQ(65534, user_mapping_.UsernameToUID("-1"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, Username2Pow32IsNobody) {
|
||||
// Out of range of uid_t.
|
||||
EXPECT_EQ(65534, user_mapping_.UsernameToUID("4294967296"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, UsernameMinus2Pow31Minus1IsNobody) {
|
||||
// Negative values should be detected as errors (except -1).
|
||||
// Even -2^31-1 which must not overflow to 2^32-1.
|
||||
EXPECT_EQ(65534, user_mapping_.UsernameToUID("-2147483649"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, Username1aIsNobody) {
|
||||
// Assuming the user "1a" does not exist.
|
||||
EXPECT_EQ(65534, user_mapping_.UsernameToUID("1a"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, UID0isRoot) {
|
||||
// Assuming the entry "root" exists.
|
||||
EXPECT_EQ("root", user_mapping_.UIDToUsername(0));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, UID1111Is1111) {
|
||||
// Assuming user with id 1111 does not exist.
|
||||
EXPECT_EQ("1111", user_mapping_.UIDToUsername(1111));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, UID2Pow32Minus2IsSame) {
|
||||
// Assuming the group "4294967294" does not exist in the system.
|
||||
// 4294967294 is the max allowed id as chown's -1 corresponds to 4294967295.
|
||||
EXPECT_EQ("4294967294", user_mapping_.UIDToUsername(4294967294));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, UID2Pow32Minus1IsMinus1) {
|
||||
// (uid_t)-1 = 4294967295.
|
||||
EXPECT_EQ("-1", user_mapping_.UIDToUsername((uid_t)-1));
|
||||
}
|
||||
|
||||
/** Tests for the range of UIDs from 0 to 2^16, if they do exist on this system
|
||||
* and check if the mapping back from the user name to the UID does work.
|
||||
*
|
||||
* In case there exists no user name for a UID, the UID itself will be
|
||||
* returned as string. Therefore, this test should work on the complete range
|
||||
* of UIDs (except for the special ID (uid_t)-1 (= 4294967295).
|
||||
*
|
||||
* We only test till 2^10 (1024) and not the complete range (4294967294). */
|
||||
TEST_F(UserMappingUnixTest, UIDsFrom0To2Pow10MapBackCorrectlyToUsernames) {
|
||||
for (uid_t uid = 0; uid <= 1024; uid++) {
|
||||
std::string username_for_uid = user_mapping_.UIDToUsername(uid);
|
||||
EXPECT_EQ(uid, user_mapping_.UsernameToUID(username_for_uid));
|
||||
}
|
||||
}
|
||||
|
||||
// Test Group functions.
|
||||
TEST_F(UserMappingUnixTest, GroupnameRootIs0) {
|
||||
// Assuming the entry "root" exists.
|
||||
EXPECT_EQ(0, user_mapping_.GroupnameToGID("root"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, Groupname1Is1) {
|
||||
// Assuming there's no user with name "1111", the number itself should be
|
||||
// returned.
|
||||
EXPECT_EQ(1111, user_mapping_.GroupnameToGID("1111"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, Groupname2Pow32Minus1IsSame) {
|
||||
// 2^32-2 would overflow in case of int32_t but remains 2^32-1 with uint32_t.
|
||||
// 2^32-1 is the reserved -1.
|
||||
EXPECT_EQ(4294967294, user_mapping_.GroupnameToGID("4294967294"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, GroupnameMinus1isNobody) {
|
||||
// -1 is used by chown to tell that gid or gid should not change. However,
|
||||
// the reverse mapping is not possible and should map to nobody.
|
||||
// (gid_t)-1 = 4294967295.
|
||||
EXPECT_EQ(65534, user_mapping_.GroupnameToGID("-1"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, Groupname2Pow32IsNobody) {
|
||||
// Out of range of gid_t.
|
||||
EXPECT_EQ(65534, user_mapping_.GroupnameToGID("4294967296"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, GroupnameMinus2Pow31Minus1IsNobody) {
|
||||
// Negative values should be detected as errors (except -1).
|
||||
// Even -2^31-1 which must not overflow to 2^32-1.
|
||||
EXPECT_EQ(65534, user_mapping_.GroupnameToGID("-2147483649"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, Groupname1aIsNobody) {
|
||||
// Assuming the user "1a" does not exist.
|
||||
EXPECT_EQ(65534, user_mapping_.GroupnameToGID("1a"));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, GID0isRoot) {
|
||||
// Assuming the entry "root" exists.
|
||||
EXPECT_EQ("root", user_mapping_.GIDToGroupname(0));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, GID1111Is1111) {
|
||||
// Assuming user with id 1111 does not exist.
|
||||
EXPECT_EQ("1111", user_mapping_.GIDToGroupname(1111));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, GID2Pow32Minus2IsSame) {
|
||||
// Assuming the group "4294967294" does not exist in the system.
|
||||
// 4294967294 is the max allowed id as chown's -1 corresponds to 4294967295.
|
||||
EXPECT_EQ("4294967294", user_mapping_.GIDToGroupname(4294967294));
|
||||
}
|
||||
|
||||
TEST_F(UserMappingUnixTest, GID2Pow32Minus1IsMinus1) {
|
||||
// (gid_t)-1 = 4294967295.
|
||||
EXPECT_EQ("-1", user_mapping_.GIDToGroupname((gid_t)-1));
|
||||
}
|
||||
|
||||
/** Tests for the range of GIDs from 0 to 2^16, if they do exist on this system
|
||||
* and check if the mapping back from the group name to the GID does work.
|
||||
*
|
||||
* In case there exists no group name for a GID, the GID itself will be
|
||||
* returned as string. Therefore, this test should work on the complete range
|
||||
* of GIDs (except for the special ID (gid_t)-1 (= 4294967295).
|
||||
*
|
||||
* We only test till 2^10 (1024) and not the complete range (4294967294). */
|
||||
TEST_F(UserMappingUnixTest, GIDsFrom0To2Pow10MapBackCorrectlyToGroupnames) {
|
||||
for (gid_t gid = 0; gid <= 1024; gid++) {
|
||||
std::string groupname_for_gid = user_mapping_.GIDToGroupname(gid);
|
||||
EXPECT_EQ(gid, user_mapping_.GroupnameToGID(groupname_for_gid));
|
||||
}
|
||||
}
|
||||
|
||||
// GetGroupnames() tests.
|
||||
|
||||
/** Test if GetGroupnames returns at least the primary group of the user and
|
||||
* its the first in list. */
|
||||
TEST_F(UserMappingUnixTest, GetGroupnamesReturnsPrimaryGroupAtFirst) {
|
||||
string primary_group_of_current_user =
|
||||
user_mapping_.GIDToGroupname(getegid());
|
||||
list<string> groupnames;
|
||||
user_mapping_.GetGroupnames(0, getegid(), getpid(), &groupnames);
|
||||
ASSERT_GE(groupnames.size(), 1);
|
||||
|
||||
EXPECT_EQ(primary_group_of_current_user,
|
||||
(*groupnames.begin()));
|
||||
}
|
||||
|
||||
#endif // !WIN32
|
||||
137
cpp/test/libxtreemfs/user_mapping_gridmap_globus_test.cpp
Normal file
137
cpp/test/libxtreemfs/user_mapping_gridmap_globus_test.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <cstdio>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "libxtreemfs/user_mapping.h"
|
||||
#include "libxtreemfs/user_mapping_gridmap_globus.h"
|
||||
#include "util/logging.h"
|
||||
#include "pbrpc/RPC.pb.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs;
|
||||
using namespace xtreemfs::pbrpc;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
class UserMappingGridmapGlobusTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
|
||||
gridmap_file_path_ = "gridmap_file_globus";
|
||||
|
||||
// Check if file already exists.
|
||||
struct stat stat_buf;
|
||||
if (!stat(gridmap_file_path_.c_str(), &stat_buf)) {
|
||||
ASSERT_FALSE("The temporary gridmap file does already exist");
|
||||
}
|
||||
|
||||
// Create a temporary gridmap file in the working directory.
|
||||
ofstream out(gridmap_file_path_.c_str());
|
||||
out << "\"/C=DE/O=GridGermany/OU=Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)/OU=CSR/CN=Michael Berlin\" root\n";
|
||||
out.close();
|
||||
ASSERT_FALSE(out.fail());
|
||||
|
||||
user_mapping_.reset(new UserMappingGridmapGlobus(
|
||||
gridmap_file_path_,
|
||||
1)); // Check every second for changes.
|
||||
user_mapping_->Start();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
user_mapping_->Stop();
|
||||
|
||||
// Delete gridmap file.
|
||||
remove(gridmap_file_path_.c_str());
|
||||
|
||||
shutdown_logger();
|
||||
atexit(google::protobuf::ShutdownProtobufLibrary);
|
||||
}
|
||||
std::string gridmap_file_path_;
|
||||
|
||||
boost::scoped_ptr<UserMapping> user_mapping_;
|
||||
};
|
||||
|
||||
TEST_F(UserMappingGridmapGlobusTest, TestBasicDNAndOUResolving) {
|
||||
string result;
|
||||
user_mapping_->LocalToGlobalUsername("root", &result);
|
||||
EXPECT_EQ("CN=Michael Berlin,OU=CSR,OU=Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB),O=GridGermany,C=DE", // NOLINT
|
||||
result);
|
||||
user_mapping_->GlobalToLocalUsername("CN=Michael Berlin,OU=CSR,OU=Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB),O=GridGermany,C=DE",
|
||||
&result);
|
||||
EXPECT_EQ("root",
|
||||
result);
|
||||
|
||||
// All OUs will be returned as list of groups of UserCredentials.
|
||||
UserCredentials uc;
|
||||
user_mapping_->GetGroupnames("root", &uc);
|
||||
ASSERT_EQ(2, uc.groups_size());
|
||||
EXPECT_EQ("CSR", uc.groups(0));
|
||||
EXPECT_EQ("Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)",
|
||||
uc.groups(1));
|
||||
|
||||
// Groups in general do not work and always return "root" or 0.
|
||||
user_mapping_->LocalToGlobalGroupname("CSR", &result);
|
||||
EXPECT_EQ("root", result);
|
||||
user_mapping_->LocalToGlobalGroupname("Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)", &result); // NOLINT
|
||||
EXPECT_EQ("root", result);
|
||||
user_mapping_->GlobalToLocalGroupname("unknowngroup", &result);
|
||||
EXPECT_EQ("root", result);
|
||||
|
||||
// List of groups is empty for unknown users.
|
||||
UserCredentials uc2;
|
||||
user_mapping_->GetGroupnames("nobody", &uc2);
|
||||
ASSERT_EQ(0, uc2.groups_size());
|
||||
}
|
||||
|
||||
TEST_F(UserMappingGridmapGlobusTest, GridmapFileReload) {
|
||||
string result;
|
||||
user_mapping_->LocalToGlobalUsername("root", &result);
|
||||
EXPECT_EQ("CN=Michael Berlin,OU=CSR,OU=Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB),O=GridGermany,C=DE", // NOLINT
|
||||
result);
|
||||
user_mapping_->GlobalToLocalUsername("CN=Michael Berlin,OU=CSR,OU=Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB),O=GridGermany,C=DE", &result); // NOLINT
|
||||
EXPECT_EQ("root", result);
|
||||
|
||||
UserCredentials uc;
|
||||
user_mapping_->GetGroupnames("root", &uc);
|
||||
ASSERT_EQ(2, uc.groups_size());
|
||||
EXPECT_EQ("CSR", uc.groups(0));
|
||||
EXPECT_EQ("Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)",
|
||||
uc.groups(1));
|
||||
|
||||
// Rewrite file with another entry.
|
||||
ofstream out(gridmap_file_path_.c_str());
|
||||
out << "\"/C=DE/O=GridGermany/OU=Dummy OU 1/CN=Dummy Username\" root\n";
|
||||
out.close();
|
||||
ASSERT_FALSE(out.fail());
|
||||
// Wait for reload.
|
||||
boost::this_thread::sleep(boost::posix_time::seconds(2));
|
||||
|
||||
// Old entry is no longer visible.
|
||||
string dn = "CN=Michael Berlin,OU=CSR,OU=Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB),O=GridGermany,C=DE"; // NOLINT
|
||||
user_mapping_->GlobalToLocalUsername(dn, &result);
|
||||
EXPECT_EQ(dn, result);
|
||||
// New entry can be seen.
|
||||
string new_dn = "CN=Dummy Username,OU=Dummy OU 1,O=GridGermany,C=DE";
|
||||
user_mapping_->LocalToGlobalUsername("root", &result);
|
||||
EXPECT_EQ(new_dn, result);
|
||||
user_mapping_->GlobalToLocalUsername(new_dn, &result);
|
||||
EXPECT_EQ("root", result);
|
||||
UserCredentials uc2;
|
||||
user_mapping_->GetGroupnames("root", &uc2);
|
||||
ASSERT_EQ(1, uc2.groups_size());
|
||||
EXPECT_EQ("Dummy OU 1", uc2.groups(0));
|
||||
}
|
||||
224
cpp/test/libxtreemfs/user_mapping_gridmap_unicore_test.cpp
Normal file
224
cpp/test/libxtreemfs/user_mapping_gridmap_unicore_test.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2014 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <cstdio>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "libxtreemfs/user_mapping.h"
|
||||
#include "libxtreemfs/user_mapping_gridmap_unicore.h"
|
||||
#include "util/logging.h"
|
||||
#include "pbrpc/RPC.pb.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs;
|
||||
using namespace xtreemfs::util;
|
||||
using namespace xtreemfs::pbrpc;
|
||||
|
||||
class UserMappingGridmapUnicoreTestGeneral : public ::testing::Test {
|
||||
protected:
|
||||
static const int kWaittimeForReload = 2;
|
||||
|
||||
virtual string GetGridmapFileContent() = 0;
|
||||
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
|
||||
gridmap_file_path_ = "gridmap_file_unicore";
|
||||
|
||||
// Check if file already exists.
|
||||
struct stat stat_buf;
|
||||
if (!stat(gridmap_file_path_.c_str(), &stat_buf)) {
|
||||
ASSERT_FALSE("The temporary gridmap file does already exist");
|
||||
}
|
||||
|
||||
// Create a temporary gridmap file in the working directory.
|
||||
ofstream out(gridmap_file_path_.c_str());
|
||||
out << GetGridmapFileContent();
|
||||
out.close();
|
||||
ASSERT_FALSE(out.fail());
|
||||
|
||||
user_mapping_.reset(new UserMappingGridmapUnicore(
|
||||
gridmap_file_path_,
|
||||
1)); // Check every second for changes.
|
||||
user_mapping_->Start();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
user_mapping_->Stop();
|
||||
|
||||
// Delete gridmap file.
|
||||
remove(gridmap_file_path_.c_str());
|
||||
|
||||
shutdown_logger();
|
||||
atexit(google::protobuf::ShutdownProtobufLibrary);
|
||||
}
|
||||
|
||||
std::string gridmap_file_path_;
|
||||
|
||||
boost::scoped_ptr<UserMapping> user_mapping_;
|
||||
};
|
||||
|
||||
class UserMappingGridmapUnicore6Test
|
||||
: public UserMappingGridmapUnicoreTestGeneral {
|
||||
private:
|
||||
virtual string GetGridmapFileContent() {
|
||||
return "225;zib;root:dgms0006:dgls0050;user;mosgrid:lifescience;CN=Patrick Schaefer,OU=CSR,OU=Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB),O=GridGermany,C=DE\n"; // NOLINT
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(UserMappingGridmapUnicore6Test, TestBasicDNAndOUResolving) {
|
||||
string dn = "CN=Patrick Schaefer,OU=CSR,OU=Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB),O=GridGermany,C=DE"; // NOLINT
|
||||
string result;
|
||||
user_mapping_->LocalToGlobalUsername("root", &result);
|
||||
EXPECT_EQ(dn, result);
|
||||
user_mapping_->GlobalToLocalUsername(dn, &result);
|
||||
EXPECT_EQ("root", result);
|
||||
|
||||
// All OUs will be returned as list of groups.
|
||||
UserCredentials uc;
|
||||
user_mapping_->GetGroupnames("root", &uc);
|
||||
ASSERT_EQ(2, uc.groups_size());
|
||||
EXPECT_EQ("CSR", uc.groups(0));
|
||||
EXPECT_EQ("Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)",
|
||||
uc.groups(1));
|
||||
|
||||
// Groups in general do not work and always return "root" or 0.
|
||||
user_mapping_->LocalToGlobalGroupname("CSR", &result);
|
||||
EXPECT_EQ("root", result);
|
||||
user_mapping_->LocalToGlobalGroupname("Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)", &result); // NOLINT
|
||||
EXPECT_EQ("root", result);
|
||||
user_mapping_->GlobalToLocalGroupname("unknowngroup", &result);
|
||||
EXPECT_EQ("root", result);
|
||||
|
||||
// List of groups is empty for unknown users.
|
||||
UserCredentials uc2;
|
||||
user_mapping_->GetGroupnames("nobody", &uc2);
|
||||
ASSERT_EQ(0, uc2.groups_size());
|
||||
}
|
||||
|
||||
TEST_F(UserMappingGridmapUnicore6Test, GridmapFileReload) {
|
||||
string dn = "CN=Patrick Schaefer,OU=CSR,OU=Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB),O=GridGermany,C=DE"; // NOLINT
|
||||
|
||||
string result;
|
||||
user_mapping_->LocalToGlobalUsername("root", &result);
|
||||
EXPECT_EQ(dn, result);
|
||||
user_mapping_->GlobalToLocalUsername(dn, &result);
|
||||
EXPECT_EQ("root", result);
|
||||
|
||||
UserCredentials uc;
|
||||
user_mapping_->GetGroupnames("root", &uc);
|
||||
ASSERT_EQ(2, uc.groups_size());
|
||||
EXPECT_EQ("CSR", uc.groups(0));
|
||||
EXPECT_EQ("Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)",
|
||||
uc.groups(1));
|
||||
|
||||
// Rewrite file with another entry.
|
||||
ofstream out(gridmap_file_path_.c_str());
|
||||
out << "225;zib;root:dgms0006:dgls0050;user;mosgrid:lifescience;CN=Dummy Username,OU=Dummy OU 1,O=GridGermany,C=DE\n"; // NOLINT
|
||||
out.close();
|
||||
ASSERT_FALSE(out.fail());
|
||||
// Wait for reload.
|
||||
boost::this_thread::sleep(boost::posix_time::seconds(kWaittimeForReload));
|
||||
|
||||
// Old entry is no longer visible.
|
||||
user_mapping_->GlobalToLocalUsername(dn, &result);
|
||||
EXPECT_EQ(dn, result);
|
||||
// New entry can be seen.
|
||||
string new_dn = "CN=Dummy Username,OU=Dummy OU 1,O=GridGermany,C=DE";
|
||||
user_mapping_->LocalToGlobalUsername("root", &result);
|
||||
EXPECT_EQ(new_dn, result);
|
||||
user_mapping_->GlobalToLocalUsername(new_dn, &result);
|
||||
EXPECT_EQ("root", result);
|
||||
UserCredentials uc2;
|
||||
user_mapping_->GetGroupnames("root", &uc2);
|
||||
ASSERT_EQ(1, uc2.groups_size());
|
||||
EXPECT_EQ("Dummy OU 1", uc2.groups(0));
|
||||
}
|
||||
|
||||
// Test for Unicore Version < 6.
|
||||
class UserMappingGridmapUnicoreTest
|
||||
: public UserMappingGridmapUnicoreTestGeneral {
|
||||
private:
|
||||
virtual string GetGridmapFileContent() {
|
||||
return "root:dgms0006=CN=Patrick Schaefer,OU=CSR,O=GridGermany,C=DE\n";
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(UserMappingGridmapUnicoreTest, TestBasicDNAndOUResolving) {
|
||||
string dn = "CN=Patrick Schaefer,OU=CSR,O=GridGermany,C=DE";
|
||||
|
||||
string result;
|
||||
user_mapping_->LocalToGlobalUsername("root", &result);
|
||||
EXPECT_EQ(dn, result);
|
||||
user_mapping_->GlobalToLocalUsername(dn, &result);
|
||||
EXPECT_EQ("root", result);
|
||||
|
||||
// All OUs will be returned as list of groups.
|
||||
UserCredentials uc;
|
||||
user_mapping_->GetGroupnames("root", &uc);
|
||||
ASSERT_EQ(1, uc.groups_size());
|
||||
EXPECT_EQ("CSR", uc.groups(0));
|
||||
|
||||
// Groups in general do not work and always return "root" or 0.
|
||||
user_mapping_->LocalToGlobalGroupname("CSR", &result);
|
||||
EXPECT_EQ("root", result);
|
||||
user_mapping_->LocalToGlobalGroupname("Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)", &result); // NOLINT
|
||||
EXPECT_EQ("root", result);
|
||||
user_mapping_->GlobalToLocalGroupname("unknowngroup", &result);
|
||||
EXPECT_EQ("root", result);
|
||||
|
||||
// List of groups is empty for unknown users.
|
||||
UserCredentials uc2;
|
||||
user_mapping_->GetGroupnames("nobody", &uc2);
|
||||
ASSERT_EQ(0, uc2.groups_size());
|
||||
}
|
||||
|
||||
TEST_F(UserMappingGridmapUnicoreTest, GridmapFileReload) {
|
||||
string dn = "CN=Patrick Schaefer,OU=CSR,O=GridGermany,C=DE";
|
||||
|
||||
string result;
|
||||
user_mapping_->LocalToGlobalUsername("root", &result);
|
||||
EXPECT_EQ(dn, result);
|
||||
user_mapping_->GlobalToLocalUsername(dn, &result);
|
||||
EXPECT_EQ("root", result);
|
||||
|
||||
UserCredentials uc;
|
||||
user_mapping_->GetGroupnames("root", &uc);
|
||||
ASSERT_EQ(1, uc.groups_size());
|
||||
EXPECT_EQ("CSR", uc.groups(0));
|
||||
|
||||
// Rewrite file with another entry.
|
||||
ofstream out(gridmap_file_path_.c_str());
|
||||
out << "root:dgms0006=CN=Dummy Username,OU=Dummy OU 1,O=GridGermany,C=DE\n"; // NOLINT
|
||||
out.close();
|
||||
ASSERT_FALSE(out.fail());
|
||||
// Wait for reload.
|
||||
boost::this_thread::sleep(boost::posix_time::seconds(kWaittimeForReload));
|
||||
|
||||
// Old entry is no longer visible.
|
||||
user_mapping_->GlobalToLocalUsername(dn, &result);
|
||||
EXPECT_EQ(dn, result);
|
||||
// New entry can be seen.
|
||||
string new_dn = "CN=Dummy Username,OU=Dummy OU 1,O=GridGermany,C=DE";
|
||||
user_mapping_->LocalToGlobalUsername("root", &result);
|
||||
EXPECT_EQ(new_dn, result);
|
||||
user_mapping_->GlobalToLocalUsername(new_dn, &result);
|
||||
EXPECT_EQ("root", result);
|
||||
UserCredentials uc2;
|
||||
user_mapping_->GetGroupnames("root", &uc2);
|
||||
ASSERT_EQ(1, uc2.groups_size());
|
||||
EXPECT_EQ("Dummy OU 1", uc2.groups(0));
|
||||
}
|
||||
337
cpp/test/libxtreemfs/uuid_iterator_test.cpp
Normal file
337
cpp/test/libxtreemfs/uuid_iterator_test.cpp
Normal file
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
|
||||
* 2012 by Matthias Noack, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "libxtreemfs/stripe_translator.h"
|
||||
#include "libxtreemfs/uuid_container.h"
|
||||
#include "libxtreemfs/uuid_item.h"
|
||||
#include "libxtreemfs/container_uuid_iterator.h"
|
||||
#include "libxtreemfs/simple_uuid_iterator.h"
|
||||
#include "libxtreemfs/xtreemfs_exception.h"
|
||||
#include "util/logging.h"
|
||||
#include "xtreemfs/GlobalTypes.pb.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
namespace xtreemfs {
|
||||
|
||||
// factory function, works fine with all default constructible iterator types
|
||||
template<class IteratorType>
|
||||
UUIDIterator* CreateUUIDIterator() {
|
||||
return new IteratorType();
|
||||
}
|
||||
|
||||
// functor to encapsulate different uuid adding mechanisms
|
||||
template<class IteratorType>
|
||||
struct UUIDAdder;
|
||||
|
||||
template<>
|
||||
struct UUIDAdder<SimpleUUIDIterator> {
|
||||
void operator()(UUIDIterator* it, string uuid) {
|
||||
static_cast<SimpleUUIDIterator*>(it)->AddUUID(uuid);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct UUIDAdder<ContainerUUIDIterator> {
|
||||
void operator()(UUIDIterator* it, string uuid) {
|
||||
created_items_.push_back(new UUIDItem(uuid));
|
||||
// safe downcast here
|
||||
static_cast<ContainerUUIDIterator*>(it)->AddUUIDItem(created_items_.back());
|
||||
}
|
||||
|
||||
typedef vector<UUIDItem*> ItemPtrList;
|
||||
|
||||
~UUIDAdder() {
|
||||
for (ItemPtrList::iterator it = created_items_.begin();
|
||||
it != created_items_.end();
|
||||
++it) {
|
||||
delete *it;
|
||||
}
|
||||
created_items_.clear();
|
||||
}
|
||||
private:
|
||||
vector<UUIDItem*> created_items_;
|
||||
};
|
||||
|
||||
|
||||
template<class IteratorType>
|
||||
class UUIDIteratorTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
|
||||
uuid_iterator_.reset(CreateUUIDIterator<IteratorType>());
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
shutdown_logger();
|
||||
atexit(google::protobuf::ShutdownProtobufLibrary);
|
||||
}
|
||||
|
||||
boost::scoped_ptr<UUIDIterator> uuid_iterator_;
|
||||
UUIDAdder<IteratorType> adder_;
|
||||
};
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST
|
||||
|
||||
using testing::Types;
|
||||
|
||||
typedef Types<SimpleUUIDIterator, ContainerUUIDIterator> Implementations;
|
||||
|
||||
TYPED_TEST_CASE(UUIDIteratorTest, Implementations);
|
||||
|
||||
TYPED_TEST(UUIDIteratorTest, ListWithOneUUID) {
|
||||
string uuid1 = "uuid1";
|
||||
string current_uuid;
|
||||
|
||||
this->adder_(this->uuid_iterator_.get(), uuid1);
|
||||
this->uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid1, current_uuid);
|
||||
|
||||
// If there is only one UUID and it fails, there is no other choice and it
|
||||
// should be always returned.
|
||||
for (int i = 0; i < 2; i++) {
|
||||
this->uuid_iterator_->MarkUUIDAsFailed(current_uuid);
|
||||
this->uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid1, current_uuid);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(UUIDIteratorTest, ClearLeavesEmptyList) {
|
||||
string uuid1 = "uuid1";
|
||||
string uuid2 = "uuid2";
|
||||
this->adder_(this->uuid_iterator_.get(), uuid1);
|
||||
this->adder_(this->uuid_iterator_.get(), uuid2);
|
||||
|
||||
// Clear the list.
|
||||
this->uuid_iterator_->Clear();
|
||||
|
||||
// There should be no element left and GetUUID should fail.
|
||||
string current_uuid;
|
||||
EXPECT_THROW({this->uuid_iterator_->GetUUID(¤t_uuid);},
|
||||
UUIDIteratorListIsEmpyException);
|
||||
}
|
||||
|
||||
TYPED_TEST(UUIDIteratorTest, ResetAfterEndOfList) {
|
||||
string uuid1 = "uuid1";
|
||||
string uuid2 = "uuid2";
|
||||
string current_uuid;
|
||||
|
||||
// Fill iterator with two UUIDs.
|
||||
this->adder_(this->uuid_iterator_.get(), uuid1);
|
||||
this->uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid1, current_uuid);
|
||||
|
||||
this->adder_(this->uuid_iterator_.get(), uuid2);
|
||||
// No entry is marked as failed yet, the first UUID is still available.
|
||||
this->uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid1, current_uuid);
|
||||
|
||||
// Mark the current entry (uuid1) as failed. uuid2 now current?
|
||||
this->uuid_iterator_->MarkUUIDAsFailed(uuid1);
|
||||
this->uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid2, current_uuid);
|
||||
|
||||
// Mark uuid1 again as failed - should have no consequences.
|
||||
this->uuid_iterator_->MarkUUIDAsFailed(uuid1);
|
||||
this->uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid2, current_uuid);
|
||||
|
||||
// Also mark uuid2 as failed now. Now all entries have failed. As we did reach
|
||||
// the end of the list, the status of all entries should be reset and set to
|
||||
// the first entry in the list.
|
||||
this->uuid_iterator_->MarkUUIDAsFailed(uuid2);
|
||||
for (list<UUIDItem*>::iterator it
|
||||
= this->uuid_iterator_->uuids_.begin();
|
||||
it != this->uuid_iterator_->uuids_.end();
|
||||
++it) {
|
||||
EXPECT_FALSE((*it)->IsFailed());
|
||||
}
|
||||
this->uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid1, current_uuid);
|
||||
}
|
||||
|
||||
TYPED_TEST(UUIDIteratorTest, SetCurrentUUID) {
|
||||
string uuid1 = "uuid1";
|
||||
string uuid2 = "uuid2";
|
||||
string uuid3 = "uuid3";
|
||||
string current_uuid;
|
||||
|
||||
this->adder_(this->uuid_iterator_.get(), uuid1);
|
||||
this->adder_(this->uuid_iterator_.get(), uuid2);
|
||||
this->adder_(this->uuid_iterator_.get(), uuid3);
|
||||
|
||||
// First UUID is current.
|
||||
this->uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid1, current_uuid);
|
||||
|
||||
// Set third as current one.
|
||||
this->uuid_iterator_->SetCurrentUUID(uuid3);
|
||||
this->uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid3, current_uuid);
|
||||
|
||||
// Fail the third (and last one): current UUID should be the first again.
|
||||
this->uuid_iterator_->MarkUUIDAsFailed(uuid3);
|
||||
this->uuid_iterator_->GetUUID(¤t_uuid);
|
||||
for (list<UUIDItem*>::iterator it
|
||||
= this->uuid_iterator_->uuids_.begin();
|
||||
it != this->uuid_iterator_->uuids_.end();
|
||||
++it) {
|
||||
EXPECT_FALSE((*it)->IsFailed());
|
||||
}
|
||||
EXPECT_EQ(uuid1, current_uuid);
|
||||
}
|
||||
|
||||
TYPED_TEST(UUIDIteratorTest, DebugString) {
|
||||
string uuid1 = "uuid1";
|
||||
string uuid2 = "uuid2";
|
||||
string uuid3 = "uuid3";
|
||||
|
||||
EXPECT_EQ("[ ]", this->uuid_iterator_->DebugString());
|
||||
|
||||
this->adder_(this->uuid_iterator_.get(), uuid1);
|
||||
EXPECT_EQ("[ [ uuid1, 0] ]", this->uuid_iterator_->DebugString());
|
||||
|
||||
this->adder_(this->uuid_iterator_.get(), uuid2);
|
||||
EXPECT_EQ("[ [ uuid1, 0], [ uuid2, 0] ]", this->uuid_iterator_->DebugString());
|
||||
|
||||
this->adder_(this->uuid_iterator_.get(), uuid3);
|
||||
EXPECT_EQ("[ [ uuid1, 0], [ uuid2, 0], [ uuid3, 0] ]", this->uuid_iterator_->DebugString());
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST
|
||||
|
||||
// Tests for SimpleUUIDIterator
|
||||
|
||||
class SimpleUUIDIteratorTest : public UUIDIteratorTest<SimpleUUIDIterator> {
|
||||
public:
|
||||
void SetUp() {
|
||||
UUIDIteratorTest<SimpleUUIDIterator>::SetUp();
|
||||
simple_uuid_iterator_ =
|
||||
static_cast<SimpleUUIDIterator*>(uuid_iterator_.get());
|
||||
}
|
||||
protected:
|
||||
SimpleUUIDIterator* simple_uuid_iterator_;
|
||||
};
|
||||
|
||||
TEST_F(SimpleUUIDIteratorTest, LaterAddsDoNotBreakIterator) {
|
||||
string uuid1 = "uuid1";
|
||||
string uuid2 = "uuid2";
|
||||
string uuid3 = "uuid3";
|
||||
string current_uuid;
|
||||
|
||||
this->adder_(this->uuid_iterator_.get(), uuid1);
|
||||
this->adder_(this->uuid_iterator_.get(), uuid2);
|
||||
|
||||
// Mark first uuid as failed and the second takes over.
|
||||
uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid1, current_uuid);
|
||||
uuid_iterator_->MarkUUIDAsFailed(uuid1);
|
||||
uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid2, current_uuid);
|
||||
|
||||
// Add a third uuid which should be the next element if the second does fail.
|
||||
this->adder_(this->uuid_iterator_.get(), uuid3);
|
||||
uuid_iterator_->MarkUUIDAsFailed(uuid2);
|
||||
uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid3, current_uuid);
|
||||
|
||||
// After all uuids have failed, the first will be returned again.
|
||||
uuid_iterator_->MarkUUIDAsFailed(uuid3);
|
||||
uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid1, current_uuid);
|
||||
}
|
||||
|
||||
TEST_F(SimpleUUIDIteratorTest, SetCurrentUUIDAddsUnknownUUID) {
|
||||
string uuid1 = "uuid1";
|
||||
string current_uuid;
|
||||
|
||||
// UUID1 not added so far. Setting it will automatically add it.
|
||||
uuid_iterator_->SetCurrentUUID(uuid1);
|
||||
uuid_iterator_->GetUUID(¤t_uuid);
|
||||
EXPECT_EQ(uuid1, current_uuid);
|
||||
}
|
||||
|
||||
// Tests for ContainerUUIDIterator
|
||||
|
||||
class ContainerUUIDIteratorTest
|
||||
: public UUIDIteratorTest<ContainerUUIDIterator> {};
|
||||
|
||||
TEST_F(ContainerUUIDIteratorTest, CreateContainerAndGetUUID) {
|
||||
// Create container from XLocList
|
||||
pbrpc::XLocSet xlocs;
|
||||
pbrpc::StripingPolicyType type = pbrpc::STRIPING_POLICY_RAID0;
|
||||
const int replicaCount = 3;
|
||||
stringstream sstream;
|
||||
|
||||
for (int i = 0; i < replicaCount; ++i) {
|
||||
pbrpc::Replica* replica = xlocs.add_replicas();
|
||||
const int stripe_width = i + 2;
|
||||
|
||||
for (int j = 0; j < stripe_width; ++j) {
|
||||
sstream.str("");
|
||||
sstream << "uuid" << i << j;
|
||||
replica->add_osd_uuids(sstream.str());
|
||||
replica->mutable_striping_policy()->set_type(type);
|
||||
replica->mutable_striping_policy()->set_stripe_size(128); // kb
|
||||
replica->mutable_striping_policy()->set_width(stripe_width);
|
||||
}
|
||||
}
|
||||
|
||||
// get all striping policies
|
||||
StripeTranslator::PolicyContainer striping_policies;
|
||||
for (int i = 0; i < xlocs.replicas_size(); ++i) {
|
||||
striping_policies.push_back(&(xlocs.replicas(i).striping_policy()));
|
||||
}
|
||||
|
||||
boost::shared_ptr<UUIDContainer> uuid_container =
|
||||
boost::make_shared<UUIDContainer>(xlocs);
|
||||
|
||||
// NOTE: We assume that all replicas use the same striping policy type and
|
||||
// that all replicas use the same stripe size.
|
||||
boost::scoped_ptr<StripeTranslator> translator(new StripeTranslatorRaid0());
|
||||
// Map offset to corresponding OSDs.
|
||||
std::vector<ReadOperation> operations;
|
||||
off_t read_offsets[] = {0, 128 * 1024};
|
||||
|
||||
for (int i = 0; i < sizeof(read_offsets) / sizeof(off_t); ++i) {
|
||||
operations.clear();
|
||||
translator->TranslateReadRequest(NULL,
|
||||
128 * 1024,
|
||||
read_offsets[i],
|
||||
striping_policies,
|
||||
&operations);
|
||||
|
||||
// Create a UUIDIterator for a specific set of offsets
|
||||
boost::scoped_ptr<ContainerUUIDIterator> uuid_iterator(
|
||||
new ContainerUUIDIterator(uuid_container,
|
||||
operations[0].osd_offsets));
|
||||
|
||||
// check results
|
||||
string actual;
|
||||
for (int j = 0; j < replicaCount; ++j) {
|
||||
uuid_iterator->GetUUID(&actual);
|
||||
uuid_iterator->MarkUUIDAsFailed(actual);
|
||||
sstream.str("");
|
||||
sstream << "uuid" << j << operations[0].osd_offsets[j];
|
||||
EXPECT_EQ(sstream.str(), actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xtreemfs
|
||||
1042
cpp/test/libxtreemfs/volume_implementation_test.cpp
Normal file
1042
cpp/test/libxtreemfs/volume_implementation_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1199
cpp/test/rpc/client_ssl_test.cpp
Normal file
1199
cpp/test/rpc/client_ssl_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
167
cpp/test/rpc/client_test.cpp
Normal file
167
cpp/test/rpc/client_test.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#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/client_implementation.h"
|
||||
#include "libxtreemfs/options.h"
|
||||
#include "libxtreemfs/uuid_resolver.h"
|
||||
#include "libxtreemfs/volume.h"
|
||||
#include "libxtreemfs/xtreemfs_exception.h"
|
||||
#include "rpc/client.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::pbrpc;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
namespace xtreemfs {
|
||||
namespace rpc {
|
||||
|
||||
class ClientTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
initialize_logger(LEVEL_WARN);
|
||||
|
||||
ASSERT_TRUE(test_env.Start());
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
test_env.Stop();
|
||||
}
|
||||
|
||||
TestEnvironment test_env;
|
||||
};
|
||||
|
||||
class ClientTestFastTimeout : public ClientTest {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
test_env.options.max_tries = 1;
|
||||
test_env.options.connect_timeout_s = 1;
|
||||
test_env.options.request_timeout_s = 1;
|
||||
|
||||
ClientTest::SetUp();
|
||||
}
|
||||
};
|
||||
|
||||
class ClientTestFastLingerTimeoutConnectTimeout : public ClientTest {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
test_env.options.linger_timeout_s = 1;
|
||||
test_env.options.request_timeout_s = 1;
|
||||
test_env.options.max_tries = 1;
|
||||
|
||||
// We set an address which definitely won't work.
|
||||
test_env.options.service_addresses = ServiceAddresses("130.73.78.255:80");
|
||||
|
||||
ClientTest::SetUp();
|
||||
}
|
||||
};
|
||||
|
||||
class ClientTestFastLingerTimeout : public ClientTest {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
test_env.options.linger_timeout_s = 1;
|
||||
test_env.options.request_timeout_s = 1;
|
||||
|
||||
ClientTest::SetUp();
|
||||
}
|
||||
};
|
||||
|
||||
class ClientTestDropConnection : public ClientTest {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
test_env.options.max_tries = 1;
|
||||
test_env.options.connect_timeout_s = 1;
|
||||
test_env.options.request_timeout_s = 1;
|
||||
|
||||
test_env.dir->DropConnection();
|
||||
|
||||
ClientTest::SetUp();
|
||||
}
|
||||
};
|
||||
|
||||
/** Is a timed out request successfully aborted? */
|
||||
TEST_F(ClientTestFastTimeout, TimeoutHandling) {
|
||||
xtreemfs::ClientImplementation* impl =
|
||||
dynamic_cast<xtreemfs::ClientImplementation*>(test_env.client.get());
|
||||
ASSERT_TRUE(impl != NULL);
|
||||
test_env.dir->AddDropRule(new DropNRule(1));
|
||||
|
||||
EXPECT_NO_THROW({
|
||||
string exception_text;
|
||||
try {
|
||||
string unused_string;
|
||||
impl->GetUUIDResolver()->VolumeNameToMRCUUID("test", &unused_string);
|
||||
} catch (const IOException& exception) {
|
||||
exception_text = exception.what();
|
||||
}
|
||||
EXPECT_TRUE(exception_text.find("Request timed out") != string::npos);
|
||||
});
|
||||
}
|
||||
|
||||
/** A request fails if the connection attempt was dropped. */
|
||||
TEST_F(ClientTestDropConnection, ConnectionTimeout) {
|
||||
xtreemfs::ClientImplementation* impl =
|
||||
dynamic_cast<xtreemfs::ClientImplementation*>(test_env.client.get());
|
||||
ASSERT_TRUE(impl != NULL);
|
||||
EXPECT_NO_THROW({
|
||||
string exception_text;
|
||||
try {
|
||||
string unused_string;
|
||||
impl->GetUUIDResolver()->VolumeNameToMRCUUID("test", &unused_string);
|
||||
} catch (const IOException& exception) {
|
||||
exception_text = exception.what();
|
||||
}
|
||||
EXPECT_TRUE(exception_text.find("Request timed out") != string::npos);
|
||||
});
|
||||
}
|
||||
|
||||
/** Inactive connections shall be successfully closed. */
|
||||
TEST_F(ClientTestFastLingerTimeout, LingerTests) {
|
||||
xtreemfs::ClientImplementation* impl =
|
||||
dynamic_cast<xtreemfs::ClientImplementation*>(test_env.client.get());
|
||||
ASSERT_TRUE(impl != NULL);
|
||||
string unused_string;
|
||||
impl->GetUUIDResolver()->VolumeNameToMRCUUID("test", &unused_string);
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::seconds(2));
|
||||
|
||||
EXPECT_EQ(0, impl->network_client_->connections_.size());
|
||||
}
|
||||
|
||||
/** Connect timeout callbacks (which are executed after deleting
|
||||
* a xtreemfs::rpc::ClientConnection object due to an expired
|
||||
* linger timeout) do not result in a segmentation fault. */
|
||||
TEST_F(ClientTestFastLingerTimeoutConnectTimeout, LingerTests) {
|
||||
xtreemfs::ClientImplementation* impl =
|
||||
dynamic_cast<xtreemfs::ClientImplementation*>(test_env.client.get());
|
||||
ASSERT_TRUE(impl != NULL);
|
||||
|
||||
// Request will fail due to a connection timeout.
|
||||
EXPECT_THROW({
|
||||
string unused_string;
|
||||
impl->GetUUIDResolver()->VolumeNameToMRCUUID("test", &unused_string);
|
||||
}, IOException);
|
||||
|
||||
// Do not race with handleTimeout() which is removing
|
||||
// the client connection due to the expired linger timeout.
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(50));
|
||||
|
||||
// At this point the connection must have been deleted
|
||||
// due to the very low linger timeout.
|
||||
EXPECT_EQ(0, impl->network_client_->connections_.size());
|
||||
}
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace xtreemfs
|
||||
Reference in New Issue
Block a user