1 #include "gtest/gtest.h"
3 #include <stdio.h> /* printf */
4 #include <stdlib.h> /* abort */
5 #include <string.h> /* memset */
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
26 #define OBJ2_ID 0xABCDEFAB
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
{
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
);
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);
61 for (uint32_t i
= 0; i
< sizeof(obj2
); i
++) {
62 obj2
[i
] = 0x20 + (i
% 10);
66 for (uint32_t i
= 0; i
< sizeof(obj3
); i
++) {
67 obj3
[i
] = 0x30 + (i
% 10);
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
) {
91 EXPECT_EQ(0, PIOS_Flash_UT_Init(&flash_id
, &flash_config
));
92 PIOS_Flash_UT_Destroy(flash_id
);
95 TEST_F(LogfsTestRaw
, LogfsInit
) {
98 EXPECT_EQ(0, PIOS_Flash_UT_Init(&flash_id
, &flash_config
));
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
{
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
);
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
)));
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
)));
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
{
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
);
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
)));