Simple wrapper for ZeroConf key/value pairs.
The servus class allows simple announcement and discovery of key/value pairs using ZeroConf networking. The same instance can be used to announce and/or to browse a ZeroConf service. If the Servus library is compiled without zeroconf support (
#define BOOST_TEST_MODULE servus_servus
#include <boost/test/unit_test.hpp>
#include <servus/servus.h>
#include <servus/uint128_t.h>
#include <random>
#ifdef SERVUS_USE_DNSSD
#include <dns_sd.h>
#endif
#ifdef _MSC_VER
#include <windows.h>
#define _sleep Sleep
#else
#define _sleep ::sleep
#endif
static const int _propagationTime = 1000;
static const int _propagationTries = 10;
namespace
{
uint16_t getRandomPort()
{
static std::random_device device;
static std::minstd_rand engine(device());
std::uniform_int_distribution<uint16_t> generator(1024u, 65535u);
return generator(engine);
}
void test(const std::string& serviceName)
{
const uint32_t port = getRandomPort();
try
{
}
catch (const std::runtime_error& e)
{
if (getenv("TRAVIS"))
{
std::cerr << "Bailing, no avahi on a Travis CI setup" << std::endl;
BOOST_CHECK_EQUAL(e.what(),
"Can't setup avahi client: Daemon not running");
return;
}
throw;
}
service.announce(port, std::to_string(port));
BOOST_CHECK_EQUAL(service.getName(), serviceName);
{
return;
}
#ifdef SERVUS_USE_DNSSD
BOOST_CHECK(servus::Result::SUCCESS == kDNSServiceErr_NoError);
#endif
if (result != servus::Result::SUCCESS)
{
std::cerr << "Bailing, got " << result
<< ": looks like a broken zeroconf setup" << std::endl;
return;
}
BOOST_CHECK_EQUAL(result, result);
BOOST_CHECK_EQUAL(result.
getString(),
"success");
BOOST_CHECK_EQUAL(result.
getCode(), 0);
std::cout << result << std::endl;
service.withdraw();
service.set("foo", "bar");
BOOST_CHECK_EQUAL(service.get("foo"), "bar");
BOOST_CHECK_EQUAL(service.get("bar"), std::string());
BOOST_CHECK(service.announce(port, std::to_string(port)));
int nLoops = _propagationTries;
while (--nLoops)
{
const servus::Strings& hosts =
if (hosts.empty() && nLoops > 1)
{
if (getenv("TRAVIS"))
{
std::cerr << "Bailing, got no hosts on a Travis CI setup"
<< std::endl;
return;
}
continue;
}
BOOST_REQUIRE_EQUAL(hosts.size(), 1);
BOOST_CHECK_EQUAL(hosts.front(), std::to_string(port));
BOOST_CHECK(service.containsKey(hosts.front(), "foo"));
BOOST_CHECK_EQUAL(service.get(hosts.front(), "foo"), "bar");
BOOST_CHECK_EQUAL(service.get("bar", "foo"), std::string());
BOOST_CHECK_EQUAL(service.get(hosts.front(), "foobar"), std::string());
break;
}
service.set("foobar", "42");
nLoops = _propagationTries;
while (--nLoops)
{
const servus::Strings& hosts =
const bool hasFoobar =
!hosts.empty() && service.containsKey(hosts.front(), "foobar");
if ((hosts.empty() || !hasFoobar) && nLoops > 1)
continue;
BOOST_REQUIRE_EQUAL(hosts.size(), 1);
BOOST_CHECK_EQUAL(service.get(hosts.front(), "foobar"), "42");
BOOST_CHECK_EQUAL(service.getKeys().size(), 2);
break;
}
BOOST_CHECK(!service.isBrowsing());
BOOST_CHECK(service.isBrowsing());
BOOST_CHECK(service.isBrowsing());
BOOST_CHECK_EQUAL(service.browse(_propagationTime), service.browse(0));
servus::Strings hosts = service.getInstances();
BOOST_REQUIRE_EQUAL(hosts.size(), 1);
BOOST_CHECK_EQUAL(service.get(hosts.front(), "foo"), "bar");
BOOST_CHECK_EQUAL(service.getKeys().size(), 2);
{
BOOST_CHECK(service2.announce(port + 1, std::to_string(port + 1)));
nLoops = _propagationTries;
while (--nLoops)
{
BOOST_CHECK(service.browse(_propagationTime));
hosts = service.getInstances();
if (hosts.size() < 2 && nLoops > 1)
continue;
BOOST_CHECK_EQUAL(hosts.size(), 2);
break;
}
}
nLoops = _propagationTries;
while (--nLoops)
{
BOOST_CHECK(service.browse(_propagationTime));
hosts = service.getInstances();
if (hosts.size() > 1 && nLoops > 1)
continue;
BOOST_CHECK_EQUAL(hosts.size(), 1);
break;
}
BOOST_CHECK(service.isBrowsing());
service.endBrowsing();
BOOST_CHECK(!service.isBrowsing());
hosts = service.getInstances();
BOOST_REQUIRE_EQUAL(hosts.size(), 1);
BOOST_CHECK_EQUAL(service.get(hosts.front(), "foo"), "bar");
BOOST_CHECK_EQUAL(service.getKeys().size(), 2);
}
}
BOOST_AUTO_TEST_CASE(test_servus)
{
std::string serviceName =
"_servustest_" + std::to_string(servus::make_UUID()) + "._tcp";
test(serviceName);
}
BOOST_AUTO_TEST_CASE(test_driver)
{
test(servus::TEST_DRIVER);
}