summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2015-05-02 02:50:20 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2015-05-02 02:50:20 +0100
commit82c224a22abece418c0d2bf0267517c207fcf802 (patch)
tree2e5b1e3264828360549d8ecd6ae77f2e41ea7a0a
parentTest against a fixed time as class is initialized once per test (diff)
downloadproject2-82c224a22abece418c0d2bf0267517c207fcf802.tar.bz2
project2-82c224a22abece418c0d2bf0267517c207fcf802.tar.xz
project2-82c224a22abece418c0d2bf0267517c207fcf802.zip
Add MySQL mocking and test cases
-rw-r--r--project2/sql/sql-modMySQL.cpp72
-rw-r--r--project2/sql/sql-modMySQL.h24
-rw-r--r--project2/sql/unittests/Jamfile.jam8
-rw-r--r--project2/sql/unittests/datasources/mysqlmock.xml4
-rw-r--r--project2/sql/unittests/mysqlschema.sql7
-rw-r--r--project2/sql/unittests/testmysql.cpp115
6 files changed, 230 insertions, 0 deletions
diff --git a/project2/sql/sql-modMySQL.cpp b/project2/sql/sql-modMySQL.cpp
index 9ca12c0..24172ce 100644
--- a/project2/sql/sql-modMySQL.cpp
+++ b/project2/sql/sql-modMySQL.cpp
@@ -1,4 +1,76 @@
#include "connectionLoader.h"
#include "../libmysqlpp/connection.h"
+#include "sql-modMySQL.h"
+#include <misc.h>
+#include <scripts.h>
+#include <logger.h>
+#include <fstream>
+
typedef MySQL::Connection MySQLConnection;
DECLARE_GENERIC_LOADER("mysql", ConnectionLoader, MySQLConnection)
+
+MockMySQLDatabase::MockMySQLDatabase(const std::string & name, const std::vector<boost::filesystem::path> & ss) :
+ master(InstanceMap<ConnectionLoader, std::string>::Get<std::invalid_argument>("mysql")->create("options=p2testmysql")),
+ testDbName(stringbf("test_%d_%d", getpid(), ++MockConnectionLoader::mocked)),
+ mockName(name)
+{
+ Logger()->messagebf(LOG_DEBUG, "Setting up new mocked database %s", testDbName);
+ DropDatabase();
+ CreateNewDatabase();
+ DB::Connection * conn = openConnection(stringbf("options=p2testmysql;database=%s", testDbName));
+ try {
+ for (auto s : ss) {
+ conn->beginTx();
+ Logger()->messagebf(LOG_DEBUG, "%s << %s", testDbName, s);
+ std::ifstream f;
+ f.open(s.string());
+ while (!f.eof()) {
+ char buf[BUFSIZ];
+ f.getline(buf, BUFSIZ, ';');
+ if (!f.eof())
+ conn->execute(buf);
+ }
+ f.close();
+ conn->commitTx();
+ }
+ Logger()->messagebf(LOG_DEBUG, "%s initialized", testDbName);
+ MockConnectionLoader::mocks[name] = boost::bind(MockMySQLDatabase::openConnection, stringbf("options=p2testmysql;database=%s", testDbName));
+ }
+ catch (...) {
+ if (conn->inTx()) {
+ conn->rollbackTx();
+ }
+ delete conn;
+ DropDatabase();
+ throw;
+ }
+}
+
+DB::Connection *
+MockMySQLDatabase::openConnection(const std::string & connStr)
+{
+ return InstanceMap<ConnectionLoader, std::string>::Get<std::invalid_argument>("mysql")->create(connStr);
+}
+
+MockMySQLDatabase::~MockMySQLDatabase()
+{
+ Logger()->messagebf(LOG_DEBUG, "Tearing down mocked database %s", testDbName);
+ DropDatabase();
+ delete master;
+ MockConnectionLoader::mocks.erase(mockName);
+ Logger()->messagebf(LOG_DEBUG, "%s torn down", testDbName);
+}
+
+void MockMySQLDatabase::DropDatabase() const
+{
+ Logger()->messagebf(LOG_INFO, "Dropping (if exists) old database %s", testDbName);
+ master->execute("DROP DATABASE IF EXISTS " + testDbName);
+}
+
+void MockMySQLDatabase::CreateNewDatabase() const
+{
+ Logger()->messagebf(LOG_INFO, "Creating new database %s", testDbName);
+ master->execute("CREATE DATABASE " + testDbName);
+}
+
+
diff --git a/project2/sql/sql-modMySQL.h b/project2/sql/sql-modMySQL.h
new file mode 100644
index 0000000..628bfdb
--- /dev/null
+++ b/project2/sql/sql-modMySQL.h
@@ -0,0 +1,24 @@
+#ifndef MOCKMYSQLDATASOURCE_H
+#define MOCKMYSQLDATASOURCE_H
+
+#include "mockDatasource.h"
+#include <boost/filesystem/path.hpp>
+
+class MockMySQLDatabase {
+ public:
+ MockMySQLDatabase(const std::string & name, const std::vector<boost::filesystem::path> & ss);
+ ~MockMySQLDatabase();
+
+ protected:
+ void DropDatabase() const;
+ void CreateNewDatabase() const;
+
+ private:
+ static DB::Connection * openConnection(const std::string & connStr);
+ const DB::Connection * master;
+ const std::string testDbName;
+ const std::string mockName;
+};
+
+#endif
+
diff --git a/project2/sql/unittests/Jamfile.jam b/project2/sql/unittests/Jamfile.jam
index d9874ce..d14aea4 100644
--- a/project2/sql/unittests/Jamfile.jam
+++ b/project2/sql/unittests/Jamfile.jam
@@ -44,3 +44,11 @@ run
<dependency>sqliteschema.sql
: testsqlite ;
+run
+ testmysql.cpp
+ : : :
+ <library>sqlTestCore
+ <library>..//p2sqlmodMySQL
+ <dependency>mysqlschema.sql
+ : testmysql ;
+
diff --git a/project2/sql/unittests/datasources/mysqlmock.xml b/project2/sql/unittests/datasources/mysqlmock.xml
new file mode 100644
index 0000000..9641bd1
--- /dev/null
+++ b/project2/sql/unittests/datasources/mysqlmock.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<project2:rdbmsdatasource xmlns:project2="http://project2.randomdan.homeip.net" name="mysqlmock">
+ <masterdsn provider="mock" dsn="mysqlmock" />
+</project2:rdbmsdatasource>
diff --git a/project2/sql/unittests/mysqlschema.sql b/project2/sql/unittests/mysqlschema.sql
new file mode 100644
index 0000000..39e63dc
--- /dev/null
+++ b/project2/sql/unittests/mysqlschema.sql
@@ -0,0 +1,7 @@
+CREATE TABLE test(
+ id int,
+ fl numeric(5,2),
+ string varchar(30),
+ dt timestamp,
+ ts time);
+INSERT INTO test VALUES(4, 123.45, 'some text', '2015-04-27 23:06:03', '38:13:12');
diff --git a/project2/sql/unittests/testmysql.cpp b/project2/sql/unittests/testmysql.cpp
new file mode 100644
index 0000000..4debd35
--- /dev/null
+++ b/project2/sql/unittests/testmysql.cpp
@@ -0,0 +1,115 @@
+#define BOOST_TEST_MODULE TestMySQL
+#include <boost/test/unit_test.hpp>
+
+#include <mockDatasource.h>
+#include <definedDirs.h>
+#include <modifycommand.h>
+#include <selectcommand.h>
+#include <column.h>
+#include <sql-modMySQL.h>
+#include "testCore.h"
+#include <sqlHandleAsVariableType.h>
+
+class StandardMockDatabase : public MockMySQLDatabase {
+ public:
+ StandardMockDatabase() : MockMySQLDatabase("mysqlmock", {
+ RootDir / "mysqlschema.sql" })
+ {
+ }
+};
+
+BOOST_GLOBAL_FIXTURE( StandardMockDatabase );
+
+BOOST_FIXTURE_TEST_SUITE( Core, TestCore );
+
+BOOST_AUTO_TEST_CASE( transactions )
+{
+ RdbmsDataSource * ds = CommonObjects::dataSource<RdbmsDataSource>("mysqlmock");
+ 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>("mysqlmock");
+ 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->bindParamT(3, testDateTime);
+ mod->bindParamT(4, testInterval);
+ 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>("mysqlmock");
+ 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, testDateTime);
+ assertColumnValueHelper(*select, 4, testInterval);
+ rows += 1;
+ }
+ delete select;
+ BOOST_REQUIRE_EQUAL(1, rows);
+ ds->close();
+}
+
+BOOST_AUTO_TEST_CASE( bindAndSelectOther )
+{
+ RdbmsDataSource * ds = CommonObjects::dataSource<RdbmsDataSource>("mysqlmock");
+ 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, boost::posix_time::ptime_from_tm({ 3, 6, 23, 27, 3, 115, 0, 0, 0, 0, 0}));
+ assertColumnValueHelper(*select, 4, boost::posix_time::time_duration(38, 13, 12));
+ rows += 1;
+ }
+ delete select;
+ BOOST_REQUIRE_EQUAL(1, rows);
+ ds->close();
+}
+
+BOOST_AUTO_TEST_SUITE_END();
+