FairMQ: Add plugin mechanism (Plugin and PluginManager classes)

This commit is contained in:
Dennis Klein
2017-04-12 13:30:32 +02:00
committed by Mohammad Al-Turany
parent ac69607250
commit 60d929b0bd
18 changed files with 871 additions and 3 deletions

View File

@@ -77,6 +77,58 @@ add_testsuite(FairMQ.Device
RUN_SERIAL ON
)
set(VERSION_MAJOR 1)
set(VERSION_MINOR 1)
set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/helper/plugins/dummy.h.in ${CMAKE_CURRENT_BINARY_DIR}/helper/plugins/dummy.h)
add_testlib(FairMQPlugin_test_dummy
SOURCES
${CMAKE_CURRENT_BINARY_DIR}/helper/plugins/dummy.h
helper/plugins/dummy.cxx
LINKS FairMQ
INCLUDES ${CMAKE_CURRENT_BINARY_DIR}/helper/plugins
HIDDEN
VERSION ${VERSION}
)
set(VERSION_MAJOR 2)
set(VERSION_MINOR 2)
set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/helper/plugins/dummy2.h.in ${CMAKE_CURRENT_BINARY_DIR}/helper/plugins/dummy2.h)
add_testlib(FairMQPlugin_test_dummy2
SOURCES
${CMAKE_CURRENT_BINARY_DIR}/helper/plugins/dummy2.h
helper/plugins/dummy2.cxx
LINKS FairMQ
INCLUDES ${CMAKE_CURRENT_BINARY_DIR}/helper/plugins
HIDDEN
VERSION ${VERSION}
)
add_testsuite(FairMQ.Plugins
SOURCES
plugins/runner.cxx
plugins/_plugin.cxx
plugins/_plugin_manager.cxx
LINKS FairMQ
DEPENDS FairMQPlugin_test_dummy FairMQPlugin_test_dummy2
TIMEOUT 10
)
add_testsuite(FairMQ.PluginsStatic
SOURCES
plugins/runner.cxx
plugins/_plugin_manager_static.cxx
LINKS FairMQ FairMQPlugin_test_dummy FairMQPlugin_test_dummy2
TIMEOUT 10
)
##############################
# Aggregate all test targets #
##############################

View File

@@ -0,0 +1,9 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <dummy.h>

View File

@@ -0,0 +1,62 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIR_MQ_TEST_PLUGIN_DUMMY
#define FAIR_MQ_TEST_PLUGIN_DUMMY
#include <fairmq/Plugin.h>
#include <string>
#include <tuple>
#include <vector>
namespace fair
{
namespace mq
{
namespace test
{
class DummyPlugin : public fair::mq::Plugin
{
public:
DummyPlugin(const std::string name, const Version version, const std::string maintainer, const std::string homepage)
: Plugin(name, version, maintainer, homepage)
{
}
}; /* class DummyPlugin */
auto DummyPluginProgramOptions() -> const boost::optional<boost::program_options::options_description>
{
using namespace boost::program_options;
using std::string;
auto plugin_options = options_description{"Dummy Plugin"};
plugin_options.add_options()
("custom-dummy-option", value<string>(), "Cool custom option.");
("custom-dummy-option2", value<string>(), "Another cool custom option.");
return plugin_options;
}
REGISTER_FAIRMQ_PLUGIN(
DummyPlugin, // Class name
test_dummy, // Plugin name (string, lower case chars only)
(fair::mq::Plugin::Version{@VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@}), // Version
"Mr. Dummy <dummy@test.net>", // Maintainer
"https://git.test.net/dummy.git", // Homepage
fair::mq::test::DummyPluginProgramOptions // Free function which declares custom program options for the plugin
// signature: () -> boost::optional<boost::program_options::options_description>
)
} /* namespace test */
} /* namespace mq */
} /* namespace fair */
#endif /* FAIR_MQ_TEST_PLUGIN_DUMMY */

View File

@@ -0,0 +1,9 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <dummy2.h>

View File

@@ -0,0 +1,44 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIR_MQ_TEST_PLUGIN_DUMMY2
#define FAIR_MQ_TEST_PLUGIN_DUMMY2
#include <fairmq/Plugin.h>
namespace fair
{
namespace mq
{
namespace test
{
class Dummy2Plugin : public fair::mq::Plugin
{
public:
Dummy2Plugin(const std::string name, const Version version, const std::string maintainer, const std::string homepage)
: Plugin(name, version, maintainer, homepage)
{
}
}; /* class Dummy2Plugin */
REGISTER_FAIRMQ_PLUGIN(
Dummy2Plugin,
test_dummy2,
(Plugin::Version{@VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@}),
"Mr. Dummy <dummy@test.net>",
"https://git.test.net/dummy.git",
fair::mq::Plugin::NoProgramOptions
)
} /* namespace test */
} /* namespace mq */
} /* namespace fair */
#endif /* FAIR_MQ_TEST_PLUGIN_DUMMY */

View File

