blob: 56bb8e4f019c74a5063d22037310124a947ccad3 [file] [log] [blame]
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +01001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include "../lib/region_file.c"
4
5#include <tests/test.h>
6#include <stdlib.h>
7#include <string.h>
8#include <commonlib/region.h>
9#include <tests/lib/region_file_data.h>
10
Julius Wernerc8931972021-04-16 16:48:32 -070011static void clear_region_file(struct region_device *rdev)
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010012{
Julius Wernerc8931972021-04-16 16:48:32 -070013 memset(rdev_mmap_full(rdev), 0xff, REGION_FILE_BUFFER_SIZE);
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010014}
15
16static int setup_region_file_test_group(void **state)
17{
18 void *mem_buffer = malloc(REGION_FILE_BUFFER_SIZE);
Julius Wernerc8931972021-04-16 16:48:32 -070019 struct region_device *dev = malloc(sizeof(struct region_device));
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010020
21 if (mem_buffer == NULL || dev == NULL) {
22 free(mem_buffer);
23 free(dev);
24 return -1;
25 }
26
Julius Wernerc8931972021-04-16 16:48:32 -070027 rdev_chain_mem_rw(dev, mem_buffer, REGION_FILE_BUFFER_SIZE);
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010028 *state = dev;
29
30 clear_region_file(dev);
31
32 return 0;
33}
34
35static int teardown_region_file_test_group(void **state)
36{
Julius Wernerc8931972021-04-16 16:48:32 -070037 struct region_device *dev = *state;
38 void *mem_buffer = rdev_mmap_full(dev);
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010039
40 free(mem_buffer);
41 free(dev);
42
43 return 0;
44}
45
46/* This function clears buffer associated with used region_device, so tests will be in clear
47 state at the beginning and leave no trace after successful execution. The cost of memsetting
48 everything twice is known, but acceptable as it grants safety and makes tests independent. */
49static int setup_teardown_region_file_test(void **state)
50{
Julius Wernerc8931972021-04-16 16:48:32 -070051 struct region_device *dev = *state;
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010052
53 clear_region_file(dev);
54
55 return 0;
56}
57
58static void test_region_file_init_empty(void **state)
59{
Julius Wernerc8931972021-04-16 16:48:32 -070060 struct region_device *rdev = *state;
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010061 struct region_file regf;
62
63 /* Test general approach using valid mem_region_device with buffer filled with 0xff.
64 Parameters cannot be NULL. */
Julius Wernerc8931972021-04-16 16:48:32 -070065 assert_int_equal(0, region_file_init(&regf, rdev));
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010066 assert_int_equal(RF_EMPTY, regf.slot);
67}
68
69static void test_region_file_init_invalid_metadata(void **state)
70{
Julius Wernerc8931972021-04-16 16:48:32 -070071 struct region_device *rdev = *state;
72 uint16_t *mem_buffer16 = (uint16_t *)rdev_mmap_full(rdev);
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010073 struct region_file regf;
74
75 /* Set number of metadata blocks to 0 */
76 mem_buffer16[0] = 0;
Julius Wernerc8931972021-04-16 16:48:32 -070077 assert_int_equal(0, region_file_init(&regf, rdev));
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010078 assert_int_equal(RF_NEED_TO_EMPTY, regf.slot);
79}
80
81static void test_region_file_init_valid_no_data(void **state)
82{
Julius Wernerc8931972021-04-16 16:48:32 -070083 struct region_device *rdev = *state;
84 uint16_t *mem_buffer16 = (uint16_t *)rdev_mmap_full(rdev);
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010085 struct region_file regf;
86
87 /* Manually allocate 4 metadata blocks and no data. */
88 mem_buffer16[0] = 4;
Julius Wernerc8931972021-04-16 16:48:32 -070089 assert_int_equal(0, region_file_init(&regf, rdev));
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010090 assert_int_equal(0, regf.slot);
91}
92
93static void test_region_file_init_invalid_data_offset(void **state)
94{
Julius Wernerc8931972021-04-16 16:48:32 -070095 struct region_device *rdev = *state;
96 uint16_t *mem_buffer16 = (uint16_t *)rdev_mmap_full(rdev);
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +010097 struct region_file regf;
98
99 /* Manually allocate 4 metadata blocks and no data. */
100 mem_buffer16[0] = 4;
101 mem_buffer16[1] = 4;
Julius Wernerc8931972021-04-16 16:48:32 -0700102 assert_int_equal(0, region_file_init(&regf, rdev));
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100103 assert_int_equal(RF_NEED_TO_EMPTY, regf.slot);
104
105 /* Set data size to be larger than region */
106 mem_buffer16[0] = 4;
107 mem_buffer16[1] = 4 + 4096;
Julius Wernerc8931972021-04-16 16:48:32 -0700108 assert_int_equal(0, region_file_init(&regf, rdev));
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100109 assert_int_equal(RF_NEED_TO_EMPTY, regf.slot);
110}
111
112static void test_region_file_init_correct_data_offset(void **state)
113{
Julius Wernerc8931972021-04-16 16:48:32 -0700114 struct region_device *rdev = *state;
115 uint16_t *mem_buffer16 = (uint16_t *)rdev_mmap_full(rdev);
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100116 struct region_file regf;
117
118 /* Set data size to 8 blocks which is correct value. */
119 mem_buffer16[0] = 4;
120 mem_buffer16[1] = 4 + 8;
Julius Wernerc8931972021-04-16 16:48:32 -0700121 assert_int_equal(0, region_file_init(&regf, rdev));
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100122 assert_int_equal(1, regf.slot);
123}
124
125static void test_region_file_init_real_data(void **state)
126{
Julius Wernerc8931972021-04-16 16:48:32 -0700127 struct region_device rdev;
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100128 struct region_file regf;
129
Julius Wernerc8931972021-04-16 16:48:32 -0700130 rdev_chain_mem_rw(&rdev, region_file_data_buffer1, REGION_FILE_BUFFER_SIZE);
131
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100132 /* Check on real example with one update */
Julius Wernerc8931972021-04-16 16:48:32 -0700133 assert_int_equal(0, region_file_init(&regf, &rdev));
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100134 /* There is one update available */
135 assert_int_equal(1, regf.slot);
136
137
138 /* Check on real example with multiple updates */
Julius Wernerc8931972021-04-16 16:48:32 -0700139 rdev_chain_mem_rw(&rdev, region_file_data_buffer2, REGION_FILE_BUFFER_SIZE);
140 assert_int_equal(0, region_file_init(&regf, &rdev));
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100141 /* There are three update available */
142 assert_int_equal(3, regf.slot);
143}
144
145static void test_region_file_init_invalid_region_device(void **state)
146{
Julius Wernerc8931972021-04-16 16:48:32 -0700147 struct region_device bad_dev;
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100148 struct region_file regf;
149
Julius Wernerc8931972021-04-16 16:48:32 -0700150 rdev_chain_mem_rw(&bad_dev, NULL, 0);
151
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100152 /* Expect fail when passing invalid region_device. */
Julius Wernerc8931972021-04-16 16:48:32 -0700153 assert_int_equal(-1, region_file_init(&regf, &bad_dev));
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100154}
155
156static void test_region_file_data(void **state)
157{
158 /* region_device with empty data buffer */
Julius Wernerc8931972021-04-16 16:48:32 -0700159 struct region_device *mrdev = *state;
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100160 /* region_device with prepared data buffer */
Julius Wernerc8931972021-04-16 16:48:32 -0700161 struct region_device rdev;
162 rdev_chain_mem_rw(&rdev, region_file_data_buffer1, REGION_FILE_BUFFER_SIZE);
163
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100164 struct region_file regf;
165 struct region_device read_rdev;
166 int ret;
167
168 /* Check if region_file_data() fails to return region_device for empty region_file */
169 ret = region_file_init(&regf, mrdev);
170 assert_int_equal(0, ret);
171 ret = region_file_data(&regf, &read_rdev);
172 assert_int_equal(-1, ret);
173
174 /* Check if region_file_data() correctly returns region_device for hardcoded
175 region_file data with update of 256 bytes */
Julius Wernerc8931972021-04-16 16:48:32 -0700176 ret = region_file_init(&regf, &rdev);
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100177 assert_int_equal(0, ret);
178 ret = region_file_data(&regf, &read_rdev);
179 assert_int_equal(0, ret);
180 assert_int_equal(region_device_sz(&read_rdev),
181 ALIGN_UP(region_file_data_buffer1_update_sz, 16));
182}
183
184static void test_region_file_update_data(void **state)
185{
Julius Wernerc8931972021-04-16 16:48:32 -0700186 struct region_device *rdev = *state;
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100187 struct region_file regf;
188 struct region_device read_rdev;
189 const size_t dummy_data_size = 256;
190 uint8_t dummy_data[dummy_data_size];
191 uint8_t output_buffer[dummy_data_size];
192 int ret;
193
194 for (int i = 0; i < dummy_data_size; ++i)
195 dummy_data[i] = 'A' + i % ('Z' - 'A');
196
197 ret = region_file_init(&regf, rdev);
198 assert_int_equal(0, ret);
199
200 /* Write half of buffer, read it and check, if it is the same.
201 region_file_update_data() should be able to deal with empty region_file. */
202 ret = region_file_update_data(&regf, dummy_data, dummy_data_size / 2);
203 assert_int_equal(0, ret);
204 region_file_data(&regf, &read_rdev);
205 assert_int_equal(ALIGN_UP(dummy_data_size / 2, 16), region_device_sz(&read_rdev));
206 rdev_readat(&read_rdev, output_buffer, 0, dummy_data_size / 2);
207 assert_memory_equal(dummy_data, output_buffer, dummy_data_size / 2);
208
209 /* Update data to a bigger size */
210 ret = region_file_update_data(&regf, dummy_data, dummy_data_size);
211 assert_int_equal(0, ret);
212 region_file_data(&regf, &read_rdev);
213 assert_int_equal(ALIGN_UP(dummy_data_size, 16), region_device_sz(&read_rdev));
214 rdev_readat(&read_rdev, output_buffer, 0, dummy_data_size);
215 assert_memory_equal(dummy_data, output_buffer, dummy_data_size);
216
217 /* Update data to smaller size and check if it was properly stored */
218 ret = region_file_update_data(&regf, dummy_data, dummy_data_size / 2 + 3);
219 assert_int_equal(0, ret);
220 region_file_data(&regf, &read_rdev);
221 assert_int_equal(ALIGN_UP(dummy_data_size / 2 + 3, 16), region_device_sz(&read_rdev));
222 rdev_readat(&read_rdev, output_buffer, 0, dummy_data_size / 2 + 3);
223 assert_memory_equal(dummy_data, output_buffer, dummy_data_size / 2 + 3);
224}
225
226static void test_region_file_update_data_arr(void **state)
227{
Julius Wernerc8931972021-04-16 16:48:32 -0700228 struct region_device *rdev = *state;
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100229 struct region_file regf;
230 struct region_device read_rdev;
231 const size_t dummy_data_size = 256;
232 uint8_t dummy_data[dummy_data_size];
233 uint8_t output_buffer[dummy_data_size * 4];
234 struct update_region_file_entry update_entries[3];
235 const size_t data1_size = dummy_data_size;
236 const size_t data2_size = dummy_data_size / 2;
237 const size_t data3_size = dummy_data_size / 4 + 3;
238 const size_t data1_offset = 0;
239 const size_t data2_offset = dummy_data_size / 4 + 2;
240 const size_t data3_offset = dummy_data_size / 8 + 5;
241 int ret;
242
243 for (int i = 0; i < dummy_data_size; ++i)
244 dummy_data[i] = 'A' + i % ('Z' - 'A');
245
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000246 update_entries[0] = (struct update_region_file_entry){
247 .size = data1_size, .data = &dummy_data[data1_offset]};
248 update_entries[1] = (struct update_region_file_entry){
249 .size = data2_size, .data = &dummy_data[data2_offset]};
250 update_entries[2] = (struct update_region_file_entry){
251 .size = data3_size, .data = &dummy_data[data3_offset]};
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100252
253 ret = region_file_init(&regf, rdev);
254 assert_int_equal(0, ret);
255
256 /* Write two update blocks as first data state. region_file_update_data_arr() should
257 be able to deal with empty region_file. */
258 ret = region_file_update_data_arr(&regf, update_entries, 2);
259 assert_int_equal(0, ret);
260 region_file_data(&regf, &read_rdev);
261 assert_int_equal(ALIGN_UP(data1_size + data2_size, 16), region_device_sz(&read_rdev));
262 ret = rdev_readat(&read_rdev, output_buffer, 0, data1_size + data2_size);
263 assert_int_equal(data1_size + data2_size, ret);
264 assert_memory_equal(&dummy_data[data1_offset], output_buffer, data1_size);
265 assert_memory_equal(&dummy_data[data1_offset + data2_offset],
266 &output_buffer[data1_size], data2_size);
267
268 /* Check if new block of data is added correctly */
269 ret = region_file_update_data_arr(&regf, update_entries, 3);
270 assert_int_equal(0, ret);
271 region_file_data(&regf, &read_rdev);
272 assert_int_equal(ALIGN_UP(data1_size + data2_size + data3_size, 16),
273 region_device_sz(&read_rdev));
274 ret = rdev_readat(&read_rdev, output_buffer, 0, data1_size + data2_size + data3_size);
275 assert_int_equal(data1_size + data2_size + data3_size, ret);
276 assert_memory_equal(&dummy_data[data1_offset], output_buffer, data1_size);
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000277 assert_memory_equal(&dummy_data[data2_offset], &output_buffer[data1_size], data2_size);
278 assert_memory_equal(&dummy_data[data3_offset], &output_buffer[data1_size + data2_size],
279 data3_size);
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100280
281 /* Check if data is correctly shrunk down to smaller size and different content */
282 ret = region_file_update_data_arr(&regf, &update_entries[1], 2);
283 assert_int_equal(0, ret);
284 region_file_data(&regf, &read_rdev);
285 assert_int_equal(ALIGN_UP(data2_size + data3_size, 16), region_device_sz(&read_rdev));
286 ret = rdev_readat(&read_rdev, output_buffer, 0, data2_size + data3_size);
287 assert_int_equal(data2_size + data3_size, ret);
288 assert_memory_equal(&dummy_data[data2_offset], &output_buffer[0], data2_size);
289 assert_memory_equal(&dummy_data[data3_offset], &output_buffer[data2_size], data3_size);
290}
291
292int main(void)
293{
294 const struct CMUnitTest tests[] = {
295 cmocka_unit_test_setup_teardown(test_region_file_init_empty,
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000296 setup_teardown_region_file_test,
297 setup_teardown_region_file_test),
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100298 cmocka_unit_test_setup_teardown(test_region_file_init_invalid_metadata,
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000299 setup_teardown_region_file_test,
300 setup_teardown_region_file_test),
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100301 cmocka_unit_test_setup_teardown(test_region_file_init_valid_no_data,
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000302 setup_teardown_region_file_test,
303 setup_teardown_region_file_test),
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100304 cmocka_unit_test_setup_teardown(test_region_file_init_invalid_data_offset,
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000305 setup_teardown_region_file_test,
306 setup_teardown_region_file_test),
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100307 cmocka_unit_test_setup_teardown(test_region_file_init_correct_data_offset,
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000308 setup_teardown_region_file_test,
309 setup_teardown_region_file_test),
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100310 cmocka_unit_test_setup_teardown(test_region_file_init_real_data,
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000311 setup_teardown_region_file_test,
312 setup_teardown_region_file_test),
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100313 cmocka_unit_test_setup_teardown(test_region_file_init_invalid_region_device,
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000314 setup_teardown_region_file_test,
315 setup_teardown_region_file_test),
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100316 cmocka_unit_test_setup_teardown(test_region_file_data,
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000317 setup_teardown_region_file_test,
318 setup_teardown_region_file_test),
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100319 cmocka_unit_test_setup_teardown(test_region_file_update_data,
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000320 setup_teardown_region_file_test,
321 setup_teardown_region_file_test),
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100322 cmocka_unit_test_setup_teardown(test_region_file_update_data_arr,
Jakub Czapigac08b6a72022-01-10 13:36:47 +0000323 setup_teardown_region_file_test,
324 setup_teardown_region_file_test),
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100325 };
326
Jakub Czapiga7c6081e2021-08-25 16:27:35 +0200327 return cb_run_group_tests(tests, setup_region_file_test_group,
328 teardown_region_file_test_group);
Jakub Czapigaeb6f80d2021-01-07 09:24:33 +0100329}