/** * @file tests/device_error.cpp * @brief Device error state tests * @date Apr 1, 2016 * @author jjacobs * @copyright 2016 Dual Inventive Technology Centre B.V. */ #include "fixtures/CANTest.hpp" #include "tests/rpc_serialize.h" #include #include #include /** * Check if initial device error is set to DNOK */ TEST(device_error, initial) { di_device_init(); } /** * Check if set and unset work as expected */ TEST(device_error, set_unset) { ASSERT_EQ(DNOK, di_device_error_set(DNE_TIMEOUT)); EXPECT_TRUE(di_device_error_is_specific_set(DNE_TIMEOUT)); di_device_error_unset(DNE_TIMEOUT); EXPECT_FALSE(di_device_error_is_specific_set(DNE_TIMEOUT)); // Try to unset a non-set error and see if it not crashes di_device_error_unset(DNE_TIMEOUT); } /** * Try to set a error in the forbidden range */ TEST(device_error, set_unset_invalid_range) { ASSERT_EQ(DNE_PARAM, di_device_error_set(DNE_DUPLICATE_PROJECT)); EXPECT_FALSE(di_device_error_is_specific_set(DNE_DUPLICATE_PROJECT)); di_device_error_unset(DNE_DUPLICATE_PROJECT); } /** * Verify the error list can be full and no one can be added */ TEST(device_error, set_returns_DNE_NOMEM) { static const di_errno_t tv[] { DNE_PARAM, DNE_RANGE, DNE_NODEV, DNE_NORES, DNE_BUSY, DNE_OPNOTSUPP, DNE_FIRMWARE_TILT, DNE_CAN_TIMEOUT, }; ASSERT_EQ(8U, di_device_error_list_size()); for (size_t n = 0; n < DI_ARRAY_SIZE(tv); n++) ASSERT_EQ(DNOK, di_device_error_set(tv[n])); ASSERT_EQ(DNE_NOMEM, di_device_error_set(DNE_CAN_IO)); di_device_error_reset_all(); ASSERT_FALSE(di_device_error_is_set()); } /** * Check if multiple same error (DNE_TIMEOUT) set work as expected */ TEST(device_error, set_error_multiple_times) { for (size_t n = 0; n < 16; n++) ASSERT_EQ(DNOK, di_device_error_set(DNE_TIMEOUT)); EXPECT_TRUE(di_device_error_is_specific_set(DNE_TIMEOUT)); di_device_error_reset_all(); ASSERT_FALSE(di_device_error_is_set()); } /** Set multiple errors */ TEST(device_error, set_multiple) { ASSERT_EQ(DNOK, di_device_error_set(DNE_TIMEOUT)); ASSERT_EQ(DNOK, di_device_error_set(DNE_FIRMWARE_EEPROM)); ASSERT_EQ(DNOK, di_device_error_set(DNE_CAN_AGAIN)); ASSERT_TRUE(di_device_error_is_set()); ASSERT_TRUE(di_device_error_is_specific_set(DNE_TIMEOUT)); ASSERT_TRUE(di_device_error_is_specific_set(DNE_FIRMWARE_EEPROM)); ASSERT_TRUE(di_device_error_is_specific_set(DNE_CAN_AGAIN)); di_device_error_reset_all(); ASSERT_FALSE(di_device_error_is_set()); } /** Verify serialize with three errors using list_write_rpc_msg_result and generates correct MessagePack */ TEST(device_error, list_write_rpc_msg_result) { auto writer = TEST_RPC_SERIALIZE_WRITER; ASSERT_EQ(DNOK, di_device_error_set(DNE_TIMEOUT)); ASSERT_EQ(DNOK, di_device_error_set(DNE_CAN_INVAL)); ASSERT_EQ(DNOK, di_device_error_set(DNE_CAN_AGAIN)); di_device_error_list_write_rpc_result_msg(writer->get()); di_device_error_reset_all(); } /** Verify serialize with three errors using list_write_rpc_msg_result and generates correct MessagePack empty array object */ TEST(device_error, list_write_rpc_msg_result_empty_array) { auto writer = TEST_RPC_SERIALIZE_WRITER; di_device_error_list_write_rpc_result_msg(writer->get()); } /** Verify the correct DI-Net CAN RPC message (result) is published with an MessagePack empty array */ TEST_F(DI_CAN, can_rpc_send_device_errors_array_pub_empty) { SetNodeid(0xdead1337); struct di_can_msg *msg; /* Publish device:errors empty array */ ASSERT_EQ(DNOK, di_can_rpc_send_device_errors(&_ctx, DI_CAN_NODEID_BROADCAST, DI_CAN_TRANSFERTYPE_PUBLISH)); msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_RPC); ASSERT_NE(nullptr, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_PUBLISH, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_RPC_TYPE_DEVICE_ERRORS, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(0xdead1337, msg->src_id); ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id); ASSERT_EQ(1U, msg->size); ASSERT_EQ(0x90, msg->msg[0]); // MessagePack empty array opcode di_can_msg_free(&msg); } /** Verify the correct DI-Net CAN RPC message (result) is replied or published */ TEST_F(DI_CAN, can_rpc_send_device_errors_array_rep_pub) { ASSERT_EQ(DNOK, di_device_error_set(DNE_TIMEOUT)); ASSERT_EQ(DNOK, di_device_error_set(DNE_CAN_INVAL)); ASSERT_EQ(DNOK, di_device_error_set(DNE_CAN_AGAIN)); SetNodeid(0xdead1337); struct di_can_msg *msg; /* Publish device:errors empty array */ ASSERT_EQ(DNOK, di_can_rpc_send_device_errors(&_ctx, DI_CAN_NODEID_BROADCAST, DI_CAN_TRANSFERTYPE_PUBLISH)); msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_RPC); ASSERT_NE(nullptr, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_PUBLISH, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_RPC_TYPE_DEVICE_ERRORS, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(0xdead1337, msg->src_id); ASSERT_EQ(DI_CAN_NODEID_BROADCAST, msg->dst_id); ASSERT_EQ(86U, msg->size); di_can_msg_free(&msg); /* Send reply device:errors empty array */ ASSERT_EQ(DNOK, di_can_rpc_send_device_errors(&_ctx, 0xcafebabe, DI_CAN_TRANSFERTYPE_REPLY)); msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_RPC); ASSERT_NE(nullptr, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_REPLY, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_RPC_TYPE_DEVICE_ERRORS, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(0xdead1337, msg->src_id); ASSERT_EQ(0xcafebabe, msg->dst_id); ASSERT_EQ(86U, msg->size); di_can_msg_free(&msg); di_device_error_reset_all(); } /** Unset errors */ TEST(device_error, unset) { di_device_error_unset(DNOK); di_device_error_unset(DNE_TIMEOUT); di_device_error_set(DNE_CAN_INVAL); ASSERT_TRUE(di_device_error_is_set()); ASSERT_TRUE(di_device_error_is_specific_set(DNE_CAN_INVAL)); di_device_error_unset(DNE_CAN_INVAL); ASSERT_FALSE(di_device_error_is_set()); } /** Verify the correct DI-Net CAN RPC message is replied with the can callbacks */ static struct di_can_callback test_device_errors_callbacks[] = { DI_CAN_RPC_CALLBACK_DEVICE_ERRORS_REQUEST_ITEM }; static struct di_can_msg *device_errors_can_rpc_generate_request(struct di_can_ctx *ctx) { struct di_can_msg *msg = di_can_msg_alloc_with_canid(ctx, DI_CAN_MSGTYPE_RPC, DI_CAN_TRANSFERTYPE_REQUEST, DI_RPC_TYPE_DEVICE_ERRORS); msg->src_id = 0xcafebabe; msg->dst_id = 0xdeadbeef; return msg; } TEST_F(DI_CAN, device_errors_can_rpc_request_callback) { SetNodeid(0xdeadbeef); di_can_callback_init(&_ctx, test_device_errors_callbacks, DI_ARRAY_SIZE(test_device_errors_callbacks)); /* Generate request and execute request callback (which must send a reply) */ struct di_can_msg *msg = device_errors_can_rpc_generate_request(&_ctx); ASSERT_NE(nullptr, msg); ASSERT_EQ(DNOK, di_can_callback_execute(&_ctx, msg)); di_can_msg_free(&msg); /* Verify empty reply array is send */ msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_RPC); ASSERT_NE(nullptr, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_REPLY, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_RPC_TYPE_DEVICE_ERRORS, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(0xdeadbeef, msg->src_id); ASSERT_EQ(0xcafebabe, msg->dst_id); ASSERT_EQ(1U, msg->size); ASSERT_EQ(0x90, msg->msg[0]); // MessagePack empty array code di_can_msg_free(&msg); /* Set 3 device errors */ ASSERT_EQ(DNOK, di_device_error_set(DNE_TIMEOUT)); ASSERT_EQ(DNOK, di_device_error_set(DNE_CAN_INVAL)); ASSERT_EQ(DNOK, di_device_error_set(DNE_CAN_AGAIN)); /* Generate request and execute request callback (which must send a reply) */ msg = device_errors_can_rpc_generate_request(&_ctx); ASSERT_NE(nullptr, msg); ASSERT_EQ(DNOK, di_can_callback_execute(&_ctx, msg)); di_can_msg_free(&msg); msg = di_can_recv(&_ctx, DI_CAN_MSGTYPE_RPC); ASSERT_NE(nullptr, msg); ASSERT_EQ(DI_CAN_TRANSFERTYPE_REPLY, DI_CAN_GET_TRANSFERTYPE(msg->canid)); ASSERT_EQ(DI_RPC_TYPE_DEVICE_ERRORS, DI_CAN_GET_DATATYPE(msg->canid)); ASSERT_EQ(0xdeadbeef, msg->src_id); ASSERT_EQ(0xcafebabe, msg->dst_id); ASSERT_EQ(86U, msg->size); ASSERT_EQ(0x93, msg->msg[0]); di_can_msg_free(&msg); }