@@ -0,0 +1,52 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <gtest/gtest.h>
#include <fairmq/Plugin.h>
#include <sstream>
#include <string>
namespace
{
using namespace std;
using fair::mq::Plugin;
TEST(Plugin, Operators)
{
auto p1 = Plugin{"dds", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/dds.git"};
auto p2 = Plugin{"dds", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/dds.git"};
auto p3 = Plugin{"file", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/file.git"};
EXPECT_EQ(p1, p2);
EXPECT_NE(p1, p3);
}
TEST(Plugin, OstreamOperators)
{
auto p1 = Plugin{"dds", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/dds.git"};
stringstream ss;
ss << p1;
EXPECT_EQ(ss.str(), string{"'dds', version '1.0.0', maintainer 'Foo Bar <foo.bar@test.net>', homepage 'https://git.test.net/dds.git'"});
}
TEST(PluginVersion, Operators)
{
struct Plugin::Version v1{1, 0, 0};
struct Plugin::Version v2{1, 0, 0};
struct Plugin::Version v3{1, 2, 0};
EXPECT_EQ(v1, v2);
EXPECT_NE(v1, v3);
EXPECT_GT(v3, v2);
EXPECT_LT(v1, v3);
EXPECT_GE(v3, v2);
EXPECT_GE(v2, v1);
EXPECT_LE(v1, v2);
EXPECT_LE(v2, v3);
}
} /* namespace */

View File

@@ -0,0 +1,103 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <gtest/gtest.h>
#include <fairmq/PluginManager.h>
#include <FairMQLogger.h>
#include <fstream>
#include <vector>
namespace
{
using namespace fair::mq;
using namespace boost::filesystem;
using namespace boost::program_options;
using namespace std;
TEST(PluginManager, LoadPlugin)
{
auto mgr = PluginManager{};
mgr.PrependSearchPath("./lib");
ASSERT_NO_THROW(mgr.LoadPlugin("test_dummy"));
ASSERT_NO_THROW(mgr.LoadPlugin("test_dummy2"));
// check order
auto expected = vector<string>{"test_dummy", "test_dummy2"};
auto actual = vector<string>{};
mgr.ForEachPlugin([&](Plugin& plugin){ actual.push_back(plugin.GetName()); });
ASSERT_TRUE(actual == expected);
// program options
auto count = 0;
mgr.ForEachPluginProgOptions([&count](const options_description& d){ ++count; });
ASSERT_EQ(count, 1);
}
TEST(PluginManager, Factory)
{
const auto args = vector<string>{"-l", "debug", "--help", "-S", ">/lib", "</home/user/lib", "/usr/local/lib", "/usr/lib"};
auto mgr = PluginManager::MakeFromCommandLineOptions(args);
const auto path1 = path{"/home/user/lib"};
const auto path2 = path{"/usr/local/lib"};
const auto path3 = path{"/usr/lib"};
const auto path4 = path{"/lib"};
const auto expected = vector<path>{path1, path2, path3, path4};
ASSERT_TRUE(static_cast<bool>(mgr));
ASSERT_TRUE(mgr->SearchPaths() == expected);
}
TEST(PluginManager, SearchPathValidation)
{
const auto path1 = path{"/tmp/test1"};
const auto path2 = path{"/tmp/test2"};
const auto path3 = path{"/tmp/test3"};
auto mgr = PluginManager{};
mgr.SetSearchPaths({path1, path2});
auto expected = vector<path>{path1, path2};
ASSERT_EQ(mgr.SearchPaths(), expected);
mgr.AppendSearchPath(path3);
expected = vector<path>{path1, path2, path3};
ASSERT_EQ(mgr.SearchPaths(), expected);
mgr.PrependSearchPath(path3);
expected = vector<path>{path3, path1, path2, path3};
ASSERT_EQ(mgr.SearchPaths(), expected);
}
TEST(PluginManager, SearchPaths)
{
const auto temp = temp_directory_path() / unique_path();
create_directories(temp);
const auto non_existing_dir = temp / "non-existing-dir";
const auto existing_dir = temp / "existing-dir";
create_directories(existing_dir);
const auto existing_file = temp / "existing-file.so";
std::fstream fs;
fs.open(existing_file.string(), std::fstream::out);
fs.close();
const auto empty_path = path{""};
auto mgr = PluginManager{};
ASSERT_NO_THROW(mgr.AppendSearchPath(non_existing_dir));
ASSERT_NO_THROW(mgr.AppendSearchPath(existing_dir));
ASSERT_THROW(mgr.AppendSearchPath(existing_file), PluginManager::BadSearchPath);
ASSERT_NO_THROW(mgr.PrependSearchPath(non_existing_dir));
ASSERT_NO_THROW(mgr.PrependSearchPath(existing_dir));
ASSERT_THROW(mgr.PrependSearchPath(existing_file), PluginManager::BadSearchPath);
ASSERT_NO_THROW(mgr.SetSearchPaths({non_existing_dir, existing_dir}));
ASSERT_THROW(mgr.SetSearchPaths({non_existing_dir, existing_file}), PluginManager::BadSearchPath);
ASSERT_THROW(mgr.SetSearchPaths({non_existing_dir, empty_path}), PluginManager::BadSearchPath);
remove_all(temp);
}
} /* namespace */

View File

@@ -0,0 +1,28 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <gtest/gtest.h>
#include <fairmq/PluginManager.h>
#include <FairMQLogger.h>
#include <vector>
namespace
{
using namespace fair::mq;
using namespace std;
TEST(PluginManager, LoadPluginStatic)
{
auto mgr = PluginManager{};
ASSERT_NO_THROW(mgr.LoadPlugin("s:test_dummy"));
ASSERT_NO_THROW(mgr.LoadPlugin("s:test_dummy2"));
}
} /* namespace */

View File

@@ -0,0 +1,16 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <gtest/gtest.h>
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "threadsafe";
return RUN_ALL_TESTS();
}