Commit 20047855 authored by Dominik Charousset's avatar Dominik Charousset

Receive BASP config directly from middleman

parent 80f74146
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <atomic> #include <atomic>
#include <string> #include <string>
#include <memory>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
...@@ -57,22 +58,67 @@ public: ...@@ -57,22 +58,67 @@ public:
using error_renderers = std::unordered_map<atom_value, error_renderer>; using error_renderers = std::unordered_map<atom_value, error_renderer>;
/// A variant type for config parameters.
using config_value = variant<std::string, double, int64_t, bool, atom_value>;
/// Helper class to generate config readers for different input types.
class option {
public:
using config_reader_sink = std::function<void (size_t, config_value&)>;
option(const char* category, const char* name, const char* explanation);
virtual ~option();
inline const char* name() const {
return name_;
}
inline const char* category() const {
return category_;
}
inline const char* explanation() const {
return explanation_;
}
virtual std::string to_string() const = 0;
virtual config_reader_sink to_sink() const = 0;
virtual message::cli_arg to_cli_arg() const = 0;
protected:
const char* category_;
const char* name_;
const char* explanation_;
};
using option_ptr = std::unique_ptr<option>;
using options_vector = std::vector<option_ptr>;
actor_system_config(); actor_system_config();
actor_system_config(int argc, char** argv); actor_system_config(int argc, char** argv);
actor_system_config& add_actor_factory(std::string name, actor_factory fun); actor_system_config& add_actor_factory(std::string name, actor_factory fun);
/// Allows others to spawn actors of type `T`
/// dynamically by using `name` as identifier.
template <class T, class... Ts> template <class T, class... Ts>
actor_system_config& add_actor_type(std::string name) { actor_system_config& add_actor_type(std::string name) {
return add_actor_factory(std::move(name), make_actor_factory<T, Ts...>()); return add_actor_factory(std::move(name), make_actor_factory<T, Ts...>());
} }
/// Allows others to spawn actors implemented by function `f`
/// dynamically by using `name` as identifier.
template <class F> template <class F>
actor_system_config& add_actor_type(std::string name, F f) { actor_system_config& add_actor_type(std::string name, F f) {
return add_actor_factory(std::move(name), make_actor_factory(std::move(f))); return add_actor_factory(std::move(name), make_actor_factory(std::move(f)));
} }
/// Adds message type `T` with runtime type info `name`.
template <class T> template <class T>
actor_system_config& add_message_type(std::string name) { actor_system_config& add_message_type(std::string name) {
static_assert(std::is_empty<T>::value static_assert(std::is_empty<T>::value
...@@ -89,10 +135,8 @@ public: ...@@ -89,10 +135,8 @@ public:
return *this; return *this;
} }
/** /// Enables the actor system to convert errors of this error category
* Enables the actor system to convert errors of this error category /// to human-readable strings via `renderer`.
* to human-readable strings via `renderer`.
*/
actor_system_config& add_error_category(atom_value category, actor_system_config& add_error_category(atom_value category,
error_renderer renderer); error_renderer renderer);
...@@ -115,6 +159,7 @@ public: ...@@ -115,6 +159,7 @@ public:
return add_error_category(category, f); return add_error_category(category, f);
} }
/// Loads module `T` with optional template parameters `Ts...`.
template <class T, class... Ts> template <class T, class... Ts>
actor_system_config& load() { actor_system_config& load() {
module_factories_.push_back([](actor_system& sys) -> actor_system::module* { module_factories_.push_back([](actor_system& sys) -> actor_system::module* {
...@@ -126,8 +171,8 @@ public: ...@@ -126,8 +171,8 @@ public:
/// Stores CLI arguments that were not consumed by CAF. /// Stores CLI arguments that were not consumed by CAF.
message args_remainder; message args_remainder;
/// Sets the parameter `name` to `val`. /// Sets a config by using its INI name `config_name` to `config_value`.
using config_value = variant<std::string, double, int64_t, bool, atom_value>; actor_system_config& set(const char* config_name, config_value config_value);
// Config parameters of scheduler. // Config parameters of scheduler.
atom_value scheduler_policy; atom_value scheduler_policy;
...@@ -141,7 +186,7 @@ public: ...@@ -141,7 +186,7 @@ public:
atom_value middleman_network_backend; atom_value middleman_network_backend;
bool middleman_enable_automatic_connections; bool middleman_enable_automatic_connections;
size_t middleman_max_consecutive_reads; size_t middleman_max_consecutive_reads;
size_t middleman_basp_heartbeat_interval; size_t middleman_heartbeat_interval;
// System parameters that are set while initializing modules. // System parameters that are set while initializing modules.
node_id network_id; node_id network_id;
...@@ -158,6 +203,7 @@ private: ...@@ -158,6 +203,7 @@ private:
actor_factories actor_factories_; actor_factories actor_factories_;
module_factories module_factories_; module_factories module_factories_;
error_renderers error_renderers_; error_renderers error_renderers_;
options_vector options_;
}; };
} // namespace caf } // namespace caf
......
...@@ -35,22 +35,22 @@ struct type_name_visitor : static_visitor<const char*> { ...@@ -35,22 +35,22 @@ struct type_name_visitor : static_visitor<const char*> {
const char* operator()(const std::string&) const { const char* operator()(const std::string&) const {
return "a string"; return "a string";
} }
const char* operator()(const double) const { const char* operator()(double) const {
return "a double"; return "a double";
} }
const char* operator()(const int64_t) const { const char* operator()(int64_t) const {
return "an integer"; return "an integer";
} }
const char* operator()(const size_t) const { const char* operator()(size_t) const {
return "an unsigned integer"; return "an unsigned integer";
} }
const char* operator()(const uint16_t) const { const char* operator()(uint16_t) const {
return "an unsigned short integer"; return "an unsigned short integer";
} }
const char* operator()(const bool) const { const char* operator()(bool) const {
return "a boolean"; return "a boolean";
} }
const char* operator()(const atom_value) const { const char* operator()(atom_value) const {
return "an atom"; return "an atom";
} }
}; };
...@@ -89,48 +89,114 @@ bool assign_config_value(uint16_t& x, int64_t& y) { ...@@ -89,48 +89,114 @@ bool assign_config_value(uint16_t& x, int64_t& y) {
return true; return true;
} }
using options_vector = actor_system_config::options_vector;
class actor_system_config_reader { class actor_system_config_reader {
public: public:
using config_value = actor_system_config::config_value; using config_value = actor_system_config::config_value;
using sink = std::function<void (size_t, config_value&)>; using sink = std::function<void (size_t, config_value&)>;
template <class T> actor_system_config_reader(options_vector& xs) {
actor_system_config_reader& bind(std::string arg_name, T& storage) { for (auto& x : xs) {
auto fun = [&storage](size_t ln, config_value& x) { std::string key = x->category();
key += '.';
key += x->name();
sinks_.emplace(std::move(key), x->to_sink());
}
}
void operator()(size_t ln, std::string name, config_value& cv) {
auto i = sinks_.find(name);
if (i == sinks_.end())
std::cerr << "error in line " << ln
<< ": unrecognized parameter name \"" << name << "\"";
else
(i->second)(ln, cv);
}
private:
std::map<std::string, sink> sinks_;
};
using cstr = const char*;
template <class T>
void add_option(options_vector& xs,
T& storage, cstr category, cstr name, cstr explanation) {
using option = actor_system_config::option;
using config_value = actor_system_config::config_value;
class impl : public option {
public:
impl(cstr ctg, cstr nm, cstr xp, T& ref) : option(ctg, nm, xp), ref_(ref) {
// nop
}
std::string to_string() const override {
return deep_to_string(ref_);
}
message::cli_arg to_cli_arg() const override {
std::string argname = "caf#";
argname += category();
argname += ".";
argname += name();
return {std::move(argname), explanation(), ref_};
}
config_reader_sink to_sink() const override {
return [=](size_t ln, config_value& x) {
// the INI parser accepts all integers as int64_t // the INI parser accepts all integers as int64_t
using cfg_type = using cfg_type =
typename std::conditional< typename std::conditional<
std::is_integral<T>::value, std::is_integral<T>::value && ! std::is_same<bool, T>::value,
int64_t, int64_t,
T T
>::type; >::type;
if (get<cfg_type>(&x) && assign_config_value(storage, get<cfg_type>(x))) if (get<cfg_type>(&x) && assign_config_value(ref_, get<cfg_type>(x)))
return; return;
type_name_visitor tnv; type_name_visitor tnv;
std::cerr << "error in line " << ln << ": expected " std::cerr << "error in line " << ln << ": expected "
<< tnv(storage) << " found " << tnv(ref_) << " found "
<< apply_visitor(tnv, x) << std::endl; << apply_visitor(tnv, x) << std::endl;
}; };
sinks_.emplace(std::move(arg_name), fun);
return *this;
} }
private:
T& ref_;
};
return xs.emplace_back(new impl(category, name, explanation, storage));
}
void operator()(size_t ln, std::string name, config_value& cv) { class opt_group {
auto i = sinks_.find(name); public:
if (i == sinks_.end()) opt_group(options_vector& xs, cstr category) : xs_(xs), category_(category) {
std::cerr << "error in line " << ln << ": unrecognized parameter name \"" // nop
<< name << "\""; }
else
(i->second)(ln, cv); template <class T>
opt_group& add(T& storage, cstr option_name, cstr explanation) {
add_option(xs_, storage, category_, option_name, explanation);
return *this;
} }
private: private:
std::map<std::string, sink> sinks_; options_vector& xs_;
cstr category_;
}; };
} // namespace <anonymous> } // namespace <anonymous>
actor_system_config::option::option(cstr ct, cstr nm, cstr xp)
: category_(ct),
name_(nm),
explanation_(xp) {
// nop
}
actor_system_config::option::~option() {
// nop
}
// in this config class, we have (1) hard-coded defaults that are overridden
// by (2) INI-file contents that are in turn overridden by (3) CLI arguments
actor_system_config::actor_system_config() { actor_system_config::actor_system_config() {
// (1) hard-coded defaults // (1) hard-coded defaults
scheduler_policy = atom("stealing"); scheduler_policy = atom("stealing");
...@@ -142,8 +208,36 @@ actor_system_config::actor_system_config() { ...@@ -142,8 +208,36 @@ actor_system_config::actor_system_config() {
middleman_network_backend = atom("default"); middleman_network_backend = atom("default");
middleman_enable_automatic_connections = false; middleman_enable_automatic_connections = false;
middleman_max_consecutive_reads = 50; middleman_max_consecutive_reads = 50;
middleman_basp_heartbeat_interval = 0; middleman_heartbeat_interval = 0;
nexus_port = 0; nexus_port = 0;
// fill our options vector for creating INI and CLI parsers
opt_group{options_, "scheduler"}
.add(scheduler_policy, "policy",
"sets the scheduling policy to either 'stealing' (default) or 'sharing'")
.add(scheduler_max_threads, "max-threads",
"sets a fixed number of worker threads for the scheduler")
.add(scheduler_max_throughput, "max-throughput",
"sets the maximum number of messages an actor consumes before yielding")
.add(scheduler_enable_profiling, "enable-profiling",
"enables or disables profiler output")
.add(scheduler_profiling_ms_resolution, "profiling-ms-resolution",
"sets the rate in ms in which the profiler collects data")
.add(scheduler_profiling_output_file, "profiling-output-file",
"sets the output file for the profiler");
opt_group{options_, "middleman"}
.add(middleman_network_backend, "network-backend",
"sets the network backend to either 'default' or 'asio' (if available)")
.add(middleman_enable_automatic_connections, "enable-automatic-connections",
"enables or disables automatic connection management (off per default)")
.add(middleman_max_consecutive_reads, "max-consecutive-reads",
"sets the maximum number of consecutive I/O reads per broker")
.add(middleman_heartbeat_interval, "heartbeat-interval",
"sets the interval (ms) of heartbeat, 0 (default) means disabling it");
opt_group{options_, "probe"}
.add(nexus_host, "nexus-host",
"sets the hostname or IP address for connecting to the Nexus")
.add(nexus_port, "probe.nexus-port",
"sets the port for connecting to the Nexus");
} }
actor_system_config::actor_system_config(int argc, char** argv) actor_system_config::actor_system_config(int argc, char** argv)
...@@ -151,6 +245,7 @@ actor_system_config::actor_system_config(int argc, char** argv) ...@@ -151,6 +245,7 @@ actor_system_config::actor_system_config(int argc, char** argv)
if (argc < 2) if (argc < 2)
return; return;
auto args = message_builder(argv, argv + argc).move_to_message(); auto args = message_builder(argv, argv + argc).move_to_message();
// extract config file name first, since INI files are overruled by CLI args
std::string config_file_name; std::string config_file_name;
args.extract_opts({ args.extract_opts({
{"caf-config-file", "", config_file_name} {"caf-config-file", "", config_file_name}
...@@ -159,68 +254,18 @@ actor_system_config::actor_system_config(int argc, char** argv) ...@@ -159,68 +254,18 @@ actor_system_config::actor_system_config(int argc, char** argv)
if (! config_file_name.empty()) { if (! config_file_name.empty()) {
std::ifstream ini{config_file_name}; std::ifstream ini{config_file_name};
if (ini.good()) { if (ini.good()) {
actor_system_config_reader consumer; actor_system_config_reader consumer{options_};
consumer.bind("scheduler.policy", scheduler_policy)
.bind("scheduler.scheduler-max-threads", scheduler_max_threads)
.bind("scheduler.max-throughput", scheduler_max_throughput)
.bind("scheduler.enable-profiling", scheduler_enable_profiling)
.bind("scheduler.profiling-ms-resolution",
scheduler_profiling_ms_resolution)
.bind("scheduler.profiling-output-file",
scheduler_profiling_output_file)
.bind("middleman.network-backend", middleman_network_backend)
.bind("middleman.enable-automatic-connections",
middleman_enable_automatic_connections)
.bind("middleman.max_consecutive_reads",
middleman_max_consecutive_reads)
.bind("middleman.basp-heartbeat-interval",
middleman_basp_heartbeat_interval)
.bind("probe.nexus-host", nexus_host)
.bind("probe.nexus-port", nexus_port);
detail::parse_ini(ini, consumer, std::cerr); detail::parse_ini(ini, consumer, std::cerr);
} }
} }
// (3) CLI options override the content of the INI file // (3) CLI options override the content of the INI file
auto res = args.extract_opts({ std::vector<message::cli_arg> cargs;
{"caf#scheduler.policy", for (auto& x : options_)
"sets the scheduling policy to either 'stealing' (default) or 'sharing'", cargs.emplace_back(x->to_cli_arg());
scheduler_policy}, cargs.emplace_back("caf-dump-config", "print config in INI format to stdout");
{"caf#scheduler.scheduler-max-threads", cargs.emplace_back("caf-help", "print this text");
"sets a fixed number of worker threads for the scheduler", cargs.emplace_back("caf-config-file", "parse INI file", config_file_name);
scheduler_max_threads}, auto res = args.extract_opts(std::move(cargs), nullptr, true);
{"caf#scheduler.max-throughput",
"sets the maximum number of messages an actor consumes before yielding",
scheduler_max_throughput},
{"caf#scheduler.enable-profiling",
"enables or disables profiler output",
scheduler_enable_profiling},
{"caf#scheduler.profiling-ms-resolution",
"sets the rate in ms in which the profiler collects data",
scheduler_profiling_ms_resolution},
{"caf#scheduler.profiling-output-file",
"sets the output file for the profiler",
scheduler_profiling_output_file},
{"caf#middleman.network-backend",
"sets the network backend to either 'default' or 'asio' (if available)",
middleman_network_backend},
{"caf#middleman.enable-automatic-connections",
"enables or disables automatic connection management (off per default)",
middleman_enable_automatic_connections},
{"caf#middleman.max_consecutive_reads",
"sets the maximum number of allowed I/O reads before scheduling others",
middleman_max_consecutive_reads},
{"caf#middleman.basp-heartbeat-interval",
"sets the interval (ms) of basp-heartbeat, 0 (default) means disabling it",
middleman_basp_heartbeat_interval},
{"caf#probe.nexus-host",
"sets the hostname or IP address for connecting to the Nexus",
nexus_host},
{"caf#probe.nexus-port",
"sets the port for connecting to the Nexus",
nexus_port},
{"caf-dump-config", "print config in INI format to stdout"},
{"caf-help", "print this text"}
}, nullptr, true);
using std::cerr; using std::cerr;
using std::cout; using std::cout;
using std::endl; using std::endl;
...@@ -259,8 +304,8 @@ actor_system_config::actor_system_config(int argc, char** argv) ...@@ -259,8 +304,8 @@ actor_system_config::actor_system_config(int argc, char** argv)
<< deep_to_string(middleman_network_backend) << endl << deep_to_string(middleman_network_backend) << endl
<< "enable-automatic-connections=" << "enable-automatic-connections="
<< deep_to_string(middleman_enable_automatic_connections) << endl << deep_to_string(middleman_enable_automatic_connections) << endl
<< "basp-heartbeat-interval=" << "heartbeat-interval="
<< middleman_basp_heartbeat_interval << endl; << middleman_heartbeat_interval << endl;
} }
args_remainder = std::move(res.remainder); args_remainder = std::move(res.remainder);
} }
...@@ -277,4 +322,20 @@ actor_system_config::add_error_category(atom_value x, error_renderer y) { ...@@ -277,4 +322,20 @@ actor_system_config::add_error_category(atom_value x, error_renderer y) {
return *this; return *this;
} }
actor_system_config&
actor_system_config::set(const char* config_name, config_value config_value) {
std::string cn;
for (auto& x : options_) {
// config_name has format "$category.$name"
cn = x->category();
cn += '.';
cn += x->name();
if (cn == config_name) {
auto f = x->to_sink();
f(0, config_value);
}
}
return *this;
}
} // namespace caf } // namespace caf
...@@ -135,8 +135,6 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee { ...@@ -135,8 +135,6 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee {
} }
}; };
/// A broker implementation for the Binary Actor System Protocol (BASP). /// A broker implementation for the Binary Actor System Protocol (BASP).
class basp_broker : public stateful_actor<basp_broker_state, broker> { class basp_broker : public stateful_actor<basp_broker_state, broker> {
public: public:
......
...@@ -261,6 +261,17 @@ public: ...@@ -261,6 +261,17 @@ public:
return new impl(sys); return new impl(sys);
} }
/// Returns the heartbeat interval in milliseconds.
inline size_t heartbeat_interval() const {
return heartbeat_interval_;
}
/// Retruns whether the middleman tries to establish
/// a direct connection to each of its peers.
inline bool enable_automatic_connections() const {
return enable_automatic_connections_;
}
protected: protected:
middleman(actor_system& ref); middleman(actor_system& ref);
...@@ -315,8 +326,10 @@ private: ...@@ -315,8 +326,10 @@ private:
hook_uptr hooks_; hook_uptr hooks_;
// actor offering asyncronous IO by managing this singleton instance // actor offering asyncronous IO by managing this singleton instance
middleman_actor manager_; middleman_actor manager_;
// configure parameters // heartbeat interval of BASP in milliseconds
size_t basp_heartbeat_interval_; size_t heartbeat_interval_;
// configures whether BASP tries to connect to all known peers
bool enable_automatic_connections_;
}; };
} // namespace io } // namespace io
......
...@@ -444,10 +444,23 @@ basp_broker::basp_broker(actor_config& cfg) ...@@ -444,10 +444,23 @@ basp_broker::basp_broker(actor_config& cfg)
behavior basp_broker::make_behavior() { behavior basp_broker::make_behavior() {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
// TODO: query this config from middleman directly if (system().middleman().enable_automatic_connections()) {
// ask the configuration server whether we should open a default port printf("enable automatic connections\n");
CAF_LOG_INFO("enable automatic connections");
// open a random port and store a record for our peers how to
// connect to this broker directly in the configuration server
auto port = add_tcp_doorman(uint16_t{0});
auto addrs = network::interfaces::list_addresses(false);
auto config_server = system().registry().get(atom("ConfigServ")); auto config_server = system().registry().get(atom("ConfigServ"));
send(config_server, get_atom::value, "middleman.enable-automatic-connections"); send(config_server, put_atom::value, "basp.default-connectivity",
make_message(port.second, std::move(addrs)));
state.enable_automatic_connections = true;
}
auto heartbeat_interval = system().middleman().heartbeat_interval();
if (heartbeat_interval > 0) {
CAF_LOG_INFO("enable heartbeat" << CAF_ARG(heartbeat_interval));
send(this, tick_atom::value, heartbeat_interval);
}
return { return {
// received from underlying broker implementation // received from underlying broker implementation
[=](new_data_msg& msg) { [=](new_data_msg& msg) {
...@@ -639,22 +652,6 @@ behavior basp_broker::make_behavior() { ...@@ -639,22 +652,6 @@ behavior basp_broker::make_behavior() {
} }
return {}; return {};
}, },
[=](ok_atom, const std::string& key, message& value) {
if (key == "middleman.enable-automatic-connections") {
value.apply([&](bool enabled) {
if (! enabled)
return;
CAF_LOG_INFO("enable automatic connection");
// open a random port and store a record for others
// how to connect to this port in the configuration server
auto port = add_tcp_doorman(uint16_t{0});
auto addrs = network::interfaces::list_addresses(false);
send(config_server, put_atom::value, "basp.default-connectivity",
make_message(port.second, std::move(addrs)));
state.enable_automatic_connections = true;
});
}
},
[=](get_atom, const node_id& x) [=](get_atom, const node_id& x)
-> std::tuple<node_id, std::string, uint16_t> { -> std::tuple<node_id, std::string, uint16_t> {
std::string addr; std::string addr;
......
...@@ -100,7 +100,10 @@ actor_system::module* middleman::make(actor_system& sys, detail::type_list<>) { ...@@ -100,7 +100,10 @@ actor_system::module* middleman::make(actor_system& sys, detail::type_list<>) {
return new impl(sys); return new impl(sys);
} }
middleman::middleman(actor_system& sys) : system_(sys) { middleman::middleman(actor_system& sys)
: system_(sys),
heartbeat_interval_(0),
enable_automatic_connections_(false) {
// nop // nop
} }
...@@ -286,10 +289,6 @@ void middleman::start() { ...@@ -286,10 +289,6 @@ void middleman::start() {
backend().thread_id(thread_.get_id()); backend().thread_id(thread_.get_id());
} }
auto basp = named_broker<basp_broker>(atom("BASP")); auto basp = named_broker<basp_broker>(atom("BASP"));
if (basp_heartbeat_interval_ > 0) {
CAF_LOG_INFO("enable basp-heartbeat: " << CAF_ARG(basp_heartbeat_interval_));
anon_send(basp, tick_atom::value, basp_heartbeat_interval_);
}
manager_ = make_middleman_actor(system(), basp); manager_ = make_middleman_actor(system(), basp);
} }
...@@ -347,7 +346,9 @@ void middleman::init(actor_system_config& cfg) { ...@@ -347,7 +346,9 @@ void middleman::init(actor_system_config& cfg) {
// set scheduling parameters for multiplexer // set scheduling parameters for multiplexer
backend().max_throughput(cfg.scheduler_max_throughput); backend().max_throughput(cfg.scheduler_max_throughput);
backend().max_consecutive_reads(cfg.middleman_max_consecutive_reads); backend().max_consecutive_reads(cfg.middleman_max_consecutive_reads);
basp_heartbeat_interval_ = cfg.middleman_basp_heartbeat_interval; // set options relevant to BASP
heartbeat_interval_ = cfg.middleman_heartbeat_interval;
enable_automatic_connections_ = cfg.middleman_enable_automatic_connections;
} }
actor_system::module::id_t middleman::id() const { actor_system::module::id_t middleman::id() const {
......
...@@ -97,8 +97,10 @@ string hexstr(const buffer& buf) { ...@@ -97,8 +97,10 @@ string hexstr(const buffer& buf) {
class fixture { class fixture {
public: public:
fixture() : system(actor_system_config{} fixture(bool autoconn = false)
.load<io::middleman, network::test_multiplexer>()) { : system(actor_system_config{}
.load<io::middleman, network::test_multiplexer>()
.set("middleman.enable-automatic-connections", autoconn)) {
auto& mm = system.middleman(); auto& mm = system.middleman();
mpx_ = dynamic_cast<network::test_multiplexer*>(&mm.backend()); mpx_ = dynamic_cast<network::test_multiplexer*>(&mm.backend());
CAF_REQUIRE(mpx_ != nullptr); CAF_REQUIRE(mpx_ != nullptr);
...@@ -427,6 +429,13 @@ private: ...@@ -427,6 +429,13 @@ private:
actor_registry* registry_; actor_registry* registry_;
}; };
class autoconn_enabled_fixture : public fixture {
public:
autoconn_enabled_fixture() : fixture(true) {
// nop
}
};
} // namespace <anonymous> } // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(basp_tests, fixture) CAF_TEST_FIXTURE_SCOPE(basp_tests, fixture)
...@@ -669,8 +678,9 @@ CAF_TEST(actor_serialize_and_deserialize) { ...@@ -669,8 +678,9 @@ CAF_TEST(actor_serialize_and_deserialize) {
} }
CAF_TEST(indirect_connections) { CAF_TEST(indirect_connections) {
// jupiter [remote hdl 0] -> mars [remote hdl 1] -> earth [this_node] // jupiter [remote hdl 0] -> mars [remote hdl 1] -> earth [this_node];
// (this node receives a message from jupiter via mars and responds via mars) // this node receives a message from jupiter via mars and responds via mars
// and any ad-hoc automatic connection requests are ignored
CAF_MESSAGE("self: " << to_string(self()->address())); CAF_MESSAGE("self: " << to_string(self()->address()));
auto ax = accept_handle::from_int(4242); auto ax = accept_handle::from_int(4242);
mpx()->provide_acceptor(4242, ax); mpx()->provide_acceptor(4242, ax);
...@@ -715,11 +725,15 @@ CAF_TEST(indirect_connections) { ...@@ -715,11 +725,15 @@ CAF_TEST(indirect_connections) {
make_message("hello from earth!")); make_message("hello from earth!"));
} }
CAF_TEST_FIXTURE_SCOPE_END()
CAF_TEST_FIXTURE_SCOPE(basp_tests_with_autoconn, autoconn_enabled_fixture)
CAF_TEST(automatic_connection) { CAF_TEST(automatic_connection) {
// this tells our BASP broker to enable the automatic connection feature // this tells our BASP broker to enable the automatic connection feature
anon_send(aut(), ok_atom::value, //anon_send(aut(), ok_atom::value,
"middleman.enable-automatic-connections", make_message(true)); // "middleman.enable-automatic-connections", make_message(true));
mpx()->exec_runnable(); // process publish message in basp_broker //mpx()->exec_runnable(); // process publish message in basp_broker
// jupiter [remote hdl 0] -> mars [remote hdl 1] -> earth [this_node] // jupiter [remote hdl 0] -> mars [remote hdl 1] -> earth [this_node]
// (this node receives a message from jupiter via mars and responds via mars, // (this node receives a message from jupiter via mars and responds via mars,
// but then also establishes a connection to jupiter directly) // but then also establishes a connection to jupiter directly)
......
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