summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2015-05-02 21:20:53 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2015-05-02 21:23:43 +0100
commit79048ae19355cb8179e1abee8be001fcb0bdfcb7 (patch)
tree66e678d8b126b567b4d1b8956f2fc235fa494124
parentAdd support for RDBMS boolean/bit types (diff)
downloadproject2-79048ae19355cb8179e1abee8be001fcb0bdfcb7.tar.bz2
project2-79048ae19355cb8179e1abee8be001fcb0bdfcb7.tar.xz
project2-79048ae19355cb8179e1abee8be001fcb0bdfcb7.zip
Add mocking and tests for ODBC.
Note: whilst intervals sort of work, ODBC thinks the column is a longvarchar in PQ, so the UTs don't cover it. Also note: the ODBC UT mock is a hack over the PQ one, probably not suitable for general purpose use
-rw-r--r--project2/sql/sql-modODBC.cpp32
-rw-r--r--project2/sql/sql-modODBC.h21
-rw-r--r--project2/sql/unittests/Jamfile.jam8
-rw-r--r--project2/sql/unittests/datasources/odbcmock.xml4
-rw-r--r--project2/sql/unittests/testodbc.cpp116
-rw-r--r--project2/sql/unittests/ut.dsn0
6 files changed, 181 insertions, 0 deletions
diff --git a/project2/sql/sql-modODBC.cpp b/project2/sql/sql-modODBC.cpp
index 284d02e..29d2441 100644
--- a/project2/sql/sql-modODBC.cpp
+++ b/project2/sql/sql-modODBC.cpp
@@ -1,4 +1,36 @@
#include "connectionLoader.h"
#include "../libodbcpp/connection.h"
+#include "sql-modODBC.h"
+#include <misc.h>
+#include <scripts.h>
+#include <logger.h>
+
typedef ODBC::Connection ODBCConnection;
DECLARE_GENERIC_LOADER("odbc", ConnectionLoader, ODBCConnection)
+
+MockODBCDatabase::MockODBCDatabase(const std::string & masterdb, const std::string & name, const std::vector<boost::filesystem::path> & ss) :
+ MockServerDatabase(masterdb, name, "odbc")
+{
+ CreateNewDatabase();
+ PlaySchemaScripts(ss);
+}
+
+DB::Connection *
+MockODBCDatabase::openConnection() const
+{
+ return InstanceMap<ConnectionLoader, std::string>::Get<std::invalid_argument>("odbc")->create(
+ stringbf("Driver=postgresql;Database=%s;uid=postgres;servername=/run/postgresql", testDbName));
+}
+
+MockODBCDatabase::~MockODBCDatabase()
+{
+ DropDatabase();
+}
+
+void MockODBCDatabase::DropDatabase() const
+{
+ Logger()->messagebf(LOG_INFO, "Killing any active connections to database %s", testDbName);
+ master->execute("SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '" + testDbName + "'");
+ MockServerDatabase::DropDatabase();
+}
+
diff --git a/project2/sql/sql-modODBC.h b/project2/sql/sql-modODBC.h
new file mode 100644
index 0000000..e7d7bdb
--- /dev/null
+++ b/project2/sql/sql-modODBC.h
@@ -0,0 +1,21 @@
+#ifndef MOCKODBCDATASOURCE_H
+#define MOCKODBCDATASOURCE_H
+
+#include "mockDatabase.h"
+#include <boost/filesystem/path.hpp>
+
+class MockODBCDatabase : public MockServerDatabase {
+ public:
+ MockODBCDatabase(const std::string & master, const std::string & name, const std::vector<boost::filesystem::path> & ss);
+ ~MockODBCDatabase();
+
+ protected:
+ void DropDatabase() const override;
+
+ private:
+ DB::Connection * openConnection() const override;
+};
+
+#endif
+
+
diff --git a/project2/sql/unittests/Jamfile.jam b/project2/sql/unittests/Jamfile.jam
index d14aea4..086e5a7 100644
--- a/project2/sql/unittests/Jamfile.jam
+++ b/project2/sql/unittests/Jamfile.jam
@@ -52,3 +52,11 @@ run
<dependency>mysqlschema.sql
: testmysql ;
+run
+ testodbc.cpp
+ : : :
+ <library>sqlTestCore
+ <library>..//p2sqlmodODBC
+ <dependency>pqschema.sql
+ : testodbc ;
+
diff --git a/project2/sql/unittests/datasources/odbcmock.xml b/project2/sql/unittests/datasources/odbcmock.xml
new file mode 100644
index 0000000..2460e75
--- /dev/null
+++ b/project2/sql/unittests/datasources/odbcmock.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<project2:rdbmsdatasource xmlns:project2="http://project2.randomdan.homeip.net" name="odbcmock">
+ <masterdsn provider="mock" dsn="odbcmock" />
+</project2:rdbmsdatasource>
diff --git a/project2/sql/unittests/testodbc.cpp b/project2/sql/unittests/testodbc.cpp
new file mode 100644
index 0000000..4fd8283
--- /dev/null
+++ b/project2/sql/unittests/testodbc.cpp
@@ -0,0 +1,116 @@
+#define BOOST_TEST_MODULE TestODBC
+#include <boost/test/unit_test.hpp>
+
+#include <mockDatasource.h>
+#include <definedDirs.h>
+#include <modifycommand.h>
+#include <selectcommand.h>
+#include <column.h>
+#include <sql-modODBC.h>
+#include "testCore.h"
+#include <sqlHandleAsVariableType.h>
+#include <definedDirs.h>
+
+class StandardMockDatabase : public MockODBCDatabase {
+ public:
+ StandardMockDatabase() : MockODBCDatabase("Driver=postgresql;Database=postgres;uid=postgres;servername=/run/postgresql", "odbcmock", {
+ RootDir / "pqschema.sql" })
+ {
+ }
+};
+
+BOOST_GLOBAL_FIXTURE( StandardMockDatabase );
+
+BOOST_FIXTURE_TEST_SUITE( Core, TestCore );
+
+BOOST_AUTO_TEST_CASE( transactions )
+{
+ RdbmsDataSource * ds = CommonObjects::dataSource<RdbmsDataSource>("odbcmock");
+ auto ro = ds->getReadonly();
+
+ BOOST_REQUIRE_EQUAL(false, ro->inTx());
+ ro->beginTx();
+ BOOST_REQUIRE_EQUAL(true, ro->inTx());
+ ro->rollbackTx();
+ BOOST_REQUIRE_EQUAL(false, ro->inTx());
+
+ ro->beginTx();
+ BOOST_REQUIRE_EQUAL(true, ro->inTx());
+ ro->commitTx();
+ BOOST_REQUIRE_EQUAL(false, ro->inTx());
+
+ ds->close();
+}
+
+BOOST_AUTO_TEST_CASE( bindAndSend )
+{
+ RdbmsDataSource * ds = CommonObjects::dataSource<RdbmsDataSource>("odbcmock");
+ auto rw = ds->getWritable();
+
+ auto mod = rw->newModifyCommand("INSERT INTO test VALUES(?, ?, ?, ?, ?)");
+ mod->bindParamI(0, testInt);
+ mod->bindParamF(1, testDouble);
+ mod->bindParamS(2, testString);
+ mod->bindParamB(3, testBool);
+ mod->bindParamT(4, testDateTime);
+ mod->execute();
+ delete mod;
+ ds->commit();
+ ds->close();
+}
+
+template<typename T>
+void
+assertColumnValueHelper(DB::SelectCommand & sel, unsigned int col, const T & t)
+{
+ HandleAsVariableType h;
+ sel[col].apply(h);
+ BOOST_REQUIRE_EQUAL(t, h.variable.as<T>());
+}
+
+BOOST_AUTO_TEST_CASE( bindAndSelect )
+{
+ RdbmsDataSource * ds = CommonObjects::dataSource<RdbmsDataSource>("odbcmock");
+ auto ro = ds->getReadonly();
+
+ auto select = ro->newSelectCommand("SELECT * FROM test WHERE id = ?");
+ select->bindParamI(0, testInt);
+ select->execute();
+ int rows = 0;
+ while (select->fetch()) {
+ assertColumnValueHelper(*select, 0, testInt);
+ assertColumnValueHelper(*select, 1, testDouble);
+ assertColumnValueHelper(*select, 2, testString);
+ assertColumnValueHelper(*select, 3, testBool);
+ assertColumnValueHelper(*select, 4, testDateTime);
+ rows += 1;
+ }
+ delete select;
+ BOOST_REQUIRE_EQUAL(1, rows);
+ ds->close();
+}
+
+BOOST_AUTO_TEST_CASE( bindAndSelectOther )
+{
+ RdbmsDataSource * ds = CommonObjects::dataSource<RdbmsDataSource>("odbcmock");
+ auto ro = ds->getReadonly();
+
+ auto select = ro->newSelectCommand("SELECT * FROM test WHERE id != ?");
+ select->bindParamI(0, testInt);
+ select->execute();
+ int rows = 0;
+ while (select->fetch()) {
+ assertColumnValueHelper(*select, 0, 4);
+ assertColumnValueHelper(*select, 1, 123.45);
+ assertColumnValueHelper(*select, 2, std::string("some text"));
+ assertColumnValueHelper(*select, 3, true);
+ assertColumnValueHelper(*select, 4, boost::posix_time::ptime_from_tm({ 3, 6, 23, 27, 3, 115, 0, 0, 0, 0, 0}));
+ rows += 1;
+ }
+ delete select;
+ BOOST_REQUIRE_EQUAL(1, rows);
+ ds->close();
+}
+
+BOOST_AUTO_TEST_SUITE_END();
+
diff --git a/project2/sql/unittests/ut.dsn b/project2/sql/unittests/ut.dsn
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/project2/sql/unittests/ut.dsn