update credits
[librepilot.git] / flight / tests / logfs / unittest.cpp
blobea4a56e3380d5bd08752c809efdfb06181285f1a
1 #include "gtest/gtest.h"
3 #include <stdio.h> /* printf */
4 #include <stdlib.h> /* abort */
5 #include <string.h> /* memset */
7 extern "C" {
8 #include "pios_flash.h" /* PIOS_FLASH_* API */
9 #include "pios_flash_ut_priv.h"
11 extern struct pios_flash_ut_cfg flash_config;
13 #include "pios_flashfs_logfs_priv.h"
15 extern struct flashfs_logfs_cfg flashfs_config_partition_a;
16 extern struct flashfs_logfs_cfg flashfs_config_partition_b;
18 #include "pios_flashfs.h" /* PIOS_FLASHFS_* */
21 #define OBJ0_ID 0xAA55AA55
23 #define OBJ1_ID 0x12345678
24 #define OBJ1_SIZE 76
26 #define OBJ2_ID 0xABCDEFAB
27 #define OBJ2_SIZE 123
29 #define OBJ3_ID 0x99999999
30 #define OBJ3_SIZE (256 - 12) // leave room for the slot header
32 #define OBJ4_ID 0x90901111
33 #define OBJ4_SIZE (768) // only fits in partition b slots
35 // To use a test fixture, derive a class from testing::Test.
36 class LogfsTestRaw : public testing::Test {
37 protected:
38 virtual void SetUp()
40 /* create an empty, appropriately sized flash filesystem */
41 FILE *theflash = fopen(FLASH_IMAGE_FILE, "wb");
42 uint8_t sector[flash_config.size_of_sector];
44 memset(sector, 0xFF, sizeof(sector));
45 for (uint32_t i = 0; i < flash_config.size_of_flash / flash_config.size_of_sector; i++) {
46 fwrite(sector, sizeof(sector), 1, theflash);
48 fclose(theflash);
50 /* Set up obj1 */
51 for (uint32_t i = 0; i < sizeof(obj1); i++) {
52 obj1[i] = 0x10 + (i % 10);
55 /* Set up a second version of obj1 with different data */
56 for (uint32_t i = 0; i < sizeof(obj1_alt); i++) {
57 obj1_alt[i] = 0xA0 + (i % 10);
60 /* Set up obj2 */
61 for (uint32_t i = 0; i < sizeof(obj2); i++) {
62 obj2[i] = 0x20 + (i % 10);
65 /* Set up obj3 */
66 for (uint32_t i = 0; i < sizeof(obj3); i++) {
67 obj3[i] = 0x30 + (i % 10);
70 /* Set up obj4 */
71 for (uint32_t i = 0; i < sizeof(obj4); i++) {
72 obj4[i] = 0x40 + (i % 10);
76 virtual void TearDown()
78 unlink("theflash.bin");
81 unsigned char obj1[OBJ1_SIZE];
82 unsigned char obj1_alt[OBJ1_SIZE];
83 unsigned char obj2[OBJ2_SIZE];
84 unsigned char obj3[OBJ3_SIZE];
85 unsigned char obj4[OBJ4_SIZE];
88 TEST_F(LogfsTestRaw, FlashInit) {
89 uintptr_t flash_id;
91 EXPECT_EQ(0, PIOS_Flash_UT_Init(&flash_id, &flash_config));
92 PIOS_Flash_UT_Destroy(flash_id);
95 TEST_F(LogfsTestRaw, LogfsInit) {
96 uintptr_t flash_id;
98 EXPECT_EQ(0, PIOS_Flash_UT_Init(&flash_id, &flash_config));
100 uintptr_t fs_id;
101 EXPECT_EQ(0, PIOS_FLASHFS_Logfs_Init(&fs_id, &flashfs_config_partition_a, &pios_ut_flash_driver, flash_id));
102 PIOS_FLASHFS_Logfs_Destroy(fs_id);
103 PIOS_Flash_UT_Destroy(flash_id);
106 class LogfsTestCooked : public LogfsTestRaw {
107 protected:
108 virtual void SetUp()
110 /* First, we need to set up the super fixture (LogfsTestRaw) */
111 LogfsTestRaw::SetUp();
113 /* Init the flash and the flashfs so we don't need to repeat this in every test */
114 EXPECT_EQ(0, PIOS_Flash_UT_Init(&flash_id, &flash_config));
115 EXPECT_EQ(0, PIOS_FLASHFS_Logfs_Init(&fs_id, &flashfs_config_partition_a, &pios_ut_flash_driver, flash_id));
118 virtual void TearDown()
120 PIOS_FLASHFS_Logfs_Destroy(fs_id);
121 PIOS_Flash_UT_Destroy(flash_id);
124 uintptr_t flash_id;
125 uintptr_t fs_id;
128 TEST_F(LogfsTestCooked, BadIdLogfsFormat) {
129 EXPECT_EQ(-1, PIOS_FLASHFS_Format(fs_id + 1));
132 TEST_F(LogfsTestCooked, BadIdSave) {
133 EXPECT_EQ(-1, PIOS_FLASHFS_ObjSave(fs_id + 1, OBJ1_ID, 0, obj1, sizeof(obj1)));
136 TEST_F(LogfsTestCooked, BadIdLoad) {
137 unsigned char obj1_check[OBJ1_SIZE];
139 memset(obj1_check, 0, sizeof(obj1_check));
140 EXPECT_EQ(-1, PIOS_FLASHFS_ObjLoad(fs_id + 1, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
143 TEST_F(LogfsTestCooked, LogfsFormat) {
144 EXPECT_EQ(0, PIOS_FLASHFS_Format(fs_id));
147 TEST_F(LogfsTestCooked, WriteOne) {
148 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
151 TEST_F(LogfsTestCooked, WriteVerifyOne) {
152 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
154 unsigned char obj1_check[OBJ1_SIZE];
155 memset(obj1_check, 0, sizeof(obj1_check));
156 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
157 EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
160 TEST_F(LogfsTestCooked, WriteVerifyDeleteVerifyOne) {
161 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
163 unsigned char obj1_check[OBJ1_SIZE];
164 memset(obj1_check, 0, sizeof(obj1_check));
165 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
166 EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
168 EXPECT_EQ(0, PIOS_FLASHFS_ObjDelete(fs_id, OBJ1_ID, 0));
170 EXPECT_EQ(-3, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
173 TEST_F(LogfsTestCooked, WriteTwoVerifyOneA) {
174 /* Write obj1 then obj2 */
175 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
176 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ2_ID, 0, obj2, sizeof(obj2)));
178 /* Read back obj1 */
179 unsigned char obj1_check[OBJ1_SIZE];
180 memset(obj1_check, 0, sizeof(obj1_check));
181 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
182 EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
185 TEST_F(LogfsTestCooked, WriteTwoVerifyOneB) {
186 /* Write obj2 then obj1 */
187 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ2_ID, 0, obj2, sizeof(obj2)));
188 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
190 /* Read back obj1 */
191 unsigned char obj1_check[OBJ1_SIZE];
192 memset(obj1_check, 0, sizeof(obj1_check));
193 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
194 EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
197 TEST_F(LogfsTestCooked, WriteZeroSize) {
198 /* Write a zero length object */
199 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ0_ID, 0, NULL, 0));
202 TEST_F(LogfsTestCooked, WriteVerifyZeroLength) {
203 /* Write a zero length object */
204 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ0_ID, 0, NULL, 0));
206 /* Read back a zero length object -- effectively an existence check */
207 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ0_ID, 0, NULL, 0));
210 TEST_F(LogfsTestCooked, WriteMaxSize) {
211 /* Write a max length object */
212 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ3_ID, 0, obj3, sizeof(obj3)));
215 TEST_F(LogfsTestCooked, ReadNonexistent) {
216 /* Read back a zero length object -- basically an existence check */
217 unsigned char obj1_check[OBJ1_SIZE];
219 memset(obj1_check, 0, sizeof(obj1_check));
220 EXPECT_EQ(-3, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
223 TEST_F(LogfsTestCooked, WriteVerifyMultiInstance) {
224 /* Write instance zero */
225 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
227 /* Write a non-zero instance ID */
228 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 123, obj1_alt, sizeof(obj1_alt)));
230 unsigned char obj1_check[OBJ1_SIZE];
232 /* Read back instance 123 */
233 memset(obj1_check, 0, sizeof(obj1_check));
234 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 123, obj1_check, sizeof(obj1_check)));
235 EXPECT_EQ(0, memcmp(obj1_alt, obj1_check, sizeof(obj1_alt)));
237 /* Read back instance 0 */
238 memset(obj1_check, 0, sizeof(obj1_check));
239 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
240 EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
243 TEST_F(LogfsTestCooked, FillFilesystemAndGarbageCollect) {
244 /* Fill up the entire filesystem with multiple instances of obj1 */
245 for (uint32_t i = 0; i < (flashfs_config_partition_a.arena_size / flashfs_config_partition_a.slot_size) - 1; i++) {
246 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, i, obj1, sizeof(obj1)));
249 /* Should fail to add a new object since the filesystem is full */
250 EXPECT_EQ(-4, PIOS_FLASHFS_ObjSave(fs_id, OBJ2_ID, 0, obj2, sizeof(obj2)));
252 /* Now save a new version of an existing object which should trigger gc and succeed */
253 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1_alt, sizeof(obj1_alt)));
255 /* Read back one of the original obj1 instances */
256 unsigned char obj1_check[OBJ1_SIZE];
257 memset(obj1_check, 0, sizeof(obj1_check));
258 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 1, obj1_check, sizeof(obj1_check)));
259 EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
261 /* Read back the new version of obj1 written after gc */
262 memset(obj1_check, 0, sizeof(obj1_check));
263 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
264 EXPECT_EQ(0, memcmp(obj1_alt, obj1_check, sizeof(obj1_alt)));
267 TEST_F(LogfsTestCooked, WriteManyVerify) {
268 for (uint32_t i = 0; i < 10000; i++) {
269 /* Write a collection of objects */
270 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ0_ID, 0, NULL, 0));
271 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
272 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 123, obj1_alt, sizeof(obj1_alt)));
273 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ2_ID, 0, obj2, sizeof(obj2)));
274 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ3_ID, 0, obj3, sizeof(obj3)));
277 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ0_ID, 0, NULL, 0));
279 unsigned char obj1_check[OBJ1_SIZE];
280 memset(obj1_check, 0, sizeof(obj1_check));
281 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
282 EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
284 unsigned char obj1_alt_check[OBJ1_SIZE];
285 memset(obj1_alt_check, 0, sizeof(obj1_alt_check));
286 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 123, obj1_alt_check, sizeof(obj1_alt_check)));
287 EXPECT_EQ(0, memcmp(obj1_alt, obj1_alt_check, sizeof(obj1_alt)));
289 unsigned char obj2_check[OBJ2_SIZE];
290 memset(obj2_check, 0, sizeof(obj2_check));
291 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ2_ID, 0, obj2_check, sizeof(obj2_check)));
292 EXPECT_EQ(0, memcmp(obj2, obj2_check, sizeof(obj2)));
294 unsigned char obj3_check[OBJ3_SIZE];
295 memset(obj3_check, 0, sizeof(obj3_check));
296 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ3_ID, 0, obj3_check, sizeof(obj3_check)));
297 EXPECT_EQ(0, memcmp(obj3, obj3_check, sizeof(obj3)));
300 class LogfsTestCookedMultiPart : public LogfsTestRaw {
301 protected:
302 virtual void SetUp()
304 /* First, we need to set up the super fixture (LogfsTestRaw) */
305 LogfsTestRaw::SetUp();
307 /* Init the flash and the flashfs so we don't need to repeat this in every test */
308 EXPECT_EQ(0, PIOS_Flash_UT_Init(&flash_id, &flash_config));
309 EXPECT_EQ(0, PIOS_FLASHFS_Logfs_Init(&fs_id_a, &flashfs_config_partition_a, &pios_ut_flash_driver, flash_id));
310 EXPECT_EQ(0, PIOS_FLASHFS_Logfs_Init(&fs_id_b, &flashfs_config_partition_b, &pios_ut_flash_driver, flash_id));
313 virtual void TearDown()
315 PIOS_FLASHFS_Logfs_Destroy(fs_id_b);
316 PIOS_FLASHFS_Logfs_Destroy(fs_id_a);
317 PIOS_Flash_UT_Destroy(flash_id);
320 uintptr_t flash_id;
321 uintptr_t fs_id_a;
322 uintptr_t fs_id_b;
325 TEST_F(LogfsTestCookedMultiPart, WriteOneWriteOneVerify) {
326 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id_a, OBJ1_ID, 0, obj1, sizeof(obj1)));
327 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id_b, OBJ2_ID, 0, obj2, sizeof(obj2)));
329 /* OBJ1 found in A */
330 unsigned char obj1_check[OBJ1_SIZE];
331 memset(obj1_check, 0, sizeof(obj1_check));
332 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id_a, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
333 EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
335 /* OBJ2 found in B */
336 unsigned char obj2_check[OBJ2_SIZE];
337 memset(obj2_check, 0, sizeof(obj2_check));
338 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id_b, OBJ2_ID, 0, obj2_check, sizeof(obj2_check)));
339 EXPECT_EQ(0, memcmp(obj2, obj2_check, sizeof(obj2)));
342 TEST_F(LogfsTestCookedMultiPart, WriteOneWriteOneFormatOneVerify) {
343 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id_a, OBJ1_ID, 0, obj1, sizeof(obj1)));
344 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id_b, OBJ2_ID, 0, obj2, sizeof(obj2)));
346 EXPECT_EQ(0, PIOS_FLASHFS_Format(fs_id_a));
348 /* OBJ2 still found in B */
349 unsigned char obj2_check[OBJ2_SIZE];
350 memset(obj2_check, 0, sizeof(obj2_check));
351 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id_b, OBJ2_ID, 0, obj2_check, sizeof(obj2_check)));
352 EXPECT_EQ(0, memcmp(obj2, obj2_check, sizeof(obj2)));
355 TEST_F(LogfsTestCookedMultiPart, WriteOneWriteOneNoCross) {
356 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id_a, OBJ1_ID, 0, obj1, sizeof(obj1)));
357 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id_b, OBJ2_ID, 0, obj2, sizeof(obj2)));
359 /* OBJ1 not found in B */
360 unsigned char obj1_check[OBJ1_SIZE];
361 memset(obj1_check, 0, sizeof(obj1_check));
362 EXPECT_EQ(-3, PIOS_FLASHFS_ObjLoad(fs_id_b, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
364 /* OBJ2 not found in A */
365 unsigned char obj2_check[OBJ2_SIZE];
366 memset(obj2_check, 0, sizeof(obj2_check));
367 EXPECT_EQ(-3, PIOS_FLASHFS_ObjLoad(fs_id_a, OBJ2_ID, 0, obj2_check, sizeof(obj2_check)));
370 TEST_F(LogfsTestCookedMultiPart, WriteOneWriteOneDeleteOne) {
371 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id_a, OBJ1_ID, 0, obj1, sizeof(obj1)));
372 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id_b, OBJ2_ID, 0, obj2, sizeof(obj2)));
374 EXPECT_EQ(0, PIOS_FLASHFS_ObjDelete(fs_id_a, OBJ1_ID, 0));
376 /* OBJ1 not found in A */
377 unsigned char obj1_check[OBJ1_SIZE];
378 memset(obj1_check, 0, sizeof(obj1_check));
379 EXPECT_EQ(-3, PIOS_FLASHFS_ObjLoad(fs_id_a, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
381 /* OBJ2 still found in B */
382 unsigned char obj2_check[OBJ2_SIZE];
383 memset(obj2_check, 0, sizeof(obj2_check));
384 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id_b, OBJ2_ID, 0, obj2_check, sizeof(obj2_check)));
387 TEST_F(LogfsTestCookedMultiPart, WriteLarge) {
388 EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id_b, OBJ4_ID, 0, obj4, sizeof(obj4)));
390 /* OBJ4 found in B */
391 unsigned char obj4_check[OBJ4_SIZE];
392 memset(obj4_check, 0, sizeof(obj4_check));
393 EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id_b, OBJ4_ID, 0, obj4_check, sizeof(obj4_check)));