/* -*- 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; DEBUG(db, "New test (memory only) database\n"); } PracroDAOTest::~PracroDAOTest() { DEBUG(db, "Delete test (memory only) database\n"); } std::string PracroDAOTest::newSessionId() { return data.sessionseq.nextval(); } void PracroDAOTest::commitTransaction(std::string sessionid, Transaction &transaction, Commit &commit, Macro &_macro, time_t now) { DEBUG(db, "(%s, %s, %s, <%u fields>, %ld)\n", transaction.user.c_str(), transaction.cpr.c_str(), _macro.attributes["name"].c_str(), commit.fields.size(), now); if(commit.fields.size() == 0) return; std::string version = _macro.attributes["version"]; std::string macro = _macro.attributes["name"]; std::stringstream timestamp; timestamp << now; dbtable_t::iterator ci = data.commits.begin(); while(ci != data.commits.end()) { dbrow_t &c = *ci; if(c["uid"] == sessionid) { break; } ci++; } if(ci == data.commits.end()) { DEBUG(testdb, "Create new commit: %s", sessionid.c_str()); dbrow_t c; c["patientid"] = transaction.cpr; c["template"] = commit.templ; c["version"] = "1.0"; c["timestamp"] = timestamp.str(); c["uid"] = sessionid; c["status"] = "active"; data.commits.push_back(c); } else { dbrow_t &c = *ci; if(c["status"] == "committed") { ERR_LOG(db, "Attempt to add to committed session %s blocked!\n", sessionid.c_str()); return; } DEBUG(testdb, "Working on old commit: %s", sessionid.c_str()); c["status"] = "active"; } dbrow_t t; t["uid"] = data.trseq.nextval(); t["patientid"] = transaction.cpr; t["template"] = commit.templ; t["macro"] = macro; t["version"] = version; t["timestamp"] = timestamp.str(); t["user"] = transaction.user; data.transactions.push_back(t); // Iterate fields... Fields::iterator fi = commit.fields.begin(); while(fi != commit.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 sessionid, std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest) { std::string macro_name = macro ? macro->attributes["name"].c_str() : "(null)"; DEBUG(db, "(%s, %s, <%u fieldnames>, %ld)\n", patientid.c_str(), macro_name.c_str(), fieldnames.size(), oldest); Values values; 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()) { dbrow_t &transaction = *ti; time_t timestamp = atol(transaction["timestamp"].c_str()); if(transaction["patientid"] == patientid && timestamp >= oldest && (transaction["macro"] == macro_name || macro == NULL)) { std::string tid = transaction["uid"]; // Find transaction values dbtable_t::iterator vi = data.fields.begin(); while(vi != data.fields.end()) { dbrow_t &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 sessionid, 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()) { dbrow_t &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) { dbrow_t fieldname; fieldname["name"] = name; fieldname["description"] = description; char buf[256]; sprintf(buf, "%lu", time(NULL)); fieldname["timestamp"] = buf; data.fieldnames.push_back(fieldname); } void PracroDAOTest::delFieldname(std::string name) { dbtable_t::iterator i = data.fieldnames.begin(); while(i != data.fieldnames.end()) { dbrow_t &row = *i; if(row["name"] == name) { data.fieldnames.erase(i); return; } i++; } } std::vector PracroDAOTest::getFieldnames() { std::vector fieldnames; dbtable_t::iterator i = data.fieldnames.begin(); while(i != data.fieldnames.end()) { dbrow_t &row = *i; Fieldname fn; fn.name = row["name"]; fn.description = row["description"]; fn.timestamp = atoll(row["timestamp"].c_str()); fieldnames.push_back(fn); i++; } return fieldnames; } bool PracroDAOTest::idle(std::string sessionid) { dbtable_t::iterator i = data.commits.begin(); while(i != data.commits.end()) { dbrow_t &commit = *i; if(commit["uid"] == sessionid) { return commit["status"] == "idle"; } i++; } return false; } void PracroDAOTest::setIdle(std::string sessionid, bool idle) { dbtable_t::iterator i = data.commits.begin(); while(i != data.commits.end()) { dbrow_t &commit = *i; if(commit["uid"] == sessionid && commit["status"] != "committed") { commit["status"] = idle?"idle":"active"; } i++; } } void PracroDAOTest::commit(std::string sessionid) { dbtable_t::iterator i = data.commits.begin(); while(i != data.commits.end()) { dbrow_t &commit = *i; if(commit["uid"] == sessionid && commit["status"] != "committed") { commit["status"] = "committed"; return; } i++; } } void PracroDAOTest::nocommit(std::string sessionid) { dbtable_t::iterator i = data.commits.begin(); while(i != data.commits.end()) { dbrow_t &commit = *i; if(commit["uid"] == sessionid && commit["status"] != "committed") { commit["status"] = "idle"; return; } i++; } } void PracroDAOTest::discard(std::string sessionid) { dbtable_t::iterator i = data.commits.begin(); while(i != data.commits.end()) { dbrow_t &commit = *i; if(commit["uid"] == sessionid && commit["status"] != "committed") { data.commits.erase(i); return; } i++; } } #ifdef TEST_PRACRODAOTEST //deps: debug.cc log.cc configuration.cc exception.cc pracrodao.cc //cflags: -I.. //libs: #include #include #define PATIENTID "1234567890" #define MACRO "testmacro" static bool vectorFind(std::vector fs, std::string name, std::string desc) { std::vector::iterator i = fs.begin(); while(i != fs.end()) { Fieldname &fn = *i; if(fn.name == name && (desc == "" || fn.description == desc)) return true; i++; } return false; } TEST_BEGIN; debug_parse("+all"); Data data; PracroDAOTest db(data); db.addFieldname("field1", "desc1"); db.addFieldname("field2", "desc2"); db.addFieldname("field3", "desc3"); db.delFieldname("field3"); std::vector fs = db.getFieldnames(); TEST_EQUAL_INT(fs.size(), 2, "Test fieldname size."); TEST_TRUE(vectorFind(fs, "field1", "desc1"), "Test fieldname 'field1'."); TEST_TRUE(vectorFind(fs, "field2", "desc2"), "Test fieldname 'field2'."); TEST_FALSE(vectorFind(fs, "field3", ""), "Test fieldname 'field3'."); std::string sid1 = db.newSessionId(); std::string sid2 = db.newSessionId(); TEST_NOTEQUAL_STR(sid1, sid2, "Do not produce the same uid each time."); Transaction transaction; transaction.cpr = PATIENTID; transaction.user = "me"; Commit commit; commit.fields["field1"] = "hello"; commit.fields["field2"] = "world"; commit.templ = "tester"; Macro macro; macro.attributes["version"] = "1.0"; macro.attributes["name"] = MACRO; time_t now = time(NULL); db.commitTransaction(sid1, transaction, commit, macro, now); TEST_EQUAL_INT(db.nrOfCommits(sid1, PATIENTID, MACRO, now), 1, "How many?"); Fieldnames fieldnames; fieldnames.push_back("field1"); fieldnames.push_back("field_nop"); Values vals = db.getLatestValues(sid1, PATIENTID, ¯o, fieldnames, 0); TEST_EQUAL_INT(vals.size(), 1, "One value"); TEST_NOTEQUAL(vals.find("field1"), vals.end(), "find value"); { std::string sid = db.newSessionId(); db.commitTransaction(sid, transaction, commit, macro, now); TEST_FALSE(db.idle(sid), "Session should not be idle."); db.setIdle(sid, true); TEST_TRUE(db.idle(sid), "Session should be idle."); db.setIdle(sid, false); TEST_FALSE(db.idle(sid), "Session1 should not be idle."); } { std::string sid = db.newSessionId(); db.commitTransaction(sid, transaction, commit, macro, now); TEST_FALSE(db.idle(sid), "Session should not be idle."); db.commit(sid); TEST_FALSE(db.idle(sid), "Session is not idle (since committed != idle)."); } { std::string sid = db.newSessionId(); db.commitTransaction(sid, transaction, commit, macro, now); TEST_FALSE(db.idle(sid), "Session should not be idle."); db.nocommit(sid); TEST_TRUE(db.idle(sid), "Session is idle."); } { std::string sid = db.newSessionId(); db.commitTransaction(sid, transaction, commit, macro, now); TEST_FALSE(db.idle(sid), "Session should not be idle."); db.discard(sid); TEST_FALSE(db.idle(sid), "Session not idle (it doesn't exist)."); } TEST_FALSE(db.idle("no such session"), "Missing session is not idle."); /* 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; */ TEST_END; #endif/*TEST_PRACRODAOTEST*/