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 <zephyr/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
time_string_to_seconds(const uint8_t * time_string)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
ZTEST(os_mgmt_info_build_date,test_info_build_date_1_build_date)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_DECODER("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, NULL, 0);
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
ZTEST(os_mgmt_info_build_date,test_info_build_date_2_all)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_DECODER("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, NULL, 0);
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
cleanup_test(void * p)249 static void cleanup_test(void *p)
250 {
251 if (nb != NULL) {
252 net_buf_unref(nb);
253 nb = NULL;
254 }
255 }
256
257 /* Build date/time test set */
258 ZTEST_SUITE(os_mgmt_info_build_date, NULL, NULL, NULL, cleanup_test, NULL);
259
260 #endif
261