146 lines
5.1 KiB
C++
146 lines
5.1 KiB
C++
/**
|
|
* @file tests/can_net_self_leader_giveup.cpp
|
|
* @brief CAN Net self node leader giveup
|
|
* @date Dec 14, 2016
|
|
* @author jjacobs
|
|
* @copyright 2016 Dual Inventive Technology Centre B.V.
|
|
*
|
|
*/
|
|
#include "fixtures/CANTest.hpp"
|
|
|
|
extern "C" {
|
|
#include "time.c"
|
|
}
|
|
|
|
/**
|
|
* Give up ROLE_LEADER from application
|
|
* * Verify if leader is able to give up leadership
|
|
* * Force self ROLE_LEADER, DISCOVER_FINISH
|
|
* * Set role from LEADER -> FOLLOWER
|
|
* * Check if self role update is published (heartbeat msg, contains type and role)
|
|
* * Check if self_was_leader is set
|
|
*/
|
|
TEST_F(DI_CAN, net_self_leader_giveup) {
|
|
SetNodeid(0xdeadbeef);
|
|
|
|
/* Set self TYPE_GATEWAY, force self ROLE_LEADER, DISCOVER_STATE_FINISH */
|
|
ASSERT_EQ(DNOK, di_can_net_self_set_node_type(&_ctx, DI_CAN_NET_NODE_TYPE_GATEWAY));
|
|
|
|
_ctx.net.discover.state = DI_CAN_NET_DISCOVER_STATE_FINISH;
|
|
_ctx.net.self.role = DI_CAN_NET_NODE_ROLE_LEADER;
|
|
|
|
ASSERT_TRUE(di_can_net_self_is_leader(&_ctx));
|
|
|
|
/* Set ROLE_FOLLOWER, check if self_was_leader is set */
|
|
ASSERT_EQ(DNOK, di_can_net_self_set_node_role(&_ctx, DI_CAN_NET_NODE_ROLE_FOLLOWER));
|
|
ASSERT_TRUE(_ctx.net.self_was_leader);
|
|
|
|
/* Verify ROLE_FOLLOWER message is published */
|
|
struct di_can_msg *msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET);
|
|
|
|
ASSERT_NE(nullptr, msg);
|
|
ASSERT_EQ(DI_CAN_TRANSFERTYPE_PUBLISH, DI_CAN_GET_TRANSFERTYPE(msg->canid));
|
|
ASSERT_EQ(DI_CAN_NET_DTYPE_HEARTBEAT, DI_CAN_GET_DATATYPE(msg->canid));
|
|
ASSERT_TRUE(msg->broadcast);
|
|
ASSERT_EQ(0xdeadbeef, msg->src_id);
|
|
ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id);
|
|
/* Verify the payload struct */
|
|
ASSERT_EQ(DI_CAN_PTYPE_STRUCT, msg->ptype);
|
|
ASSERT_EQ(2U, msg->size);
|
|
ASSERT_EQ(DI_CAN_NET_NODE_TYPE_GATEWAY, msg->msg[0]);
|
|
ASSERT_EQ(DI_CAN_NET_NODE_ROLE_FOLLOWER, msg->msg[1]);
|
|
|
|
di_can_msg_free(&msg);
|
|
|
|
/* Set ROLE_FOLLOWER again so we allow to become leader again */
|
|
ASSERT_EQ(DNOK, di_can_net_self_set_node_role(&_ctx, DI_CAN_NET_NODE_ROLE_FOLLOWER));
|
|
ASSERT_FALSE(_ctx.net.self_was_leader);
|
|
|
|
/* Verify no message is published because we are already the follower */
|
|
msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET);
|
|
ASSERT_EQ(nullptr, msg);
|
|
}
|
|
|
|
/**
|
|
* Give up ROLE_LEADER from application check correct events are emitted
|
|
* * Force self ROLE_LEADER, DISCOVER_FINISH
|
|
* * Set role from LEADER -> FOLLOWER
|
|
* * Update node list and try for self to become LEADER
|
|
*/
|
|
static size_t g_ev_idx = 0;
|
|
|
|
static void net_self_leader_giveup_event_cb(const struct di_can_net *ctx,
|
|
const enum di_can_net_node_events ev,
|
|
const struct di_can_net_node *node)
|
|
{
|
|
(void)ctx;
|
|
|
|
static const struct _tv {
|
|
const enum di_can_net_node_events ev;
|
|
const enum di_can_net_node_roles role;
|
|
} tv[] = {
|
|
{ DI_CAN_NET_NODE_EVENT_LEADER_TAKEOVER_FAILED, DI_CAN_NET_NODE_ROLE_FOLLOWER },
|
|
{ DI_CAN_NET_NODE_EVENT_LEADER_TAKEOVER_FAILED, DI_CAN_NET_NODE_ROLE_FOLLOWER },
|
|
{ DI_CAN_NET_NODE_EVENT_LEADER_TAKEOVER_FAILED, DI_CAN_NET_NODE_ROLE_FOLLOWER },
|
|
{ DI_CAN_NET_NODE_EVENT_ROLE_LEADER, DI_CAN_NET_NODE_ROLE_FOLLOWER }
|
|
};
|
|
|
|
printf("event(%d): node: %04x, type: %02x, role: %02x\n", ev, node->nodeid, node->type, node->role);
|
|
|
|
ASSERT_TRUE(di_can_net_node_is_self(ctx, node));
|
|
ASSERT_EQ(0xdeadbeef, node->nodeid);
|
|
ASSERT_EQ(DI_CAN_NET_NODE_TYPE_GATEWAY, node->type);
|
|
ASSERT_GT(DI_ARRAY_SIZE(tv), g_ev_idx);
|
|
ASSERT_EQ(tv[g_ev_idx].ev, ev);
|
|
ASSERT_EQ(tv[g_ev_idx].role, node->role);
|
|
|
|
g_ev_idx++;
|
|
}
|
|
|
|
TEST_F(DI_CAN, net_self_leader_giveup_events) {
|
|
SetNodeid(0xdeadbeef);
|
|
|
|
di_can_net_node_set_event_callback(&_ctx, net_self_leader_giveup_event_cb);
|
|
|
|
/* Set self TYPE_GATEWAY, set self ROLE_FOLLOWER (and self_was_leader), DISCOVER_STATE_FINISH */
|
|
ASSERT_EQ(DNOK, di_can_net_self_set_node_type(&_ctx, DI_CAN_NET_NODE_TYPE_GATEWAY));
|
|
_ctx.net.discover.state = DI_CAN_NET_DISCOVER_STATE_FINISH;
|
|
_ctx.net.self.role = DI_CAN_NET_NODE_ROLE_FOLLOWER;
|
|
_ctx.net.self_was_leader = true;
|
|
|
|
/* Force discover timeout, execute net subsystem (results in leadership) */
|
|
_di_time_uptime = DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS;
|
|
|
|
/* XXX NOTE: Because we run from the ROLE_FOLLOWER FSM, we get 3 times the LEADER_TAKEOVER_FAILED event */
|
|
ASSERT_EQ(0U, g_ev_idx);
|
|
|
|
di_can_net_execute(&_ctx);
|
|
di_can_net_execute(&_ctx);
|
|
di_can_net_execute(&_ctx);
|
|
|
|
ASSERT_EQ(3U, g_ev_idx);
|
|
|
|
/* Set the ROLE_FOLLOWER so we can become the ROLE_LEADER */
|
|
ASSERT_EQ(DNOK, di_can_net_self_set_node_role(&_ctx, DI_CAN_NET_NODE_ROLE_FOLLOWER));
|
|
|
|
di_can_net_execute(&_ctx);
|
|
ASSERT_EQ(4U, g_ev_idx);
|
|
|
|
/* Verify ROLE_LEADER update is published because */
|
|
struct di_can_msg *msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET);
|
|
|
|
ASSERT_NE(nullptr, msg);
|
|
ASSERT_EQ(DI_CAN_TRANSFERTYPE_PUBLISH, DI_CAN_GET_TRANSFERTYPE(msg->canid));
|
|
ASSERT_EQ(DI_CAN_NET_DTYPE_HEARTBEAT, DI_CAN_GET_DATATYPE(msg->canid));
|
|
ASSERT_TRUE(msg->broadcast);
|
|
ASSERT_EQ(0xdeadbeef, msg->src_id);
|
|
ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id);
|
|
/* Verify the payload struct */
|
|
ASSERT_EQ(DI_CAN_PTYPE_STRUCT, msg->ptype);
|
|
ASSERT_EQ(2U, msg->size);
|
|
ASSERT_EQ(DI_CAN_NET_NODE_TYPE_GATEWAY, msg->msg[0]);
|
|
ASSERT_EQ(DI_CAN_NET_NODE_ROLE_LEADER, msg->msg[1]);
|
|
|
|
di_can_msg_free(&msg);
|
|
}
|