Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

185 lines
4.8 KiB
C++

// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE net.backend.tcp
#include "caf/net/backend/tcp.hpp"
#include "caf/net/test/host_fixture.hpp"
#include "caf/test/dsl.hpp"
#include <string>
#include <thread>
#include "caf/actor_system_config.hpp"
#include "caf/ip_endpoint.hpp"
#include "caf/net/middleman.hpp"
#include "caf/net/socket_guard.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include "caf/uri.hpp"
using namespace caf;
using namespace caf::net;
using namespace std::literals::string_literals;
namespace {
behavior dummy_actor(event_based_actor*) {
return {
// nop
};
}
struct earth_node {
uri operator()() {
return unbox(make_uri("tcp://earth"));
}
};
struct mars_node {
uri operator()() {
return unbox(make_uri("tcp://mars"));
}
};
template <class Node>
struct config : actor_system_config {
config() {
Node this_node;
put(content, "caf.middleman.this-node", this_node());
load<middleman, backend::tcp>();
}
};
class planet_driver {
public:
virtual ~planet_driver() = default;
virtual bool handle_io_event() = 0;
};
template <class Node>
class planet : public test_coordinator_fixture<config<Node>> {
public:
planet(planet_driver& driver)
: mm(this->sys.network_manager()), mpx(mm.mpx()), driver_(driver) {
mpx->set_thread_id();
}
node_id id() const {
return this->sys.node();
}
bool handle_io_event() override {
return driver_.handle_io_event();
}
net::middleman& mm;
multiplexer_ptr mpx;
private:
planet_driver& driver_;
};
struct fixture : host_fixture, planet_driver {
fixture() : earth(*this), mars(*this) {
earth.run();
mars.run();
CAF_REQUIRE_EQUAL(earth.mpx->num_socket_managers(), 2);
CAF_REQUIRE_EQUAL(mars.mpx->num_socket_managers(), 2);
}
bool handle_io_event() override {
return earth.mpx->poll_once(false) || mars.mpx->poll_once(false);
}
void run() {
earth.run();
}
planet<earth_node> earth;
planet<mars_node> mars;
};
} // namespace
CAF_TEST_FIXTURE_SCOPE(tcp_backend_tests, fixture)
CAF_TEST(doorman accept) {
auto backend = earth.mm.backend("tcp");
CAF_CHECK(backend);
uri::authority_type auth;
auth.host = "localhost"s;
auth.port = backend->port();
CAF_MESSAGE("trying to connect to earth at " << CAF_ARG(auth));
auto sock = make_connected_tcp_stream_socket(auth);
CAF_CHECK(sock);
auto guard = make_socket_guard(*sock);
int runs = 0;
while (earth.mpx->num_socket_managers() < 3) {
if (++runs >= 5)
CAF_FAIL("doorman did not create endpoint_manager");
run();
}
CAF_CHECK_EQUAL(earth.mpx->num_socket_managers(), 3);
}
CAF_TEST(connect) {
uri::authority_type auth;
auth.host = "0.0.0.0"s;
auth.port = 0;
auto acceptor = unbox(make_tcp_accept_socket(auth, false));
auto acc_guard = make_socket_guard(acceptor);
auto port = unbox(local_port(acc_guard.socket()));
auto uri_str = std::string("tcp://localhost:") + std::to_string(port);
CAF_MESSAGE("connecting to " << CAF_ARG(uri_str));
CAF_CHECK(earth.mm.connect(*make_uri(uri_str)));
auto sock = unbox(accept(acc_guard.socket()));
auto sock_guard = make_socket_guard(sock);
handle_io_event();
CAF_CHECK_EQUAL(earth.mpx->num_socket_managers(), 3);
}
CAF_TEST(publish) {
auto dummy = earth.sys.spawn(dummy_actor);
auto path = "dummy"s;
CAF_MESSAGE("publishing actor " << CAF_ARG(path));
earth.mm.publish(dummy, path);
CAF_MESSAGE("check registry for " << CAF_ARG(path));
CAF_CHECK_NOT_EQUAL(earth.sys.registry().get(path), nullptr);
}
CAF_TEST(resolve) {
using std::chrono::milliseconds;
using std::chrono::seconds;
auto sockets = unbox(make_stream_socket_pair());
auto earth_be = reinterpret_cast<net::backend::tcp*>(earth.mm.backend("tcp"));
CAF_CHECK(earth_be->emplace(mars.id(), sockets.first));
auto mars_be = reinterpret_cast<net::backend::tcp*>(mars.mm.backend("tcp"));
CAF_CHECK(mars_be->emplace(earth.id(), sockets.second));
handle_io_event();
CAF_CHECK_EQUAL(earth.mpx->num_socket_managers(), 3);
CAF_CHECK_EQUAL(mars.mpx->num_socket_managers(), 3);
auto dummy = earth.sys.spawn(dummy_actor);
earth.mm.publish(dummy, "dummy"s);
auto locator = unbox(make_uri("tcp://earth/name/dummy"s));
CAF_MESSAGE("resolve " << CAF_ARG(locator));
mars.mm.resolve(locator, mars.self);
mars.run();
earth.run();
mars.run();
mars.self->receive(
[](strong_actor_ptr& ptr, const std::set<std::string>&) {
CAF_MESSAGE("resolved actor!");
CAF_CHECK_NOT_EQUAL(ptr, nullptr);
},
[](const error& err) {
CAF_FAIL("got error while resolving: " << CAF_ARG(err));
},
after(std::chrono::seconds(0)) >>
[] { CAF_FAIL("manager did not respond with a proxy."); });
}
CAF_TEST_FIXTURE_SCOPE_END()