Commit 15c34afd authored by Thomas Markwalder's avatar Thomas Markwalder

[master] Lease and host back ends now validate schema version during open

    Merge branch 'trac5629'
parents 3313bc92 3033f888
......@@ -1576,9 +1576,22 @@ CqlHostDataSourceImpl::CqlHostDataSourceImpl(const CqlConnection::ParameterMap&
// Open the database.
dbconn_.openDatabase();
// Prepare the version exchange first.
dbconn_.prepareStatements(CqlVersionExchange::tagged_statements_);
// Validate the schema version.
std::pair<uint32_t, uint32_t> code_version(CQL_SCHEMA_VERSION_MAJOR,
CQL_SCHEMA_VERSION_MINOR);
std::pair<uint32_t, uint32_t> db_version = getVersion();
if (code_version != db_version) {
isc_throw(DbOpenError, "Cassandra schema version mismatch: need version: "
<< code_version.first << "." << code_version.second
<< " found version: " << db_version.first << "."
<< db_version.second);
}
// Prepare all possible statements.
dbconn_.prepareStatements(CqlHostExchange::tagged_statements_);
dbconn_.prepareStatements(CqlVersionExchange::tagged_statements_);
}
CqlHostDataSourceImpl::~CqlHostDataSourceImpl() {
......
......@@ -78,7 +78,8 @@ public:
/// concerned with the database.
///
/// @throw isc::dhcp::NoDatabaseName Mandatory database name not given
/// @throw isc::dhcp::DbOpenError Error opening the database
/// @throw isc::dhcp::DbOpenError Error opening the database or if the
/// schema version is invalid.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
explicit CqlHostDataSource(const DatabaseConnection::ParameterMap& parameters);
......
......@@ -1854,9 +1854,24 @@ CqlLeaseStatsQuery::executeSelect(const CqlConnection& connection, const AnyArra
CqlLeaseMgr::CqlLeaseMgr(const DatabaseConnection::ParameterMap &parameters)
: LeaseMgr(), dbconn_(parameters) {
dbconn_.openDatabase();
// Prepare the version exchange first.
dbconn_.prepareStatements(CqlVersionExchange::tagged_statements_);
// Validate the schema version.
std::pair<uint32_t, uint32_t> code_version(CQL_SCHEMA_VERSION_MAJOR,
CQL_SCHEMA_VERSION_MINOR);
std::pair<uint32_t, uint32_t> db_version = getVersion();
if (code_version != db_version) {
isc_throw(DbOpenError, "Cassandra schema version mismatch: need version: "
<< code_version.first << "." << code_version.second
<< " found version: " << db_version.first << "."
<< db_version.second);
}
// Now prepare the rest of the exchanges.
dbconn_.prepareStatements(CqlLease4Exchange::tagged_statements_);
dbconn_.prepareStatements(CqlLease6Exchange::tagged_statements_);
dbconn_.prepareStatements(CqlVersionExchange::tagged_statements_);
dbconn_.prepareStatements(CqlLeaseStatsQuery::tagged_statements_);
}
......
......@@ -66,7 +66,8 @@ public:
/// concerned with the database.
///
/// @throw isc::dhcp::NoDatabaseName Mandatory database name not given
/// @throw isc::dhcp::DbOpenError Error opening the database
/// @throw isc::dhcp::DbOpenError Error opening the database or the schema
/// version is invalid.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
explicit CqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters);
......
......@@ -1906,7 +1906,6 @@ public:
GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address
GET_HOST_PREFIX, // Gets host by IPv6 prefix
GET_HOST_SUBID6_ADDR, // Gets host by IPv6 SubnetID and IPv6 prefix
GET_VERSION, // Obtain version number
INSERT_HOST, // Insert new host to collection
INSERT_V6_RESRV, // Insert v6 reservation
INSERT_V4_OPTION, // Insert DHCPv4 option
......@@ -1933,6 +1932,21 @@ public:
/// @brief Destructor.
~MySqlHostDataSourceImpl();
/// @brief Returns backend version.
///
/// The method is called by the constructor after opening the database
/// but prior to preparing SQL statements, to verify that the schema version
/// is correct. Thus it must not rely on a pre-prepared statement or
/// formal statement execution error checking.
//
/// @return Version number stored in the database, as a pair of unsigned
/// integers. "first" is the major version number, "second" the
/// minor number.
///
/// @throw isc::dhcp::DbOperationError An operation on the open database
/// has failed.
std::pair<uint32_t, uint32_t> getVersion() const;
/// @brief Executes statements which inserts a row into one of the tables.
///
/// @param stindex Index of a statement being executed.
......@@ -2232,10 +2246,6 @@ TaggedStatementArray tagged_statements = { {
"WHERE h.dhcp6_subnet_id = ? AND r.address = ? "
"ORDER BY h.host_id, o.option_id, r.reservation_id"},
// Retrieves MySQL schema version.
{MySqlHostDataSourceImpl::GET_VERSION,
"SELECT version, minor FROM schema_version"},
// Inserts a host into the 'hosts' table.
{MySqlHostDataSourceImpl::INSERT_HOST,
"INSERT INTO hosts(host_id, dhcp_identifier, dhcp_identifier_type, "
......@@ -2293,6 +2303,17 @@ MySqlHostDataSourceImpl(const MySqlConnection::ParameterMap& parameters)
// Open the database.
conn_.openDatabase();
// Test schema version before we try to prepare statements.
std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR,
MYSQL_SCHEMA_VERSION_MINOR);
std::pair<uint32_t, uint32_t> db_version = getVersion();
if (code_version != db_version) {
isc_throw(DbOpenError, "MySQL schema version mismatch: need version: "
<< code_version.first << "." << code_version.second
<< " found version: " << db_version.first << "."
<< db_version.second);
}
// Enable autocommit. In case transaction is explicitly used, this
// setting will be overwritten for the transaction. However, there are
// cases when lack of autocommit could cause transactions to hang
......@@ -2341,6 +2362,67 @@ MySqlHostDataSourceImpl::~MySqlHostDataSourceImpl() {
// closed in the destructor of the mysql_ member variable.
}
std::pair<uint32_t, uint32_t>
MySqlHostDataSourceImpl::getVersion() const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
DHCPSRV_MYSQL_HOST_DB_GET_VERSION);
// Allocate a new statement.
MYSQL_STMT *stmt = mysql_stmt_init(conn_.mysql_);
if (stmt == NULL) {
isc_throw(DbOperationError, "unable to allocate MySQL prepared "
"statement structure, reason: " << mysql_error(conn_.mysql_));
}
// Prepare the statement from SQL text.
const char* version_sql = "SELECT version, minor FROM schema_version";
int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
if (status != 0) {
isc_throw(DbOperationError, "unable to prepare MySQL statement <"
<< version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
}
// Execute the prepared statement.
if (mysql_stmt_execute(stmt) != 0) {
isc_throw(DbOperationError, "cannot execute schema version query <"
<< version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
}
// Bind the output of the statement to the appropriate variables.
MYSQL_BIND bind[2];
memset(bind, 0, sizeof(bind));
uint32_t major;
bind[0].buffer_type = MYSQL_TYPE_LONG;
bind[0].is_unsigned = 1;
bind[0].buffer = &major;
bind[0].buffer_length = sizeof(major);
uint32_t minor;
bind[1].buffer_type = MYSQL_TYPE_LONG;
bind[1].is_unsigned = 1;
bind[1].buffer = &minor;
bind[1].buffer_length = sizeof(minor);
if (mysql_stmt_bind_result(stmt, bind)) {
isc_throw(DbOperationError, "unable to bind result set for <"
<< version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
}
// Fetch the data.
if (mysql_stmt_fetch(stmt)) {
mysql_stmt_close(stmt);
isc_throw(DbOperationError, "unable to bind result set for <"
<< version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
}
// Discard the statement and its resources
mysql_stmt_close(stmt);
return (std::make_pair(major, minor));
}
void
MySqlHostDataSourceImpl::addStatement(StatementIndex stindex,
std::vector<MYSQL_BIND>& bind) {
......@@ -2907,54 +2989,7 @@ std::string MySqlHostDataSource::getDescription() const {
}
std::pair<uint32_t, uint32_t> MySqlHostDataSource::getVersion() const {
const MySqlHostDataSourceImpl::StatementIndex stindex =
MySqlHostDataSourceImpl::GET_VERSION;
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
DHCPSRV_MYSQL_HOST_DB_GET_VERSION);
uint32_t major; // Major version number
uint32_t minor; // Minor version number
// Execute the prepared statement
int status = mysql_stmt_execute(impl_->conn_.statements_[stindex]);
if (status != 0) {
isc_throw(DbOperationError, "unable to execute <"
<< impl_->conn_.text_statements_[stindex]
<< "> - reason: " << mysql_error(impl_->conn_.mysql_));
}
// Bind the output of the statement to the appropriate variables.
MYSQL_BIND bind[2];
memset(bind, 0, sizeof(bind));
bind[0].buffer_type = MYSQL_TYPE_LONG;
bind[0].is_unsigned = 1;
bind[0].buffer = &major;
bind[0].buffer_length = sizeof(major);
bind[1].buffer_type = MYSQL_TYPE_LONG;
bind[1].is_unsigned = 1;
bind[1].buffer = &minor;
bind[1].buffer_length = sizeof(minor);
status = mysql_stmt_bind_result(impl_->conn_.statements_[stindex], bind);
if (status != 0) {
isc_throw(DbOperationError, "unable to bind result set: "
<< mysql_error(impl_->conn_.mysql_));
}
// Fetch the data and set up the "release" object to release associated
// resources when this method exits then retrieve the data.
// mysql_stmt_fetch return value other than 0 means error occurrence.
MySqlFreeResult fetch_release(impl_->conn_.statements_[stindex]);
status = mysql_stmt_fetch(impl_->conn_.statements_[stindex]);
if (status != 0) {
isc_throw(DbOperationError, "unable to obtain result set: "
<< mysql_error(impl_->conn_.mysql_));
}
return (std::make_pair(major, minor));
return(impl_->getVersion());
}
void
......
......@@ -49,7 +49,8 @@ public:
/// concerned with the database.
///
/// @throw isc::dhcp::NoDatabaseName Mandatory database name not given
/// @throw isc::dhcp::DbOpenError Error opening the database
/// @throw isc::dhcp::DbOpenError Error opening the database or the
/// schema version is invalid.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
MySqlHostDataSource(const DatabaseConnection::ParameterMap& parameters);
......
......@@ -209,8 +209,6 @@ tagged_statements = { {
"WHERE state != ? AND expire < ? "
"ORDER BY expire ASC "
"LIMIT ?"},
{MySqlLeaseMgr::GET_VERSION,
"SELECT version, minor FROM schema_version"},
{MySqlLeaseMgr::INSERT_LEASE4,
"INSERT INTO lease4(address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
......@@ -1501,6 +1499,18 @@ MySqlLeaseMgr::MySqlLeaseMgr(const MySqlConnection::ParameterMap& parameters)
// Open the database.
conn_.openDatabase();
// Test schema version before we try to prepare statements.
std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR,
MYSQL_SCHEMA_VERSION_MINOR);
std::pair<uint32_t, uint32_t> db_version = getVersion();
if (code_version != db_version) {
isc_throw(DbOpenError,
"MySQL schema version mismatch: need version: "
<< code_version.first << "." << code_version.second
<< " found version: " << db_version.first << "."
<< db_version.second);
}
// Enable autocommit. To avoid a flush to disk on every commit, the global
// parameter innodb_flush_log_at_trx_commit should be set to 2. This will
// cause the changes to be written to the log, but flushed to disk in the
......@@ -2372,40 +2382,60 @@ MySqlLeaseMgr::getDescription() const {
std::pair<uint32_t, uint32_t>
MySqlLeaseMgr::getVersion() const {
const StatementIndex stindex = GET_VERSION;
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
DHCPSRV_MYSQL_GET_VERSION);
uint32_t major; // Major version number
uint32_t minor; // Minor version number
// Allocate a new statement.
MYSQL_STMT *stmt = mysql_stmt_init(conn_.mysql_);
if (stmt == NULL) {
isc_throw(DbOperationError, "unable to allocate MySQL prepared "
"statement structure, reason: " << mysql_error(conn_.mysql_));
}
// Prepare the statement from SQL text.
const char* version_sql = "SELECT version, minor FROM schema_version";
int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
if (status != 0) {
isc_throw(DbOperationError, "unable to prepare MySQL statement <"
<< version_sql << ">, reason: " << mysql_error(conn_.mysql_));
}
// Execute the prepared statement
int status = mysql_stmt_execute(conn_.statements_[stindex]);
checkError(status, stindex, "unable to execute statement");
// Execute the prepared statement.
if (mysql_stmt_execute(stmt) != 0) {
isc_throw(DbOperationError, "cannot execute schema version query <"
<< version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
}
// Bind the output of the statement to the appropriate variables.
MYSQL_BIND bind[2];
memset(bind, 0, sizeof(bind));
uint32_t major;
bind[0].buffer_type = MYSQL_TYPE_LONG;
bind[0].is_unsigned = 1;
bind[0].buffer = &major;
bind[0].buffer_length = sizeof(major);
uint32_t minor;
bind[1].buffer_type = MYSQL_TYPE_LONG;
bind[1].is_unsigned = 1;
bind[1].buffer = &minor;
bind[1].buffer_length = sizeof(minor);
status = mysql_stmt_bind_result(conn_.statements_[stindex], bind);
checkError(status, stindex, "unable to bind result set");
if (mysql_stmt_bind_result(stmt, bind)) {
isc_throw(DbOperationError, "unable to bind result set for <"
<< version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
}
// Fetch the data.
if (mysql_stmt_fetch(stmt)) {
mysql_stmt_close(stmt);
isc_throw(DbOperationError, "unable to bind result set for <"
<< version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
}
// Fetch the data and set up the "release" object to release associated
// resources when this method exits then retrieve the data.
MySqlFreeResult fetch_release(conn_.statements_[stindex]);
status = mysql_stmt_fetch(conn_.statements_[stindex]);
checkError(status, stindex, "unable to fetch result set");
// Discard the statement and its resources
mysql_stmt_close(stmt);
return (std::make_pair(major, minor));
}
......
......@@ -53,7 +53,8 @@ public:
/// concerned with the database.
///
/// @throw isc::dhcp::NoDatabaseName Mandatory database name not given
/// @throw isc::dhcp::DbOpenError Error opening the database
/// @throw isc::dhcp::DbOpenError Error opening the database or the schema
/// version is incorrect.
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
MySqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters);
......@@ -472,6 +473,11 @@ public:
/// @brief Returns backend version.
///
/// The method is called by the constructor after opening the database
/// but prior to preparing SQL statements, to verify that the schema version
/// is correct. Thus it must not rely on a pre-prepared statement or
/// formal statement execution error checking.
///
/// @return Version number as a pair of unsigned integers. "first" is the
/// major version number, "second" the minor number.
///
......@@ -517,7 +523,6 @@ public:
GET_LEASE6_DUID_IAID_SUBID, // Get lease6 by DUID, IAID and subnet ID
GET_LEASE6_SUBID, // Get IPv6 leases by subnet ID
GET_LEASE6_EXPIRE, // Get lease6 by expiration.
GET_VERSION, // Obtain version number
INSERT_LEASE4, // Add entry to lease4 table
INSERT_LEASE6, // Add entry to lease6 table
UPDATE_LEASE4, // Update a Lease4 entry
......
......@@ -1259,7 +1259,6 @@ public:
GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address
GET_HOST_PREFIX, // Gets host by IPv6 prefix
GET_HOST_SUBID6_ADDR, // Gets host by IPv6 SubnetID and IPv6 prefix
GET_VERSION, // Obtain version number
INSERT_HOST, // Insert new host to collection
INSERT_V6_RESRV, // Insert v6 reservation
INSERT_V4_HOST_OPTION, // Insert DHCPv4 option
......@@ -1606,14 +1605,6 @@ TaggedStatementArray tagged_statements = { {
"ORDER BY h.host_id, o.option_id, r.reservation_id"
},
// PgSqlHostDataSourceImpl::GET_VERSION
// Retrieves PgSQL schema version.
{0,
{ OID_NONE },
"get_version",
"SELECT version, minor FROM schema_version"
},
// PgSqlHostDataSourceImpl::INSERT_HOST
// Inserts a host into the 'hosts' table. Returns the inserted host id.
{12,
......@@ -1709,6 +1700,19 @@ PgSqlHostDataSourceImpl(const PgSqlConnection::ParameterMap& parameters)
// Open the database.
conn_.openDatabase();
// Validate the schema version first.
std::pair<uint32_t, uint32_t> code_version(PG_SCHEMA_VERSION_MAJOR,
PG_SCHEMA_VERSION_MINOR);
std::pair<uint32_t, uint32_t> db_version = getVersion();
if (code_version != db_version) {
isc_throw(DbOpenError,
"PostgreSQL schema version mismatch: need version: "
<< code_version.first << "." << code_version.second
<< " found version: " << db_version.first << "."
<< db_version.second);
}
// Now prepare the SQL statements.
conn_.prepareStatements(tagged_statements.begin(),
tagged_statements.begin() + WRITE_STMTS_BEGIN);
......@@ -1896,15 +1900,18 @@ getHost(const SubnetID& subnet_id,
std::pair<uint32_t, uint32_t> PgSqlHostDataSourceImpl::getVersion() const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
DHCPSRV_PGSQL_HOST_DB_GET_VERSION);
PgSqlResult r(PQexecPrepared(conn_, "get_version", 0, NULL, NULL, NULL, 0));
conn_.checkStatementError(r, tagged_statements[GET_VERSION]);
const char* version_sql = "SELECT version, minor FROM schema_version;";
PgSqlResult r(PQexec(conn_, version_sql));
if(PQresultStatus(r) != PGRES_TUPLES_OK) {
isc_throw(DbOperationError, "unable to execute PostgreSQL statement <"
<< version_sql << ">, reason: " << PQerrorMessage(conn_));
}
uint32_t version;
PgSqlExchange::getColumnValue(r, 0, 0, version);
uint32_t minor;
PgSqlExchange::getColumnValue(r, 0, 0, minor);
PgSqlExchange::getColumnValue(r, 0, 1, minor);
return (std::make_pair(version, minor));
}
......
......@@ -257,6 +257,11 @@ public:
/// @brief Returns backend version.
///
/// The method is called by the constructor after opening the database
/// but prior to preparing SQL statements, to verify that the schema version
/// is correct. Thus it must not rely on a pre-prepared statement or
/// formal statement execution error checking.
///
/// @return Version number stored in the database, as a pair of unsigned
/// integers. "first" is the major version number, "second" the
/// minor number.
......
......@@ -202,11 +202,6 @@ PgSqlTaggedStatement tagged_statements[] = {
"ORDER BY expire "
"LIMIT $3"},
// GET_VERSION
{ 0, { OID_NONE },
"get_version",
"SELECT version, minor FROM schema_version"},
// INSERT_LEASE4
{ 10, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
OID_BOOL, OID_BOOL, OID_VARCHAR, OID_INT8 },
......@@ -1000,6 +995,20 @@ PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
: LeaseMgr(), exchange4_(new PgSqlLease4Exchange()),
exchange6_(new PgSqlLease6Exchange()), conn_(parameters) {
conn_.openDatabase();
// Validate schema version first.
std::pair<uint32_t, uint32_t> code_version(PG_SCHEMA_VERSION_MAJOR,
PG_SCHEMA_VERSION_MINOR);
std::pair<uint32_t, uint32_t> db_version = getVersion();
if (code_version != db_version) {
isc_throw(DbOpenError,
"PostgreSQL schema version mismatch: need version: "
<< code_version.first << "." << code_version.second
<< " found version: " << db_version.first << "."
<< db_version.second);
}
// Now prepare the SQL statements.
int i = 0;
for( ; tagged_statements[i].text != NULL ; ++i) {
conn_.prepareStatement(tagged_statements[i]);
......@@ -1010,16 +1019,6 @@ PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
isc_throw(DbOpenError, "Number of statements prepared: " << i
<< " does not match expected count:" << NUM_STATEMENTS);
}
pair<uint32_t, uint32_t> code_version(PG_SCHEMA_VERSION_MAJOR, PG_SCHEMA_VERSION_MINOR);
pair<uint32_t, uint32_t> db_version = getVersion();
if (code_version != db_version) {
isc_throw(DbOpenError,
"PostgreSQL schema version mismatch: need version: "
<< code_version.first << "." << code_version.second
<< " found version: " << db_version.first << "."
<< db_version.second);
}
}
PgSqlLeaseMgr::~PgSqlLeaseMgr() {
......@@ -1681,8 +1680,12 @@ PgSqlLeaseMgr::getVersion() const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
DHCPSRV_PGSQL_GET_VERSION);
PgSqlResult r(PQexecPrepared(conn_, "get_version", 0, NULL, NULL, NULL, 0));
conn_.checkStatementError(r, tagged_statements[GET_VERSION]);
const char* version_sql = "SELECT version, minor FROM schema_version;";
PgSqlResult r(PQexec(conn_, version_sql));
if(PQresultStatus(r) != PGRES_TUPLES_OK) {
isc_throw(DbOperationError, "unable to execute PostgreSQL statement <"
<< version_sql << ", reason: " << PQerrorMessage(conn_));
}
istringstream tmp;
uint32_t version;
......
......@@ -442,6 +442,11 @@ public:
/// @brief Returns backend version.
///
/// The method is called by the constructor after opening the database
/// but prior to preparing SQL statements, to verify that the schema version
/// is correct. Thus it must not rely on a pre-prepared statement or
/// formal statement execution error checking.
///
/// @return Version number as a pair of unsigned integers. "first" is the
/// major version number, "second" the minor number.
///
......@@ -486,7 +491,6 @@ public:
GET_LEASE6_DUID_IAID_SUBID, // Get lease6 by DUID, IAID and subnet ID
GET_LEASE6_SUBID, // Get IPv6 leases by subnet ID
GET_LEASE6_EXPIRE, // Get expired lease6
GET_VERSION, // Obtain version number
INSERT_LEASE4, // Add entry to lease4 table
INSERT_LEASE6, // Add entry to lease6 table
UPDATE_LEASE4, // Update a Lease4 entry
......
......@@ -2842,16 +2842,19 @@ LeaseMgrDbLostCallbackTest::testDbLostCallback() {
// Clear the callback invocation marker.
callback_called_ = false;
// Verify we can execute a query.
// Verify we can execute a query. We do not care if
// we find a lease or not.
LeaseMgr& lm = LeaseMgrFactory::instance();
pair<uint32_t, uint32_t> version;
ASSERT_NO_THROW(version = lm.getVersion());
Lease4Ptr lease;
ASSERT_NO_THROW(lease = lm.getLease4(IOAddress("192.0.1.0")));
// Now close the sql socket out from under backend client
ASSERT_EQ(0, close(sql_socket));
// A query should fail with DbOperationError.
ASSERT_THROW(version = lm.getVersion(), DbOperationError);
ASSERT_THROW(lease = lm.getLease4(IOAddress("192.0.1.0")),
DbOperationError);
// Our lost connectivity callback should have been invoked.
EXPECT_TRUE(callback_called_);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment