Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers atomic_usage.cpp Source File

atomic_usage.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017-2017 ARM Limited
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to deal
00006  * in the Software without restriction, including without limitation the rights
00007  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  * copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00020  * SOFTWARE.
00021  */
00022 
00023 
00024 /**
00025  * This file contains code which performs various atomic operations using
00026  * littlefs. It is intended for use in tests and test applications to
00027  * validate that the defined behavior below is being met.
00028  *
00029  * # Defined behavior
00030  * - A file rename is atomic (Note - rename can be used to replace a file)
00031  *      - Atomic file rename tested by setup/perform/check_file_rename
00032  *      - Atomic file replace tested by setup/perform/check_file_rename_replace
00033  * - A directory rename is atomic (Note - rename can be used to replace an empty directory)
00034  *      - Tested by setup/perform/check_directory_rename
00035  * - Directory create is atomic
00036  * - Directory delete is atomic
00037  * - File create is atomic
00038  * - File delete is atomic
00039  * - File contents are atomically written on close
00040  *      - Tested by setup/perform/check_file_change_contents
00041  */
00042 
00043 
00044 #include "mbed.h"
00045 #include "greentea-client/test_env.h"
00046 #include "unity.h"
00047 #include "utest.h"
00048 #include <stdlib.h>
00049 #include <errno.h>
00050 
00051 #include "ObservingBlockDevice.h"
00052 #include "ExhaustibleBlockDevice.h"
00053 #include "FileSystem.h"
00054 
00055 #include "atomic_usage.h"
00056 
00057 // test configuration
00058 #ifndef MBED_TEST_FILESYSTEM
00059 #define MBED_TEST_FILESYSTEM LittleFileSystem
00060 #endif
00061 
00062 #ifndef MBED_TEST_FILESYSTEM_DECL
00063 #define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs")
00064 #endif
00065 
00066 
00067 // declarations
00068 #define STRINGIZE(x) STRINGIZE2(x)
00069 #define STRINGIZE2(x) #x
00070 #define INCLUDE(x) STRINGIZE(x.h)
00071 
00072 #include INCLUDE(MBED_TEST_FILESYSTEM)
00073 
00074 
00075 #define DEBUG(...)
00076 #define DEBUG_CHECK(...)
00077 #define BUFFER_SIZE             64
00078 // Version is written to a file and is used
00079 // to determine if a reformat is required
00080 #define ATOMIC_USAGE_VERSION    1
00081 
00082 #define ARRAY_LENGTH(array)     (sizeof(array) / sizeof(array[0]))
00083 
00084 #define TEST_ASSERT_OR_EXIT(condition)              \
00085         TEST_ASSERT(condition); if (!(condition)) {error("Assert failed");}
00086 
00087 #define TEST_ASSERT_EQUAL_OR_EXIT(expected, actual) \
00088         TEST_ASSERT_EQUAL(expected, actual); if ((int64_t)(expected) != (int64_t)(actual)) {error("Assert failed");}
00089 
00090 using namespace utest::v1;
00091 
00092 typedef void (*test_function_t)(FileSystem *fs);
00093 typedef bool (*test_function_bool_t)(FileSystem *fs);
00094 
00095 struct TestEntry {
00096     const char *name;
00097     test_function_t setup;
00098     test_function_bool_t perform;
00099     test_function_t check;
00100 };
00101 
00102 /**
00103  * Write data to the file while checking for error conditions
00104  *
00105  * @param file File to write to
00106  * @param data Data to write
00107  * @param size Size of data to write
00108  * @return true if flash has been exhausted, false otherwise
00109  */
00110 static bool file_write(File *file, uint8_t *data, uint32_t size)
00111 {
00112     int res = file->write(data, size);
00113     if (-ENOSPC  == res) {
00114         return true;
00115     }
00116     TEST_ASSERT_EQUAL_OR_EXIT(size, res);
00117     return false;
00118 }
00119 
00120 /**
00121  * Write padding data of the given size
00122  *
00123  * @param file Pointer to the file to write to
00124  * @param padding Value to pad
00125  * @param size Size to pad
00126  * @return true if flash has been exhausted, false otherwise
00127  */
00128 static bool file_pad(File *file, char padding, uint32_t size)
00129 {
00130     uint8_t buf[BUFFER_SIZE];
00131     memset(buf, padding, sizeof(buf));
00132 
00133     while (size > 0) {
00134         uint32_t write_size = sizeof(buf) <= size ? sizeof(buf) : size;
00135         if (file_write(file, buf, write_size)) {
00136             return true;
00137         }
00138         size -= write_size;
00139     }
00140 
00141     return false;
00142 }
00143 
00144 /*
00145  * Similar to fscanf but uses and mbed file
00146  *
00147  * @param file File to scan from
00148  * @param format Format string of values to read
00149  * @return the number of arguments read
00150  */
00151 static int file_scanf(File *file, const char *format, ...)
00152 {
00153     uint8_t buf[BUFFER_SIZE];
00154     va_list args;
00155     memset(buf, 0, sizeof(buf));
00156 
00157     int res = file->read(buf, sizeof(buf) - 1);
00158     TEST_ASSERT_OR_EXIT(res >= 0);
00159 
00160     va_start (args, format);
00161     int count = vsscanf((char*)buf, format, args);
00162     va_end (args);
00163     TEST_ASSERT_OR_EXIT(count >= 0);
00164 
00165     return count;
00166 }
00167 
00168 /*
00169  * Similar to fprintf but uses and mbed file
00170  *
00171  * @param file File to print to
00172  * @param format Format string of values to write
00173  * @return size written to file or -1 on out of space
00174  */
00175 static int file_printf(File *file, const char *format, ...)
00176 {
00177     uint8_t buf[BUFFER_SIZE];
00178     va_list args;
00179     va_start (args, format);
00180     int size = vsprintf((char*)buf, format, args);
00181     va_end (args);
00182     TEST_ASSERT_OR_EXIT((size >= 0) && (size <= (int)sizeof(buf)));
00183 
00184     if (file_write(file, buf, size)) {
00185         return -1;
00186     }
00187 
00188     return size;
00189 }
00190 
00191 
00192 static const char FILE_RENAME_A[] = "file_to_rename_a.txt";
00193 static const char FILE_RENAME_B[] = "file_to_rename_b.txt";
00194 static const char FILE_RENAME_CONTENTS[] = "Test contents for the file to be renamed";
00195 static const int FILE_RENAME_LEN = strlen(FILE_RENAME_CONTENTS);
00196 
00197 /**
00198  * Setup for the file rename test
00199  *
00200  * Create file FILE_RENAME_A with contents FILE_RENAME_CONTENTS.
00201  */
00202 static void setup_file_rename(FileSystem *fs)
00203 {
00204     DEBUG("setup_file_rename()\n");
00205 
00206     File file;
00207 
00208     int res = file.open(fs, FILE_RENAME_A, O_WRONLY | O_CREAT);
00209     DEBUG("  open result %i\n", res);
00210     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00211 
00212     res = file.write(FILE_RENAME_CONTENTS, FILE_RENAME_LEN);
00213     DEBUG("  write result %i\n", res);
00214     TEST_ASSERT_EQUAL_OR_EXIT(FILE_RENAME_LEN, res);
00215 }
00216 
00217 /**
00218  * Change the file name to either FILE_RENAME_A or FILE_RENAME_B
00219  */
00220 static bool perform_file_rename(FileSystem *fs)
00221 {
00222     DEBUG("perform_file_rename()\n");
00223 
00224     struct stat st;
00225     int res = fs->stat(FILE_RENAME_A, &st);
00226     const char *src = (res == 0) ? FILE_RENAME_A : FILE_RENAME_B;
00227     const char *dst = (res == 0) ? FILE_RENAME_B : FILE_RENAME_A;
00228 
00229     DEBUG("  stat result  %i\n", res);
00230     TEST_ASSERT_OR_EXIT((res == -ENOENT) || (res == 0));
00231 
00232     DEBUG("  Renaming %s to %s\n", src, dst);
00233     res = fs->rename(src, dst);
00234     if (-ENOSPC  == res) {
00235         return true;
00236     }
00237     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00238     return false;
00239 }
00240 
00241 /**
00242  * Check that the file rename is in a good state
00243  *
00244  * Check that there is only one file and that file contains the correct
00245  * contents.
00246  *
00247  * Allowed states:
00248  * - File FILE_RENAME_A exists with contents and FILE_RENAME_B does not
00249  * - File FILE_RENAME_B exists with contents and FILE_RENAME_A does not
00250  *
00251  */
00252 static void check_file_rename(FileSystem *fs)
00253 {
00254 
00255     int files = 0;
00256     int valids = 0;
00257     const char * const filenames[] = {FILE_RENAME_A, FILE_RENAME_B};
00258 
00259     for (int i = 0; i < 2; i++) {
00260         File file;
00261         if (file.open(fs, filenames[i], O_RDONLY) == 0) {
00262             uint8_t buf[BUFFER_SIZE];
00263             files++;
00264             memset(buf, 0, sizeof(buf));
00265             int res = file.read(buf, FILE_RENAME_LEN);
00266             if (res != FILE_RENAME_LEN) {
00267                 break;
00268             }
00269             if (memcmp(buf, FILE_RENAME_CONTENTS, FILE_RENAME_LEN) != 0) {
00270                 break;
00271             }
00272             valids++;
00273         }
00274     }
00275 
00276     TEST_ASSERT_EQUAL_OR_EXIT(1, files);
00277     TEST_ASSERT_EQUAL_OR_EXIT(1, valids);
00278 }
00279 
00280 
00281 static const char  FILE_RENAME_REPLACE[] = "rename_replace_file.txt";
00282 static const char  FILE_RENAME_REPLACE_NEW[] = "new_rename_replace_file.txt";
00283 static const char  FILE_RENAME_REPLACE_FMT[] = "file replace count: %lu\n";
00284 
00285 /**
00286  * Create the file FILE_RENAME_REPLACE with initial contents
00287  *
00288  * Create an write an initial count of 0 to the file.
00289  */
00290 static void setup_file_rename_replace(FileSystem *fs)
00291 {
00292     DEBUG("setup_file_rename_replace()\n");
00293     File file;
00294 
00295     // Write out initial count
00296 
00297     int res = file.open(fs, FILE_RENAME_REPLACE, O_WRONLY | O_CREAT);
00298     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00299 
00300     uint32_t count = 0;
00301     uint8_t buf[BUFFER_SIZE];
00302     memset(buf, 0, sizeof(buf));
00303     const int length = sprintf((char*)buf, FILE_RENAME_REPLACE_FMT, count);
00304     TEST_ASSERT_OR_EXIT(length > 0);
00305 
00306     res = file.write(buf, length);
00307     DEBUG("  write result %i\n", res);
00308     TEST_ASSERT_EQUAL_OR_EXIT(length, res);
00309 }
00310 
00311 /**
00312  * Atomically increment the count in FILE_RENAME_REPLACE using a rename
00313  */
00314 bool perform_file_rename_replace(FileSystem *fs)
00315 {
00316     DEBUG("perform_file_rename_replace()\n");
00317     File file;
00318 
00319     // Read in previous count
00320 
00321     int res = file.open(fs, FILE_RENAME_REPLACE, O_RDONLY);
00322     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00323 
00324     uint64_t count;
00325     int args_read = file_scanf(&file, FILE_RENAME_REPLACE_FMT, &count);
00326     TEST_ASSERT_EQUAL_OR_EXIT(1, args_read);
00327 
00328     res = file.close();
00329     if (-ENOSPC  == res) {
00330         return true;
00331     }
00332     TEST_ASSERT_EQUAL(0, res);
00333 
00334     // Write out new count
00335 
00336     count++;
00337 
00338     res = file.open(fs, FILE_RENAME_REPLACE_NEW, O_WRONLY | O_CREAT);
00339     if (-ENOSPC  == res) {
00340         return true;
00341     }
00342     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00343 
00344     if (file_printf(&file, FILE_RENAME_REPLACE_FMT, count) <= 0) {
00345         return true;
00346     }
00347 
00348     res = file.close();
00349     if (-ENOSPC  == res) {
00350         return true;
00351     }
00352     TEST_ASSERT_EQUAL(0, res);
00353 
00354     // Rename file
00355 
00356     res = fs->rename(FILE_RENAME_REPLACE_NEW, FILE_RENAME_REPLACE);
00357     if (-ENOSPC  == res) {
00358         return true;
00359     }
00360     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00361     DEBUG("  count %llu -> %llu\n", count - 1, count);
00362 
00363     return false;
00364 }
00365 
00366 /**
00367  * Check that FILE_RENAME_REPLACE always has a valid count
00368  *
00369  * Allowed states:
00370  * - FILE_RENAME_REPLACE exists with valid contents
00371  */
00372 static void check_file_rename_replace(FileSystem *fs)
00373 {
00374     DEBUG_CHECK("check_file_rename_replace()\n");
00375     File file;
00376 
00377     // Read in previous count
00378 
00379     int res = file.open(fs, FILE_RENAME_REPLACE, O_RDONLY);
00380     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00381 
00382     uint64_t count;
00383     int args_read = file_scanf(&file, FILE_RENAME_REPLACE_FMT, &count);
00384     TEST_ASSERT_EQUAL_OR_EXIT(1, args_read);
00385     DEBUG_CHECK("  count %llu\n", count);
00386 }
00387 
00388 
00389 static const char DIRECTORY_RENAME_A[] = "dir_a";
00390 static const char DIRECTORY_RENAME_B[] = "dir_b";
00391 
00392 /**
00393  * Create DIRECTORY_RENAME_A with initial contents
00394  */
00395 static void setup_directory_rename(FileSystem *fs)
00396 {
00397     DEBUG("setup_directory_rename()\n");
00398 
00399     int res = fs->mkdir(DIRECTORY_RENAME_A, 0777);
00400     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00401 }
00402 
00403 /*
00404  * Change the directory name from either DIRECTORY_RENAME_A or DIRECTORY_RENAME_B to the other
00405  */
00406 static bool perform_directory_rename(FileSystem *fs)
00407 {
00408     DEBUG("perform_directory_rename()\n");
00409 
00410     struct stat st;
00411     int res = fs->stat(DIRECTORY_RENAME_A, &st);
00412     const char *src = (res == 0) ? DIRECTORY_RENAME_A : DIRECTORY_RENAME_B;
00413     const char *dst = (res == 0) ? DIRECTORY_RENAME_B : DIRECTORY_RENAME_A;
00414 
00415     DEBUG("  stat result  %i\n", res);
00416     TEST_ASSERT_OR_EXIT((res == -ENOENT) || (res == 0));
00417 
00418     DEBUG("  Renaming %s to %s\n", src, dst);
00419     res = fs->rename(src, dst);
00420     if (-ENOSPC  == res) {
00421         return true;
00422     }
00423     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00424     return false;
00425 }
00426 
00427 /*
00428  * Change the directory name from either DIRECTORY_RENAME_A or DIRECTORY_RENAME_B to the other
00429  *
00430  * Allowed states:
00431  * - DIRECTORY_RENAME_A exists with valid contents and DIRECTORY_RENAME_B does not exist
00432  * - DIRECTORY_RENAME_B exists with valid contents and DIRECTORY_RENAME_A does not exist
00433  */
00434 static void check_directory_rename(FileSystem *fs)
00435 {
00436     DEBUG_CHECK("check_directory_rename()\n");
00437 
00438     static const char *directory_names[] = {
00439         DIRECTORY_RENAME_A,
00440         DIRECTORY_RENAME_B
00441     };
00442 
00443     size_t directories = 0;
00444     for (size_t i = 0; i < ARRAY_LENGTH(directory_names); i++) {
00445         Dir dir;
00446         int res = dir.open(fs, directory_names[i]);
00447         TEST_ASSERT_OR_EXIT((res == -ENOENT) || (res == 0));
00448         if (res == 0) {
00449             directories++;
00450         }
00451     }
00452     TEST_ASSERT_EQUAL_OR_EXIT(1, directories);
00453 }
00454 
00455 
00456 static const char CHANGE_CONTENTS_NAME[] = "file_changing_contents.txt";
00457 static const char CHANGE_CONTENTS_FILL = ' ';
00458 static const uint32_t BLOCK_SIZE = 512;
00459 
00460 /**
00461  * Create file CHANGE_CONTENTS_NAME with initial contents
00462  *
00463  * File contains three blocks of data each which start
00464  * with a count.
00465  */
00466 static void setup_file_change_contents(FileSystem *fs)
00467 {
00468     DEBUG("setup_file_change_contents()\n");
00469 
00470     File file;
00471     int res = file.open(fs, CHANGE_CONTENTS_NAME, O_WRONLY | O_CREAT);
00472     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00473 
00474     for (int count = 1; count <= 3; count++) {
00475         int size = file_printf(&file, "%lu\n", count);
00476         TEST_ASSERT_OR_EXIT(size >= 0);
00477 
00478         bool dead = file_pad(&file, CHANGE_CONTENTS_FILL, BLOCK_SIZE - size);
00479         TEST_ASSERT_EQUAL_OR_EXIT(false, dead);
00480     }
00481 }
00482 
00483 /**
00484  * Atomically increment the counts in the file CHANGE_CONTENTS_NAME
00485  *
00486  * Read in the current counts, increment them and then write them
00487  * back in non-sequential order.
00488  */
00489 static bool perform_file_change_contents(FileSystem *fs)
00490 {
00491     DEBUG("perform_file_change_contents()\n");
00492     File file;
00493 
00494     int res = file.open(fs, CHANGE_CONTENTS_NAME,  O_RDWR);
00495     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00496 
00497     // Read in values
00498     uint32_t values[3];
00499     for (int i = 0; i < 3; i++) {
00500         file.seek(i * BLOCK_SIZE);
00501         int args_read = file_scanf(&file, "%lu\n", &values[i]);
00502         TEST_ASSERT_EQUAL_OR_EXIT(1, args_read);
00503     }
00504 
00505     // Increment values
00506     for (int i = 0; i < 3; i++) {
00507         values[i]++;
00508     }
00509 
00510     // Write values out of order
00511     int i;
00512     i = 0;
00513     file.seek(i * BLOCK_SIZE);
00514     if (file_printf(&file, "%lu\n", values[i]) <= 0) {
00515         return true;
00516     }
00517     DEBUG("    value[%i]: %lu -> %lu\n", i, values[i] - 1, values[i]);
00518 
00519     i = 2;
00520     file.seek(i * BLOCK_SIZE);
00521     if (file_printf(&file, "%lu\n", values[i]) <= 0) {
00522         return true;
00523     }
00524     DEBUG("    value[%i]: %lu -> %lu\n", i, values[i] - 1, values[i]);
00525 
00526     i = 1;
00527     file.seek(i * BLOCK_SIZE);
00528     if (file_printf(&file, "%lu\n", values[i]) <= 0) {
00529         return true;
00530     }
00531     DEBUG("    value[%i]: %lu -> %lu\n", i, values[i] - 1, values[i]);
00532 
00533     res = file.close();
00534     if (-ENOSPC  == res) {
00535         return true;
00536     }
00537     TEST_ASSERT_EQUAL(0, res);
00538 
00539     return false;
00540 }
00541 
00542 /*
00543  * Change the directory name from either DIRECTORY_RENAME_A or DIRECTORY_RENAME_B to the other
00544  *
00545  * Allowed states:
00546  * - CHANGE_CONTENTS_NAME exists and contains 3 counts which are in order
00547  */
00548 static void check_file_change_contents(FileSystem *fs)
00549 {
00550     DEBUG_CHECK("check_file_change_contents()\n");
00551     File file;
00552 
00553     int res = file.open(fs, CHANGE_CONTENTS_NAME,  O_RDONLY);
00554     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00555 
00556     // Read in values
00557     uint32_t values[3];
00558     for (int i = 0; i < 3; i++) {
00559         file.seek(i * BLOCK_SIZE);
00560         int args_read = file_scanf(&file, "%lu\n", &values[i]);
00561         TEST_ASSERT_EQUAL_OR_EXIT(1, args_read);
00562         DEBUG_CHECK("    value[%i]: %lu\n", i, values[i]);
00563     }
00564 
00565     TEST_ASSERT_EQUAL_OR_EXIT(values[0] + 1, values[1]);
00566     TEST_ASSERT_EQUAL_OR_EXIT(values[1] + 1, values[2]);
00567 }
00568 
00569 
00570 static const TestEntry atomic_test_entries[] = {
00571     {"File rename", setup_file_rename, perform_file_rename, check_file_rename},
00572     {"File rename replace", setup_file_rename_replace, perform_file_rename_replace, check_file_rename_replace},
00573     {"Directory rename", setup_directory_rename, perform_directory_rename, check_directory_rename},
00574     {"File change contents", setup_file_change_contents, perform_file_change_contents, check_file_change_contents},
00575 };
00576 
00577 static const char  FILE_SETUP_COMPLETE[] = "setup_complete.txt";
00578 static const char  FILE_SETUP_COMPLETE_FMT[] = "Test version: %lu\n";
00579 
00580 static bool format_required(BlockDevice *bd)
00581 {
00582     MBED_TEST_FILESYSTEM_DECL;
00583 
00584     if (fs.mount(bd) != 0) {
00585         return true;
00586     }
00587 
00588     // Check if setup complete file exists
00589     File file;
00590     int res = file.open(&fs, FILE_SETUP_COMPLETE,  O_RDONLY);
00591     if (res != 0) {
00592         return true;
00593     }
00594 
00595     // Read contents of setup complete file
00596     uint8_t buf[BUFFER_SIZE];
00597     memset(buf, 0, sizeof(buf));
00598     int size_read = file.read(buf, sizeof(buf) - 1);
00599     if (size_read <= 0) {
00600         return true;
00601     }
00602 
00603     // Get the test version
00604     uint32_t version = 0;
00605     res = sscanf((char*)buf, FILE_SETUP_COMPLETE_FMT, &version);
00606     if (res != 1) {
00607         return true;
00608     }
00609 
00610     if (ATOMIC_USAGE_VERSION != version) {
00611         return true;
00612     }
00613 
00614     // Setup file exists and is the correct version
00615     return false;
00616 }
00617 
00618 static void format(BlockDevice *bd)
00619 {
00620     MBED_TEST_FILESYSTEM_DECL;
00621 
00622     int res = fs.format(bd);
00623     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00624 
00625     res = fs.mount(bd);
00626     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00627 
00628     for (size_t i = 0; i < ARRAY_LENGTH(atomic_test_entries); i++) {
00629         atomic_test_entries[i].setup(&fs);
00630     }
00631 
00632     File file;
00633     res = file.open(&fs, FILE_SETUP_COMPLETE, O_CREAT | O_WRONLY);
00634     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00635 
00636     int size = file_printf(&file, FILE_SETUP_COMPLETE_FMT, (uint32_t)ATOMIC_USAGE_VERSION);
00637     TEST_ASSERT_OR_EXIT(size >= 0);
00638 }
00639 
00640 static int64_t get_cycle_count(FileSystem *fs)
00641 {
00642     File file;
00643 
00644     int res = file.open(fs, FILE_RENAME_REPLACE, O_RDONLY);
00645     TEST_ASSERT_EQUAL_OR_EXIT(0, res);
00646 
00647     uint64_t count = 0;
00648     int args_read = file_scanf(&file, FILE_RENAME_REPLACE_FMT, &count);
00649     TEST_ASSERT_EQUAL_OR_EXIT(1, args_read);
00650 
00651     file.close();
00652 
00653     return (int64_t)count;
00654 }
00655 
00656 bool setup_atomic_operations(BlockDevice *bd, bool force_rebuild)
00657 {
00658     if (force_rebuild || format_required(bd)) {
00659         format(bd);
00660         TEST_ASSERT_EQUAL_OR_EXIT(false, format_required(bd));
00661         return true;
00662     }
00663     return false;
00664 }
00665 
00666 int64_t perform_atomic_operations(BlockDevice *bd)
00667 {
00668     MBED_TEST_FILESYSTEM_DECL;
00669     bool out_of_space = false;
00670 
00671     fs.mount(bd);
00672 
00673     for (size_t i = 0; i < ARRAY_LENGTH(atomic_test_entries); i++) {
00674         out_of_space |= atomic_test_entries[i].perform(&fs);
00675     }
00676 
00677     int64_t cycle_count = get_cycle_count(&fs);
00678 
00679     fs.unmount();
00680 
00681     if (out_of_space) {
00682         return -1;
00683     } else  {
00684         return cycle_count;
00685     }
00686 }
00687 
00688 void check_atomic_operations(BlockDevice *bd)
00689 {
00690     MBED_TEST_FILESYSTEM_DECL;
00691     fs.mount(bd);
00692 
00693     for (size_t i = 0; i < ARRAY_LENGTH(atomic_test_entries); i++) {
00694         atomic_test_entries[i].check(&fs);
00695     }
00696 
00697     fs.unmount();
00698 }