/* * Copyright (c) 2021 - 2024 Stefan Strobel * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * @file test_integration_transport.cpp * @brief integration test implementation for the transport layer * @author Stefan Strobel */ #include "test/framework/catch.hpp" extern "C" { #include "shellmatta.h" } #include static uint32_t write_callCnt = 0u; static char write_data[1024]; static uint32_t write_length; static const char *doSomethingArguments; static uint32_t doSomethingLength; static char *doSomethingStdin; static uint32_t doSomethingStdinLength; static shellmatta_retCode_t writeFct(const char* data, uint32_t length) { write_callCnt ++; while((length > 0) && (write_length < sizeof(write_data))) { write_data[write_length] = *data; data ++; length --; write_length ++; } return SHELLMATTA_OK; } static shellmatta_retCode_t doSomething(shellmatta_handle_t handle, const char *arguments, uint32_t length) { doSomethingArguments = arguments; doSomethingLength = length; shellmatta_read(handle, &doSomethingStdin, &doSomethingStdinLength); shellmatta_printf(handle, "%s - length: %u", arguments, length); return SHELLMATTA_OK; } shellmatta_cmd_t doSomethingCmd = { (char*)"doSomething", (char*)"do", (char*)"Function does something", (char*)"use me, please", doSomething, NULL }; static shellmatta_retCode_t largePayload(shellmatta_handle_t handle, const char *arguments, uint32_t length) { uint32_t i; for (i = 0u; i < 8; i ++) { shellmatta_printf(handle, "This is my very very very very large payload\r\n"); } (void)arguments; (void)length; return SHELLMATTA_OK; } shellmatta_cmd_t largePayloadCmd = { (char*)"largePayload", (char*)"lp", (char*)"Function returns large payload", (char*)"i have much to say", largePayload, NULL }; static shellmatta_retCode_t largePayloadAtOnce(shellmatta_handle_t handle, const char *arguments, uint32_t length) { shellmatta_write(handle, (char*)"This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n", 46u*8u); (void)arguments; (void)length; return SHELLMATTA_OK; } shellmatta_cmd_t largePayloadAtOnceCmd = { (char*)"largePayload", (char*)"lp", (char*)"Function returns large payload", (char*)"i have much to say", largePayloadAtOnce, NULL }; SCENARIO("Integration test of Transport layer", "[integration, transport]") { GIVEN("Shellmatta up and running with one command") { shellmatta_instance_t inst; shellmatta_handle_t handle; char buffer[1024]; char historyBuffer[1024]; shellmatta_doInit( &inst, &handle, buffer, sizeof(buffer), historyBuffer, sizeof(historyBuffer), "shellmatta->", NULL, writeFct); shellmatta_addCmd(handle, &doSomethingCmd); write_callCnt = 0u; memset(write_data, 0, sizeof(write_data)); write_length = 0u; WHEN("Invalid CRC is passed") { /* check with invalid payload */ shellmatta_processData(handle, (char*)"\x01\x01\x00\x16\x00\x00\x00\x00" "doSomething argument\r\n" "\x00\x00\x00\x00", 34u); THEN("Shellmatta responds with CRC error") { char *dummyData = (char*)"crc error\r\n\r\nshellmatta->"; CHECK(write_length == strlen(dummyData)); REQUIRE(strcmp(dummyData, write_data) == 0); } } WHEN("Valid CRC is passed") { /* check with valid payload - disable echo to reduce cluttering */ shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, false, '\r'); shellmatta_processData(handle, (char*)"\x01\x01\x00\x16\x00\x00\x00\x00" "doSomething argument\r\n" "\x7b\x49\xfa\x72", 34u); THEN("The shellmatta responds to the command") { char *dummyData = (char*)"\x01\x01\x00\x2f\x00\x00\x01\x01" "doSomething argument - length: 20" "\r\n" "shellmatta->" "\xc8\xae\xc0\x56"; CHECK(write_length == 59u); REQUIRE(memcmp(write_data, dummyData, 59) == 0); } } WHEN("Large payload is written by shellmatta in steps") { /* add large payload command */ shellmatta_addCmd(handle, &largePayloadCmd); /* check with valid payload - disable echo to reduce cluttering */ shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, false, '\r'); shellmatta_processData(handle, (char*)"\x01\x01\x00\x0e\x00\x00\x00\x00" "largePayload\r\n" "\xad\x33\x31\xcc", 26u); THEN("The shellmatta responds multiple telegrams") { char *dummyData = (char*)"\x01\x01\x00\xff\x00\x00\x01\x01" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very" "\x0f\x90\xc0\xfd" "\x01\x01\x00\x7f\x00\x00\x01\x02" " very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "\r\n" "shellmatta->" "\x00\xc9\x5d\x37"; CHECK(write_length == 406u); REQUIRE(memcmp(write_data, dummyData, 406u) == 0); } } WHEN("Large payload is written by shellmatta at once") { /* add large payload command */ shellmatta_addCmd(handle, &largePayloadAtOnceCmd); /* check with valid payload - disable echo to reduce cluttering */ shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, false, '\r'); shellmatta_processData(handle, (char*)"\x01\x01\x00\x0e\x00\x00\x00\x00" "largePayload\r\n" "\xad\x33\x31\xcc", 26u); THEN("The shellmatta responds multiple telegrams") { char *dummyData = (char*)"\x01\x01\x00\xff\x00\x00\x01\x01" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very" "\x0f\x90\xc0\xfd" "\x01\x01\x00\x7f\x00\x00\x01\x02" " very large payload\r\n" "This is my very very very very large payload\r\n" "This is my very very very very large payload\r\n" "\r\n" "shellmatta->" "\x00\xc9\x5d\x37"; CHECK(write_length == 406u); REQUIRE(memcmp(write_data, dummyData, 406u) == 0); } } WHEN("manual mode is used after transport layer mode") { /* check with valid payload - disable echo to reduce cluttering */ shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, false, '\r'); shellmatta_processData(handle, (char*)"\x01\x01\x00\x16\x00\x00\x00\x00" "doSomething argument\r\n" "\x7b\x49\xfa\x72", 34u); shellmatta_processData(handle, (char*)"doSomething argument\r\n", 22u); THEN("The shellmatta responds to the command") { char *dummyData = (char*)"\x01\x01\x00\x2f\x00\x00\x01\x01" "doSomething argument - length: 20" "\r\n" "shellmatta->" "\xc8\xae\xc0\x56" "doSomething argument - length: 20\r\n" "shellmatta->"; CHECK(write_length == 106); REQUIRE(memcmp(write_data, dummyData, 106) == 0); } } WHEN("disabling auto flush") { /* check with valid payload - disable echo to reduce cluttering */ shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, false, '\r'); shellmatta_transport_configure(handle, false, true, NULL); shellmatta_processData(handle, (char*)"\x01\x01\x00\x16\x00\x00\x00\x00" "doSomething argument\r\n" "\x7b\x49\xfa\x72", 34u); THEN("The Shellmatta does not respond") { CHECK(write_length == 0u); AND_WHEN("The flush method is called") { shellmatta_transport_flush(handle); THEN("The shellmatta returns the data") { char *dummyData = (char*)"\x01\x01\x00\x2f\x00\x00\x01\x01" "doSomething argument - length: 20" "\r\n" "shellmatta->" "\xc8\xae\xc0\x56"; CHECK(write_length == 59u); REQUIRE(memcmp(write_data, dummyData, 59) == 0); } } } } WHEN("Sequence counter is requested") { /* request sequence counter */ shellmatta_processData(handle, (char*)"\x01\x01\x01\x00\x00\x00\x00\x00" "\xc4\xa3\x07\xe6", 12u); THEN("The valid Sequence counter is returned") { char *dummyData = (char*)"\x01\x01\x81\x00\x00\x00\x01\x01" "\xb4\x0f\x12\xe9"; CHECK(write_length == 12); REQUIRE(memcmp(write_data, dummyData, 12) == 0); } AND_WHEN("Sequence counter is requested again") { /* request sequence counter again */ write_callCnt = 0u; memset(write_data, 0, sizeof(write_data)); write_length = 0u; shellmatta_processData(handle, (char*)"\x01\x01\x01\x00\x00\x00\x00\x00" "\xc4\xa3\x07\xe6", 12u); THEN("The next Sequence counter is returned") { char *dummyData = (char*)"\x01\x01\x81\x00\x00\x00\x02\x02" "\x06\x2b\x10\x90"; CHECK(write_length == 12); REQUIRE(memcmp(write_data, dummyData, 12) == 0); } } } } } SCENARIO("Integration test of Transport layer with mandatory transport layer", "[integration, transport]") { GIVEN("Shellmatta up and running with one command") { shellmatta_instance_t inst; shellmatta_handle_t handle; shellmatta_retCode_t ret; char buffer[1024]; char historyBuffer[1024]; shellmatta_doInit( &inst, &handle, buffer, sizeof(buffer), historyBuffer, sizeof(historyBuffer), "shellmatta->", NULL, writeFct); shellmatta_addCmd(handle, &doSomethingCmd); write_callCnt = 0u; memset(write_data, 0, sizeof(write_data)); write_length = 0u; WHEN("The tansport layer is set to mandatory") { ret = shellmatta_transport_configure(handle, true, false, NULL); CHECK(ret == SHELLMATTA_OK); AND_WHEN("manual mode is used after transport layer mode") { /* check with valid payload - disable echo to reduce cluttering */ shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, false, '\r'); shellmatta_processData(handle, (char*)"\x01\x01\x00\x16\x00\x00\x00\x00" "doSomething argument\r\n" "\x7b\x49\xfa\x72", 34u); shellmatta_processData(handle, (char*)"doSomething argument\r\n", 22u); THEN("The shellmatta responds only to the first command - and waits for a new telegram to start") { char *dummyData = (char*)"\x01\x01\x00\x2f\x00\x00\x01\x01" "doSomething argument - length: 20" "\r\n" "shellmatta->" "\xc8\xae\xc0\x56"; CHECK(write_length == 59); CHECK(memcmp(write_data, dummyData, write_length) == 0); REQUIRE(inst.transportLayer.state == SHELLMATTA_TRANSPORT_STATE_WAIT); } } } } } SCENARIO("Integration test of Transport layer - reset transport layer", "[integration, transport]") { GIVEN("Shellmatta up and running with one command") { shellmatta_instance_t inst; shellmatta_handle_t handle; shellmatta_retCode_t ret; char buffer[1024]; char historyBuffer[1024]; shellmatta_doInit( &inst, &handle, buffer, sizeof(buffer), historyBuffer, sizeof(historyBuffer), "shellmatta->", NULL, writeFct); shellmatta_addCmd(handle, &doSomethingCmd); write_callCnt = 0u; memset(write_data, 0, sizeof(write_data)); write_length = 0u; WHEN("The tansport layer is set to mandatory") { ret = shellmatta_transport_configure(handle, true, false, NULL); CHECK(ret == SHELLMATTA_OK); AND_WHEN("A partial telegram is passed") { /* check with valid payload - disable echo to reduce cluttering */ shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, false, '\r'); shellmatta_processData(handle, (char*)"\x01\x01\x00\x16\x00\x00\x00\x00" "doSomething argument", 28u); THEN("The transport layer is in state SHELLMATTA_TRANSPORT_STATE_GET_PAYLOAD") { CHECK(write_length == 0); CHECK_THAT(inst.transportLayer.inPacket.payload, Catch::Matchers::Equals("doSomething argument")); REQUIRE(inst.transportLayer.state == SHELLMATTA_TRANSPORT_STATE_GET_PAYLOAD); AND_WHEN("The transport layer is resetted") { ret = shellmatta_transport_reset(handle); CHECK(ret == SHELLMATTA_OK); THEN("The transport layer is in state wait again and no payload is set") { CHECK(write_length == 0); CHECK(inst.transportLayer.inPacket.payload[0] == '\0'); REQUIRE(inst.transportLayer.state == SHELLMATTA_TRANSPORT_STATE_WAIT); } } } } } } }