diff options
-rw-r--r-- | icetray/Jamfile.jam | 59 | ||||
-rw-r--r-- | icetray/abstractDatabaseClient.cpp | 37 | ||||
-rw-r--r-- | icetray/abstractDatabaseClient.h | 67 | ||||
-rw-r--r-- | icetray/defaultPool.cpp | 16 | ||||
-rw-r--r-- | icetray/defaultPool.h | 15 | ||||
-rw-r--r-- | icetray/dryice.cpp | 49 | ||||
-rw-r--r-- | icetray/dryice.h | 32 | ||||
-rw-r--r-- | icetray/icetrayService.cpp | 40 | ||||
-rw-r--r-- | icetray/icetrayService.h | 33 | ||||
-rw-r--r-- | icetray/mockPool.cpp | 21 | ||||
-rw-r--r-- | icetray/mockPool.h | 20 | ||||
-rw-r--r-- | icetray/test.cpp | 6 | ||||
-rw-r--r-- | icetray/unittests/Jamfile.jam | 41 | ||||
-rw-r--r-- | icetray/unittests/testDefaultPool.cpp | 25 | ||||
-rw-r--r-- | icetray/unittests/testIceTray.cpp | 47 | ||||
-rw-r--r-- | icetray/unittests/testIceTrayService.ice | 6 | ||||
-rw-r--r-- | icetray/unittests/testIceTrayService.sql | 5 | ||||
-rw-r--r-- | icetray/unittests/testIceTrayServiceI.cpp | 33 | ||||
-rw-r--r-- | icetray/unittests/testIceTrayServiceI.h | 23 |
19 files changed, 575 insertions, 0 deletions
diff --git a/icetray/Jamfile.jam b/icetray/Jamfile.jam new file mode 100644 index 0000000..02e7ba3 --- /dev/null +++ b/icetray/Jamfile.jam @@ -0,0 +1,59 @@ +lib adhocutil : : : : <include>/usr/include/adhocutil ; +lib slicer : : : : <include>/usr/include/slicer ; +lib slicer-db : : : : <include>/usr/include/slicer ; +lib Ice ; +lib IceUtil ; +lib pthread ; +lib dl ; +lib IceBox ; +lib dbppcore : : : : <include>/usr/include/dbpp ; +lib boost_system ; +lib boost_thread ; + +build-project unittests ; + +lib icetray : + abstractDatabaseClient.cpp + defaultPool.cpp + icetrayService.cpp + test.cpp + : + <library>adhocutil + <library>dbppcore + <library>Ice + <library>IceUtil + <library>IceBox + <library>pthread + <library>slicer + <library>slicer-db + <library>boost_system + <library>boost_thread + <library>..//glibmm + <cflags>-fvisibility=hidden + : : + <include>. + <library>dbppcore + <library>adhocutil + <library>slicer + <library>slicer-db + <library>boost_thread + ; + +lib dryice : + dryice.cpp + mockPool.cpp + : + <library>adhocutil + <library>icetray + <library>Ice + <library>IceUtil + <library>IceBox + <library>pthread + <library>boost_system + <library>boost_thread + <library>dl + <cflags>-fvisibility=hidden + : : + <include>. + ; + diff --git a/icetray/abstractDatabaseClient.cpp b/icetray/abstractDatabaseClient.cpp new file mode 100644 index 0000000..0d3489c --- /dev/null +++ b/icetray/abstractDatabaseClient.cpp @@ -0,0 +1,37 @@ +#include "abstractDatabaseClient.h" +#include <cache.impl.h> + +template DLL_PUBLIC void AdHoc::Cache<IceTray::AbstractDatabaseClient::CacheItem, IceTray::AbstractDatabaseClient::CacheKey>::add(const IceTray::AbstractDatabaseClient::CacheKey &, const IceTray::AbstractDatabaseClient::CacheItem &, time_t); +template DLL_PUBLIC const IceTray::AbstractDatabaseClient::CacheItem * AdHoc::Cache<IceTray::AbstractDatabaseClient::CacheItem, IceTray::AbstractDatabaseClient::CacheKey>::get(const IceTray::AbstractDatabaseClient::CacheKey &) const; + +namespace IceTray { +AbstractDatabaseClient::AbstractDatabaseClient(boost::shared_ptr<AdHoc::ResourcePool<DB::Connection>> d) : + db(d) +{ +} + +template<> +void +AbstractDatabaseClient::bind1(int o, DB::Command * cmd, const std::string & p) +{ + cmd->bindParamS(o, p); +} + +template<> +void +AbstractDatabaseClient::bind1(int o, DB::Command * cmd, const int & p) +{ + cmd->bindParamI(o, p); +} + +void +AbstractDatabaseClient::bind(int, DB::Command *) +{ +} + +void +AbstractDatabaseClient::keyPushParams(CacheKey &) +{ +} +} + diff --git a/icetray/abstractDatabaseClient.h b/icetray/abstractDatabaseClient.h new file mode 100644 index 0000000..817d1ed --- /dev/null +++ b/icetray/abstractDatabaseClient.h @@ -0,0 +1,67 @@ +#ifndef ABSTRACTDATABASECLIENT_H +#define ABSTRACTDATABASECLIENT_H + +#include <connectionPool.h> +#include <db/sqlSelectDeserializer.h> +#include <slicer/slicer.h> +#include <cache.h> +#include <boost/any.hpp> +#include <boost/shared_ptr.hpp> +#include <visibility.h> + +namespace IceTray { +class DLL_PUBLIC AbstractDatabaseClient { + public: + AbstractDatabaseClient(boost::shared_ptr<AdHoc::ResourcePool<DB::Connection>> d); + typedef std::vector<std::size_t> CacheKey; + typedef boost::shared_ptr<boost::any> CacheItem; + + template<typename Domain, typename Sql, typename ... Params> + Domain inline fetch(const Params & ... params) + { + CacheKey key; + key.reserve(sizeof...(Params) + 2); + key.push_back(Sql::hash); + key.push_back(typeid(Domain).hash_code()); + keyPushParams(key, params...); + if (auto cached = cache.get(key)) { + return boost::any_cast<Domain>(**cached); + } + auto c = db->get(); + auto s = DB::SelectCommandPtr(c->newSelectCommand(Sql::sql)); + bind(0, s.get(), params...); + Domain d = Slicer::DeserializeAny<Slicer::SqlSelectDeserializer, Domain>(*s); + s.reset(); + c.release(); + cache.add(key, CacheItem(new boost::any(d)), time(NULL) + 40); + return d; + } + + template<typename Param, typename ... Params> + static void inline bind(int offset, DB::Command * cmd, const Param & p, const Params & ... params) + { + bind1(offset, cmd, p); + bind(offset + 1, cmd, params...); + } + + static void bind(int offset, DB::Command * cmd); + + template<typename Param> + static void bind1(int offset, DB::Command * cmd, const Param & p); + + template<typename Param, typename ... Params> + static void inline keyPushParams(CacheKey & k, const Param & p, const Params & ... params) + { + k.push_back(std::hash<Param>()(p)); + keyPushParams(k, params...); + } + + static void keyPushParams(CacheKey &); + + boost::shared_ptr<AdHoc::ResourcePool<DB::Connection>> db; + AdHoc::Cache<CacheItem, CacheKey> cache; +}; +} + +#endif + diff --git a/icetray/defaultPool.cpp b/icetray/defaultPool.cpp new file mode 100644 index 0000000..c3f7e50 --- /dev/null +++ b/icetray/defaultPool.cpp @@ -0,0 +1,16 @@ +#include "defaultPool.h" +#include "icetrayService.h" + +namespace IceTray { + DefaultPool::DefaultPool(const std::string & name, const std::string & type, Ice::PropertiesPtr p) : + DB::ConnectionPool( + p->getPropertyAsIntWithDefault(name + ".Database.PoolMax", 10), + p->getPropertyAsIntWithDefault(name + ".Database.PoolKeep", 2), + p->getPropertyWithDefault(name + ".Database.Type", type), + p->getProperty(name + ".Database.ConnectionString")) + { + } + + FACTORY(DefaultPool, PoolProvider); +} + diff --git a/icetray/defaultPool.h b/icetray/defaultPool.h new file mode 100644 index 0000000..5b06ea2 --- /dev/null +++ b/icetray/defaultPool.h @@ -0,0 +1,15 @@ +#ifndef ICETRAY_DEFAULTPOOL_H +#define ICETRAY_DEFAULTPOOL_H + +#include <connectionPool.h> +#include <Ice/Properties.h> + +namespace IceTray { + class DefaultPool : public DB::ConnectionPool { + public: + DefaultPool(const std::string & name, const std::string & type, Ice::PropertiesPtr p); + }; +} + +#endif + diff --git a/icetray/dryice.cpp b/icetray/dryice.cpp new file mode 100644 index 0000000..50f85cb --- /dev/null +++ b/icetray/dryice.cpp @@ -0,0 +1,49 @@ +#include "dryice.h" +#include <boost/assert.hpp> +#include <dlfcn.h> +#include <factory.h> +#include <Ice/Initialize.h> + +namespace IceTray { + typedef IceBox::Service *(* SetupFunction)(Ice::CommunicatorPtr); + + DryIce::DryIce(const Ice::StringSeq & cmdline) + { + void * i = dlsym(NULL, "createIceTrayService"); + BOOST_VERIFY(i); + auto sf = (SetupFunction)i; + BOOST_VERIFY(sf); + Ice::StringSeq args; + Ice::InitializationData id; + id.properties = Ice::createProperties(); + id.properties->setProperty("DryIce.Endpoints", "tcp -p 9002"); + id.properties->setProperty("DryIce.PoolProvider", "MockPool"); + id.properties->parseCommandLineOptions("", cmdline); + ic = Ice::initialize(args, id); + s = sf(nullptr); + s->start("DryIce", ic, {}); + } + + DryIce::~DryIce() + { + if (s) { + s->stop(); + s = NULL; + } + if (ic) { + ic->destroy(); + ic = NULL; + } + } + + DryIceClient::DryIceClient() + { + ic = Ice::initialize(); + } + + DryIceClient::~DryIceClient() + { + ic->destroy(); + } +} + diff --git a/icetray/dryice.h b/icetray/dryice.h new file mode 100644 index 0000000..f81a48c --- /dev/null +++ b/icetray/dryice.h @@ -0,0 +1,32 @@ +#ifndef ICETRAY_TESTSETUP_H +#define ICETRAY_TESTSETUP_H + +#include <Ice/Communicator.h> +#include <IceBox/IceBox.h> +#include <visibility.h> + +namespace IceTray { + class DLL_PUBLIC DryIce { + public: + DryIce(const Ice::StringSeq & = Ice::StringSeq()); + DryIce(const DryIce &) = delete; + virtual ~DryIce(); + + void operator=(const DryIce &) = delete; + + protected: + Ice::CommunicatorPtr ic; + IceBox::ServicePtr s; + }; + + class DLL_PUBLIC DryIceClient { + public: + DryIceClient(); + virtual ~DryIceClient(); + + Ice::CommunicatorPtr ic; + }; +} + +#endif + diff --git a/icetray/icetrayService.cpp b/icetray/icetrayService.cpp new file mode 100644 index 0000000..335c08b --- /dev/null +++ b/icetray/icetrayService.cpp @@ -0,0 +1,40 @@ +#include <Ice/Ice.h> +#include <visibility.h> +#include <factory.impl.h> +#include "icetrayService.h" + +namespace IceTray { + void Service::start(const std::string & name, const Ice::CommunicatorPtr & ic, const Ice::StringSeq & args) + { + adp = ic->createObjectAdapter(name); + addObjects(name, ic, args, adp); + adp->activate(); + } + + void Service::stop() + { + adp->deactivate(); + adp->destroy(); + } + + boost::shared_ptr<AdHoc::ResourcePool<DB::Connection>> Service::getConnectionPool(const Ice::CommunicatorPtr & ic, const std::string & type, const std::string & name) + { + auto p = ic->getProperties(); + return boost::shared_ptr<AdHoc::ResourcePool<DB::Connection>>(PoolProvider::createNew( + p->getPropertyWithDefault("DryIce.PoolProvider", "DefaultPool"), + name, type, p)); + } +} + +extern "C" { + DLL_PUBLIC + IceBox::Service * + createIceTrayService(Ice::CommunicatorPtr) + { + return IceTray::ServiceFactory::createNew("default"); + } +} + +INSTANTIATEVOIDFACTORY(IceTray::Service); +INSTANTIATEFACTORY(IceTray::PoolType, const std::string &, const std::string &, Ice::PropertiesPtr); + diff --git a/icetray/icetrayService.h b/icetray/icetrayService.h new file mode 100644 index 0000000..10a1700 --- /dev/null +++ b/icetray/icetrayService.h @@ -0,0 +1,33 @@ +#ifndef ICETRAY_SERVICE_H +#define ICETRAY_SERVICE_H + +#include <IceBox/IceBox.h> +#include <factory.h> +#include <visibility.h> +#include <connectionPool.h> + +namespace IceTray { + typedef AdHoc::ResourcePool<DB::Connection> PoolType; + typedef boost::shared_ptr<PoolType> PoolTypePtr; + + class DLL_PUBLIC Service : public IceBox::Service, public AdHoc::AbstractPluginImplementation { + public: + typedef boost::shared_ptr<DB::ConnectionPool> DBCPoolPtr; + + virtual void addObjects(const std::string & name, const Ice::CommunicatorPtr & ic, const Ice::StringSeq &, const Ice::ObjectAdapterPtr &) = 0; + + void start(const std::string & name, const Ice::CommunicatorPtr & ic, const Ice::StringSeq & args) override; + + void stop() override; + + PoolTypePtr getConnectionPool(const Ice::CommunicatorPtr & ic, const std::string & type, const std::string & prefix); + + Ice::ObjectAdapterPtr adp; + }; + + typedef AdHoc::Factory<Service> ServiceFactory; + typedef AdHoc::Factory<PoolType, const std::string &, const std::string &, Ice::PropertiesPtr> PoolProvider; +} + +#endif + diff --git a/icetray/mockPool.cpp b/icetray/mockPool.cpp new file mode 100644 index 0000000..3035949 --- /dev/null +++ b/icetray/mockPool.cpp @@ -0,0 +1,21 @@ +#include "mockPool.h" +#include "icetrayService.h" +#include <factory.impl.h> + +namespace IceTray { + MockPool::MockPool(const std::string & name, const std::string &, Ice::PropertiesPtr p) : + AdHoc::ResourcePool<DB::Connection>( + p->getPropertyAsIntWithDefault(name + ".Database.PoolMax", 10), + p->getPropertyAsIntWithDefault(name + ".Database.PoolKeep", 2)), + name(name) + { + } + + DB::Connection * MockPool::createResource() const + { + return DB::MockDatabase::openConnectionTo(name); + } + + FACTORY(MockPool, PoolProvider); +}; + diff --git a/icetray/mockPool.h b/icetray/mockPool.h new file mode 100644 index 0000000..6a2df85 --- /dev/null +++ b/icetray/mockPool.h @@ -0,0 +1,20 @@ +#ifndef ICETRAY_MOCKPOOL_H +#define ICETRAY_MOCKPOOL_H + +#include <connectionPool.h> +#include <mockDatabase.h> +#include <Ice/Properties.h> + +namespace IceTray { + class MockPool : public AdHoc::ResourcePool<DB::Connection> { + public: + MockPool(const std::string & name, const std::string &, Ice::PropertiesPtr p); + + DB::Connection * createResource() const override; + + const std::string name; + }; +} + +#endif + diff --git a/icetray/test.cpp b/icetray/test.cpp new file mode 100644 index 0000000..5ccaa01 --- /dev/null +++ b/icetray/test.cpp @@ -0,0 +1,6 @@ +#include <factory.impl.h> +#include <boost/any.hpp> + +template class std::shared_ptr<boost::any>; +INSTANTIATEFACTORY(int, std::shared_ptr<boost::any>); + diff --git a/icetray/unittests/Jamfile.jam b/icetray/unittests/Jamfile.jam new file mode 100644 index 0000000..b1a9e40 --- /dev/null +++ b/icetray/unittests/Jamfile.jam @@ -0,0 +1,41 @@ +import testing ; + +lib boost_utf : : <name>boost_unit_test_framework ; +lib boost_filesystem ; +lib dbpp-postgresql : : : : <include>/usr/include/dbpp-postgresql ; + +path-constant me : . ; + +alias testCommon : : : : + <define>ROOT=\"$(me)\" + <library>..//adhocutil + <library>..//dryice + <library>..//icetray + <library>..//IceBox + <library>..//IceUtil + <library>..//Ice + <library>..//pthread + <library>boost_utf + <library>..//boost_system + <define>BOOST_TEST_DYN_LINK + ; +run + testIceTray.cpp + testIceTrayService.ice + testIceTrayServiceI.cpp + : + testIceTrayService.sql + : : + <library>testCommon + <library>boost_filesystem + <library>dbpp-postgresql + : + testIceTray ; + +run + testDefaultPool.cpp + : : : + <library>testCommon + : + testDefaultPool ; + diff --git a/icetray/unittests/testDefaultPool.cpp b/icetray/unittests/testDefaultPool.cpp new file mode 100644 index 0000000..7dfa360 --- /dev/null +++ b/icetray/unittests/testDefaultPool.cpp @@ -0,0 +1,25 @@ +#define BOOST_TEST_MODULE TestIceTray +#include <boost/test/unit_test.hpp> + +#include <factory.h> +#include <factory.impl.h> +#include <connectionPool.h> +#include <error.h> +#include <icetrayService.h> +#include <Ice/Initialize.h> +#include <Ice/Properties.h> + +BOOST_AUTO_TEST_CASE( defaultPool ) +{ + auto p = Ice::createProperties(); + p->setProperty("testcase.Database.ConnectionString", "host=randomdan.homeip.net user=gentoo"); + auto pool = IceTray::PoolProvider::createNew("DefaultPool", "testcase", "postgresql", p); + BOOST_REQUIRE(pool); + BOOST_REQUIRE_EQUAL(0, pool->inUseCount()); + { + auto c = pool->get(); + c->ping(); + } + delete pool; +} + diff --git a/icetray/unittests/testIceTray.cpp b/icetray/unittests/testIceTray.cpp new file mode 100644 index 0000000..b3eb9dc --- /dev/null +++ b/icetray/unittests/testIceTray.cpp @@ -0,0 +1,47 @@ +#define BOOST_TEST_MODULE TestIceTray +#include <boost/test/unit_test.hpp> + +#include <dryice.h> +#include <Ice/Communicator.h> +#include "testIceTrayServiceI.h" + +#include <mock.h> +#include <definedDirs.h> + +class Service : public IceTray::DryIce, PQ::Mock { + public: + Service() : + PQ::Mock("user=postgres dbname=postgres", "icetraydb", { + rootDir / "testIceTrayService.sql" + }) + { + } +}; + +BOOST_GLOBAL_FIXTURE( Service ); + +class Client : public IceTray::DryIceClient { + public: + Client() : + p(TestIceTray::TestIceTrayServicePrx::checkedCast(ic->stringToProxy("test:tcp -p 9002"))) + { + } + TestIceTray::TestIceTrayServicePrx p; +}; + +BOOST_FIXTURE_TEST_SUITE( client, Client ); + +BOOST_AUTO_TEST_CASE( startup ) +{ + BOOST_REQUIRE(ic); +} + +BOOST_AUTO_TEST_CASE( services ) +{ + BOOST_REQUIRE(p); + p->ice_ping(); + p->method(); +} + +BOOST_AUTO_TEST_SUITE_END(); + diff --git a/icetray/unittests/testIceTrayService.ice b/icetray/unittests/testIceTrayService.ice new file mode 100644 index 0000000..9c17127 --- /dev/null +++ b/icetray/unittests/testIceTrayService.ice @@ -0,0 +1,6 @@ +module TestIceTray { + interface TestIceTrayService { + void method(); + }; +}; + diff --git a/icetray/unittests/testIceTrayService.sql b/icetray/unittests/testIceTrayService.sql new file mode 100644 index 0000000..7d9a7e7 --- /dev/null +++ b/icetray/unittests/testIceTrayService.sql @@ -0,0 +1,5 @@ +CREATE TABLE testTable ( + id int, + name text, + primary key(id)); + diff --git a/icetray/unittests/testIceTrayServiceI.cpp b/icetray/unittests/testIceTrayServiceI.cpp new file mode 100644 index 0000000..501e1b1 --- /dev/null +++ b/icetray/unittests/testIceTrayServiceI.cpp @@ -0,0 +1,33 @@ +#include "testIceTrayServiceI.h" +#include <factory.h> +#include <Ice/ObjectAdapter.h> +#include <Ice/Communicator.h> +#include <boost/assert.hpp> + +namespace TestIceTray { + struct TestSql { + static const std::string sql; + static const std::size_t hash; + }; + const std::string TestSql::sql("SELECT COUNT(*) FROM testTable WHERE id = ? AND name = ?"); + const std::size_t TestSql::hash(std::hash<std::string>()(sql)); + TestIceTrayServiceI::TestIceTrayServiceI(boost::shared_ptr<AdHoc::ResourcePool<DB::Connection>> d) : + IceTray::AbstractDatabaseClient(d) + { + } + + void TestIceTrayServiceI::method(const Ice::Current &) + { + Ice::Int id = 4; + std::string name = "test"; + BOOST_VERIFY((fetch<int, TestSql>(id, name)) == (fetch<int, TestSql>(id, name))); + } + + void TestService::addObjects(const std::string &, const Ice::CommunicatorPtr & ic, const Ice::StringSeq &, const Ice::ObjectAdapterPtr & adp) + { + adp->add(new TestIceTray::TestIceTrayServiceI(getConnectionPool(ic, "postgresql", "icetraydb")), ic->stringToIdentity("test")); + } + + NAMEDFACTORY("default", TestService, IceTray::ServiceFactory); +} + diff --git a/icetray/unittests/testIceTrayServiceI.h b/icetray/unittests/testIceTrayServiceI.h new file mode 100644 index 0000000..6bb5503 --- /dev/null +++ b/icetray/unittests/testIceTrayServiceI.h @@ -0,0 +1,23 @@ +#ifndef TEST_ICETRAY_SERVICE_IMPL_H +#define TEST_ICETRAY_SERVICE_IMPL_H + +#include <testIceTrayService.h> +#include <icetrayService.h> +#include <abstractDatabaseClient.h> + +namespace TestIceTray { + class TestIceTrayServiceI : IceTray::AbstractDatabaseClient, public TestIceTrayService { + public: + TestIceTrayServiceI(boost::shared_ptr<AdHoc::ResourcePool<DB::Connection>> db); + + void method(const Ice::Current &) override; + }; + + class TestService : public IceTray::Service { + public: + void addObjects(const std::string &, const Ice::CommunicatorPtr &, const Ice::StringSeq &, const Ice::ObjectAdapterPtr &) override; + }; +} + +#endif + |