|
| 1 | +/* |
| 2 | + * Copyright (c) 2022 Nordic Semiconductor ASA |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#if defined(CONFIG_BUILD_DATE_TIME_TEST) |
| 8 | + |
| 9 | +#include <stdlib.h> |
| 10 | +#include <zephyr/ztest.h> |
| 11 | +#include <zephyr/net/buf.h> |
| 12 | +#include <zephyr/mgmt/mcumgr/mgmt/mgmt.h> |
| 13 | +#include <zephyr/mgmt/mcumgr/transport/smp_dummy.h> |
| 14 | +#include <zephyr/mgmt/mcumgr/mgmt/callbacks.h> |
| 15 | +#include <zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h> |
| 16 | +#include <os_mgmt_processor.h> |
| 17 | +#include <zcbor_common.h> |
| 18 | +#include <zcbor_decode.h> |
| 19 | +#include <zcbor_encode.h> |
| 20 | +#include <mgmt/mcumgr/util/zcbor_bulk.h> |
| 21 | +#include <version.h> |
| 22 | +#include <smp_internal.h> |
| 23 | +#include "smp_test_util.h" |
| 24 | + |
| 25 | +#define SMP_RESPONSE_WAIT_TIME 3 |
| 26 | +#define ZCBOR_BUFFER_SIZE 256 |
| 27 | +#define OUTPUT_BUFFER_SIZE 256 |
| 28 | +#define ZCBOR_HISTORY_ARRAY_SIZE 4 |
| 29 | + |
| 30 | +static struct net_buf *nb; |
| 31 | + |
| 32 | +/* Responses to commands */ |
| 33 | +extern uint8_t *test_date_time; |
| 34 | +const uint8_t response_all_board_revision_left[] = "Zephyr unknown " STRINGIFY(BUILD_VERSION) " " |
| 35 | + KERNEL_VERSION_STRING " "; |
| 36 | +const uint8_t response_all_board_revision_right[] = " " CONFIG_ARCH " " PROCESSOR_NAME " " |
| 37 | + CONFIG_BOARD "@" CONFIG_BOARD_REVISION |
| 38 | + " Zephyr"; |
| 39 | +const uint8_t response_all_left[] = "Zephyr unknown " STRINGIFY(BUILD_VERSION) " " |
| 40 | + KERNEL_VERSION_STRING " "; |
| 41 | +const uint8_t response_all_right[] = " " CONFIG_ARCH " " PROCESSOR_NAME " " CONFIG_BOARD " Zephyr"; |
| 42 | + |
| 43 | +const uint8_t query_build_date[] = "b"; |
| 44 | +const uint8_t query_all[] = "a"; |
| 45 | + |
| 46 | +#define DATE_CHECK_LEFT_CHARS 11 |
| 47 | +#define DATE_CHECK_RIGHT_CHARS 5 |
| 48 | +#define TIME_CHECK_HH_START_CHAR 11 |
| 49 | + |
| 50 | +#define TIME_HH_OFFSET 0 |
| 51 | +#define TIME_MM_OFFSET 3 |
| 52 | +#define TIME_SS_OFFSET 6 |
| 53 | + |
| 54 | +#define SECONDS_PER_HOUR 3600 |
| 55 | +#define SECONDS_PER_MINUTE 60 |
| 56 | + |
| 57 | +#define TIME_DIFFERENCE_ALLOWANCE 60 |
| 58 | + |
| 59 | +static int32_t time_string_to_seconds(const uint8_t *time_string) |
| 60 | +{ |
| 61 | + uint8_t time_hh; |
| 62 | + uint8_t time_mm; |
| 63 | + uint8_t time_ss; |
| 64 | + |
| 65 | + /* Convert times to separate fields and then to timestamps which can be compared */ |
| 66 | + time_hh = ((time_string[TIME_HH_OFFSET] - '0') * 10) + |
| 67 | + (time_string[TIME_HH_OFFSET + 1] - '0'); |
| 68 | + time_mm = ((time_string[TIME_MM_OFFSET] - '0') * 10) + |
| 69 | + (time_string[TIME_MM_OFFSET + 1] - '0'); |
| 70 | + time_ss = ((time_string[TIME_SS_OFFSET] - '0') * 10) + |
| 71 | + (time_string[TIME_SS_OFFSET + 1] - '0'); |
| 72 | + |
| 73 | + return (time_hh * SECONDS_PER_HOUR) + (time_mm * SECONDS_PER_MINUTE) + time_ss; |
| 74 | +} |
| 75 | + |
| 76 | +ZTEST(os_mgmt_info_build_date, test_info_build_date_1_build_date) |
| 77 | +{ |
| 78 | + uint8_t buffer[ZCBOR_BUFFER_SIZE]; |
| 79 | + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; |
| 80 | + bool ok; |
| 81 | + uint16_t buffer_size; |
| 82 | + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; |
| 83 | + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; |
| 84 | + bool received; |
| 85 | + struct zcbor_string output = { 0 }; |
| 86 | + size_t decoded = 0; |
| 87 | + int32_t expected_time_seconds; |
| 88 | + int32_t received_time_seconds; |
| 89 | + |
| 90 | + struct zcbor_map_decode_key_val output_decode[] = { |
| 91 | + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), |
| 92 | + }; |
| 93 | + |
| 94 | + memset(buffer, 0, sizeof(buffer)); |
| 95 | + memset(buffer_out, 0, sizeof(buffer_out)); |
| 96 | + buffer_size = 0; |
| 97 | + memset(zse, 0, sizeof(zse)); |
| 98 | + memset(zsd, 0, sizeof(zsd)); |
| 99 | + |
| 100 | + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); |
| 101 | + |
| 102 | + ok = create_mcumgr_format_packet(zse, query_build_date, buffer, buffer_out, &buffer_size); |
| 103 | + zassert_true(ok, "Expected packet creation to be successful\n"); |
| 104 | + |
| 105 | + /* Enable dummy SMP backend and ready for usage */ |
| 106 | + smp_dummy_enable(); |
| 107 | + smp_dummy_clear_state(); |
| 108 | + |
| 109 | + /* Send test echo command to dummy SMP backend */ |
| 110 | + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); |
| 111 | + smp_dummy_add_data(); |
| 112 | + |
| 113 | + /* For a short duration to see if response has been received */ |
| 114 | + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); |
| 115 | + |
| 116 | + zassert_true(received, "Expected to receive data but timed out\n"); |
| 117 | + |
| 118 | + /* Retrieve response buffer and ensure validity */ |
| 119 | + nb = smp_dummy_get_outgoing(); |
| 120 | + smp_dummy_disable(); |
| 121 | + |
| 122 | + /* Process received data by removing header */ |
| 123 | + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); |
| 124 | + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); |
| 125 | + |
| 126 | + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; |
| 127 | + |
| 128 | + zassert_true(ok, "Expected decode to be successful\n"); |
| 129 | + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); |
| 130 | + |
| 131 | + zassert_equal(strlen(test_date_time), output.len, |
| 132 | + "Expected to receive %d bytes but got %d\n", |
| 133 | + strlen(test_date_time), output.len); |
| 134 | + |
| 135 | + /* Check left and right sides of date which should match */ |
| 136 | + zassert_mem_equal(test_date_time, output.value, DATE_CHECK_LEFT_CHARS, |
| 137 | + "Expected received data mismatch"); |
| 138 | + zassert_mem_equal(&test_date_time[(strlen(test_date_time) - DATE_CHECK_RIGHT_CHARS)], |
| 139 | + &output.value[(strlen(test_date_time) - DATE_CHECK_RIGHT_CHARS)], |
| 140 | + DATE_CHECK_RIGHT_CHARS, "Expected received data mismatch"); |
| 141 | + |
| 142 | + /* Extract time strings into timestamps */ |
| 143 | + expected_time_seconds = time_string_to_seconds(&test_date_time[TIME_CHECK_HH_START_CHAR]); |
| 144 | + received_time_seconds = time_string_to_seconds(&output.value[TIME_CHECK_HH_START_CHAR]); |
| 145 | + |
| 146 | + zassert_within(expected_time_seconds, received_time_seconds, TIME_DIFFERENCE_ALLOWANCE, |
| 147 | + "Expected times to be within %d seconds but got %d", |
| 148 | + TIME_DIFFERENCE_ALLOWANCE, |
| 149 | + abs(expected_time_seconds - received_time_seconds)); |
| 150 | +} |
| 151 | + |
| 152 | +ZTEST(os_mgmt_info_build_date, test_info_build_date_2_all) |
| 153 | +{ |
| 154 | + uint8_t buffer[ZCBOR_BUFFER_SIZE]; |
| 155 | + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; |
| 156 | + bool ok; |
| 157 | + uint16_t buffer_size; |
| 158 | + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; |
| 159 | + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; |
| 160 | + bool received; |
| 161 | + struct zcbor_string output = { 0 }; |
| 162 | + size_t decoded = 0; |
| 163 | + int32_t expected_time_seconds; |
| 164 | + int32_t received_time_seconds; |
| 165 | + |
| 166 | + struct zcbor_map_decode_key_val output_decode[] = { |
| 167 | + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), |
| 168 | + }; |
| 169 | + |
| 170 | + memset(buffer, 0, sizeof(buffer)); |
| 171 | + memset(buffer_out, 0, sizeof(buffer_out)); |
| 172 | + buffer_size = 0; |
| 173 | + memset(zse, 0, sizeof(zse)); |
| 174 | + memset(zsd, 0, sizeof(zsd)); |
| 175 | + |
| 176 | + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); |
| 177 | + |
| 178 | + ok = create_mcumgr_format_packet(zse, query_all, buffer, buffer_out, &buffer_size); |
| 179 | + zassert_true(ok, "Expected packet creation to be successful\n"); |
| 180 | + |
| 181 | + /* Enable dummy SMP backend and ready for usage */ |
| 182 | + smp_dummy_enable(); |
| 183 | + smp_dummy_clear_state(); |
| 184 | + |
| 185 | + /* Send test echo command to dummy SMP backend */ |
| 186 | + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); |
| 187 | + smp_dummy_add_data(); |
| 188 | + |
| 189 | + /* For a short duration to see if response has been received */ |
| 190 | + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); |
| 191 | + |
| 192 | + zassert_true(received, "Expected to receive data but timed out\n"); |
| 193 | + |
| 194 | + /* Retrieve response buffer and ensure validity */ |
| 195 | + nb = smp_dummy_get_outgoing(); |
| 196 | + smp_dummy_disable(); |
| 197 | + |
| 198 | + /* Process received data by removing header */ |
| 199 | + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); |
| 200 | + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); |
| 201 | + |
| 202 | + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; |
| 203 | + |
| 204 | + zassert_true(ok, "Expected decode to be successful\n"); |
| 205 | + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); |
| 206 | + |
| 207 | + if (sizeof(CONFIG_BOARD_REVISION) > 1) { |
| 208 | + /* Check with board revision */ |
| 209 | + zassert_equal((strlen(test_date_time) + strlen(response_all_board_revision_left) + |
| 210 | + strlen(response_all_board_revision_right)), output.len, |
| 211 | + "Expected to receive %d bytes but got %d\n", |
| 212 | + (strlen(test_date_time) + strlen(response_all_board_revision_left) + |
| 213 | + strlen(response_all_board_revision_right)), output.len); |
| 214 | + |
| 215 | + zassert_mem_equal(response_all_board_revision_left, output.value, |
| 216 | + strlen(response_all_board_revision_left), |
| 217 | + "Expected received data mismatch"); |
| 218 | + zassert_mem_equal(response_all_board_revision_right, |
| 219 | + &output.value[strlen(response_all_board_revision_left) + |
| 220 | + strlen(test_date_time)], |
| 221 | + strlen(response_all_board_revision_right), |
| 222 | + "Expected received data mismatch"); |
| 223 | + } else { |
| 224 | + /* Check without board revision */ |
| 225 | + zassert_equal((strlen(test_date_time) + strlen(response_all_left) + |
| 226 | + strlen(response_all_right)), output.len, |
| 227 | + "Expected to receive %d bytes but got %d\n", |
| 228 | + (strlen(test_date_time) + strlen(response_all_left) + |
| 229 | + strlen(response_all_right)), output.len); |
| 230 | + |
| 231 | + zassert_mem_equal(response_all_left, output.value, strlen(response_all_left), |
| 232 | + "Expected received data mismatch"); |
| 233 | + zassert_mem_equal(response_all_right, &output.value[strlen(response_all_left) + |
| 234 | + strlen(test_date_time)], strlen(response_all_right), |
| 235 | + "Expected received data mismatch"); |
| 236 | + } |
| 237 | + |
| 238 | + /* Extract time strings into timestamps */ |
| 239 | + expected_time_seconds = time_string_to_seconds(&test_date_time[TIME_CHECK_HH_START_CHAR]); |
| 240 | + received_time_seconds = time_string_to_seconds(&output.value[(strlen(response_all_left) + |
| 241 | + TIME_CHECK_HH_START_CHAR)]); |
| 242 | + |
| 243 | + zassert_within(expected_time_seconds, received_time_seconds, TIME_DIFFERENCE_ALLOWANCE, |
| 244 | + "Expected times to be within %d seconds but got %d", |
| 245 | + TIME_DIFFERENCE_ALLOWANCE, |
| 246 | + abs(expected_time_seconds - received_time_seconds)); |
| 247 | +} |
| 248 | + |
| 249 | +static void *setup_tests(void) |
| 250 | +{ |
| 251 | + /* Register os_mgmt mcumgr group */ |
| 252 | + os_mgmt_register_group(); |
| 253 | + |
| 254 | + return NULL; |
| 255 | +} |
| 256 | + |
| 257 | +static void cleanup_test(void *p) |
| 258 | +{ |
| 259 | + if (nb != NULL) { |
| 260 | + net_buf_unref(nb); |
| 261 | + nb = NULL; |
| 262 | + } |
| 263 | +} |
| 264 | + |
| 265 | +/* Build date/time test set */ |
| 266 | +ZTEST_SUITE(os_mgmt_info_build_date, NULL, setup_tests, NULL, cleanup_test, NULL); |
| 267 | + |
| 268 | +#endif |
0 commit comments