summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/src/Makefile.am20
-rw-r--r--server/src/configuration.cc1
-rw-r--r--server/src/configuration.h1
-rw-r--r--server/src/configurationparser.cc6
-rw-r--r--server/src/database.cc5
-rw-r--r--server/src/pracrod.cc13
-rw-r--r--server/src/pracrodaotest.cc336
-rw-r--r--server/src/pracrodaotest.h93
-rw-r--r--server/src/server.cc2
9 files changed, 475 insertions, 2 deletions
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
@@ -105,6 +105,12 @@ void ConfigurationParser::reload()
}
try {
+ std::string a = lookup("database_backend");
+ Conf::database_backend = a;
+ } catch( ... ) {
+ }
+
+ try {
std::string a = lookup("database_addr");
Conf::database_addr = a;
} catch( ... ) {
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 <stdlib.h>
+#include <sstream>
+
+#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<std::string, std::string> &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<std::string, std::string> &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<std::string, std::string> &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<Fieldname> PracroDAOTest::getFieldnames()
+{
+ // TODO
+
+ std::vector<Fieldname> 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 <string>
+#include <vector>
+#include <map>
+
+#include <config.h>
+
+#include "pracrodao.h"
+
+typedef std::map<std::string, std::string> 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 &macro, 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<Fieldname> 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);