138 lines
5.1 KiB
C++
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();
|
|
}
|