/** * @file tests/can_msg_gc.cpp * @date Mar 13, 2019 * @copyright 2019 Dual Inventive Technology Centre B.V. * * CAN Message buffer test */ #include #include #include "fixtures/CANTest.hpp" extern "C" { #include "can.c" #include "time.c" #include "can/msg.c" } /** * Put test message into the pool for garbage collection */ static void test_can_msg_gc_put(DI_CAN *t, struct di_can_ctx *ctx, struct di_can_msg **msg) { uint8_t _msg[] = "0123456789"; *msg = di_can_msg_alloc_reassemble(ctx); if (*msg) { ASSERT_NE((void *)NULL, (*msg)->buf); di_buffer_memcpy((*msg)->buf, 0, _msg, sizeof(_msg)); } DI_CAN_SET_MSGTYPE((*msg)->canid, DI_CAN_MSGTYPE_RAW); ASSERT_NE(nullptr, *msg); ASSERT_NE(nullptr, (*msg)->buf); ASSERT_STREQ((const char *)_msg, (const char *)(*msg)->buf->data); ASSERT_EQ(t->getCurrentMsgTimeout(), (*msg)->timeout); } /** * Normal garbage collect test * This uses the single garbage collect run */ TEST_F(DI_CAN, gc_single) { struct di_can_msg *msg; /* Test garbage collection on m->timeout = 1000ms uptime = 2000ms */ test_can_msg_gc_put(this, &_ctx, &msg); msg->timeout = 1000; _di_time_uptime = 2000; di_can_msg_gc(&_ctx, DI_CAN_GC_SINGLE); ASSERT_EQ(0U, msg->timeout); /* Test garbage collection on m->timeout = 1000ms uptime = 1000ms */ test_can_msg_gc_put(this, &_ctx, &msg); msg->timeout = 1000; _di_time_uptime = 1000; di_can_msg_gc(&_ctx, DI_CAN_GC_SINGLE); ASSERT_EQ(0U, msg->timeout); /* Test garbage collection skip on m->timeout = 1000ms uptime = 750ms */ test_can_msg_gc_put(this, &_ctx, &msg); _di_time_uptime = 750; di_can_msg_gc(&_ctx, DI_CAN_GC_SINGLE); ASSERT_EQ(1500, msg->timeout); /* Now garbage collect previous message */ _di_time_uptime = 1000; di_can_msg_gc(&_ctx, DI_CAN_GC_SINGLE); msg = di_can_msg_get_ready_type(&_ctx, DI_CAN_MSGTYPE_RAW); ASSERT_EQ(nullptr, msg); } /** * Test if the di_can_msg_alloc_reassemble executed the DI_CAN_GC_SINGLE * when the message pool is depleted. */ TEST_F(DI_CAN, gc_single_alloc_reassemble_internal) { struct di_can_msg *msg; // Check if the context message timeout is set ASSERT_EQ(DI_CAN_CFG_MSG_TIMEOUT, _ctx.msg.timeout); // Deplete the pool for (size_t n = 0; n < _ctx.msg.pool.size; n++) { msg = di_can_msg_alloc_reassemble(&_ctx); ASSERT_NE(nullptr, msg); ASSERT_EQ(getCurrentMsgTimeout(), msg->timeout); } // Check if the pool is depleted by trying to alloc with gc ASSERT_EQ(nullptr, di_can_msg_alloc_reassemble(&_ctx)); // Run GC single and check if the pool messages are stil in REASSEMBLE state _di_can_msg_gc(&_ctx, DI_CAN_GC_ALL); ASSERT_EQ(nullptr, di_can_msg_alloc_reassemble(&_ctx)); // Move time forward so all allocated REASSEMBLE state messages expire _di_time_uptime = getCurrentMsgTimeout(); msg = di_can_msg_alloc_reassemble(&_ctx); ASSERT_NE(nullptr, msg); ASSERT_EQ(getCurrentMsgTimeout(), msg->timeout); } /** * Garbage collection skip and immediate macro test * * Put message * * Set garbage collect to skip * * Garbage collect */ TEST_F(DI_CAN, gc_timeout_skip_and_immediate) { struct di_buffer *b; struct di_can_msg *msg; /* Test if message GC is skipped */ test_can_msg_gc_put(this, &_ctx, &msg); msg->timeout = DI_CAN_TIMEOUT_GC_SKIP; msg->state = DI_CAN_MSG_STATE_READY; b = msg->buf; _di_time_uptime = 1000; di_can_msg_gc(&_ctx, DI_CAN_GC_ALL); msg = di_can_msg_get_ready_type(&_ctx, DI_CAN_MSGTYPE_RAW); ASSERT_NE(nullptr, msg); ASSERT_EQ(b, msg->buf); // Message state after get is application so the GC will not touch it ASSERT_EQ(DI_CAN_MSG_STATE_APPLICATION, msg->state); msg->state = DI_CAN_MSG_STATE_READY; // Test if message GC is immediate _di_time_uptime = 0; DI_CAN_SET_MSGTYPE(msg->canid, DI_CAN_MSGTYPE_RAW); msg->timeout = DI_CAN_TIMEOUT_GC_IMMEDIATE; msg = di_can_msg_get_ready_type(&_ctx, DI_CAN_MSGTYPE_RAW); ASSERT_NE(nullptr, msg); di_can_msg_gc(&_ctx, DI_CAN_GC_ALL); msg = di_can_msg_get_ready_type(&_ctx, DI_CAN_MSGTYPE_RAW); ASSERT_EQ(nullptr, msg); }