Commit 765c0d79 authored by Andrei Pavel's avatar Andrei Pavel

boost::any for CHDS

parent 4cd773d5
...@@ -89,10 +89,6 @@ struct StatementTagHash { ...@@ -89,10 +89,6 @@ struct StatementTagHash {
} }
}; };
/// Define CQL schema version: 2.0
const uint32_t CQL_SCHEMA_VERSION_MAJOR = 2;
const uint32_t CQL_SCHEMA_VERSION_MINOR = 0;
/// @brief Equality function for StatementMap keys /// @brief Equality function for StatementMap keys
struct StatementTagEqual { struct StatementTagEqual {
bool operator()(StatementTag const& lhs, StatementTag const& rhs) const { bool operator()(StatementTag const& lhs, StatementTag const& rhs) const {
......
This diff is collapsed.
// Copyright (C) 2016 Deutsche Telekom AG. // Copyright (C) 2016-2017 Deutsche Telekom AG.
// //
// Author: Andrei Pavel <andrei.pavel@qualitance.com> // Author: Andrei Pavel <andrei.pavel@qualitance.com>
// //
...@@ -20,15 +20,13 @@ ...@@ -20,15 +20,13 @@
#include <dhcpsrv/base_host_data_source.h> #include <dhcpsrv/base_host_data_source.h>
#include <dhcpsrv/cql_connection.h> #include <dhcpsrv/cql_connection.h>
#include <stdint.h>
#include <string> #include <string>
#include <utility> #include <vector>
namespace isc { namespace isc {
namespace dhcp { namespace dhcp {
/// Forward declaration to the implementation of @ref CqlHostDataSource. /// @brief Forward declaration to the implementation of @ref CqlHostDataSource.
class CqlHostDataSourceImpl; class CqlHostDataSourceImpl;
/// @brief Cassandra host data source /// @brief Cassandra host data source
...@@ -53,7 +51,7 @@ public: ...@@ -53,7 +51,7 @@ public:
/// ///
/// Finally, all the CQL commands are pre-compiled. /// Finally, all the CQL commands are pre-compiled.
/// ///
/// @param parameters A data structure relating keywords and values /// @param parameters a data structure relating keywords and values
/// concerned with the database. /// concerned with the database.
/// ///
/// @throw isc::dhcp::NoDatabaseName Mandatory database name not given /// @throw isc::dhcp::NoDatabaseName Mandatory database name not given
...@@ -68,8 +66,7 @@ public: ...@@ -68,8 +66,7 @@ public:
/// Releases prepared CQL statements used by the backend. /// Releases prepared CQL statements used by the backend.
virtual ~CqlHostDataSource(); virtual ~CqlHostDataSource();
/// @brief Adds a new @ref Host to the Cassandra database along with it's /// @brief Adds a new host to the collection.
/// reservations and options.
/// ///
/// The implementations of this method should guard against duplicate /// The implementations of this method should guard against duplicate
/// reservations for the same @ref Host, where possible. For example, when /// reservations for the same @ref Host, where possible. For example, when
...@@ -80,7 +77,7 @@ public: ...@@ -80,7 +77,7 @@ public:
/// @ref DUID. /// @ref DUID.
/// ///
/// @param host pointer to the new @ref Host being added. /// @param host pointer to the new @ref Host being added.
virtual void add(const HostPtr& host); virtual void add(const HostPtr& host) override;
/// @brief Retrieves a single @ref Host connected to an IPv4 subnet. /// @brief Retrieves a single @ref Host connected to an IPv4 subnet.
/// ///
...@@ -100,14 +97,14 @@ public: ...@@ -100,14 +97,14 @@ public:
/// @throw BadValue if both or neither of subnet_id and duid are specified /// @throw BadValue if both or neither of subnet_id and duid are specified
virtual ConstHostPtr get4(const SubnetID& subnet_id, virtual ConstHostPtr get4(const SubnetID& subnet_id,
const HWAddrPtr& hwaddr, const HWAddrPtr& hwaddr,
const DuidPtr& duid = DuidPtr()) const; const DuidPtr& duid = DuidPtr()) const override;
/// @brief Retrieves a @ref Host connected to an IPv4 subnet. /// @brief Retrieves a @ref Host connected to an IPv4 subnet.
/// ///
/// @param subnet_id subnet identifier to filter by /// @param subnet_id subnet identifier to filter by
/// @param identifier_type identifier type to filter by /// @param identifier_type identifier type to filter by
/// @param identifier_begin pointer to the beginning of a buffer containing a /// @param identifier_begin pointer to the beginning of a buffer containing
/// host identifier to filter by /// a host identifier to filter by
/// @param identifier_len length of the host identifier buffer /// @param identifier_len length of the host identifier buffer
/// ///
/// @return @ref Host object for which a reservation has been made using the /// @return @ref Host object for which a reservation has been made using the
...@@ -115,7 +112,7 @@ public: ...@@ -115,7 +112,7 @@ public:
virtual ConstHostPtr get4(const SubnetID& subnet_id, virtual ConstHostPtr get4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type, const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin, const uint8_t* identifier_begin,
const size_t identifier_len) const; const size_t identifier_len) const override;
/// @brief Retrieves a @ref Host connected to an IPv4 subnet. /// @brief Retrieves a @ref Host connected to an IPv4 subnet.
/// ///
...@@ -130,8 +127,9 @@ public: ...@@ -130,8 +127,9 @@ public:
/// @return Const @ref Host object /// @return Const @ref Host object
/// ///
/// @throw BadValue if address in not a valid IPv4address /// @throw BadValue if address in not a valid IPv4address
virtual ConstHostPtr get4(const SubnetID& subnet_id, virtual ConstHostPtr
const asiolink::IOAddress& address) const; get4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const override;
/// @brief Retrieves a @ref Host connected to an IPv6 subnet. /// @brief Retrieves a @ref Host connected to an IPv6 subnet.
/// ///
...@@ -148,16 +146,17 @@ public: ...@@ -148,16 +146,17 @@ public:
/// @return @ref Host object using a specified @ref HWAddr or @ref DUID /// @return @ref Host object using a specified @ref HWAddr or @ref DUID
/// ///
/// @throw BadValue if both or neither of subnet_id and duid are specified /// @throw BadValue if both or neither of subnet_id and duid are specified
virtual ConstHostPtr get6(const SubnetID& subnet_id, virtual ConstHostPtr
const DuidPtr& duid, get6(const SubnetID& subnet_id,
const HWAddrPtr& hwaddr = HWAddrPtr()) const; const DuidPtr& duid,
const HWAddrPtr& hwaddr = HWAddrPtr()) const override;
/// @brief Returns a @ref Host connected to an IPv6 subnet. /// @brief Returns a @ref Host connected to an IPv6 subnet.
/// ///
/// @param subnet_id subnet identifier to filter by /// @param subnet_id subnet identifier to filter by
/// @param identifier_type identifier type to filter by /// @param identifier_type identifier type to filter by
/// @param identifier_begin pointer to the beginning of a buffer containing a /// @param identifier_begin pointer to the beginning of a buffer containing
/// host identifier to filter by /// a host identifier to filter by
/// @param identifier_len length of the host identifier buffer /// @param identifier_len length of the host identifier buffer
/// ///
/// @return Const @ref Host object for which reservation has been made using /// @return Const @ref Host object for which reservation has been made using
...@@ -165,7 +164,7 @@ public: ...@@ -165,7 +164,7 @@ public:
virtual ConstHostPtr get6(const SubnetID& subnet_id, virtual ConstHostPtr get6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type, const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin, const uint8_t* identifier_begin,
const size_t identifier_len) const; const size_t identifier_len) const override;
/// @brief Returns a @ref Host with the specified reservation prefix. /// @brief Returns a @ref Host with the specified reservation prefix.
/// ///
...@@ -177,7 +176,7 @@ public: ...@@ -177,7 +176,7 @@ public:
/// @throw MultipleRecords if two or more rows are returned from the /// @throw MultipleRecords if two or more rows are returned from the
/// Cassandra database /// Cassandra database
virtual ConstHostPtr get6(const asiolink::IOAddress& prefix, virtual ConstHostPtr get6(const asiolink::IOAddress& prefix,
const uint8_t prefix_len) const; const uint8_t prefix_len) const override;
/// @brief Returns a host connected to the IPv6 subnet and having /// @brief Returns a host connected to the IPv6 subnet and having
/// a reservation for a specified IPv6 address or prefix. /// a reservation for a specified IPv6 address or prefix.
...@@ -186,8 +185,9 @@ public: ...@@ -186,8 +185,9 @@ public:
/// @param address reserved IPv6 address/prefix. /// @param address reserved IPv6 address/prefix.
/// ///
/// @return Const @c Host object using a specified IPv6 address/prefix. /// @return Const @c Host object using a specified IPv6 address/prefix.
virtual ConstHostPtr get6(const SubnetID& subnet_id, virtual ConstHostPtr
const asiolink::IOAddress& address) const; get6(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const override;
/// @brief Return all @ref Host objects for the specified @ref HWAddr or /// @brief Return all @ref Host objects for the specified @ref HWAddr or
/// @ref DUID. /// @ref DUID.
...@@ -211,8 +211,9 @@ public: ...@@ -211,8 +211,9 @@ public:
/// @param duid client id or NULL if not available, e.g. DHCPv4 client case. /// @param duid client id or NULL if not available, e.g. DHCPv4 client case.
/// ///
/// @return collection of const @ref Host objects. /// @return collection of const @ref Host objects.
virtual ConstHostCollection getAll(const HWAddrPtr& hwaddr, virtual ConstHostCollection
const DuidPtr& duid = DuidPtr()) const; getAll(const HWAddrPtr& hwaddr,
const DuidPtr& duid = DuidPtr()) const override;
/// @brief Return all hosts connected to any subnet for which reservations /// @brief Return all hosts connected to any subnet for which reservations
/// have been made using a specified identifier. /// have been made using a specified identifier.
...@@ -223,14 +224,14 @@ public: ...@@ -223,14 +224,14 @@ public:
/// ///
/// @param identifier_type Identifier type. /// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing /// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier. /// an identifier.
/// @param identifier_len Identifier length. /// @param identifier_len Identifier length.
/// ///
/// @return Collection of const @ref Host objects. /// @return Collection of const @ref Host objects.
virtual ConstHostCollection virtual ConstHostCollection
getAll(const Host::IdentifierType& identifier_type, getAll(const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin, const uint8_t* identifier_begin,
const size_t identifier_len) const; const size_t identifier_len) const override;
/// @brief Returns a collection of hosts using the specified IPv4 address. /// @brief Returns a collection of hosts using the specified IPv4 address.
/// ///
...@@ -241,7 +242,55 @@ public: ...@@ -241,7 +242,55 @@ public:
/// ///
/// @return Collection of const @ref Host objects. /// @return Collection of const @ref Host objects.
virtual ConstHostCollection virtual ConstHostCollection
getAll4(const asiolink::IOAddress& address) const; getAll4(const asiolink::IOAddress& address) const override;
/// @brief Attempts to delete a host by (subnet-id, address)
///
/// This method supports both v4 and v6.
///
/// @param subnet_id subnet identfier.
/// @param addr specified address.
/// @return true if deletion was successful, false if the host was not
/// there.
/// @throw various exceptions in case of errors
virtual bool del(const SubnetID& subnet_id,
const asiolink::IOAddress& addr);
/// @brief Attempts to delete a host by (subnet-id4, identifier,
/// identifier-type)
///
/// This method supports both v4 hosts only.
///
/// @param subnet_id IPv4 Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
/// @return true if deletion was successful, false if the host was not
/// there.
/// @throw various exceptions in case of errors
virtual bool del4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len);
/// @brief Attempts to delete a host by (subnet-id6, identifier,
/// identifier-type)
///
/// This method supports both v6 hosts only.
///
/// @param subnet_id IPv6 Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
/// @return true if deletion was successful, false if the host was not
/// there.
/// @throw various exceptions in case of errors
virtual bool del6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len);
/// @brief Returns description of the backend. /// @brief Returns description of the backend.
/// ///
...@@ -258,7 +307,7 @@ public: ...@@ -258,7 +307,7 @@ public:
/// @brief Return backend type /// @brief Return backend type
/// ///
/// @return backend type "cql" /// @return backend type "cql"
virtual std::string getType() const; virtual std::string getType() const override;
/// @brief Retrieves schema version. /// @brief Retrieves schema version.
/// ///
...@@ -268,24 +317,24 @@ public: ...@@ -268,24 +317,24 @@ public:
/// ///
/// @throw isc::dhcp::DbOperationError An operation on the open database /// @throw isc::dhcp::DbOperationError An operation on the open database
/// has failed. /// has failed.
virtual std::pair<uint32_t, uint32_t> getVersion() const; virtual VersionPair getVersion() const;
/// @brief Commit Transactions /// @brief Commit Transactions
/// ///
/// Commits all pending database operations. /// Commits all pending database operations.
virtual void commit(); virtual void commit() override;
/// @brief Rollback Transactions /// @brief Rollback Transactions
/// ///
/// Rolls back all pending database operations. /// Rolls back all pending database operations.
virtual void rollback(); virtual void rollback() override;
private: private:
/// @brief Pointer to the implementation of the @ref CqlHostDataSource. /// @brief Pointer to the implementation of the @ref CqlHostDataSource.
CqlHostDataSourceImpl* impl_; CqlHostDataSourceImpl* impl_;
}; // class CqlHostDataSource }; // class CqlHostDataSource
}; // namespace dhcp } // namespace dhcp
}; // namespace isc } // namespace isc
#endif // CQL_HOST_DATA_SOURCE_H #endif // CQL_HOST_DATA_SOURCE_H
...@@ -197,9 +197,6 @@ V6) is about to open a Cassandra lease database. The parameters of ...@@ -197,9 +197,6 @@ V6) is about to open a Cassandra lease database. The parameters of
the connection including database name and username needed to access it the connection including database name and username needed to access it
(but not the password if any) are logged. (but not the password if any) are logged.
% DHCPSRV_CQL_COMMIT committing to Cassandra database.
A commit call been issued on the server. For Cassandra, this is a no-op.
% DHCPSRV_CQL_CONNECTION_COMMIT committing to Cassandra database on current connection. % DHCPSRV_CQL_CONNECTION_COMMIT committing to Cassandra database on current connection.
A commit call been issued on the server. For Cassandra, this is a no-op. A commit call been issued on the server. For Cassandra, this is a no-op.
...@@ -231,9 +228,6 @@ The server has issued a rollback transaction call on an opened transaction. ...@@ -231,9 +228,6 @@ The server has issued a rollback transaction call on an opened transaction.
% DHCPSRV_CQL_TRANSACTION_MGR_TRANSACTION_NOT_FOUND failed to select a transaction. % DHCPSRV_CQL_TRANSACTION_MGR_TRANSACTION_NOT_FOUND failed to select a transaction.
The server failed to select a transaction to operate on. The server failed to select a transaction to operate on.
% DHCPSRV_CQL_BEGIN_TRANSACTION begin transaction.
The server has issued a begin transaction call.
% DHCPSRV_CQL_CONNECTION_BEGIN_TRANSACTION begin transaction on current connection. % DHCPSRV_CQL_CONNECTION_BEGIN_TRANSACTION begin transaction on current connection.
The server has issued a begin transaction call. The server has issued a begin transaction call.
...@@ -246,12 +240,6 @@ The server has issued a commit transaction call. ...@@ -246,12 +240,6 @@ The server has issued a commit transaction call.
% DHCPSRV_CQL_TRANSACTION_MGR_ROLLBACK_TRANSACTION rollback transaction action has been initiated. % DHCPSRV_CQL_TRANSACTION_MGR_ROLLBACK_TRANSACTION rollback transaction action has been initiated.
The server has issued a rollback transaction call. The server has issued a rollback transaction call.
% DHCPSRV_CQL_DB opening Cassandra lease database: %1
This informational message is logged when a DHCP server (either V4 or
V6) is about to open a Cassandra lease database. The parameters of
the connection including database name and username needed to access it
(but not the password if any) are logged.
% DHCPSRV_CQL_DELETE_ADDR deleting lease for address %1 % DHCPSRV_CQL_DELETE_ADDR deleting lease for address %1
A debug message issued when the server is attempting to delete a lease from the A debug message issued when the server is attempting to delete a lease from the
Cassandra database for the specified address. Cassandra database for the specified address.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "config.h" #include <config.h>
#include <dhcpsrv/dhcpsrv_log.h> #include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/host_data_source_factory.h> #include <dhcpsrv/host_data_source_factory.h>
...@@ -38,7 +38,6 @@ using namespace std; ...@@ -38,7 +38,6 @@ using namespace std;
namespace isc { namespace isc {
namespace dhcp { namespace dhcp {
HostDataSourcePtr& HostDataSourcePtr&
HostDataSourceFactory::getHostDataSourcePtr() { HostDataSourceFactory::getHostDataSourcePtr() {
static HostDataSourcePtr hostDataSourcePtr; static HostDataSourcePtr hostDataSourcePtr;
...@@ -115,5 +114,5 @@ HostDataSourceFactory::instance() { ...@@ -115,5 +114,5 @@ HostDataSourceFactory::instance() {
} }
#endif #endif
}; // namespace dhcp } // namespace dhcp
}; // namespace isc } // namespace isc
// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") // Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
// //
// This Source Code Form is subject to the terms of the Mozilla Public // This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
...@@ -20,25 +20,21 @@ ...@@ -20,25 +20,21 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <algorithm> #include <algorithm>
#include <iostream>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <utility> #include <utility>
namespace {
using namespace isc; using namespace isc;
using namespace isc::asiolink; using namespace isc::asiolink;
using namespace isc::dhcp; using namespace isc::dhcp;
using namespace isc::dhcp::test; using namespace isc::dhcp::test;
using namespace std;
namespace {
class CqlHostDataSourceTest : public GenericHostDataSourceTest { class CqlHostDataSourceTest : public GenericHostDataSourceTest {
public: public:
/// @brief Constructor /// @brief Clears the database and opens connection to it.
/// void initializeTest() {
/// Deletes everything from the database and opens it.
CqlHostDataSourceTest() {
// Ensure schema is the correct one. // Ensure schema is the correct one.
destroyCqlSchema(false, true); destroyCqlSchema(false, true);
createCqlSchema(false, true); createCqlSchema(false, true);
...@@ -58,15 +54,31 @@ public: ...@@ -58,15 +54,31 @@ public:
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr(); hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
} }
/// @brief Destroys the HDS and the schema.
void destroyTest() {
try {
hdsptr_->rollback();
} catch (...) {
// Rollback may fail if backend is in read only mode. That's ok.
}
HostDataSourceFactory::destroy();
destroyCqlSchema(false, true);
}
/// @brief Constructor
///
/// Deletes everything from the database and opens it.
CqlHostDataSourceTest() {
initializeTest();
}
/// @brief Destructor /// @brief Destructor
/// ///
/// Rolls back all pending transactions. The deletion of myhdsptr_ will /// Rolls back all pending transactions. The deletion of myhdsptr_ will
/// close the database. Then reopen it and delete everything created by the /// close the database. Then reopen it and delete everything created by the
/// test. /// test.
virtual ~CqlHostDataSourceTest() { virtual ~CqlHostDataSourceTest() {
hdsptr_->rollback(); destroyTest();
HostDataSourceFactory::destroy();
destroyCqlSchema(false, true);
} }
/// @brief Reopen the database /// @brief Reopen the database
...@@ -169,7 +181,7 @@ TEST(CqlHostDataSource, OpenDatabase) { ...@@ -169,7 +181,7 @@ TEST(CqlHostDataSource, OpenDatabase) {
destroyCqlSchema(false, true); destroyCqlSchema(false, true);
} }
/// @brief Check conversion functions /// @brief Check conversion methods
/// ///
/// The server works using cltt and valid_filetime. In the database, the /// The server works using cltt and valid_filetime. In the database, the
/// information is stored as expire_time and valid-lifetime, which are /// information is stored as expire_time and valid-lifetime, which are
...@@ -475,8 +487,7 @@ TEST_F(CqlHostDataSourceTest, testAddRollback) { ...@@ -475,8 +487,7 @@ TEST_F(CqlHostDataSourceTest, testAddRollback) {
CqlConnection connection(params); CqlConnection connection(params);
ASSERT_NO_THROW(connection.openDatabase()); ASSERT_NO_THROW(connection.openDatabase());
// Drop every table so we make sure host_ipv6_reservation_options doesn't // Drop every table so we make sure host_reservations doesn't exist anymore.
// exist anymore
destroyCqlSchema(false, true); destroyCqlSchema(false, true);
// Create a host with a reservation. // Create a host with a reservation.
......
...@@ -86,6 +86,13 @@ public: ...@@ -86,6 +86,13 @@ public:
/// @return Identifier in textual form acceptable by Host constructor /// @return Identifier in textual form acceptable by Host constructor
std::vector<uint8_t> generateIdentifier(const bool new_identifier = true); std::vector<uint8_t> generateIdentifier(const bool new_identifier = true);
/// @brief Checks if the reservation is in the range of reservations.
///
/// @param resrv Reservation to be searched for.
/// @param range Range of reservations returned by the @c Host object
/// in which the reservation will be searched
bool reservationExists(const IPv6Resrv& resrv, const IPv6ResrvRange& range);
/// @brief Compares hardware addresses of the two hosts. /// @brief Compares hardware addresses of the two hosts.
/// ///
/// This method compares two hardware address and uses gtest /// This method compares two hardware address and uses gtest
...@@ -122,11 +129,11 @@ public: ...@@ -122,11 +129,11 @@ public:
/// @param host2 second host to compare /// @param host2 second host to compare
void compareHosts(const ConstHostPtr& host1, const ConstHostPtr& host2); void compareHosts(const ConstHostPtr& host1, const ConstHostPtr& host2);
/// @ brief Used to sort a host collection by IPv4 subnet id. /// @brief Used to sort a host collection by IPv4 subnet id.
static bool compareHostsForSort4(const ConstHostPtr& host1, static bool compareHostsForSort4(const ConstHostPtr& host1,
const ConstHostPtr& host2); const ConstHostPtr& host2);
/// @ brief Used to sort a host collection by IPv6 subnet id. /// @brief Used to sort a host collection by IPv6 subnet id.
static bool compareHostsForSort6(const ConstHostPtr& host1, static bool compareHostsForSort6(const ConstHostPtr& host1,
const ConstHostPtr& host2); const ConstHostPtr& host2);
...@@ -434,7 +441,7 @@ public: ...@@ -434,7 +441,7 @@ public:
void testClientIdNotHWAddr(); void testClientIdNotHWAddr();
/// @brief Test adds specified number of hosts with unique hostnames, then /// @brief Test adds specified number of hosts with unique hostnames, then
/// retrieves them and checks that the hostnames are set properly. /// retrives them and checks that the hostnames are set properly.
/// ///
/// Uses gtest macros to report failures. /// Uses gtest macros to report failures.
/// ///
......
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