summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--icetray/Jamfile.jam59
-rw-r--r--icetray/abstractDatabaseClient.cpp37
-rw-r--r--icetray/abstractDatabaseClient.h67
-rw-r--r--icetray/defaultPool.cpp16
-rw-r--r--icetray/defaultPool.h15
-rw-r--r--icetray/dryice.cpp49
-rw-r--r--icetray/dryice.h32
-rw-r--r--icetray/icetrayService.cpp40
-rw-r--r--icetray/icetrayService.h33
-rw-r--r--icetray/mockPool.cpp21
-rw-r--r--icetray/mockPool.h20
-rw-r--r--icetray/test.cpp6
-rw-r--r--icetray/unittests/Jamfile.jam41
-rw-r--r--icetray/unittests/testDefaultPool.cpp25
-rw-r--r--icetray/unittests/testIceTray.cpp47
-rw-r--r--icetray/unittests/testIceTrayService.ice6
-rw-r--r--icetray/unittests/testIceTrayService.sql5
-rw-r--r--icetray/unittests/testIceTrayServiceI.cpp33
-rw-r--r--icetray/unittests/testIceTrayServiceI.h23
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
+