From d35bafeec39b6688a8dd07c51ea304e348b10fa2 Mon Sep 17 00:00:00 2001 From: deva Date: Fri, 7 Aug 2009 11:27:18 +0000 Subject: Added new testdb, that can be activated through the cli (-d testdb) or through the config file (database_backend = testdb) . --- server/src/Makefile.am | 20 +++ server/src/configuration.cc | 1 + server/src/configuration.h | 1 + server/src/configurationparser.cc | 6 + server/src/database.cc | 5 + server/src/pracrod.cc | 13 +- server/src/pracrodaotest.cc | 336 ++++++++++++++++++++++++++++++++++++++ server/src/pracrodaotest.h | 93 +++++++++++ server/src/server.cc | 2 +- 9 files changed, 475 insertions(+), 2 deletions(-) create mode 100644 server/src/pracrodaotest.cc create mode 100644 server/src/pracrodaotest.h diff --git a/server/src/Makefile.am b/server/src/Makefile.am index 3bc3069..399d7fa 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -25,6 +25,7 @@ pracrod_SOURCES = \ macroparser.cc \ pracrodao.cc \ pracrodaopgsql.cc \ + pracrodaotest.cc \ resumeparser.cc \ saxparser.cc \ server.cc \ @@ -59,6 +60,7 @@ macrotool_SOURCES = \ macrotool_util.cc \ pracrodao.cc \ pracrodaopgsql.cc \ + pracrodaotest.cc \ saxparser.cc \ templateparser.cc \ versionstr.cc @@ -88,6 +90,7 @@ EXTRA_DIST = \ macrotool_util.h \ pracrodao.h \ pracrodaopgsql.h \ + pracrodaotest.h \ resumeparser.h \ saxparser.h \ server.h \ @@ -106,6 +109,8 @@ EXTRA_DIST = \ ################ TESTFILES = \ + test_pracrodaotest \ + test_widgetgenerator \ test_configurationparser \ test_exception \ test_templateheaderparser \ @@ -143,6 +148,21 @@ test: $(TESTFILES) test_clean: rm -f $(TESTFILES) $(TESTLOGS) +TEST_PRACRODAOTEST_FILES = \ + pracrodaotest.cc \ + pracrodao.cc \ + $(BASICFILES) +test_pracrodaotest: $(TEST_PRACRODAOTEST_FILES) + @../../tools/test $(TEST_PRACRODAOTEST_FILES) $(BASICFLAGS) + +TEST_WIDGETGENERATOR_FILES = \ + widgetgenerator.cc \ + xml_encode_decode.cc \ + luaquerymapper.cc \ + $(BASICFILES) +test_widgetgenerator: $(TEST_WIDGETGENERATOR_FILES) + @../../tools/test $(TEST_WIDGETGENERATOR_FILES) $(BASICFLAGS) $(LUA_LIBS) + TEST_CONFIGURATIONPARSER_FILES = \ configurationparser.cc \ configuration.cc \ diff --git a/server/src/configuration.cc b/server/src/configuration.cc index c921da6..c1dcab1 100644 --- a/server/src/configuration.cc +++ b/server/src/configuration.cc @@ -41,6 +41,7 @@ time_t Conf::pentominos_max_ttl = 7 * 60 * 60 * 24; std::string Conf::pentominos_addr = "localhost"; port_t Conf::pentominos_port = 11108; +std::string Conf::database_backend = "pgsql"; std::string Conf::database_addr = "localhost"; std::string Conf::database_user = "pracro"; std::string Conf::database_passwd = "pracro"; diff --git a/server/src/configuration.h b/server/src/configuration.h index 56a2f0e..3d9f7f1 100644 --- a/server/src/configuration.h +++ b/server/src/configuration.h @@ -48,6 +48,7 @@ namespace Conf { extern std::string pentominos_addr; extern port_t pentominos_port; + extern std::string database_backend; extern std::string database_addr; extern std::string database_user; extern std::string database_passwd; diff --git a/server/src/configurationparser.cc b/server/src/configurationparser.cc index a3e7532..8247a45 100644 --- a/server/src/configurationparser.cc +++ b/server/src/configurationparser.cc @@ -104,6 +104,12 @@ void ConfigurationParser::reload() } catch( ... ) { } + try { + std::string a = lookup("database_backend"); + Conf::database_backend = a; + } catch( ... ) { + } + try { std::string a = lookup("database_addr"); Conf::database_addr = a; diff --git a/server/src/database.cc b/server/src/database.cc index 5a03126..9a4905b 100644 --- a/server/src/database.cc +++ b/server/src/database.cc @@ -32,6 +32,7 @@ #include "debug.h" #include "pracrodaopgsql.h" +#include "pracrodaotest.h" Database::Database(std::string _backend, std::string _host, std::string _port, std::string _user, std::string _passwd, std::string _dbname) { @@ -42,6 +43,10 @@ Database::Database(std::string _backend, std::string _host, std::string _port, s dao = new PracroDAOPgsql(_host, _port, _user, _passwd, _dbname); } #endif/*WITHOUT_DB*/ + if(_backend == "testdb") { + Data data; + dao = new PracroDAOTest(data, true); + } } Database::~Database() diff --git a/server/src/pracrod.cc b/server/src/pracrod.cc index a929f63..75f58a6 100644 --- a/server/src/pracrod.cc +++ b/server/src/pracrod.cc @@ -88,6 +88,7 @@ static const char usage_str[] = " -v, --version Print version information and exit.\n" " -h, --help Print this message and exit.\n" " -D, --debug ddd Enable debug messages on 'ddd'; see documentation for details\n" +" -d --database db Use db as the database backend. Can be one of pgsql or testdb (default pgsql).\n" ; ConfigurationParser *configparser = NULL; @@ -145,6 +146,7 @@ int main(int argc, char *argv[]) bool foreground = false; char *xml_basedir = NULL; char *debugstr = NULL; + std::string database; pracro_debug_init(); @@ -160,15 +162,20 @@ int main(int argc, char *argv[]) {"version", no_argument, 0, 'v'}, {"xml-basedir", required_argument, 0, 'x'}, {"debug", required_argument, 0, 'D'}, + {"database", required_argument, 0, 'd'}, {0, 0, 0, 0} }; - c = getopt_long (argc, argv, "D:hvfc:u:g:x:", long_options, &option_index); + c = getopt_long (argc, argv, "D:hvfc:u:g:x:d:", long_options, &option_index); if (c == -1) break; switch(c) { + case 'd': + database = optarg; + break; + case 'c': configfile = strdup(optarg); break; @@ -217,6 +224,10 @@ int main(int argc, char *argv[]) if(configfile) configparser = new ConfigurationParser(configfile); else configparser = new ConfigurationParser(ETC"/pracrod.conf"); + if(database != "") { + Conf::database_backend = database; + } + if(!user) { user = strdup(Conf::server_user.c_str()); } diff --git a/server/src/pracrodaotest.cc b/server/src/pracrodaotest.cc new file mode 100644 index 0000000..c084e5b --- /dev/null +++ b/server/src/pracrodaotest.cc @@ -0,0 +1,336 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * pracrodaotest.cc + * + * Fri Aug 7 10:25:07 CEST 2009 + * Copyright 2009 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "pracrodaotest.h" + +#include +#include + +#include "debug.h" + +PracroDAOTest::PracroDAOTest(Data &data, bool ignore_fieldnames) + : PracroDAO("", "", "", "", "") +{ + this->data = data; + this->ignore_fieldnames = ignore_fieldnames; + PRACRO_DEBUG(db, "New test (memory only) database\n"); +} + +PracroDAOTest::~PracroDAOTest() +{ + PRACRO_DEBUG(db, "Delete test (memory only) database\n"); +} + +void PracroDAOTest::commitTransaction(std::string user, std::string patientid, + Macro &_macro, Fields &fields, time_t now) +{ + PRACRO_DEBUG(db, "(%s, %s, %s, <%u fields>, %ld)\n", + user.c_str(), + patientid.c_str(), + _macro.attributes["name"].c_str(), + fields.size(), + now); + if(fields.size() == 0) return; + + std::string version = _macro.attributes["version"]; + std::string macro = _macro.attributes["name"]; + std::stringstream timestamp; timestamp << now; + + dbrow_t t; + t["uid"] = data.trseq.nextval(); + t["patientid"] = patientid; + t["macro"] = macro; + t["version"] = version; + t["timestamp"] = timestamp.str(); + t["user"] = user; + data.transactions.push_back(t); + + // Iterate fields... + Fields::iterator fi = fields.begin(); + while(fi != fields.end()) { + + if(ignore_fieldnames == false) { + // Search for it in fieldnames table + dbtable_t::iterator ti = data.fieldnames.begin(); + while(ti != data.fieldnames.end()) { + + // If found, insert the field values into the fields table. + if(fi->first == (*ti)["name"]) { + + dbrow_t f; + f["transaction"] = data.trseq.currval(); + f["name"] = fi->first; + f["value"] = fi->second; + data.fields.push_back(f); + + } + + ti++; + } + } else { + dbrow_t f; + f["transaction"] = data.trseq.currval(); + f["name"] = fi->first; + f["value"] = fi->second; + data.fields.push_back(f); + } + + fi++; + } +} + +Values PracroDAOTest::getLatestValues(std::string patientid, Macro *macro, + Fieldnames &fieldnames, time_t oldest) +{ + PRACRO_DEBUG(db, "(%s, %s, <%u fieldnames>, %ld)\n", + patientid.c_str(), + macro ? macro->attributes["name"].c_str() : "(null)", fieldnames.size(), + oldest); + Values values; + + // TODO: Take Macro* into account. If supplied (not NULL) the macro name, and + // optionally version number should match the transaction. + + Fieldnames::iterator fi = fieldnames.begin(); + while(fi != fieldnames.end()) { + std::string fieldname = *fi; + + // Find matching transactions + dbtable_t::iterator ti = data.transactions.begin(); + while(ti != data.transactions.end()) { + std::map &transaction = *ti; + time_t timestamp = atol(transaction["timestamp"].c_str()); + if(transaction["patientid"] == patientid && timestamp >= oldest) { + std::string tid = transaction["uid"]; + + // Find transaction values + dbtable_t::iterator vi = data.fields.begin(); + while(vi != data.fields.end()) { + std::map &field = *vi; + + // Upon match, insert it into values + if(field["transaction"] == tid && field["name"] == fieldname) { + if(values.find(fieldname) == values.end() || values[fieldname].timestamp < timestamp) { + values[fieldname].timestamp = timestamp; + values[fieldname].value = field["value"]; + values[fieldname].source = "testdb"; + } + } + vi++; + } + + } + ti++; + } + + fi++; + } + + return values; +} + + +unsigned PracroDAOTest::nrOfCommits(std::string patientid, std::string macroname, time_t oldest) +{ + unsigned num = 0; + + // Find and count matching transactions + dbtable_t::iterator ti = data.transactions.begin(); + while(ti != data.transactions.end()) { + std::map &transaction = *ti; + time_t timestamp = atol(transaction["timestamp"].c_str()); + if(transaction["patientid"] == patientid && + transaction["macro"] == macroname && + timestamp >= oldest) { + num++; + } + ti++; + } + + return num; +} + +void PracroDAOTest::addFieldname(std::string name, std::string description) +{ + // TODO + + /* + std::stringstream timestamp; timestamp << time(NULL); + std::string ts; + try { + pqxx::work W(*conn); + ts = "INSERT INTO fieldnames (name, description, \"timestamp\") VALUES (" + " '" + W.esc(name) + "', " + " '" + W.esc(description) + "', " + " '" + W.esc(timestamp.str()) + "' " + ")" + ; + PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str()); + pqxx::result R = W.exec(ts); + W.commit(); + } catch (std::exception &e) { + PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str()); + } + */ +} + +void PracroDAOTest::delFieldname(std::string name) +{ + // TODO + + /* + std::string ts; + try { + pqxx::work W(*conn); + ts = "DELETE FROM fieldnames WHERE name=" + "'" + W.esc(name) + "' "; + PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str()); + pqxx::result R = W.exec(ts); + W.commit(); + } catch (std::exception &e) { + PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str()); + } + */ +} + +std::vector PracroDAOTest::getFieldnames() +{ + // TODO + + std::vector fieldnames; + /* + std::string query; + try { + pqxx::work W(*conn); + query = "SELECT * FROM fieldnames"; + PRACRO_DEBUG(sql, "Query: %s\n", query.c_str()); + pqxx::result R = W.exec(query); + pqxx::result::const_iterator ri = R.begin(); + while(ri != R.end()) { + Fieldname f; + f.name = (*ri)[0].c_str(); + f.description = (*ri)[1].c_str(); + f.timestamp = atol((*ri)[2].c_str()); + fieldnames.push_back(f); + ri++; + } + } catch (std::exception &e) { + PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), query.c_str()); + } + */ + return fieldnames; +} + + + + +#ifdef TEST_PRACRODAOTEST + +#define PATIENTID "1234567890" + +int main() +{ + time_t now = time(NULL); + + Data data; + + // Add some fieldnames + dbrow_t f; + f["name"] = "field1"; data.fieldnames.push_back(f); + f["name"] = "field2"; data.fieldnames.push_back(f); + f["name"] = "field3"; data.fieldnames.push_back(f); + + PracroDAOTest db(data); + + // Make a commit + Macro macro; + macro.attributes["version"] = "1.0"; + macro.attributes["name"] = "testmacro"; + + Fields fields; + fields["field1"] = "testval1"; + fields["field2"] = "testval2"; + fields["field3"] = "testval3"; + fields["field4"] = "testval4"; + db.commitTransaction("testuser", PATIENTID, macro, fields, now); + + // Retrieve the data again + unsigned num = db.nrOfCommits(PATIENTID, "testmacro", now); + if(num != 1) return 1; + + Fieldnames fieldnames; + fieldnames.push_back("field1"); + fieldnames.push_back("field2"); + fieldnames.push_back("field3"); + fieldnames.push_back("field4"); + Values values = db.getLatestValues(PATIENTID, NULL, fieldnames, now); + + Values::iterator i = values.begin(); + while(i != values.end()) { + printf("%s => %s\n", i->first.c_str(), i->second.value.c_str()); + i++; + } + if(values["field1"].value != "testval1") return 1; + if(values["field2"].value != "testval2") return 1; + if(values["field3"].value != "testval3") return 1; + + // This value was not committed, since it wasn't in the fieldnames table. + if(values.find("field4") != values.end()) return 1; + + // Make another commit (one second later) + fields["field1"] = "testval1-2"; + fields["field2"] = "testval2-2"; + fields["field3"] = "testval3-2"; + fields["field4"] = "testval4-2"; + db.commitTransaction("testuser", PATIENTID, macro, fields, now+1); + + // Retrieve the data again + num = db.nrOfCommits(PATIENTID, "testmacro", now); + if(num != 2) return 1; + + fieldnames.push_back("field1"); + fieldnames.push_back("field2"); + fieldnames.push_back("field3"); + fieldnames.push_back("field4"); + values = db.getLatestValues(PATIENTID, NULL, fieldnames, now); + + i = values.begin(); + while(i != values.end()) { + printf("%s => %s\n", i->first.c_str(), i->second.value.c_str()); + i++; + } + if(values["field1"].value != "testval1-2") return 1; + if(values["field2"].value != "testval2-2") return 1; + if(values["field3"].value != "testval3-2") return 1; + + // This value was not committed, since it wasn't in the fieldnames table. + if(values.find("field4") != values.end()) return 1; + + return 0; +} + +#endif/*TEST_PRACRODAOTEST*/ diff --git a/server/src/pracrodaotest.h b/server/src/pracrodaotest.h new file mode 100644 index 0000000..8dd4655 --- /dev/null +++ b/server/src/pracrodaotest.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * pracrodaotest.h + * + * Fri Aug 7 10:25:07 CEST 2009 + * Copyright 2009 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pracro. + * + * Pracro is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pracro is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pracro; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PRACRO_PRACRODAOTEST_H__ +#define __PRACRO_PRACRODAOTEST_H__ + +#include +#include +#include + +#include + +#include "pracrodao.h" + +typedef std::map dbrow_t; +typedef std::vector< dbrow_t > dbtable_t; + +class dbcounter_t { +public: + dbcounter_t() + { + counter = 0; + } + + std::string nextval() + { + counter++; + return currval(); + } + + std::string currval() + { + char buf[32]; + sprintf(buf, "%d", counter); + return buf; + } + +private: + size_t counter; +}; + +class Data { +public: + dbcounter_t trseq; + dbtable_t transactions; + dbtable_t fieldnames; + dbtable_t fields; +}; + +class PracroDAOTest : public PracroDAO +{ +public: + PracroDAOTest(Data &data, bool ignore_fieldnames = false); + ~PracroDAOTest(); + + void commitTransaction(std::string user, std::string patientid, Macro ¯o, Fields &fields, time_t now); + Values getLatestValues(std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest); + unsigned nrOfCommits(std::string patientid, std::string macroname, time_t oldest); + + void addFieldname(std::string name, std::string description); + void delFieldname(std::string name); + std::vector getFieldnames(); + +private: + Data data; + bool ignore_fieldnames; +}; + +#endif/*__PRACRO_PRACRODAOTEST_H__*/ diff --git a/server/src/server.cc b/server/src/server.cc index d0e9524..a47eb28 100644 --- a/server/src/server.cc +++ b/server/src/server.cc @@ -299,7 +299,7 @@ static void handleConnection(TCPSocket *socket) pentominos_socket.connect(Conf::pentominos_addr, Conf::pentominos_port); #endif/*WITHOUT_PENTOMINOS*/ - Database db("pgsql", Conf::database_addr, "", Conf::database_user, Conf::database_passwd, ""); + Database db(Conf::database_backend, Conf::database_addr, "", Conf::database_user, Conf::database_passwd, ""); JournalWriter journalwriter(Conf::journal_commit_addr.c_str(), Conf::journal_commit_port); -- cgit v1.2.3