summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2015-04-30 00:27:27 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2015-04-30 00:27:27 +0100
commitd80e4e4f5505f5da52eed454b174bbac03886a02 (patch)
treef8378ed4c5101387601252fdf62aea6fd0e8c9a1
parentSelect some values and validate them (diff)
downloadproject2-d80e4e4f5505f5da52eed454b174bbac03886a02.tar.bz2
project2-d80e4e4f5505f5da52eed454b174bbac03886a02.tar.xz
project2-d80e4e4f5505f5da52eed454b174bbac03886a02.zip
Adds support for SQLite, SQLite mocking and some basic tests
-rw-r--r--project2/Jamfile.jam2
-rw-r--r--project2/sql/Jamfile.jam14
-rw-r--r--project2/sql/sql-modSQLite.cpp61
-rw-r--r--project2/sql/sql-modSQLite.h24
-rw-r--r--project2/sql/unittests/Jamfile.jam28
-rw-r--r--project2/sql/unittests/datasources/sqlitemock.xml5
-rw-r--r--project2/sql/unittests/sqliteschema.sql6
-rw-r--r--project2/sql/unittests/testsqlite.cpp89
8 files changed, 219 insertions, 10 deletions
diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam
index 8e083e7..70c8c5b 100644
--- a/project2/Jamfile.jam
+++ b/project2/Jamfile.jam
@@ -4,6 +4,7 @@ import feature : feature ;
feature odbc : yes no ;
feature pq : yes no ;
feature mysql : yes no ;
+feature sqlite : yes no ;
alias p2parts : : : :
<library>url//p2url
@@ -22,6 +23,7 @@ alias p2parts : : : :
<odbc>yes:<library>sql//p2sqlmodODBC
<pq>yes:<library>sql//p2sqlmodPQ
<mysql>yes:<library>sql//p2sqlmodMySQL
+ <sqlite>yes:<library>sql//p2sqlmodSQLite
;
alias p2daemonparts : : : :
diff --git a/project2/sql/Jamfile.jam b/project2/sql/Jamfile.jam
index 306c94a..01ba44b 100644
--- a/project2/sql/Jamfile.jam
+++ b/project2/sql/Jamfile.jam
@@ -2,6 +2,7 @@ alias glibmm : : : :
<cflags>"`pkg-config --cflags glibmm-2.4`"
<linkflags>"`pkg-config --libs glibmm-2.4`"
;
+lib boost_filesystem ;
build-project unittests ;
@@ -16,6 +17,19 @@ lib p2sqlmodMySQL :
: :
<library>../../libmysqlpp//mysqlpp
;
+
+explicit library p2sqlmodSQLite ;
+lib p2sqlmodSQLite :
+ sql-modSQLite.cpp :
+ <library>../../libsqlitepp//sqlitepp
+ <library>glibmm
+ <include>../../libmisc
+ <library>../common//p2common
+ <library>p2sql
+ <library>boost_filesystem
+ : :
+ <library>../../libsqlitepp//sqlitepp
+ ;
explicit library p2sqlmodODBC ;
lib p2sqlmodODBC :
diff --git a/project2/sql/sql-modSQLite.cpp b/project2/sql/sql-modSQLite.cpp
new file mode 100644
index 0000000..6b4cb85
--- /dev/null
+++ b/project2/sql/sql-modSQLite.cpp
@@ -0,0 +1,61 @@
+#include "connectionLoader.h"
+#include "../libsqlitepp/connection.h"
+#include "sql-modSQLite.h"
+#include <misc.h>
+#include <scripts.h>
+#include <logger.h>
+#include <boost/filesystem/operations.hpp>
+
+typedef SQLite::Connection SQLiteConnection;
+DECLARE_GENERIC_LOADER("sqlite", ConnectionLoader, SQLiteConnection)
+
+MockSQLiteDatabase::MockSQLiteDatabase(const std::string & name, const std::vector<boost::filesystem::path> & ss) :
+ testDbPath(boost::filesystem::path("/tmp") / "sqliteut" / stringbf("%d", getpid()) / stringbf("%d", ++MockConnectionLoader::mocked)),
+ mockName(name)
+{
+ Logger()->messagebf(LOG_DEBUG, "Setting up new mocked database at %s", testDbPath);
+ DropDatabase();
+ CreateNewDatabase();
+ try {
+ for (auto s : ss) {
+ Logger()->messagebf(LOG_DEBUG, "%s << %s", testDbPath, s);
+ if (system(("sqlite3 -bail " + testDbPath.string() + " < " + s.string()).c_str())) {
+ throw std::runtime_error("Failed to execute " + s.string());
+ }
+ }
+ Logger()->messagebf(LOG_DEBUG, "%s initialized", testDbPath);
+ MockConnectionLoader::mocks[name] = boost::bind(MockSQLiteDatabase::openConnection, testDbPath.string());
+ }
+ catch (...) {
+ DropDatabase();
+ throw;
+ }
+}
+
+DB::Connection *
+MockSQLiteDatabase::openConnection(const std::string & connStr)
+{
+ return InstanceMap<ConnectionLoader, std::string>::Get<std::invalid_argument>("sqlite")->create(connStr);
+}
+
+MockSQLiteDatabase::~MockSQLiteDatabase()
+{
+ Logger()->messagebf(LOG_DEBUG, "Tearing down mocked database %s", testDbPath);
+ DropDatabase();
+ MockConnectionLoader::mocks.erase(mockName);
+ Logger()->messagebf(LOG_DEBUG, "%s torn down", testDbPath);
+}
+
+void MockSQLiteDatabase::DropDatabase() const
+{
+ Logger()->messagebf(LOG_INFO, "Deleting database %s", testDbPath);
+ boost::filesystem::remove(testDbPath);
+}
+
+void MockSQLiteDatabase::CreateNewDatabase() const
+{
+ Logger()->messagebf(LOG_INFO, "Creating new database at %s", testDbPath);
+ boost::filesystem::create_directories(testDbPath.parent_path());
+}
+
+
diff --git a/project2/sql/sql-modSQLite.h b/project2/sql/sql-modSQLite.h
new file mode 100644
index 0000000..267ba0b
--- /dev/null
+++ b/project2/sql/sql-modSQLite.h
@@ -0,0 +1,24 @@
+#ifndef MOCKSQLITEDATASOURCE_H
+#define MOCKSQLITEDATASOURCE_H
+
+#include "mockDatasource.h"
+#include <boost/filesystem/path.hpp>
+
+class MockSQLiteDatabase {
+ public:
+ MockSQLiteDatabase(const std::string & name, const std::vector<boost::filesystem::path> & ss);
+ ~MockSQLiteDatabase();
+
+ protected:
+ void DropDatabase() const;
+ void CreateNewDatabase() const;
+
+ private:
+ static DB::Connection * openConnection(const std::string & connStr);
+ const boost::filesystem::path testDbPath;
+ const std::string mockName;
+};
+
+#endif
+
+
diff --git a/project2/sql/unittests/Jamfile.jam b/project2/sql/unittests/Jamfile.jam
index 24db2e5..d9874ce 100644
--- a/project2/sql/unittests/Jamfile.jam
+++ b/project2/sql/unittests/Jamfile.jam
@@ -1,4 +1,3 @@
-
import testing ;
lib boost_system ;
@@ -10,29 +9,38 @@ path-constant me : . ;
lib sqlTestCore :
testCore.cpp
- : :
+ :
<library>../../ut//p2ut
<library>../../common//p2common
<library>boost_filesystem
<define>ROOT=\"$(me)\"
- ;
-
-run
- testpq.cpp
- : : :
- <define>BOOST_TEST_DYN_LINK
- <library>sqlTestCore
+ : :
<library>../../common//p2common
<library>../../basics//p2basics
<library>../../ut//p2ut
<library>../../lib//p2lib
<library>../../xml//p2xml
<library>..//p2sql
- <library>..//p2sqlmodPQ
<library>boost_system
<library>boost_filesystem
<library>../../ut//boost_utf
<define>ROOT=\"$(me)\"
+ <define>BOOST_TEST_DYN_LINK
+ ;
+
+run
+ testpq.cpp
+ : : :
+ <library>sqlTestCore
+ <library>..//p2sqlmodPQ
<dependency>pqschema.sql
: testpq ;
+run
+ testsqlite.cpp
+ : : :
+ <library>sqlTestCore
+ <library>..//p2sqlmodSQLite
+ <dependency>sqliteschema.sql
+ : testsqlite ;
+
diff --git a/project2/sql/unittests/datasources/sqlitemock.xml b/project2/sql/unittests/datasources/sqlitemock.xml
new file mode 100644
index 0000000..762de90
--- /dev/null
+++ b/project2/sql/unittests/datasources/sqlitemock.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<project2:rdbmsdatasource xmlns:project2="http://project2.randomdan.homeip.net" name="sqlitemock">
+ <masterdsn provider="mock" dsn="sqlitemock" />
+</project2:rdbmsdatasource>
+
diff --git a/project2/sql/unittests/sqliteschema.sql b/project2/sql/unittests/sqliteschema.sql
new file mode 100644
index 0000000..393d21a
--- /dev/null
+++ b/project2/sql/unittests/sqliteschema.sql
@@ -0,0 +1,6 @@
+CREATE TABLE test(
+ id int,
+ fl numeric(5,2),
+ string text);
+INSERT INTO test VALUES(4, 123.45, 'some text');
+
diff --git a/project2/sql/unittests/testsqlite.cpp b/project2/sql/unittests/testsqlite.cpp
new file mode 100644
index 0000000..89a1f77
--- /dev/null
+++ b/project2/sql/unittests/testsqlite.cpp
@@ -0,0 +1,89 @@
+#define BOOST_TEST_MODULE TestSQLite
+#include <boost/test/unit_test.hpp>
+
+#include <mockDatasource.h>
+#include <definedDirs.h>
+#include <modifycommand.h>
+#include <selectcommand.h>
+#include <column.h>
+#include <sql-modSQLite.h>
+#include "testCore.h"
+#include <sqlHandleAsVariableType.h>
+
+class StandardMockDatabase : public MockSQLiteDatabase {
+ public:
+ StandardMockDatabase() : MockSQLiteDatabase("sqlitemock", {
+ RootDir / "sqliteschema.sql" })
+ {
+ }
+};
+
+BOOST_GLOBAL_FIXTURE( StandardMockDatabase );
+
+BOOST_FIXTURE_TEST_SUITE( Core, TestCore );
+
+BOOST_AUTO_TEST_CASE( transactions )
+{
+ RdbmsDataSource * ds = CommonObjects::dataSource<RdbmsDataSource>("sqlitemock");
+ 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>("sqlitemock");
+ 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->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>("sqlitemock");
+ 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);
+ rows += 1;
+ }
+ delete select;
+ BOOST_REQUIRE_EQUAL(1, rows);
+ ds->close();
+}
+
+BOOST_AUTO_TEST_SUITE_END();
+