src.dualinventive.com/jjacobs/dinetrpcll-sniffer/libdi/tests/can_net_discover_fsm.cpp

138 lines
5.1 KiB
C++

/**
* @file tests/can_net_discover_fsm.cpp
* @brief CAN Net discover FSM (network nodes discover, follower, leader)
* @date Nov 28, 2016
* @author jjacobs
* @copyright 2016 Dual Inventive Technology Centre B.V.
*/
#include "fixtures/CANTest.hpp"
extern "C" {
#include "time.c" // Necessary to manipulate di_time_get_uptime(), to force a discover timeout
}
/**
* Verify the discover state is correctly updated and the broadcast request is send
* UNKNOWN -> REQUEST -> FINISH (due to timeout)
* This is from the passive role (and all other roles)
*/
TEST_F(DI_CAN, net_discover_fsm_state) {
/* Initialize */
SetNodeid(0x1337dead);
ASSERT_EQ(0x1337dead, _ctx.nodeid);
ASSERT_EQ(0x1337dead, _ctx.net.self.nodeid);
ASSERT_EQ(DI_CAN_NET_NODE_ROLE_PASSIVE, _ctx.net.self.role);
/* Init -> UNKNOWN */
ASSERT_EQ(DI_CAN_NET_DISCOVER_STATE_UNKNOWN, _ctx.net.discover.state);
ASSERT_EQ(0, _ctx.net.discover.time);
/* UNKNOWN -> REQUEST */
_di_time_uptime = 1234;
di_can_net_discover_fsm(&_ctx);
ASSERT_EQ(DI_CAN_NET_DISCOVER_STATE_REQUEST, _ctx.net.discover.state);
ASSERT_EQ(1234 + DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS, _ctx.net.discover.time);
/* Verify the correct request is send (recv msg from loopback) */
struct di_can_msg *msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET);
ASSERT_NE(nullptr, msg);
ASSERT_EQ(DI_CAN_MSGTYPE_NET, DI_CAN_GET_MSGTYPE(msg->canid));
ASSERT_EQ(DI_CAN_NET_DTYPE_DISCOVER, DI_CAN_GET_DATATYPE(msg->canid));
ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id);
ASSERT_EQ(0x1337dead, msg->src_id);
ASSERT_EQ(0U, msg->size);
ASSERT_EQ(nullptr, msg->msg);
di_can_msg_free(&msg);
/* REQUEST -> REQUEST (due to timeout not exceeded)
Update local uptime to just one millisecond before the timeout
Then execute the discover FSM twice and verify if it is still in the REQUEST state
*/
_di_time_uptime = 1234 + DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS - 1;
di_can_net_discover_fsm(&_ctx);
/* Verify subsequent call doesn't result in losing the REQUEST state (and timeout) */
di_can_net_discover_fsm(&_ctx);
ASSERT_EQ(DI_CAN_NET_DISCOVER_STATE_REQUEST, _ctx.net.discover.state);
ASSERT_EQ(1234 + DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS, _ctx.net.discover.time);
/* REQUEST -> FINISH (due to discover timeout based on di_time_get_uptime())
Update local uptime to the timeout
Then execute the discover FSM and verify if it is in the FINISH state
*/
_di_time_uptime = 1234 + DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS;
di_can_net_discover_fsm(&_ctx);
ASSERT_EQ(DI_CAN_NET_DISCOVER_STATE_FINISH, _ctx.net.discover.state);
ASSERT_EQ(1234 + DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS, _ctx.net.discover.time);
/* Verify subsequent calls doesn't result in losing the FINISH state */
di_can_net_discover_fsm(&_ctx);
ASSERT_EQ(DI_CAN_NET_DISCOVER_STATE_FINISH, _ctx.net.discover.state);
ASSERT_EQ(1234 + DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS, _ctx.net.discover.time);
}
/**
* Verify the follower becomes the leader when DISCOVER state is FINISH
* This test simulates no other nodes on the network (replies)
*/
TEST_F(DI_CAN, net_discover_fsm_follower) {
/* Initialize */
SetNodeid(0x12345678);
ASSERT_EQ(0x12345678, _ctx.nodeid);
ASSERT_EQ(0x12345678, _ctx.net.self.nodeid);
ASSERT_EQ(DI_CAN_NET_NODE_TYPE_UNKNOWN, _ctx.net.self.type);
ASSERT_EQ(DI_CAN_NET_NODE_ROLE_PASSIVE, _ctx.net.self.role);
/* Set self to follower role (this publishes the role update using the heartbeat dtype) */
ASSERT_EQ(DNOK, di_can_net_self_set_node_role(&_ctx, DI_CAN_NET_NODE_ROLE_FOLLOWER));
/* Discover the network */
_di_time_uptime = 1234;
di_can_net_discover_fsm(&_ctx);
ASSERT_EQ(DI_CAN_NET_DISCOVER_STATE_REQUEST, _ctx.net.discover.state);
ASSERT_EQ(1234 + DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS, _ctx.net.discover.time);
/* Read the DI_CAN_NET_DTYPE_HEARTBEAT publish message which was send by the
* di_can_net_self_set_node_role call (necessary for fast-takeover)
*/
struct di_can_msg *msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET);
ASSERT_NE((void *)NULL, 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_EQ(DI_CAN_PTYPE_STRUCT, msg->ptype);
ASSERT_EQ(2U, msg->size);
ASSERT_EQ(0x12345678, msg->src_id);
ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id);
di_can_msg_free(&msg);
/* Verify the correct request is send (recv msg from loopback) */
msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_NET);
ASSERT_NE(nullptr, msg);
ASSERT_EQ(DI_CAN_MSGTYPE_NET, DI_CAN_GET_MSGTYPE(msg->canid));
ASSERT_EQ(DI_CAN_NET_DTYPE_DISCOVER, DI_CAN_GET_DATATYPE(msg->canid));
ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id);
ASSERT_EQ(0x12345678, msg->src_id);
ASSERT_EQ(0U, msg->size);
ASSERT_EQ(nullptr, msg->msg);
di_can_msg_free(&msg);
/* Finish the discovery (by timeout) */
_di_time_uptime = 1234 + DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS;
di_can_net_discover_fsm(&_ctx);
ASSERT_EQ(DI_CAN_NET_DISCOVER_STATE_FINISH, _ctx.net.discover.state);
ASSERT_EQ(1234 + DI_CAN_NET_CFG_DISCOVER_TIMEOUT_MS, _ctx.net.discover.time);
/* Check if we are the leader */
ASSERT_TRUE(di_can_net_self_is_leader(&_ctx));
PrintNetNodes();
}