diff options
author | NingSun <ning.sun@intel.com> | 2018-02-08 08:34:03 -0800 |
---|---|---|
committer | NingSun <ning.sun@intel.com> | 2018-02-08 09:14:52 -0800 |
commit | 0c89b3ccba7c9b7332ab67ae1936aff51ca62367 (patch) | |
tree | 70c1b1d160d4c6d0a83395ca9a87c1264d0d3439 /SoftHSMv2/src/lib/object_store/test/DBTests.cpp | |
parent | 945613b4db4e07f75d2bc7463db580ddfaa700fd (diff) |
Initial sshsm project structure
Issue-ID: AAF-94
Change-Id: I5e82fff418e7567b161acf9b98013a9b85ffc5b4
Signed-off-by: NingSun <ning.sun@intel.com>
Diffstat (limited to 'SoftHSMv2/src/lib/object_store/test/DBTests.cpp')
-rw-r--r-- | SoftHSMv2/src/lib/object_store/test/DBTests.cpp | 648 |
1 files changed, 648 insertions, 0 deletions
diff --git a/SoftHSMv2/src/lib/object_store/test/DBTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBTests.cpp new file mode 100644 index 0000000..d787a83 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBTests.cpp @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBTests.cpp + + Contains lowest level test cases for the database backend implementation. + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "DBTests.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db); + +static int dummy_print(const char *, va_list ) +{ + return 0; +} + +void test_a_db::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); + null = NULL; +} + +void test_a_db::tearDown() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void test_a_db::checks_for_empty_connection_parameters() +{ + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + + DB::Connection *connection = DB::Connection::Create("","TestToken"); + CPPUNIT_ASSERT_EQUAL(connection, null); + + connection = DB::Connection::Create("testdir",""); + CPPUNIT_ASSERT_EQUAL(connection, null); + + connection = DB::Connection::Create("",""); + CPPUNIT_ASSERT_EQUAL(connection, null); + + DB::setLogErrorHandler(eh); +} + +void test_a_db::can_be_connected_to_database() +{ + + DB::Connection *connection = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection != null); + bool isConnected = connection->connect(); + delete connection; + CPPUNIT_ASSERT(isConnected); +#ifndef _WIN32 + CPPUNIT_ASSERT_EQUAL(system("test -f ./testdir/TestToken"), 0); +#else + CPPUNIT_ASSERT(GetFileAttributes("testdir\\TestToken") != INVALID_FILE_ATTRIBUTES); +#endif +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection); + +void test_a_db_with_a_connection::setUp() +{ + test_a_db::setUp(); + connection = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection != null); + CPPUNIT_ASSERT(connection->connect()); +} + +void test_a_db_with_a_connection::tearDown() +{ + CPPUNIT_ASSERT(connection != null); + connection->close(); + delete connection; + test_a_db::tearDown(); +} + +void test_a_db_with_a_connection::can_prepare_statements() +{ + DB::Statement statement = connection->prepare("PRAGMA database_list;"); + CPPUNIT_ASSERT(statement.isValid()); +} + +void test_a_db_with_a_connection::can_perform_statements() +{ + DB::Statement statement = connection->prepare("PRAGMA database_list;"); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + // only expect a single row in the result, so nextRow should now fail + CPPUNIT_ASSERT(!result.nextRow()); +} + +void test_a_db_with_a_connection::maintains_correct_refcounts() +{ + DB::Statement statement = connection->prepare("PRAGMA database_list;"); + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1); + { + DB::Statement statement1 = statement; + DB::Statement statement2 = statement; + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 3); + CPPUNIT_ASSERT(statement1.isValid()); + CPPUNIT_ASSERT(statement2.isValid()); + } + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1); + + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // Statement is referenced by the result because it provides the query record cursor state. + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 2); + + result = DB::Result(); + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1); +} +void test_a_db_with_a_connection::can_create_tables() +{ + CPPUNIT_ASSERT(!connection->tableExists("object")); + DB::Statement cr_object = connection->prepare("create table object (id integer primary key autoincrement);"); + CPPUNIT_ASSERT(connection->execute(cr_object)); + CPPUNIT_ASSERT(connection->tableExists("object")); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection_with_tables); + +void test_a_db_with_a_connection_with_tables::setUp() +{ + test_a_db_with_a_connection::setUp(); + can_create_tables(); + + // attribute_text + CPPUNIT_ASSERT(!connection->tableExists("attribute_text")); + DB::Statement cr_attr_text = connection->prepare( + "create table attribute_text (" + "value text," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_text)); + CPPUNIT_ASSERT(connection->tableExists("attribute_text")); + + // attribute_integer + CPPUNIT_ASSERT(!connection->tableExists("attribute_integer")); + DB::Statement cr_attr_integer = connection->prepare( + "create table attribute_integer (" + "value integer," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_integer)); + CPPUNIT_ASSERT(connection->tableExists("attribute_integer")); + + // attribute_blob + CPPUNIT_ASSERT(!connection->tableExists("attribute_blob")); + DB::Statement cr_attr_blob = connection->prepare( + "create table attribute_blob (" + "value blob," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_blob)); + CPPUNIT_ASSERT(connection->tableExists("attribute_blob")); + + // attribute_boolean + CPPUNIT_ASSERT(!connection->tableExists("attribute_boolean")); + DB::Statement cr_attr_boolean = connection->prepare( + "create table attribute_boolean (" + "value boolean," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_boolean)); + CPPUNIT_ASSERT(connection->tableExists("attribute_boolean")); + + // attribute_datetime + CPPUNIT_ASSERT(!connection->tableExists("attribute_datetime")); + DB::Statement cr_attr_datetime = connection->prepare( + "create table attribute_datetime (" + "value datetime," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_datetime)); + CPPUNIT_ASSERT(connection->tableExists("attribute_datetime")); + + // attribute_real + CPPUNIT_ASSERT(!connection->tableExists("attribute_real")); + DB::Statement cr_attr_real = connection->prepare( + "create table attribute_real (" + "value real," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_real)); + CPPUNIT_ASSERT(connection->tableExists("attribute_real")); +} + +void test_a_db_with_a_connection_with_tables::tearDown() +{ + test_a_db_with_a_connection::tearDown(); +} + +void test_a_db_with_a_connection_with_tables::can_insert_records() +{ + DB::Statement statement = connection->prepare("insert into object default values"); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + statement = connection->prepare( + "insert into attribute_text (value,type,object_id) values ('%s',%d,%lld)", + "testing testing testing", + 1234, + object_id); + CPPUNIT_ASSERT(connection->execute(statement)); +} + +void test_a_db_with_a_connection_with_tables::can_retrieve_records() +{ + can_insert_records(); + + DB::Statement statement = connection->prepare( + "select value from attribute_text as t where t.type=%d", + 1234); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT_EQUAL(std::string(result.getString(1)), std::string("testing testing testing")); +} + +void test_a_db_with_a_connection_with_tables::can_cascade_delete_objects_and_attributes() +{ + can_insert_records(); + + DB::Statement statement = connection->prepare("select id from object"); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + long long object_id = result.getLongLong(1); + + statement = connection->prepare("delete from object where id=%lld",object_id); + CPPUNIT_ASSERT(connection->execute(statement)); + + statement = connection->prepare("select * from attribute_text where object_id=%lld",object_id); + result = connection->perform(statement); + + // Check cascade delete was successful. + CPPUNIT_ASSERT(!result.isValid()); +} + + +void test_a_db_with_a_connection_with_tables::can_update_text_attribute() +{ + can_insert_records(); + + // query all objects + DB::Statement statement = connection->prepare("select id from object"); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + long long object_id = result.getLongLong(1); // field indices start at 1 + + statement = connection->prepare( + "update attribute_text set value='test test test' where type=%d and object_id=%lld", + 1234, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); +} + +void test_a_db_with_a_connection_with_tables::can_update_text_attribute_bound_value() +{ + can_insert_records(); + + // query all objects + DB::Statement statement = connection->prepare("select id from object"); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + long long object_id = result.getLongLong(1); // field indices start at 1 + + statement = connection->prepare( + "update attribute_text set value=? where type=%d and object_id=%lld", + 1234, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + std::string msg("testing quote ' and accents é."); + + CPPUNIT_ASSERT(DB::Bindings(statement).bindText(1,msg.c_str(),msg.size(),NULL)); + CPPUNIT_ASSERT(connection->execute(statement)); + + statement = connection->prepare( + "select value from attribute_text as t where t.type=%d and t.object_id=%lld", + 1234, + object_id); + result = connection->perform(statement); + CPPUNIT_ASSERT_EQUAL(std::string(result.getString(1)), msg); +} + +void test_a_db_with_a_connection_with_tables::can_update_integer_attribute_bound_value() +{ + // insert new object + DB::Statement statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert integer attribute + statement = connection->prepare( + "insert into attribute_integer (value,type,object_id) values (%lld,%d,%lld)", + 1111, + 1235, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update integer attribute statement + statement = connection->prepare( + "update attribute_integer set value=? where type=%d and object_id=%lld", + 1235, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // bind long long value to the parameter an update the record + CPPUNIT_ASSERT(DB::Bindings(statement).bindInt64(1,2222)); + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the value from the record + DB::Statement retrieveStmt = connection->prepare( + "select value from attribute_integer as t where t.type=%d and t.object_id=%lld", + 1235, + object_id); + CPPUNIT_ASSERT(retrieveStmt.isValid()); + DB::Result result = connection->perform(retrieveStmt); + CPPUNIT_ASSERT_EQUAL(result.getLongLong(1), (long long)2222); + + // verify that binding to a parameter before resetting the statement will fail. + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + DB::Bindings bindings(statement); + CPPUNIT_ASSERT(!bindings.bindInt(1,3333)); + DB::setLogErrorHandler(eh); + + // reset statement and bind another value to the statement + CPPUNIT_ASSERT(bindings.reset()); + CPPUNIT_ASSERT(bindings.bindInt(1,3333)); + + // perform the update statement again with the newly bound value + CPPUNIT_ASSERT(connection->execute(statement)); + + // reset the retrieve statement and perform it again to get the latest value of the integer attribute + CPPUNIT_ASSERT(retrieveStmt.reset()); + result = connection->perform(retrieveStmt); + CPPUNIT_ASSERT(result.isValid()); + CPPUNIT_ASSERT_EQUAL(result.getLongLong(1), (long long)3333); +} + +void test_a_db_with_a_connection_with_tables::can_update_blob_attribute_bound_value() +{ + // insert new object + DB::Statement statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert blob attribute + statement = connection->prepare( + "insert into attribute_blob (value,type,object_id) values (X'012345',%d,%lld)", + 1236, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update blob attribute statement + statement = connection->prepare( + "update attribute_blob set value=? where type=%d and object_id=%lld", + 1236, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // bind blob (with embedded zero!) to the parameter + const char data[] = {10,11,0,12,13,14,15,16}; + std::string msg(data,sizeof(data)); + CPPUNIT_ASSERT(DB::Bindings(statement).bindBlob(1,msg.data(),msg.size(),NULL)); + + // update the blob value of the attribute + CPPUNIT_ASSERT(connection->execute(statement)); + + // retrieve the blob value from the attribute + statement = connection->prepare( + "select value from attribute_blob as t where t.type=%d and t.object_id=%lld", + 1236, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved blob value matches the original data. + CPPUNIT_ASSERT_EQUAL(result.getFieldLength(1), sizeof(data)); + std::string msgstored((const char *)result.getBinary(1),result.getFieldLength(1)); + CPPUNIT_ASSERT_EQUAL(msg, msgstored); +} + + +void test_a_db_with_a_connection_with_tables::will_not_insert_non_existing_attribute_on_update() +{ + DB::Statement statement; + DB::Result result; + + // Insert new object + statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // Updating an attribute before it is created will succeed, but will not insert an attribute. + statement = connection->prepare( + "update attribute_boolean set value=1 where type=%d and object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the boolean value from the attribute should fail + statement = connection->prepare( + "select value from attribute_boolean as t where t.type=%d and t.object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + result = connection->perform(statement); + CPPUNIT_ASSERT(!result.isValid()); +} + + +void test_a_db_with_a_connection_with_tables::can_update_boolean_attribute_bound_value() +{ + //SQLite doesn't have a boolean data type, use 0 (false) and 1 (true) + + DB::Statement statement; + DB::Result result; + + // Insert new object + statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert boolean attribute + statement = connection->prepare( + "insert into attribute_boolean (value,type,object_id) values (1,%d,%lld)", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update boolean attribute statement + statement = connection->prepare( + "update attribute_boolean set value=? where type=%d and object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // Bind 0 (false) to the first parameter + CPPUNIT_ASSERT(DB::Bindings(statement).bindInt(1,0)); + + // Execute the statement to update the attribute value. + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the boolean value from the attribute + statement = connection->prepare( + "select value from attribute_boolean as t where t.type=%d and t.object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved value matches the original value + CPPUNIT_ASSERT_EQUAL(result.getInt(1), 0); +} + + +void test_a_db_with_a_connection_with_tables::can_update_real_attribute_bound_value() +{ + // insert new object + DB::Statement statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert real value + statement = connection->prepare( + "insert into attribute_real (value,type,object_id) values(%f,%d,%lld)", + 1.238, + 1238, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update real attribute statement + statement = connection->prepare( + "update attribute_real set value=? where type=%d and object_id=%lld", + 1238, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // Bind 3333.3333 to the first parameter + CPPUNIT_ASSERT(DB::Bindings(statement).bindDouble(1,3333.3333)); + + // Execute the statement to update the attribute value + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the double value from the attribute + statement = connection->prepare( + "select value from attribute_real as t where t.type=%d and t.object_id=%lld", + 1238, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved value matches the original value. + CPPUNIT_ASSERT_DOUBLES_EQUAL(result.getDouble(1), 3333.3333, 0.00001); +} + +void test_a_db_with_a_connection_with_tables::supports_transactions() +{ + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + CPPUNIT_ASSERT(!connection->rollbackTransaction()); + DB::setLogErrorHandler(eh); + + CPPUNIT_ASSERT(connection->beginTransactionRW()); + CPPUNIT_ASSERT(connection->rollbackTransaction()); + + eh = DB::setLogErrorHandler(dummy_print); + CPPUNIT_ASSERT(!connection->commitTransaction()); + DB::setLogErrorHandler(eh); + + CPPUNIT_ASSERT(connection->beginTransactionRW()); + can_update_real_attribute_bound_value(); + CPPUNIT_ASSERT(connection->commitTransaction()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection_with_tables_with_a_second_connection_open); + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::setUp() +{ + test_a_db_with_a_connection_with_tables::setUp(); + connection2 = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection2 != null); + CPPUNIT_ASSERT(connection2->connect()); + connection2->setBusyTimeout(10); +} + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::tearDown() +{ + CPPUNIT_ASSERT(connection2 != null); + connection2->close(); + delete connection2; + test_a_db_with_a_connection_with_tables::tearDown(); +} + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::handles_nested_transactions() +{ + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + + DB::Connection *connection1 = connection; + + CPPUNIT_ASSERT(connection1->beginTransactionRW()); + + CPPUNIT_ASSERT(connection2->beginTransactionRO()); + CPPUNIT_ASSERT(connection2->rollbackTransaction()); + CPPUNIT_ASSERT(!connection2->beginTransactionRW()); + + CPPUNIT_ASSERT(connection1->commitTransaction()); + + DB::setLogErrorHandler(eh); +} + + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::supports_transactions_with_other_connections_open() +{ + CPPUNIT_ASSERT(connection2->beginTransactionRO()); + + supports_transactions(); + + // Retrieve the double value from the attribute + DB::Statement statement = connection2->prepare( + "select value from attribute_real as t where t.type=%d and t.object_id=%lld", + 1238, + connection->lastInsertRowId()); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection2->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved value matches the original value. + CPPUNIT_ASSERT_DOUBLES_EQUAL(result.getDouble(1), 3333.3333, 0.00001); + + CPPUNIT_ASSERT(connection2->commitTransaction()); +} |