Commit fd952bb6 authored by Eric Cano's avatar Eric Cano
Browse files

Enabled rados based unitests for scheduler and scheduler database unit test.

Added a list method for the backends so we can clean up the rados store before running each unit test, which expects a fresh store.
Added a new command line tool to list the contents of the backends.
parent cb707179
......@@ -19,6 +19,7 @@
#pragma once
#include <string>
#include <list>
namespace cta { namespace objectstore {
......@@ -63,6 +64,12 @@ public:
*/
virtual bool exists(std::string name) = 0;
/**
* Lists all objects
* @return list of all object names
*/
virtual std::list<std::string> list() = 0;
/**
* RAII class holding locks
*/
......
......@@ -101,6 +101,15 @@ bool BackendRados::exists(std::string name) {
}
}
std::list<std::string> BackendRados::list() {
std::list<std::string> ret;
for (auto o=m_radosCtx.nobjects_begin(); o!=m_radosCtx.nobjects_end(); o++) {
ret.push_back(o->get_oid());
}
return ret;
}
void BackendRados::ScopedLock::release() {
if (!m_lockSet) return;
cta::exception::Errnum::throwOnReturnedErrno(
......
......@@ -54,6 +54,8 @@ public:
virtual bool exists(std::string name);
virtual std::list<std::string> list();
class ScopedLock: public Backend::ScopedLock {
friend class BackendRados;
public:
......
......@@ -19,6 +19,7 @@
#include "BackendVFS.hpp"
#include "common/exception/Errnum.hpp"
#include "common/Utils.hpp"
#include "tapeserver/castor/tape/tapeserver/utils/Regex.hpp"
#include <fstream>
#include <stdlib.h>
......@@ -31,6 +32,7 @@
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <dirent.h>
#undef DEBUG_PRINT_LOGS
#ifdef DEBUG_PRINT_LOGS
#include <iostream>
......@@ -175,6 +177,21 @@ bool BackendVFS::exists(std::string name) {
return (stat(path.c_str(), &buffer)==0 && stat(lockPath.c_str(), &buffer)==0);
}
std::list<std::string> BackendVFS::list() {
std::list<std::string> ret;
// We should not list ., .. and the .<object>.lock files
castor::tape::utils::Regex re("^(\\..+\\.lock|\\.{1,2})$");
::DIR * dir = ::opendir(m_root.c_str());
cta::exception::Errnum::throwOnNull(dir);
while (struct ::dirent * ent=::readdir(dir)) {
if (re.exec(ent->d_name).empty()) {
ret.push_back(ent->d_name);
}
}
return ret;
}
BackendVFS::Parameters* BackendVFS::getParams() {
std::unique_ptr<Parameters> ret(new Parameters);
......
......@@ -69,6 +69,8 @@ public:
virtual bool exists(std::string name);
virtual std::list<std::string> list();
class ScopedLock: public Backend::ScopedLock {
friend class BackendVFS;
public:
......
......@@ -46,4 +46,8 @@ target_link_libraries(ctaobjectstoreunittests
add_executable(makeMinimalVFS makeMinimalVFS.cpp)
target_link_libraries(makeMinimalVFS
protobuf CTAObjectStore ctacommon)
\ No newline at end of file
protobuf CTAObjectStore ctacommon)
add_executable(listObjectStore listObjectStore.cpp)
target_link_libraries(listObjectStore
protobuf CTAObjectStore ctacommon)
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* This program will create a VFS backend for the object store and populate
* it with the minimum elements (the root entry). The program will then print out
* the path the backend store and exit
*/
#include "BackendVFS.hpp"
#include "BackendFactory.hpp"
#include "RootEntry.hpp"
#include "Agent.hpp"
#include <iostream>
#include <stdexcept>
int main(int argc, char ** argv) {
try {
std::unique_ptr<cta::objectstore::Backend> be;
if (1 == argc) {
be.reset(new cta::objectstore::BackendVFS);
} else if (2 == argc) {
be.reset(cta::objectstore::BackendFactory::createBackend(argv[1]).release());
} else {
throw std::runtime_error("Wrong number of arguments: expected 0 or 1");
}
// If the backend is a VFS, make sure we don't delete it on exit.
// If not, nevermind.
try {
dynamic_cast<cta::objectstore::BackendVFS &>(*be).noDeleteOnExit();
} catch (std::bad_cast &){}
std::cout << "Object store path: " << be->getParams()->toURL() << std::endl;
auto l = be->list();
for (auto o=l.begin(); o!=l.end(); o++) {
std::cout << *o << std::endl;
}
} catch (std::exception & e) {
std::cerr << "Failed to initialise the root entry in a new VFS backend store"
<< std::endl << e.what() << std::endl;
}
}
\ No newline at end of file
......@@ -29,6 +29,9 @@
#include "objectstore/RootEntry.hpp"
#include "objectstore/Agent.hpp"
#include "objectstore/BackendVFS.hpp"
#include "objectstore/BackendRados.hpp"
#include "objectstore/BackendFactory.hpp"
#include <memory>
namespace cta {
......@@ -46,36 +49,9 @@ namespace {
template <class BackendType>
class OStoreDBWrapper: public SchedulerDatabase {
public:
OStoreDBWrapper(const std::string &context): m_backend(),
m_OStoreDB(m_backend), m_agent(m_backend) {
// We need to populate the root entry before using.
objectstore::RootEntry re(m_backend);
re.initialize();
re.insert();
objectstore::ScopedExclusiveLock rel(re);
re.fetch();
m_agent.generateName("OStoreDBFactory");
m_agent.initialize();
objectstore::CreationLog cl(cta::UserIdentity(1111, 1111), "systemhost",
time(NULL), "Initial creation of the object store structures");
re.addOrGetAgentRegisterPointerAndCommit(m_agent,cl);
rel.release();
m_agent.insertAndRegisterSelf();
rel.lock(re);
re.addOrGetDriveRegisterPointerAndCommit(m_agent, cl);
re.addOrGetSchedulerGlobalLockAndCommit(m_agent, cl);
rel.release();
m_OStoreDB.setAgent(m_agent);
}
OStoreDBWrapper(const std::string &context, const std::string &URL = "");
virtual ~OStoreDBWrapper() throw() {
try {
m_OStoreDB.setAgent(*((objectstore::Agent*)NULL));
objectstore::ScopedExclusiveLock agl(m_agent);
m_agent.fetch();
m_agent.removeAndUnregisterSelf();
} catch (cta::exception::Exception &) {}
}
~OStoreDBWrapper() throw () {}
virtual void assertIsAdminOnAdminHost(const SecurityIdentity& id) const {
m_OStoreDB.assertIsAdminOnAdminHost(id);
......@@ -235,11 +211,68 @@ public:
return m_OStoreDB.getDriveStates();
}
private:
BackendType m_backend;
std::unique_ptr <cta::objectstore::Backend> m_backend;
cta::OStoreDB m_OStoreDB;
objectstore::Agent m_agent;
};
template <>
OStoreDBWrapper<cta::objectstore::BackendVFS>::OStoreDBWrapper(
const std::string &context, const std::string &URL) :
m_backend(new cta::objectstore::BackendVFS()),
m_OStoreDB(*m_backend), m_agent(*m_backend) {
// We need to populate the root entry before using.
objectstore::RootEntry re(*m_backend);
re.initialize();
re.insert();
objectstore::ScopedExclusiveLock rel(re);
re.fetch();
m_agent.generateName("OStoreDBFactory");
m_agent.initialize();
objectstore::CreationLog cl(cta::UserIdentity(1111, 1111), "systemhost",
time(NULL), "Initial creation of the object store structures");
re.addOrGetAgentRegisterPointerAndCommit(m_agent, cl);
rel.release();
m_agent.insertAndRegisterSelf();
rel.lock(re);
re.addOrGetDriveRegisterPointerAndCommit(m_agent, cl);
re.addOrGetSchedulerGlobalLockAndCommit(m_agent, cl);
rel.release();
m_OStoreDB.setAgent(m_agent);
}
template <>
OStoreDBWrapper<cta::objectstore::BackendRados>::OStoreDBWrapper(
const std::string &context, const std::string &URL) :
m_backend(cta::objectstore::BackendFactory::createBackend(URL).release()),
m_OStoreDB(*m_backend), m_agent(*m_backend) {
// We need to first clean up possible left overs in the pool
auto l = m_backend->list();
for (auto o=l.begin(); o!=l.end(); o++) {
try {
m_backend->remove(*o);
} catch (std::exception &) {}
}
// We need to populate the root entry before using.
objectstore::RootEntry re(*m_backend);
re.initialize();
re.insert();
objectstore::ScopedExclusiveLock rel(re);
re.fetch();
m_agent.generateName("OStoreDBFactory");
m_agent.initialize();
objectstore::CreationLog cl(cta::UserIdentity(1111, 1111), "systemhost",
time(NULL), "Initial creation of the object store structures");
re.addOrGetAgentRegisterPointerAndCommit(m_agent, cl);
rel.release();
m_agent.insertAndRegisterSelf();
rel.lock(re);
re.addOrGetDriveRegisterPointerAndCommit(m_agent, cl);
re.addOrGetSchedulerGlobalLockAndCommit(m_agent, cl);
rel.release();
m_OStoreDB.setAgent(m_agent);
}
}
/**
......@@ -252,7 +285,7 @@ public:
/**
* Constructor
*/
OStoreDBFactory() {}
OStoreDBFactory(const std::string & URL = ""): m_URL(URL) {}
/**
* Destructor.
......@@ -265,8 +298,11 @@ public:
* @return A newly created scheduler database object.
*/
std::unique_ptr<SchedulerDatabase> create() const {
return std::unique_ptr<SchedulerDatabase>(new OStoreDBWrapper<BackendType>("UnitTest"));
return std::unique_ptr<SchedulerDatabase>(new OStoreDBWrapper<BackendType>("UnitTest", m_URL));
}
private:
std::string m_URL;
}; // class OStoreDBFactory
} // namespace cta
......@@ -28,6 +28,7 @@
#include "scheduler/SchedulerDatabaseFactory.hpp"
#include "common/SecurityIdentity.hpp"
#include "OStoreDB/OStoreDBFactory.hpp"
#include "objectstore/BackendRados.hpp"
#include <exception>
#include <gtest/gtest.h>
......@@ -634,9 +635,21 @@ INSTANTIATE_TEST_CASE_P(MockSchedulerDatabaseTest, SchedulerDatabaseTest,
::testing::Values(SchedulerDatabaseTestParam(mockDbFactory)));
#endif
static cta::OStoreDBFactory<cta::objectstore::BackendVFS> OStoreDBFactory;
#define TEST_VFS
#ifdef TEST_VFS
static cta::OStoreDBFactory<cta::objectstore::BackendVFS> OStoreDBFactoryVFS;
INSTANTIATE_TEST_CASE_P(OStoreSchedulerDatabaseTest, SchedulerDatabaseTest,
::testing::Values(SchedulerDatabaseTestParam(OStoreDBFactory)));
INSTANTIATE_TEST_CASE_P(OStoreSchedulerDatabaseTestVFS, SchedulerDatabaseTest,
::testing::Values(SchedulerDatabaseTestParam(OStoreDBFactoryVFS)));
#endif
#define TEST_RADOS
#ifdef TEST_RADOS
static cta::OStoreDBFactory<cta::objectstore::BackendRados> OStoreDBFactoryRados("rados://tapetest@tapetest");
INSTANTIATE_TEST_CASE_P(OStoreSchedulerDatabaseTestRados, SchedulerDatabaseTest,
::testing::Values(SchedulerDatabaseTestParam(OStoreDBFactoryRados)));
#endif
} // namespace unitTests
......@@ -2615,8 +2615,19 @@ INSTANTIATE_TEST_CASE_P(MockSchedulerTest, SchedulerTest,
::testing::Values(SchedulerTestParam(mockNsFactory, mockDbFactory)));
#endif
static cta::OStoreDBFactory<cta::objectstore::BackendVFS> OStoreDBFactory;
#define TEST_VFS
#ifdef TEST_VFS
static cta::OStoreDBFactory<cta::objectstore::BackendVFS> OStoreDBFactoryVFS;
INSTANTIATE_TEST_CASE_P(OStoreDBPlusMockSchedulerTest, SchedulerTest,
::testing::Values(SchedulerTestParam(mockNsFactory, OStoreDBFactory)));
INSTANTIATE_TEST_CASE_P(OStoreDBPlusMockSchedulerTestVFS, SchedulerTest,
::testing::Values(SchedulerTestParam(mockNsFactory, OStoreDBFactoryVFS)));
#endif
#define TEST_RADOS
#ifdef TEST_RADOS
static cta::OStoreDBFactory<cta::objectstore::BackendRados> OStoreDBFactoryRados("rados://tapetest@tapetest");
INSTANTIATE_TEST_CASE_P(OStoreDBPlusMockSchedulerTestRados, SchedulerTest,
::testing::Values(SchedulerTestParam(mockNsFactory, OStoreDBFactoryRados)));
#endif
} // namespace unitTests
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment