1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <assert.h>
18 #include <lk/macros.h>
19 #include <malloc.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <time.h>
23 #include <uapi/err.h>
24 
25 #include <lib/storage/storage.h>
26 
27 #ifndef STORAGE_FAKE
28 #include <lib/system_state/system_state.h>
29 #include <lib/unittest/unittest.h>
30 #include <trusty/time.h>
31 #endif
32 
33 #include <trusty_unittest.h>
34 
35 #define TLOG_TAG "ss_unittest"
36 
37 #if STORAGE_UNITTEST_ON_EMULATOR
38 #define ENABLED_ON_EMULATOR_ONLY(name) name
39 #else
40 #define ENABLED_ON_EMULATOR_ONLY(name) DISABLED_##name
41 #endif
42 
43 typedef void (*test_body)(storage_session_t ss, storage_session_t ss_aux);
44 
45 static const char* storage_test_client_port;
46 static storage_session_t storage_test_ss_persist = STORAGE_INVALID_SESSION;
47 
48 typedef struct {
49     storage_session_t ss;
50     storage_session_t ss_aux;
51 } StorageTest_t;
52 
StorageTest_SetUp(StorageTest_t * state)53 void StorageTest_SetUp(StorageTest_t* state) {
54     state->ss = STORAGE_INVALID_SESSION;
55     state->ss_aux = STORAGE_INVALID_SESSION;
56 
57     if (storage_test_ss_persist != STORAGE_INVALID_SESSION) {
58         storage_close_session(storage_test_ss_persist);
59         storage_test_ss_persist = STORAGE_INVALID_SESSION;
60     }
61 
62     int rc = storage_open_session(&state->ss, storage_test_client_port);
63     if (rc < 0) {
64         TLOGE("failed (%d) to open session\n", rc);
65         return;
66     }
67 
68 #ifndef STORAGE_FAKE
69     rc = storage_open_session(&state->ss_aux, storage_test_client_port);
70     if (rc < 0) {
71         TLOGE("failed (%d) to open session\n", rc);
72         storage_close_session(state->ss);
73         return;
74     }
75 #endif
76 };
77 
StorageTest_TearDown(StorageTest_t * state)78 void StorageTest_TearDown(StorageTest_t* state) {
79     storage_close_session(state->ss);
80 
81 #ifndef STORAGE_FAKE
82     storage_close_session(state->ss_aux);
83 #endif
84 }
85 
86 #undef TEST_F
87 #define TEST_F(suite_name, test_name)                                   \
88     TEST_F_CUSTOM_ARGS(suite_name, test_name, (state.ss, state.ss_aux), \
89                        (storage_session_t ss, storage_session_t ss_aux))
90 
91 #ifndef STORAGE_FAKE
TEST_FIXTURE_ALIAS(StorageInitNoCommitSmallTest,StorageTest)92 TEST_FIXTURE_ALIAS(StorageInitNoCommitSmallTest, StorageTest)
93 TEST_FIXTURE_ALIAS(StorageInitNoCommitLargeTest, StorageTest)
94 TEST_FIXTURE_ALIAS(StorageInitNoCommitCleanupTest, StorageTest)
95 #endif
96 TEST_FIXTURE_ALIAS(StorageInitTest, StorageTest)
97 TEST_FIXTURE_ALIAS(StorageCheckTest, StorageTest)
98 TEST_FIXTURE_ALIAS(StorageCleanTest, StorageTest)
99 
100 static inline bool is_32bit_aligned(size_t sz) {
101     return ((sz & 0x3) == 0);
102 }
103 
is_valid_size(size_t sz)104 static inline bool is_valid_size(size_t sz) {
105     return (sz > 0) && is_32bit_aligned(sz);
106 }
107 
is_valid_offset(storage_off_t off)108 static bool is_valid_offset(storage_off_t off) {
109     return (off & 0x3) == 0ULL;
110 }
111 
fill_pattern32(uint32_t * buf,size_t len,storage_off_t off)112 static void fill_pattern32(uint32_t* buf, size_t len, storage_off_t off) {
113     size_t cnt = len / sizeof(uint32_t);
114     uint32_t pattern = (uint32_t)(off / sizeof(uint32_t));
115     for (; cnt > 0; cnt--) {
116         *buf++ = pattern++;
117     }
118 }
119 
check_pattern32(const uint32_t * buf,size_t len,storage_off_t off)120 static bool check_pattern32(const uint32_t* buf,
121                             size_t len,
122                             storage_off_t off) {
123     size_t cnt = len / sizeof(uint32_t);
124     uint32_t pattern = (uint32_t)(off / sizeof(uint32_t));
125     for (; cnt > 0; cnt--) {
126         if (*buf != pattern)
127             return false;
128         buf++;
129         pattern++;
130     }
131     return true;
132 }
133 
check_value32(const uint32_t * buf,size_t len,uint32_t val)134 static bool check_value32(const uint32_t* buf, size_t len, uint32_t val) {
135     size_t cnt = len / sizeof(uint32_t);
136     for (; cnt > 0; cnt--) {
137         if (*buf != val)
138             return false;
139         buf++;
140     }
141     return true;
142 }
143 
WriteZeroChunk(file_handle_t handle,storage_off_t off,size_t chunk_len,uint32_t opflags)144 static int WriteZeroChunk(file_handle_t handle,
145                           storage_off_t off,
146                           size_t chunk_len,
147                           uint32_t opflags) {
148     uint32_t data_buf[chunk_len / sizeof(uint32_t)];
149 
150     assert(is_valid_size(chunk_len));
151     assert(is_valid_offset(off));
152 
153     memset(data_buf, 0, chunk_len);
154 
155     return storage_write(handle, off, data_buf, sizeof(data_buf), opflags);
156 }
157 
WritePatternChunk(file_handle_t handle,storage_off_t off,size_t chunk_len,uint32_t opflags)158 static int WritePatternChunk(file_handle_t handle,
159                              storage_off_t off,
160                              size_t chunk_len,
161                              uint32_t opflags) {
162     uint32_t data_buf[chunk_len / sizeof(uint32_t)];
163 
164     assert(is_valid_size(chunk_len));
165     assert(is_valid_offset(off));
166 
167     fill_pattern32(data_buf, chunk_len, off);
168 
169     return storage_write(handle, off, data_buf, sizeof(data_buf), opflags);
170 }
171 
WritePatternExt(file_handle_t handle,storage_off_t off,size_t data_len,size_t chunk_len,uint32_t extra_opflags)172 static int WritePatternExt(file_handle_t handle,
173                            storage_off_t off,
174                            size_t data_len,
175                            size_t chunk_len,
176                            uint32_t extra_opflags) {
177     size_t written = 0;
178 
179     assert(is_valid_size(data_len));
180     assert(is_valid_size(chunk_len));
181 
182     while (data_len) {
183         if (data_len < chunk_len)
184             chunk_len = data_len;
185         int rc = WritePatternChunk(handle, off, chunk_len,
186                                    (chunk_len == data_len) ? extra_opflags : 0);
187         if (rc < 0)
188             return rc;
189         if ((size_t)rc != chunk_len)
190             return written + rc;
191         off += chunk_len;
192         data_len -= chunk_len;
193         written += chunk_len;
194     }
195     return (int)written;
196 }
197 
WritePattern(file_handle_t handle,storage_off_t off,size_t data_len,size_t chunk_len,bool complete)198 static int WritePattern(file_handle_t handle,
199                         storage_off_t off,
200                         size_t data_len,
201                         size_t chunk_len,
202                         bool complete) {
203     return WritePatternExt(handle, off, data_len, chunk_len,
204                            complete ? STORAGE_OP_COMPLETE : 0);
205 }
206 
ReadChunk(file_handle_t handle,storage_off_t off,size_t chunk_len,size_t head_len,size_t pattern_len,size_t tail_len)207 static int ReadChunk(file_handle_t handle,
208                      storage_off_t off,
209                      size_t chunk_len,
210                      size_t head_len,
211                      size_t pattern_len,
212                      size_t tail_len) {
213     int rc;
214     uint32_t data_buf[chunk_len / sizeof(uint32_t)];
215     uint8_t* data_ptr = (uint8_t*)data_buf;
216 
217     assert(is_valid_size(chunk_len));
218     assert(is_valid_offset(off));
219     assert((head_len + pattern_len + tail_len) == chunk_len);
220 
221     rc = storage_read(handle, off, data_buf, chunk_len);
222     if ((size_t)rc != chunk_len)
223         return rc;
224 
225     if (head_len) {
226         if (!check_value32((const uint32_t*)data_ptr, head_len, 0))
227             return ERR_CHECKSUM_FAIL;
228         data_ptr += head_len;
229         off += head_len;
230     }
231 
232     if (pattern_len) {
233         if (!check_pattern32((const uint32_t*)data_ptr, pattern_len, off))
234             return ERR_CHECKSUM_FAIL;
235         data_ptr += pattern_len;
236     }
237 
238     if (tail_len) {
239         if (!check_value32((const uint32_t*)data_ptr, tail_len, 0))
240             return ERR_CHECKSUM_FAIL;
241     }
242 
243     return chunk_len;
244 }
245 
ReadPattern(file_handle_t handle,storage_off_t off,size_t data_len,size_t chunk_len)246 static int ReadPattern(file_handle_t handle,
247                        storage_off_t off,
248                        size_t data_len,
249                        size_t chunk_len) {
250     int rc;
251     size_t bytes_read = 0;
252     uint32_t data_buf[chunk_len / sizeof(uint32_t)];
253 
254     assert(is_valid_size(chunk_len));
255     assert(is_valid_size(data_len));
256     assert(is_valid_offset(off));
257 
258     while (data_len) {
259         if (chunk_len > data_len)
260             chunk_len = data_len;
261         rc = storage_read(handle, off, data_buf, sizeof(data_buf));
262         if (rc < 0)
263             return rc;
264         if ((size_t)rc != chunk_len)
265             return bytes_read + rc;
266         if (!check_pattern32(data_buf, chunk_len, off))
267             return ERR_CHECKSUM_FAIL;
268         off += chunk_len;
269         data_len -= chunk_len;
270         bytes_read += chunk_len;
271     }
272     return bytes_read;
273 }
274 
ReadPatternEOF(file_handle_t handle,storage_off_t off,size_t chunk_len)275 static int ReadPatternEOF(file_handle_t handle,
276                           storage_off_t off,
277                           size_t chunk_len) {
278     int rc;
279     size_t bytes_read = 0;
280     uint32_t data_buf[chunk_len / sizeof(uint32_t)];
281 
282     assert(is_valid_size(chunk_len));
283 
284     while (true) {
285         rc = storage_read(handle, off, data_buf, sizeof(data_buf));
286         if (rc < 0)
287             return rc;
288         if (rc == 0)
289             break;  // end of file reached
290         if (!is_valid_size((size_t)rc))
291             return ERR_BAD_LEN;
292         if (!check_pattern32(data_buf, rc, off))
293             return ERR_CHECKSUM_FAIL;
294         off += rc;
295         bytes_read += rc;
296     }
297     return bytes_read;
298 }
299 
TEST_F(StorageTest,CreateDelete)300 TEST_F(StorageTest, CreateDelete) {
301     int rc;
302     file_handle_t handle;
303     const char* fname = "test_create_delete_file";
304 
305     // make sure test file does not exist (expect success or ERR_NOT_FOUND)
306     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
307     rc = (rc == ERR_NOT_FOUND) ? 0 : rc;
308     ASSERT_EQ(0, rc, "delete test file");
309 
310     // one more time (expect ERR_NOT_FOUND)
311     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
312     ASSERT_EQ(ERR_NOT_FOUND, rc, "delete again");
313 
314     // create file (expect 0)
315     rc = storage_open_file(
316             ss, &handle, fname,
317             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
318             STORAGE_OP_COMPLETE);
319     ASSERT_EQ(0, rc, "create test file");
320 
321     // try to create it again while it is still opened (expect
322     // ERR_ALREADY_EXISTS)
323     rc = storage_open_file(
324             ss, &handle, fname,
325             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
326             STORAGE_OP_COMPLETE);
327     ASSERT_EQ(ERR_ALREADY_EXISTS, rc, "create again");
328 
329     // close it
330     storage_close_file(handle);
331 
332     // try to create it again while it is closed (expect ERR_ALREADY_EXISTS)
333     rc = storage_open_file(
334             ss, &handle, fname,
335             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
336             STORAGE_OP_COMPLETE);
337     ASSERT_EQ(ERR_ALREADY_EXISTS, rc, "create again");
338 
339     // delete file (expect 0)
340     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
341     ASSERT_EQ(0, rc, "delete test file");
342 
343     // one more time (expect ERR_NOT_FOUND)
344     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
345     ASSERT_EQ(ERR_NOT_FOUND, rc, "delete again");
346 
347 test_abort:;
348 }
349 
350 #ifndef STORAGE_FAKE
351 // Moving file and opening directory is not supported in fake secure
352 // storage implementation.
353 
DeleteAllFiles(storage_session_t ss)354 static int DeleteAllFiles(storage_session_t ss) {
355     int rc;
356     struct storage_open_dir_state* dir;
357     char file_name_dir[64];
358     uint8_t read_dir_flags;
359     int deleted = 0;
360 
361     // read all test files and delete
362     rc = storage_open_dir(ss, "", &dir);
363     if (rc != 0) {
364         return rc;
365     }
366 
367     while (true) {
368         rc = storage_read_dir(ss, dir, &read_dir_flags, file_name_dir,
369                               sizeof(file_name_dir));
370         if (rc == 0)
371             break;
372         if (rc < 0) {
373             deleted = rc;
374             goto cleanup;
375         }
376         if ((read_dir_flags & STORAGE_FILE_LIST_STATE_MASK) !=
377             STORAGE_FILE_LIST_REMOVED) {
378             rc = storage_delete_file(ss, file_name_dir, 0);
379             if (rc != 0) {
380                 deleted = rc;
381                 goto cleanup;
382             }
383             deleted++;
384         }
385     }
386 
387     rc = storage_end_transaction(ss, true);
388     if (rc != 0) {
389         deleted = rc;
390         goto cleanup;
391     }
392 
393 cleanup:
394     storage_close_dir(ss, dir);
395 
396     return deleted;
397 }
398 
TEST_F(StorageTest,ReadAndDelete)399 TEST_F(StorageTest, ReadAndDelete) {
400     int rc;
401     file_handle_t handle;
402     const char* fname_pat = "test_read_and_delete_%03d_file";
403     char file_name[64];
404     struct storage_open_dir_state* dir;
405     char file_name_dir[64];
406     uint8_t read_dir_flags;
407     int i;
408     int file_count = 100;
409 
410     // clean up dir before the test
411     rc = DeleteAllFiles(ss);
412     ASSERT_LE(0, rc, "cleanup");
413 
414     // make sure test files do not exist (expect ERR_NOT_FOUND)
415     for (i = 0; i < file_count; i++) {
416         snprintf(file_name, sizeof(file_name), fname_pat, i);
417         rc = storage_delete_file(ss, file_name, STORAGE_OP_COMPLETE);
418         ASSERT_EQ(ERR_NOT_FOUND, rc, "exists before test");
419     }
420 
421     // create test files
422     for (i = 0; i < file_count; i++) {
423         snprintf(file_name, sizeof(file_name), fname_pat, i);
424         rc = storage_open_file(
425                 ss, &handle, file_name,
426                 STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
427                 STORAGE_OP_COMPLETE);
428         ASSERT_EQ(0, rc, "create test file");
429 
430         // close it
431         storage_close_file(handle);
432     }
433 
434     // delete all files by reading the dir
435     rc = DeleteAllFiles(ss);
436     ASSERT_EQ(file_count, rc, "delete_all");
437 
438     // test empty dir
439     rc = storage_open_dir(ss, "", &dir);
440     ASSERT_EQ(0, rc, "open_dir");
441 
442     rc = storage_read_dir(ss, dir, &read_dir_flags, file_name_dir,
443                           sizeof(file_name_dir));
444     ASSERT_EQ(0, rc, "read_dir");
445     ASSERT_EQ(STORAGE_FILE_LIST_END,
446               read_dir_flags & STORAGE_FILE_LIST_STATE_MASK, "dir flags");
447 
448     storage_close_dir(ss, dir);
449 
450     // make sure test files do not exist (expect ERR_NOT_FOUND)
451     for (i = 0; i < file_count; i++) {
452         snprintf(file_name, sizeof(file_name), fname_pat, i);
453         rc = storage_delete_file(ss, file_name, STORAGE_OP_COMPLETE);
454         ASSERT_EQ(ERR_NOT_FOUND, rc, "delete after test");
455     }
456 
457 test_abort:
458     for (i = 0; i < file_count; i++) {
459         snprintf(file_name, sizeof(file_name), fname_pat, i);
460         rc = storage_delete_file(ss, file_name, STORAGE_OP_COMPLETE);
461     }
462 }
463 
TEST_F(StorageTest,CreateMoveDelete)464 TEST_F(StorageTest, CreateMoveDelete) {
465     int rc;
466     file_handle_t handle;
467     const char* fname1 = "test_create_move_delete_1_file";
468     const char* fname2 = "test_create_move_delete_2_file";
469 
470     // make sure test file does not exist (expect success or ERR_NOT_FOUND)
471     rc = storage_delete_file(ss, fname1, STORAGE_OP_COMPLETE);
472     rc = (rc == ERR_NOT_FOUND) ? 0 : rc;
473     ASSERT_EQ(0, rc, "delete test file1");
474     rc = storage_delete_file(ss, fname2, STORAGE_OP_COMPLETE);
475     rc = (rc == ERR_NOT_FOUND) ? 0 : rc;
476     ASSERT_EQ(0, rc, "delete test file2");
477 
478     // one more time (expect ERR_NOT_FOUND)
479     rc = storage_delete_file(ss, fname1, STORAGE_OP_COMPLETE);
480     ASSERT_EQ(ERR_NOT_FOUND, rc, "delete 1 again");
481     rc = storage_delete_file(ss, fname2, STORAGE_OP_COMPLETE);
482     ASSERT_EQ(ERR_NOT_FOUND, rc, "delete 2 again");
483 
484     // create file (expect 0)
485     rc = storage_open_file(
486             ss, &handle, fname1,
487             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
488             STORAGE_OP_COMPLETE);
489     ASSERT_EQ(0, rc, "create test file");
490 
491     // move file
492     rc = storage_move_file(ss, handle, fname1, fname2,
493                            STORAGE_FILE_MOVE_CREATE |
494                                    STORAGE_FILE_MOVE_CREATE_EXCLUSIVE |
495                                    STORAGE_FILE_MOVE_OPEN_FILE,
496                            STORAGE_OP_COMPLETE);
497     ASSERT_EQ(0, rc, "move test file");
498 
499     // try to create it again while it is still opened (expect
500     // ERR_ALREADY_EXISTS)
501     rc = storage_open_file(
502             ss, &handle, fname2,
503             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
504             STORAGE_OP_COMPLETE);
505     ASSERT_EQ(ERR_ALREADY_EXISTS, rc, "create again");
506 
507     // close it
508     storage_close_file(handle);
509 
510     // try to create it again while it is closed (expect ERR_ALREADY_EXISTS)
511     rc = storage_open_file(
512             ss, &handle, fname2,
513             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
514             STORAGE_OP_COMPLETE);
515     ASSERT_EQ(ERR_ALREADY_EXISTS, rc, "create again");
516 
517     // create file1 (expect 0)
518     rc = storage_open_file(
519             ss, &handle, fname1,
520             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
521             STORAGE_OP_COMPLETE);
522     ASSERT_EQ(0, rc, "create test file");
523 
524     // move file
525     rc = storage_move_file(ss, handle, fname1, fname2,
526                            STORAGE_FILE_MOVE_CREATE |
527                                    STORAGE_FILE_MOVE_CREATE_EXCLUSIVE |
528                                    STORAGE_FILE_MOVE_OPEN_FILE,
529                            STORAGE_OP_COMPLETE);
530     ASSERT_EQ(ERR_ALREADY_EXISTS, rc, "move test file");
531 
532     // close it
533     storage_close_file(handle);
534 
535     // delete file (expect 0)
536     rc = storage_delete_file(ss, fname2, STORAGE_OP_COMPLETE);
537     ASSERT_EQ(0, rc, "delete test file");
538 
539     // one more time (expect ERR_NOT_FOUND)
540     rc = storage_delete_file(ss, fname2, STORAGE_OP_COMPLETE);
541     ASSERT_EQ(ERR_NOT_FOUND, rc, "delete again");
542 
543 test_abort:
544     storage_delete_file(ss, fname1, STORAGE_OP_COMPLETE);
545     storage_delete_file(ss, fname2, STORAGE_OP_COMPLETE);
546 }
547 
TEST_F(StorageTest,FileList)548 TEST_F(StorageTest, FileList) {
549     int rc;
550     file_handle_t handle;
551     struct storage_open_dir_state* dir;
552     const char* fname_pat = "test_file_list_%d_file";
553     char file_name[64];
554     char file_name_dir[64];
555     uint8_t read_dir_flags;
556     int i;
557     int file_count = 100;
558 
559     // clean up dir before the test
560     rc = DeleteAllFiles(ss);
561     ASSERT_LE(0, rc, "cleanup");
562 
563     // make sure test files do not exist (expect ERR_NOT_FOUND)
564     for (i = 0; i < file_count; i++) {
565         snprintf(file_name, sizeof(file_name), fname_pat, i);
566         rc = storage_delete_file(ss, file_name, STORAGE_OP_COMPLETE);
567         ASSERT_EQ(ERR_NOT_FOUND, rc, "delete 1 again");
568     }
569 
570     // test empty dir
571     rc = storage_open_dir(ss, "", &dir);
572     ASSERT_EQ(0, rc, "open_dir");
573 
574     rc = storage_read_dir(ss, dir, &read_dir_flags, file_name_dir,
575                           sizeof(file_name_dir));
576     ASSERT_EQ(0, rc, "read_dir");
577     ASSERT_EQ(STORAGE_FILE_LIST_END,
578               read_dir_flags & STORAGE_FILE_LIST_STATE_MASK, "dir flags");
579 
580     storage_close_dir(ss, dir);
581 
582     // create file (expect 0)
583     snprintf(file_name, sizeof(file_name), fname_pat, 0);
584     rc = storage_open_file(
585             ss, &handle, file_name,
586             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
587             STORAGE_OP_COMPLETE);
588     ASSERT_EQ(0, rc, "create test file 1");
589 
590     // close it
591     storage_close_file(handle);
592 
593     for (i = 1; i < file_count; i++) {
594         snprintf(file_name, sizeof(file_name), fname_pat, i);
595         rc = storage_open_file(
596                 ss, &handle, file_name,
597                 STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
598                 0);
599         ASSERT_EQ(0, rc, "create test file 2");
600 
601         // close it
602         storage_close_file(handle);
603     }
604 
605     // test read_dir fname1 committed, fname2 added
606     rc = storage_open_dir(ss, "", &dir);
607     ASSERT_EQ(0, rc, "open_dir");
608 
609     snprintf(file_name, sizeof(file_name), fname_pat, 0);
610     rc = storage_read_dir(ss, dir, &read_dir_flags, file_name_dir,
611                           sizeof(file_name_dir));
612     ASSERT_EQ(strlen(file_name) + 1, rc, "read_dir");
613     ASSERT_EQ(STORAGE_FILE_LIST_COMMITTED,
614               read_dir_flags & STORAGE_FILE_LIST_STATE_MASK, "dir flags");
615     ASSERT_EQ(0, strcmp(file_name, file_name_dir), "file name");
616 
617     for (i = 1; i < file_count; i++) {
618         rc = storage_read_dir(ss, dir, &read_dir_flags, file_name_dir,
619                               sizeof(file_name_dir));
620         ASSERT_EQ(strlen(file_name_dir) + 1, rc, "read_dir");
621         ASSERT_EQ(STORAGE_FILE_LIST_ADDED,
622                   read_dir_flags & STORAGE_FILE_LIST_STATE_MASK, "dir flags");
623         ASSERT_NE(0, strcmp(file_name, file_name_dir), "file name");
624     }
625 
626     rc = storage_read_dir(ss, dir, &read_dir_flags, file_name_dir,
627                           sizeof(file_name_dir));
628     ASSERT_EQ(0, rc, "read_dir");
629     ASSERT_EQ(STORAGE_FILE_LIST_END,
630               read_dir_flags & STORAGE_FILE_LIST_STATE_MASK, "end dir flag");
631 
632     storage_close_dir(ss, dir);
633 
634     rc = storage_end_transaction(ss, true);
635     ASSERT_EQ(0, rc, "commit");
636 
637 test_abort:
638     for (i = 0; i < file_count; i++) {
639         snprintf(file_name, sizeof(file_name), fname_pat, i);
640         rc = storage_delete_file(ss, file_name, STORAGE_OP_COMPLETE);
641     }
642 }
643 #endif
644 
TEST_F(StorageTest,DeleteOpened)645 TEST_F(StorageTest, DeleteOpened) {
646     int rc;
647     file_handle_t handle;
648     const char* fname = "delete_opened_test_file";
649 
650     // make sure test file does not exist (expect success or ERR_NOT_FOUND)
651     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
652     rc = (rc == ERR_NOT_FOUND) ? 0 : rc;
653     ASSERT_EQ(0, rc);
654 
655     // one more time (expect ERR_NOT_FOUND)
656     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
657     ASSERT_EQ(ERR_NOT_FOUND, rc);
658 
659     // open/create file (expect 0)
660     rc = storage_open_file(
661             ss, &handle, fname,
662             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
663             STORAGE_OP_COMPLETE);
664     ASSERT_EQ(0, rc);
665 
666     // delete opened file (expect 0)
667     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
668     ASSERT_EQ(0, rc);
669 
670     // one more time (expect ERR_NOT_FOUND)
671     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
672     ASSERT_EQ(ERR_NOT_FOUND, rc);
673 
674     // close file
675     storage_close_file(handle);
676 
677     // one more time (expect ERR_NOT_FOUND)
678     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
679     ASSERT_EQ(ERR_NOT_FOUND, rc);
680 
681 test_abort:;
682 }
683 
TEST_F(StorageTest,OpenNoCreate)684 TEST_F(StorageTest, OpenNoCreate) {
685     int rc;
686     file_handle_t handle;
687     const char* fname = "test_open_no_create_file";
688 
689     // make sure test file does not exist (expect success or ERR_NOT_FOUND)
690     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
691     rc = (rc == ERR_NOT_FOUND) ? 0 : rc;
692     ASSERT_EQ(0, rc);
693 
694     // open non-existing file (expect ERR_NOT_FOUND)
695     rc = storage_open_file(ss, &handle, fname, 0, 0);
696     ASSERT_EQ(ERR_NOT_FOUND, rc);
697 
698     // create file (expect 0)
699     rc = storage_open_file(
700             ss, &handle, fname,
701             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
702             STORAGE_OP_COMPLETE);
703     ASSERT_EQ(0, rc);
704     storage_close_file(handle);
705 
706     // open existing file (expect 0)
707     rc = storage_open_file(ss, &handle, fname, 0, 0);
708     ASSERT_EQ(0, rc);
709 
710     // close it
711     storage_close_file(handle);
712 
713     // delete file (expect 0)
714     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
715     ASSERT_EQ(0, rc);
716 
717 test_abort:;
718 }
719 
TEST_F(StorageTest,OpenOrCreate)720 TEST_F(StorageTest, OpenOrCreate) {
721     int rc;
722     file_handle_t handle;
723     const char* fname = "test_open_create_file";
724 
725     // make sure test file does not exist (expect success or ERR_NOT_FOUND)
726     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
727     rc = (rc == ERR_NOT_FOUND) ? 0 : rc;
728     ASSERT_EQ(0, rc);
729 
730     // open/create a non-existing file (expect 0)
731     rc = storage_open_file(ss, &handle, fname, STORAGE_FILE_OPEN_CREATE,
732                            STORAGE_OP_COMPLETE);
733     ASSERT_EQ(0, rc);
734     storage_close_file(handle);
735 
736     // open/create an existing file (expect 0)
737     rc = storage_open_file(ss, &handle, fname, STORAGE_FILE_OPEN_CREATE,
738                            STORAGE_OP_COMPLETE);
739     ASSERT_EQ(0, rc);
740     storage_close_file(handle);
741 
742     // delete file (expect 0)
743     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
744     ASSERT_EQ(0, rc);
745 
746 test_abort:;
747 }
748 
TEST_F(StorageTest,OpenCreateDeleteCharset)749 TEST_F(StorageTest, OpenCreateDeleteCharset) {
750     int rc;
751     file_handle_t handle;
752     const char* fname =
753             "ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz_01234.56789";
754 
755     // open/create file (expect 0)
756     rc = storage_open_file(ss, &handle, fname, STORAGE_FILE_OPEN_CREATE,
757                            STORAGE_OP_COMPLETE);
758     ASSERT_EQ(0, rc);
759     storage_close_file(handle);
760 
761     // open/create an existing file (expect 0)
762     rc = storage_open_file(ss, &handle, fname, 0, 0);
763     ASSERT_EQ(0, rc);
764     storage_close_file(handle);
765 
766     // delete file (expect 0)
767     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
768     ASSERT_EQ(0, rc);
769 
770     // open again
771     rc = storage_open_file(ss, &handle, fname, 0, 0);
772     ASSERT_EQ(ERR_NOT_FOUND, rc);
773 
774 test_abort:;
775 }
776 
TEST_F(StorageTest,WriteReadSequential)777 TEST_F(StorageTest, WriteReadSequential) {
778     int rc;
779     size_t blk = 2048;
780     file_handle_t handle;
781     const char* fname = "test_write_read_sequential";
782 
783     // make sure test file does not exist (expect success or ERR_NOT_FOUND)
784     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
785     rc = (rc == ERR_NOT_FOUND) ? 0 : rc;
786     ASSERT_EQ(0, rc);
787 
788     // create file.
789     rc = storage_open_file(
790             ss, &handle, fname,
791             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
792             STORAGE_OP_COMPLETE);
793     ASSERT_EQ(0, rc);
794 
795     // write a bunch of blocks (sequentially)
796     rc = WritePattern(handle, 0, 32 * blk, blk, true);
797     ASSERT_EQ((int)(32 * blk), rc);
798 
799     rc = ReadPattern(handle, 0, 32 * blk, blk);
800     ASSERT_EQ((int)(32 * blk), rc);
801 
802     // close file
803     storage_close_file(handle);
804 
805     // open the same file again
806     rc = storage_open_file(ss, &handle, fname, 0, 0);
807     ASSERT_EQ(0, rc);
808 
809     // read data back (sequentially) and check pattern again
810     rc = ReadPattern(handle, 0, 32 * blk, blk);
811     ASSERT_EQ((int)(32 * blk), rc);
812 
813     // cleanup
814     storage_close_file(handle);
815     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
816 
817 test_abort:;
818 }
819 
TEST_F(StorageTest,OpenTruncate)820 TEST_F(StorageTest, OpenTruncate) {
821     int rc;
822     uint32_t val;
823     size_t blk = 2048;
824     file_handle_t handle;
825     const char* fname = "test_open_truncate";
826 
827     // make sure test file does not exist (expect success or ERR_NOT_FOUND)
828     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
829     rc = (rc == ERR_NOT_FOUND) ? 0 : rc;
830     ASSERT_EQ(0, rc);
831 
832     // create file.
833     rc = storage_open_file(
834             ss, &handle, fname,
835             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
836             STORAGE_OP_COMPLETE);
837     ASSERT_EQ(0, rc);
838 
839     // write some data and read it back
840     rc = WritePatternChunk(handle, 0, blk, true);
841     ASSERT_EQ((int)blk, rc);
842 
843     rc = ReadPattern(handle, 0, blk, blk);
844     ASSERT_EQ((int)blk, rc);
845 
846     // close file
847     storage_close_file(handle);
848 
849     // reopen with truncate
850     rc = storage_open_file(ss, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE,
851                            STORAGE_OP_COMPLETE);
852     ASSERT_EQ(0, rc);
853 
854     /* try to read data back (expect no data) */
855     rc = storage_read(handle, 0LL, &val, sizeof(val));
856     ASSERT_EQ(0, rc);
857 
858     // cleanup
859     storage_close_file(handle);
860     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
861 
862 test_abort:;
863 }
864 
TEST_F(StorageTest,OpenSame)865 TEST_F(StorageTest, OpenSame) {
866     int rc;
867     file_handle_t handle1;
868     file_handle_t handle2;
869     file_handle_t handle3;
870     const char* fname = "test_open_same_file";
871 
872     // open/create file (expect 0)
873     rc = storage_open_file(ss, &handle1, fname, STORAGE_FILE_OPEN_CREATE,
874                            STORAGE_OP_COMPLETE);
875     ASSERT_EQ(0, rc);
876     storage_close_file(handle1);
877 
878     // open an existing file first time (expect 0)
879     rc = storage_open_file(ss, &handle1, fname, 0, 0);
880     ASSERT_EQ(0, rc);
881 
882     // open the same file second time (is not allowed)
883     rc = storage_open_file(ss, &handle2, fname, 0, 0);
884     ASSERT_EQ(ERR_NOT_ALLOWED, rc);
885 
886     // delete file (expect 0)
887     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
888     ASSERT_EQ(0, rc);
889 
890     // open deleted file (expect ERR_NOT_FOUND)
891     rc = storage_open_file(ss, &handle3, fname, 0, 0);
892     ASSERT_EQ(ERR_NOT_FOUND, rc);
893 
894     // close file
895     storage_close_file(handle1);
896 
897 test_abort:;
898 }
899 
TEST_F(StorageTest,OpenMany)900 TEST_F(StorageTest, OpenMany) {
901     int rc;
902     file_handle_t handles[10];
903     char filename[10];
904     const char* fname_fmt = "mf%d";
905 
906     // open or create a bunch of files (expect 0)
907     for (uint32_t i = 0; i < countof(handles); ++i) {
908         snprintf(filename, sizeof(filename), fname_fmt, i);
909         rc = storage_open_file(ss, &handles[i], filename,
910                                STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
911         ASSERT_EQ(0, rc);
912     }
913 
914     // check that all handles are different
915     for (uint32_t i = 0; i < countof(handles) - 1; i++) {
916         for (uint32_t j = i + 1; j < countof(handles); j++) {
917             ASSERT_NE(handles[i], handles[j]);
918         }
919     }
920 
921     // close them all
922     for (uint32_t i = 0; i < countof(handles); ++i) {
923         storage_close_file(handles[i]);
924     }
925 
926     // open all files without CREATE flags (expect 0)
927     for (uint32_t i = 0; i < countof(handles); ++i) {
928         snprintf(filename, sizeof(filename), fname_fmt, i);
929         rc = storage_open_file(ss, &handles[i], filename, 0, 0);
930         ASSERT_EQ(0, rc);
931     }
932 
933     // check that all handles are different
934     for (uint32_t i = 0; i < countof(handles) - 1; i++) {
935         for (uint32_t j = i + 1; j < countof(handles); j++) {
936             ASSERT_NE(handles[i], handles[j]);
937         }
938     }
939 
940     // close and remove all test files
941     for (uint32_t i = 0; i < countof(handles); ++i) {
942         storage_close_file(handles[i]);
943         snprintf(filename, sizeof(filename), fname_fmt, i);
944         rc = storage_delete_file(ss, filename, STORAGE_OP_COMPLETE);
945         ASSERT_EQ(0, rc);
946     }
947 
948 test_abort:;
949 }
950 
TEST_F(StorageTest,ReadAtEOF)951 TEST_F(StorageTest, ReadAtEOF) {
952     int rc;
953     uint32_t val;
954     size_t blk = 2048;
955     file_handle_t handle;
956     const char* fname = "test_read_eof";
957 
958     // open/create/truncate file
959     rc = storage_open_file(
960             ss, &handle, fname,
961             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
962             STORAGE_OP_COMPLETE);
963     ASSERT_EQ(0, rc);
964 
965     // write block at offset 0
966     rc = WritePatternChunk(handle, 0, blk, true);
967     ASSERT_EQ((int)blk, rc);
968 
969     // close file
970     storage_close_file(handle);
971 
972     // open same file again
973     rc = storage_open_file(ss, &handle, fname, 0, 0);
974     ASSERT_EQ(0, rc);
975 
976     // read the whole block back and check pattern again
977     rc = ReadPattern(handle, 0, blk, blk);
978     ASSERT_EQ((int)blk, rc);
979 
980     // read at end of file (expected 0 bytes)
981     rc = storage_read(handle, blk, &val, sizeof(val));
982     ASSERT_EQ(0, rc);
983 
984     // partial read at end of the file (expected partial data)
985     rc = ReadPatternEOF(handle, blk / 2, blk);
986     ASSERT_EQ((int)blk / 2, rc);
987 
988     // read past end of file
989     rc = storage_read(handle, blk + 2, &val, sizeof(val));
990     ASSERT_EQ(ERR_NOT_VALID, rc);
991 
992     // cleanup
993     storage_close_file(handle);
994     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
995 
996 test_abort:;
997 }
998 
TEST_F(StorageTest,GetFileSize)999 TEST_F(StorageTest, GetFileSize) {
1000     int rc;
1001     size_t blk = 2048;
1002     storage_off_t size;
1003     file_handle_t handle;
1004     const char* fname = "test_get_file_size";
1005 
1006     // open/create/truncate file.
1007     rc = storage_open_file(
1008             ss, &handle, fname,
1009             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1010             STORAGE_OP_COMPLETE);
1011     ASSERT_EQ(0, rc);
1012 
1013     // check file size (expect success and size == 0)
1014     size = 1;
1015     rc = storage_get_file_size(handle, &size);
1016     ASSERT_EQ(0, rc);
1017     ASSERT_EQ((storage_off_t)0, size);
1018 
1019     // write block
1020     rc = WritePatternChunk(handle, 0, blk, true);
1021     ASSERT_EQ((int)blk, rc);
1022 
1023     // check size
1024     rc = storage_get_file_size(handle, &size);
1025     ASSERT_EQ(0, rc);
1026     ASSERT_EQ(blk, size);
1027 
1028     // write another block
1029     rc = WritePatternChunk(handle, blk, blk, true);
1030     ASSERT_EQ((int)blk, rc);
1031 
1032     // check size again
1033     rc = storage_get_file_size(handle, &size);
1034     ASSERT_EQ(0, rc);
1035     ASSERT_EQ(blk * 2, size);
1036 
1037     // cleanup
1038     storage_close_file(handle);
1039     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1040 
1041 test_abort:;
1042 }
1043 
TEST_F(StorageTest,SetFileSize)1044 TEST_F(StorageTest, SetFileSize) {
1045     int rc;
1046     size_t blk = 2048;
1047     storage_off_t size;
1048     file_handle_t handle;
1049     const char* fname = "test_set_file_size";
1050 
1051     // open/create/truncate file.
1052     rc = storage_open_file(
1053             ss, &handle, fname,
1054             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1055             STORAGE_OP_COMPLETE);
1056     ASSERT_EQ(0, rc);
1057 
1058     // check file size (expect success and size == 0)
1059     size = 1;
1060     rc = storage_get_file_size(handle, &size);
1061     ASSERT_EQ(0, rc);
1062     ASSERT_EQ((storage_off_t)0, size);
1063 
1064     // write block
1065     rc = WritePatternChunk(handle, 0, blk, true);
1066     ASSERT_EQ((int)blk, rc);
1067 
1068     // check size
1069     rc = storage_get_file_size(handle, &size);
1070     ASSERT_EQ(0, rc);
1071     ASSERT_EQ(blk, size);
1072 
1073     storage_close_file(handle);
1074 
1075     // reopen normally
1076     rc = storage_open_file(ss, &handle, fname, 0, 0);
1077     ASSERT_EQ(0, rc);
1078 
1079     // check size again
1080     rc = storage_get_file_size(handle, &size);
1081     ASSERT_EQ(0, rc);
1082     ASSERT_EQ(blk, size);
1083 
1084     // set file size to half
1085     rc = storage_set_file_size(handle, blk / 2, STORAGE_OP_COMPLETE);
1086     ASSERT_EQ(0, rc);
1087 
1088     // check size again (should be half of original size)
1089     rc = storage_get_file_size(handle, &size);
1090     ASSERT_EQ(0, rc);
1091     ASSERT_EQ(blk / 2, size);
1092 
1093     // read data back
1094     rc = ReadPatternEOF(handle, 0, blk);
1095     ASSERT_EQ((int)blk / 2, rc);
1096 
1097     // set file size to 0
1098     rc = storage_set_file_size(handle, 0, STORAGE_OP_COMPLETE);
1099     ASSERT_EQ(0, rc);
1100 
1101     // check size again (should be 0)
1102     rc = storage_get_file_size(handle, &size);
1103     ASSERT_EQ(0, rc);
1104     ASSERT_EQ((storage_off_t)0LL, size);
1105 
1106     // try to read again
1107     rc = ReadPatternEOF(handle, 0, blk);
1108     ASSERT_EQ(0, rc);
1109 
1110     // cleanup
1111     storage_close_file(handle);
1112     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1113 
1114 test_abort:;
1115 }
1116 
TEST_F(StorageTest,WriteReadAtOffset)1117 TEST_F(StorageTest, WriteReadAtOffset) {
1118     int rc;
1119     file_handle_t handle;
1120     size_t blk = 2048;
1121     size_t blk_cnt = 32;
1122     const char* fname = "test_write_at_offset";
1123 
1124     // create/truncate file.
1125     rc = storage_open_file(
1126             ss, &handle, fname,
1127             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1128             STORAGE_OP_COMPLETE);
1129     ASSERT_EQ(0, rc);
1130 
1131     // write a bunch of blocks filled with zeroes
1132     for (size_t i = 0; i < blk_cnt; i++) {
1133         rc = WriteZeroChunk(handle, i * blk, blk, true);
1134         ASSERT_EQ((int)blk, rc);
1135     }
1136 
1137     storage_off_t off1 = blk;
1138     storage_off_t off2 = blk * (blk_cnt - 1);
1139 
1140     // write known pattern data at non-zero offset1
1141     rc = WritePatternChunk(handle, off1, blk, true);
1142     ASSERT_EQ((int)blk, rc);
1143 
1144     // write known pattern data at non-zero offset2
1145     rc = WritePatternChunk(handle, off2, blk, true);
1146     ASSERT_EQ((int)blk, rc);
1147 
1148     // read data back at offset1
1149     rc = ReadPattern(handle, off1, blk, blk);
1150     ASSERT_EQ((int)blk, rc);
1151 
1152     // read data back at offset2
1153     rc = ReadPattern(handle, off2, blk, blk);
1154     ASSERT_EQ((int)blk, rc);
1155 
1156     // read partially written data at end of file(expect to get data only, no
1157     // padding)
1158     rc = ReadPatternEOF(handle, off2 + blk / 2, blk);
1159     ASSERT_EQ((int)blk / 2, rc);
1160 
1161     // read data at offset 0 (expect success and zero data)
1162     rc = ReadChunk(handle, 0, blk, blk, 0, 0);
1163     ASSERT_EQ((int)blk, rc);
1164 
1165     // read data from gap (expect success and zero data)
1166     rc = ReadChunk(handle, off1 + blk, blk, blk, 0, 0);
1167     ASSERT_EQ((int)blk, rc);
1168 
1169     // read partially written data (start pointing within written data)
1170     // (expect to get written data back and zeroes at the end)
1171     rc = ReadChunk(handle, off1 + blk / 2, blk, 0, blk / 2, blk / 2);
1172     ASSERT_EQ((int)blk, rc);
1173 
1174     // read partially written data (start pointing within unwritten data)
1175     // expect to get zeroes at the beginning and proper data at the end
1176     rc = ReadChunk(handle, off1 - blk / 2, blk, blk / 2, blk / 2, 0);
1177     ASSERT_EQ((int)blk, rc);
1178 
1179     // cleanup
1180     storage_close_file(handle);
1181     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1182 
1183 test_abort:;
1184 }
1185 
TEST_F(StorageTest,WriteReadAtOffsetSparse)1186 TEST_F(StorageTest, WriteReadAtOffsetSparse) {
1187     int rc;
1188     file_handle_t handle;
1189     size_t blk = 2048;
1190     size_t blk_cnt = 32;
1191     const char* fname = "test_write_at_offset";
1192 
1193     // create/truncate file.
1194     rc = storage_open_file(
1195             ss, &handle, fname,
1196             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1197             STORAGE_OP_COMPLETE);
1198     ASSERT_EQ(0, rc);
1199 
1200     storage_off_t off1 = blk;
1201     storage_off_t off2 = blk * (blk_cnt - 1);
1202 
1203     // write known pattern data at non-zero offset1
1204     rc = WritePatternChunk(handle, off1, blk, true);
1205     ASSERT_EQ((int)blk, rc);
1206 
1207     // write known pattern data at non-zero offset2
1208     rc = WritePatternChunk(handle, off2, blk, true);
1209     ASSERT_EQ((int)blk, rc);
1210 
1211     // read data back at offset1
1212     rc = ReadPattern(handle, off1, blk, blk);
1213     ASSERT_EQ((int)blk, rc);
1214 
1215     // read data back at offset2
1216     rc = ReadPattern(handle, off2, blk, blk);
1217     ASSERT_EQ((int)blk, rc);
1218 
1219     // read partially written data at end of file(expect to get data only, no
1220     // padding)
1221     rc = ReadPatternEOF(handle, off2 + blk / 2, blk);
1222     ASSERT_EQ((int)blk / 2, rc);
1223 
1224     // read data at offset 0 (expect success and zero data)
1225     rc = ReadChunk(handle, 0, blk, blk, 0, 0);
1226     ASSERT_EQ((int)blk, rc);
1227 
1228     // read data from gap (expect success and zero data)
1229     rc = ReadChunk(handle, off1 + blk, blk, blk, 0, 0);
1230     ASSERT_EQ((int)blk, rc);
1231 
1232     // read partially written data (start pointing within written data)
1233     // (expect to get written data back and zeroes at the end)
1234     rc = ReadChunk(handle, off1 + blk / 2, blk, 0, blk / 2, blk / 2);
1235     ASSERT_EQ((int)blk, rc);
1236 
1237     // read partially written data (start pointing within unwritten data)
1238     // expect to get zeroes at the beginning and proper data at the end
1239     rc = ReadChunk(handle, off1 - blk / 2, blk, blk / 2, blk / 2, 0);
1240     ASSERT_EQ((int)blk, rc);
1241 
1242     // set file size to half way into first written block
1243     rc = storage_set_file_size(handle, off1 + blk / 2, STORAGE_OP_COMPLETE);
1244     ASSERT_EQ(0, rc);
1245 
1246     // read partially written data at end of file(expect to get data only, no
1247     // padding)
1248     rc = ReadPatternEOF(handle, off1, blk);
1249     ASSERT_EQ((int)blk / 2, rc);
1250 
1251     // write known pattern data at non-zero offset2
1252     rc = WritePatternChunk(handle, off2, blk, true);
1253     ASSERT_EQ((int)blk, rc);
1254 
1255     // read data back at offset1
1256     rc = ReadPattern(handle, off1, blk / 2, blk / 2);
1257     ASSERT_EQ((int)blk / 2, rc);
1258 
1259     // read data from gap (expect success and zero data)
1260     rc = ReadChunk(handle, off1 + blk / 2, blk, blk, 0, 0);
1261     ASSERT_EQ((int)blk, rc);
1262 
1263     // write known pattern data at non-zero offset1 - test again with
1264     // set_file_size
1265     rc = WritePatternChunk(handle, off1, blk, true);
1266     ASSERT_EQ((int)blk, rc);
1267 
1268     // set file size to half way into first written block
1269     rc = storage_set_file_size(handle, off1 + blk / 2, STORAGE_OP_COMPLETE);
1270     ASSERT_EQ(0, rc);
1271 
1272     // read partially written data at end of file(expect to get data only, no
1273     // padding)
1274     rc = ReadPatternEOF(handle, off1, blk);
1275     ASSERT_EQ((int)blk / 2, rc);
1276 
1277     // set file size to offset2
1278     rc = storage_set_file_size(handle, off2, STORAGE_OP_COMPLETE);
1279     ASSERT_EQ(0, rc);
1280 
1281     // write known pattern data at non-zero offset2
1282     rc = WritePatternChunk(handle, off2, blk, true);
1283     ASSERT_EQ((int)blk, rc);
1284 
1285     // read data back at offset1
1286     rc = ReadPattern(handle, off1, blk / 2, blk / 2);
1287     ASSERT_EQ((int)blk / 2, rc);
1288 
1289     // read data from gap (expect success and zero data)
1290     rc = ReadChunk(handle, off1 + blk / 2, blk, blk, 0, 0);
1291     ASSERT_EQ((int)blk, rc);
1292 
1293     // cleanup
1294     storage_close_file(handle);
1295     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1296 
1297 test_abort:;
1298 }
1299 
1300 #ifndef STORAGE_FAKE
1301 // STORAGE_FAKE does not support multiple sessionsa
1302 
1303 // Leave a small transaction open with uncommitted data blocks. This test should
1304 // fit in the cache so no data should need to be written to disk. This can be
1305 // used on a newly wiped filesystem to test the cleanup path if storageproxyd
1306 // disconnects before anything has been written.
TEST_F(StorageInitNoCommitSmallTest,CreatePersistentNoCommitSmall)1307 TEST_F(StorageInitNoCommitSmallTest, CreatePersistentNoCommitSmall) {
1308     int rc;
1309     file_handle_t handle;
1310     const char* fname = "test_persistent_small_uncommited_file";
1311 
1312     rc = storage_open_session(&storage_test_ss_persist,
1313                               storage_test_client_port);
1314     ASSERT_EQ(0, rc);
1315 
1316     // create/truncate file.
1317     rc = storage_open_file(
1318             storage_test_ss_persist, &handle, fname,
1319             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0);
1320     ASSERT_EQ(0, rc);
1321 
1322     // close but do not delete file
1323     storage_close_file(handle);
1324 
1325 test_abort:;
1326 }
1327 
1328 // Leave large a transaction open with uncommitted data blocks. This can be used
1329 // on a newly wiped filesystem to leave it in a state where only data blocks
1330 // have been written and expose bugs in how we auto clear the td partition.
TEST_F(StorageInitNoCommitLargeTest,CreatePersistentNoCommitLarge)1331 TEST_F(StorageInitNoCommitLargeTest, CreatePersistentNoCommitLarge) {
1332     int rc;
1333     file_handle_t handle;
1334     size_t blk = 2048;
1335     // Size of file should be too large to fit in block cache
1336     size_t file_size = 64 * 2048;
1337     const char* fname = "test_persistent_large_uncommited_file";
1338 
1339     rc = storage_open_session(&storage_test_ss_persist,
1340                               storage_test_client_port);
1341     ASSERT_EQ(0, rc);
1342 
1343     // create/truncate file.
1344     rc = storage_open_file(
1345             storage_test_ss_persist, &handle, fname,
1346             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0);
1347     ASSERT_EQ(0, rc);
1348 
1349     // write a bunch of blocks filled with pattern
1350     rc = WritePattern(handle, 0, file_size, blk, false);
1351     ASSERT_EQ((int)file_size, rc);
1352 
1353     // close but do not delete file
1354     storage_close_file(handle);
1355 
1356 test_abort:;
1357 }
1358 
1359 // Empty test that can be used to close the session created by
1360 // CreatePersistentNoCommitSmall or CreatePersistentNoCommitLarge.
TEST_F(StorageInitNoCommitCleanupTest,NoCommitCleanup)1361 TEST_F(StorageInitNoCommitCleanupTest, NoCommitCleanup) {
1362     // Fixture setup function closes the previous persistent session.
1363 }
1364 #endif
1365 
TEST_F(StorageInitTest,CreatePersistent32K)1366 TEST_F(StorageInitTest, CreatePersistent32K) {
1367     int rc;
1368     file_handle_t handle;
1369     size_t blk = 2048;
1370     size_t file_size = 32768;
1371     const char* fname = "test_persistent_32K_file";
1372 
1373     // create/truncate file. Don't commit until the write is complete so we
1374     // only perform a single superblock update
1375     rc = storage_open_file(
1376             ss, &handle, fname,
1377             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0);
1378     ASSERT_EQ(0, rc);
1379 
1380     // write a bunch of blocks filled with pattern
1381     rc = WritePattern(handle, 0, file_size, blk, true);
1382     ASSERT_EQ((int)file_size, rc);
1383 
1384     // close but do not delete file
1385     storage_close_file(handle);
1386 
1387 test_abort:;
1388 }
1389 
TEST_F(StorageCheckTest,ReadPersistent32k)1390 TEST_F(StorageCheckTest, ReadPersistent32k) {
1391     int rc;
1392     file_handle_t handle;
1393     size_t exp_len = 32 * 1024;
1394     const char* fname = "test_persistent_32K_file";
1395 
1396     // create/truncate file.
1397     rc = storage_open_file(ss, &handle, fname, 0, 0);
1398     ASSERT_EQ(0, rc);
1399 
1400     rc = ReadPatternEOF(handle, 0, 2048);
1401     ASSERT_EQ((int)exp_len, rc);
1402 
1403     rc = ReadPatternEOF(handle, 0, 1024);
1404     ASSERT_EQ((int)exp_len, rc);
1405 
1406     rc = ReadPatternEOF(handle, 0, 332);
1407     ASSERT_EQ((int)exp_len, rc);
1408 
1409     // close but do not delete file
1410     storage_close_file(handle);
1411 
1412 test_abort:;
1413 }
1414 
TEST_F(StorageCleanTest,CleanUpPersistent32K)1415 TEST_F(StorageCleanTest, CleanUpPersistent32K) {
1416     int rc;
1417     const char* fname = "test_persistent_32K_file";
1418 
1419     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1420     rc = (rc == ERR_NOT_FOUND) ? 0 : rc;
1421     ASSERT_EQ(0, rc);
1422 
1423 test_abort:;
1424 }
1425 
TEST_F(StorageTest,WriteReadLong)1426 TEST_F(StorageTest, WriteReadLong) {
1427     int rc;
1428     file_handle_t handle;
1429     size_t wc = 10000;
1430     const char* fname = "test_write_read_long";
1431 
1432     uint32_t* test_buf_ = malloc(wc * sizeof(uint32_t));
1433     ASSERT_NE(NULL, test_buf_);
1434 
1435     rc = storage_open_file(
1436             ss, &handle, fname,
1437             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1438             STORAGE_OP_COMPLETE);
1439     ASSERT_EQ(0, rc);
1440 
1441     fill_pattern32(test_buf_, wc * sizeof(uint32_t), 0);
1442     rc = storage_write(handle, 0, test_buf_, wc * sizeof(uint32_t),
1443                        STORAGE_OP_COMPLETE);
1444     ASSERT_EQ((int)(wc * sizeof(uint32_t)), rc);
1445 
1446     rc = storage_read(handle, 0, test_buf_, wc * sizeof(uint32_t));
1447     ASSERT_EQ((int)(wc * sizeof(uint32_t)), rc);
1448 
1449     bool res = check_pattern32(test_buf_, wc * sizeof(uint32_t), 0);
1450     ASSERT_EQ(true, res);
1451 
1452     // cleanup
1453     storage_close_file(handle);
1454     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1455 
1456 test_abort:
1457     if (test_buf_)
1458         free(test_buf_);
1459 }
1460 
1461 // Negative tests
1462 
TEST_F(StorageTest,OpenInvalidFileName)1463 TEST_F(StorageTest, OpenInvalidFileName) {
1464     int rc;
1465     file_handle_t handle;
1466     const char* fname1 = "";
1467     const char* fname2 = "ffff$ffff";
1468     const char* fname3 = "ffff\\ffff";
1469     char max_name[STORAGE_MAX_NAME_LENGTH_BYTES + 1];
1470 
1471     rc = storage_open_file(
1472             ss, &handle, fname1,
1473             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1474             STORAGE_OP_COMPLETE);
1475     ASSERT_EQ(ERR_NOT_VALID, rc);
1476 
1477     rc = storage_open_file(
1478             ss, &handle, fname2,
1479             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1480             STORAGE_OP_COMPLETE);
1481     ASSERT_EQ(ERR_NOT_VALID, rc);
1482 
1483     rc = storage_open_file(
1484             ss, &handle, fname3,
1485             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1486             STORAGE_OP_COMPLETE);
1487     ASSERT_EQ(ERR_NOT_VALID, rc);
1488 
1489     /* max name */
1490     memset(max_name, 'a', sizeof(max_name));
1491     max_name[sizeof(max_name) - 1] = 0;
1492 
1493     rc = storage_open_file(
1494             ss, &handle, max_name,
1495             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1496             STORAGE_OP_COMPLETE);
1497     ASSERT_EQ(ERR_NOT_VALID, rc);
1498 
1499     max_name[sizeof(max_name) - 2] = 0;
1500     rc = storage_open_file(
1501             ss, &handle, max_name,
1502             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1503             STORAGE_OP_COMPLETE);
1504     ASSERT_EQ(0, rc);
1505 
1506     storage_close_file(handle);
1507     storage_delete_file(ss, max_name, STORAGE_OP_COMPLETE);
1508 
1509 test_abort:;
1510 }
1511 
TEST_F(StorageTest,BadFileHandle)1512 TEST_F(StorageTest, BadFileHandle) {
1513     int rc;
1514     file_handle_t handle;
1515     const char* fname = "test_invalid_file_handle";
1516 
1517     rc = storage_open_file(
1518             ss, &handle, fname,
1519             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1520             STORAGE_OP_COMPLETE);
1521     ASSERT_EQ(0, rc);
1522 
1523     // write to invalid file handle
1524     uint32_t val = 0xDEDBEEF;
1525     rc = storage_write(handle + 1, 0, &val, sizeof(val), STORAGE_OP_COMPLETE);
1526     ASSERT_EQ(ERR_NOT_VALID, rc);
1527 
1528     // read from invalid handle
1529     rc = storage_read(handle + 1, 0, &val, sizeof(val));
1530     ASSERT_EQ(ERR_NOT_VALID, rc);
1531 
1532     // set size
1533     rc = storage_set_file_size(handle + 1, 0, STORAGE_OP_COMPLETE);
1534     ASSERT_EQ(ERR_NOT_VALID, rc);
1535 
1536     // get size
1537     storage_off_t fsize = (storage_off_t)(-1);
1538     rc = storage_get_file_size(handle + 1, &fsize);
1539     ASSERT_EQ(ERR_NOT_VALID, rc);
1540 
1541     // close (there is no way to check errors here)
1542     storage_close_file(handle + 1);
1543 
1544     storage_close_file(handle);
1545     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1546 
1547 test_abort:;
1548 }
1549 
TEST_F(StorageTest,ClosedFileHandle)1550 TEST_F(StorageTest, ClosedFileHandle) {
1551     int rc;
1552     file_handle_t handle1;
1553     file_handle_t handle2;
1554     const char* fname1 = "test_invalid_file_handle1";
1555     const char* fname2 = "test_invalid_file_handle2";
1556 
1557     rc = storage_open_file(
1558             ss, &handle1, fname1,
1559             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1560             STORAGE_OP_COMPLETE);
1561     ASSERT_EQ(0, rc);
1562 
1563     rc = storage_open_file(
1564             ss, &handle2, fname2,
1565             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1566             STORAGE_OP_COMPLETE);
1567     ASSERT_EQ(0, rc);
1568 
1569     // close first file handle
1570     storage_close_file(handle1);
1571 
1572     // write to invalid file handle
1573     uint32_t val = 0xDEDBEEF;
1574     rc = storage_write(handle1, 0, &val, sizeof(val), STORAGE_OP_COMPLETE);
1575     ASSERT_EQ(ERR_NOT_VALID, rc);
1576 
1577     // read from invalid handle
1578     rc = storage_read(handle1, 0, &val, sizeof(val));
1579     ASSERT_EQ(ERR_NOT_VALID, rc);
1580 
1581     // set size
1582     rc = storage_set_file_size(handle1, 0, STORAGE_OP_COMPLETE);
1583     ASSERT_EQ(ERR_NOT_VALID, rc);
1584 
1585     // get size
1586     storage_off_t fsize = (storage_off_t)(-1);
1587     rc = storage_get_file_size(handle1, &fsize);
1588     ASSERT_EQ(ERR_NOT_VALID, rc);
1589 
1590     // close (there is no way to check errors here)
1591     storage_close_file(handle1);
1592 
1593     // clean up
1594     storage_close_file(handle2);
1595     storage_delete_file(ss, fname1, STORAGE_OP_COMPLETE);
1596     storage_delete_file(ss, fname2, STORAGE_OP_COMPLETE);
1597 
1598 test_abort:;
1599 }
1600 
1601 #ifndef STORAGE_FAKE
TEST_F(StorageTest,TransactDiscardInactive)1602 TEST_F(StorageTest, TransactDiscardInactive) {
1603     int rc;
1604 
1605     // discard current transaction (there should not be any)
1606     rc = storage_end_transaction(ss, false);
1607     ASSERT_EQ(0, rc);
1608 
1609     // try it again
1610     rc = storage_end_transaction(ss, false);
1611     ASSERT_EQ(0, rc);
1612 
1613 test_abort:;
1614 }
1615 
TEST_F(StorageTest,TransactCommitInactive)1616 TEST_F(StorageTest, TransactCommitInactive) {
1617     int rc;
1618 
1619     // try to commit current transaction
1620     rc = storage_end_transaction(ss, true);
1621     ASSERT_EQ(0, rc);
1622 
1623     // try it again
1624     rc = storage_end_transaction(ss, true);
1625     ASSERT_EQ(0, rc);
1626 
1627 test_abort:;
1628 }
1629 
TEST_F(StorageTest,TransactDiscardWrite)1630 TEST_F(StorageTest, TransactDiscardWrite) {
1631     int rc;
1632     file_handle_t handle;
1633     size_t blk = 2048;
1634     size_t exp_len = 32 * 1024;
1635     storage_off_t fsize = (storage_off_t)(-1);
1636     const char* fname = "test_transact_discard_write";
1637 
1638     // open create truncate file (with commit)
1639     rc = storage_open_file(
1640             ss, &handle, fname,
1641             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1642             STORAGE_OP_COMPLETE);
1643     ASSERT_EQ(0, rc);
1644 
1645     // check file size
1646     rc = storage_get_file_size(handle, &fsize);
1647     ASSERT_EQ(0, rc);
1648     ASSERT_EQ((storage_off_t)0, fsize);
1649 
1650     // write (without commit)
1651     rc = WritePattern(handle, 0, exp_len, blk, false);
1652     ASSERT_EQ((int)exp_len, rc);
1653 
1654     // check file size
1655     rc = storage_get_file_size(handle, &fsize);
1656     ASSERT_EQ(0, rc);
1657     ASSERT_EQ((storage_off_t)exp_len, fsize);
1658 
1659     // abort current transaction
1660     rc = storage_end_transaction(ss, false);
1661     ASSERT_EQ(0, rc);
1662 
1663     // check file size
1664     rc = storage_get_file_size(handle, &fsize);
1665     ASSERT_EQ(0, rc);
1666     ASSERT_EQ((storage_off_t)0, fsize);
1667 
1668     // cleanup
1669     storage_close_file(handle);
1670     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1671 
1672 test_abort:;
1673 }
1674 
TEST_F(StorageTest,TransactDiscardWriteAppend)1675 TEST_F(StorageTest, TransactDiscardWriteAppend) {
1676     int rc;
1677     file_handle_t handle;
1678     size_t blk = 2048;
1679     size_t exp_len = 32 * 1024;
1680     storage_off_t fsize = (storage_off_t)(-1);
1681     const char* fname = "test_transact_write_append";
1682 
1683     // open create truncate file (with commit)
1684     rc = storage_open_file(
1685             ss, &handle, fname,
1686             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1687             STORAGE_OP_COMPLETE);
1688     ASSERT_EQ(0, rc);
1689 
1690     // write data with commit
1691     rc = WritePattern(handle, 0, exp_len / 2, blk, true);
1692     ASSERT_EQ((int)exp_len / 2, rc);
1693 
1694     // write data without commit
1695     rc = WritePattern(handle, exp_len / 2, exp_len / 2, blk, false);
1696     ASSERT_EQ((int)exp_len / 2, rc);
1697 
1698     // check file size (should be exp_len)
1699     rc = storage_get_file_size(handle, &fsize);
1700     ASSERT_EQ(0, rc);
1701     ASSERT_EQ((storage_off_t)exp_len, fsize);
1702 
1703     // discard transaction
1704     rc = storage_end_transaction(ss, false);
1705     ASSERT_EQ(0, rc);
1706 
1707     // check file size, it should be exp_len/2
1708     rc = storage_get_file_size(handle, &fsize);
1709     ASSERT_EQ(0, rc);
1710     ASSERT_EQ((storage_off_t)exp_len / 2, fsize);
1711 
1712     // check file data
1713     rc = ReadPatternEOF(handle, 0, blk);
1714     ASSERT_EQ((int)exp_len / 2, rc);
1715 
1716     // cleanup
1717     storage_close_file(handle);
1718     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1719 
1720 test_abort:;
1721 }
1722 
TEST_F(StorageTest,TransactDiscardWriteRead)1723 TEST_F(StorageTest, TransactDiscardWriteRead) {
1724     int rc;
1725     file_handle_t handle;
1726     size_t blk = 2048;
1727     storage_off_t fsize = (storage_off_t)(-1);
1728     const char* fname = "test_transact_discard_write_read";
1729 
1730     // open create truncate file (with commit)
1731     rc = storage_open_file(
1732             ss, &handle, fname,
1733             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1734             STORAGE_OP_COMPLETE);
1735     ASSERT_EQ(0, rc);
1736 
1737     // check file size
1738     rc = storage_get_file_size(handle, &fsize);
1739     ASSERT_EQ(0, rc);
1740     ASSERT_EQ((storage_off_t)0, fsize);
1741 
1742     // Fill with zeroes (with commit)
1743     for (uint32_t i = 0; i < 32; i++) {
1744         rc = WriteZeroChunk(handle, i * blk, blk, true);
1745         ASSERT_EQ((int)blk, rc);
1746     }
1747 
1748     // check that test chunk is filled with zeroes
1749     rc = ReadChunk(handle, blk, blk, blk, 0, 0);
1750     ASSERT_EQ((int)blk, rc);
1751 
1752     // write test pattern (without commit)
1753     rc = WritePattern(handle, blk, blk, blk, false);
1754     ASSERT_EQ((int)blk, rc);
1755 
1756     // read it back an check pattern
1757     rc = ReadChunk(handle, blk, blk, 0, blk, 0);
1758     ASSERT_EQ((int)blk, rc);
1759 
1760     // abort current transaction
1761     rc = storage_end_transaction(ss, false);
1762     ASSERT_EQ(0, rc);
1763 
1764     // read same chunk back (should be filled with zeros)
1765     rc = ReadChunk(handle, blk, blk, blk, 0, 0);
1766     ASSERT_EQ((int)blk, rc);
1767 
1768     // cleanup
1769     storage_close_file(handle);
1770     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1771 
1772 test_abort:;
1773 }
1774 
TEST_F(StorageTest,TransactDiscardWriteMany)1775 TEST_F(StorageTest, TransactDiscardWriteMany) {
1776     int rc;
1777     file_handle_t handle1;
1778     file_handle_t handle2;
1779     size_t blk = 2048;
1780     size_t exp_len1 = 32 * 1024;
1781     size_t exp_len2 = 31 * 1024;
1782     storage_off_t fsize = (storage_off_t)(-1);
1783     const char* fname1 = "test_transact_discard_write_file1";
1784     const char* fname2 = "test_transact_discard_write_file2";
1785 
1786     // open create truncate (with commit)
1787     rc = storage_open_file(
1788             ss, &handle1, fname1,
1789             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1790             STORAGE_OP_COMPLETE);
1791     ASSERT_EQ(0, rc);
1792 
1793     // open create truncate (with commit)
1794     rc = storage_open_file(
1795             ss, &handle2, fname2,
1796             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1797             STORAGE_OP_COMPLETE);
1798     ASSERT_EQ(0, rc);
1799 
1800     // file1: fill file with pattern (without commit)
1801     rc = WritePattern(handle1, 0, exp_len1, blk, false);
1802     ASSERT_EQ((int)exp_len1, rc);
1803 
1804     // file2: fill file with pattern (without commit)
1805     rc = WritePattern(handle2, 0, exp_len2, blk, false);
1806     ASSERT_EQ((int)exp_len2, rc);
1807 
1808     // check file size, it should be exp_len1
1809     rc = storage_get_file_size(handle1, &fsize);
1810     ASSERT_EQ(0, rc);
1811     ASSERT_EQ((storage_off_t)exp_len1, fsize);
1812 
1813     // check file size, it should be exp_len2
1814     rc = storage_get_file_size(handle2, &fsize);
1815     ASSERT_EQ(0, rc);
1816     ASSERT_EQ((storage_off_t)exp_len2, fsize);
1817 
1818     // discard transaction
1819     rc = storage_end_transaction(ss, false);
1820     ASSERT_EQ(0, rc);
1821 
1822     // check file size, it should be 0
1823     rc = storage_get_file_size(handle1, &fsize);
1824     ASSERT_EQ(0, rc);
1825     ASSERT_EQ((storage_off_t)0, fsize);
1826 
1827     // check file size, it should be 0
1828     rc = storage_get_file_size(handle2, &fsize);
1829     ASSERT_EQ(0, rc);
1830     ASSERT_EQ((storage_off_t)0, fsize);
1831 
1832     // check data
1833     rc = ReadPatternEOF(handle1, 0, blk);
1834     ASSERT_EQ(0, rc);
1835 
1836     rc = ReadPatternEOF(handle2, 0, blk);
1837     ASSERT_EQ(0, rc);
1838 
1839     // cleanup
1840     storage_close_file(handle1);
1841     storage_delete_file(ss, fname1, STORAGE_OP_COMPLETE);
1842     storage_close_file(handle2);
1843     storage_delete_file(ss, fname2, STORAGE_OP_COMPLETE);
1844 
1845 test_abort:;
1846 }
1847 
TEST_F(StorageTest,TransactDiscardTruncate)1848 TEST_F(StorageTest, TransactDiscardTruncate) {
1849     int rc;
1850     file_handle_t handle;
1851     size_t blk = 2048;
1852     size_t exp_len = 32 * 1024;
1853     storage_off_t fsize = (storage_off_t)(-1);
1854     const char* fname = "test_transact_discard_truncate";
1855 
1856     // open create truncate file (with commit)
1857     rc = storage_open_file(
1858             ss, &handle, fname,
1859             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1860             STORAGE_OP_COMPLETE);
1861     ASSERT_EQ(0, rc);
1862 
1863     // write data (with commit)
1864     rc = WritePattern(handle, 0, exp_len, blk, true);
1865     ASSERT_EQ((int)exp_len, rc);
1866 
1867     // check file size
1868     rc = storage_get_file_size(handle, &fsize);
1869     ASSERT_EQ(0, rc);
1870     ASSERT_EQ((storage_off_t)exp_len, fsize);
1871 
1872     // close file
1873     storage_close_file(handle);
1874 
1875     // open truncate file (without commit)
1876     rc = storage_open_file(ss, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
1877     ASSERT_EQ(0, rc);
1878 
1879     // check file size
1880     rc = storage_get_file_size(handle, &fsize);
1881     ASSERT_EQ(0, rc);
1882     ASSERT_EQ((storage_off_t)0, fsize);
1883 
1884     // abort current transaction
1885     rc = storage_end_transaction(ss, false);
1886     ASSERT_EQ(0, rc);
1887 
1888     // check file size (should be an oruginal size)
1889     rc = storage_get_file_size(handle, &fsize);
1890     ASSERT_EQ(0, rc);
1891     ASSERT_EQ((storage_off_t)exp_len, fsize);
1892 
1893     // cleanup
1894     storage_close_file(handle);
1895     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1896 
1897 test_abort:;
1898 }
1899 
TEST_F(StorageTest,TransactDiscardSetSize)1900 TEST_F(StorageTest, TransactDiscardSetSize) {
1901     int rc;
1902     file_handle_t handle;
1903     size_t blk = 2048;
1904     size_t exp_len = 32 * 1024;
1905     storage_off_t fsize = (storage_off_t)(-1);
1906     const char* fname = "test_transact_discard_set_size";
1907 
1908     // open create truncate file (with commit)
1909     rc = storage_open_file(
1910             ss, &handle, fname,
1911             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1912             STORAGE_OP_COMPLETE);
1913     ASSERT_EQ(0, rc);
1914 
1915     // write data (with commit)
1916     rc = WritePattern(handle, 0, exp_len, blk, true);
1917     ASSERT_EQ((int)exp_len, rc);
1918 
1919     // check file size
1920     rc = storage_get_file_size(handle, &fsize);
1921     ASSERT_EQ(0, rc);
1922     ASSERT_EQ((storage_off_t)exp_len, fsize);
1923 
1924     // set file size to half of original (no commit)
1925     rc = storage_set_file_size(handle, (storage_off_t)exp_len / 2, 0);
1926     ASSERT_EQ(0, rc);
1927 
1928     // check file size
1929     rc = storage_get_file_size(handle, &fsize);
1930     ASSERT_EQ(0, rc);
1931     ASSERT_EQ((storage_off_t)exp_len / 2, fsize);
1932 
1933     // set file size to 1/3 of original (no commit)
1934     rc = storage_set_file_size(handle, (storage_off_t)exp_len / 3, 0);
1935     ASSERT_EQ(0, rc);
1936 
1937     // check file size
1938     rc = storage_get_file_size(handle, &fsize);
1939     ASSERT_EQ(0, rc);
1940     ASSERT_EQ((storage_off_t)exp_len / 3, fsize);
1941 
1942     // abort current transaction
1943     rc = storage_end_transaction(ss, false);
1944     ASSERT_EQ(0, rc);
1945 
1946     // check file size (should be an original size)
1947     rc = storage_get_file_size(handle, &fsize);
1948     ASSERT_EQ(0, rc);
1949     ASSERT_EQ((storage_off_t)exp_len, fsize);
1950 
1951     // cleanup
1952     storage_close_file(handle);
1953     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
1954 
1955 test_abort:;
1956 }
1957 
TEST_F(StorageTest,TransactDiscardDelete)1958 TEST_F(StorageTest, TransactDiscardDelete) {
1959     int rc;
1960     file_handle_t handle;
1961     size_t blk = 2048;
1962     size_t exp_len = 32 * 1024;
1963     storage_off_t fsize = (storage_off_t)(-1);
1964     const char* fname = "test_transact_discard_delete";
1965 
1966     // open create truncate file (with commit)
1967     rc = storage_open_file(
1968             ss, &handle, fname,
1969             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
1970             STORAGE_OP_COMPLETE);
1971     ASSERT_EQ(0, rc);
1972 
1973     // write data (with commit)
1974     rc = WritePattern(handle, 0, exp_len, blk, true);
1975     ASSERT_EQ((int)exp_len, rc);
1976 
1977     // close it
1978     storage_close_file(handle);
1979 
1980     // delete file (without commit)
1981     rc = storage_delete_file(ss, fname, 0);
1982     ASSERT_EQ(0, rc);
1983 
1984     // try to open it (should fail)
1985     rc = storage_open_file(ss, &handle, fname, 0, 0);
1986     ASSERT_EQ(ERR_NOT_FOUND, rc);
1987 
1988     // abort current transaction
1989     rc = storage_end_transaction(ss, false);
1990     ASSERT_EQ(0, rc);
1991 
1992     // try to open it
1993     rc = storage_open_file(ss, &handle, fname, 0, 0);
1994     ASSERT_EQ(0, rc);
1995 
1996     // check file size (should be an original size)
1997     rc = storage_get_file_size(handle, &fsize);
1998     ASSERT_EQ(0, rc);
1999     ASSERT_EQ((storage_off_t)exp_len, fsize);
2000 
2001     // cleanup
2002     storage_close_file(handle);
2003     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2004 
2005 test_abort:;
2006 }
2007 
TEST_F(StorageTest,TransactDiscardCreate)2008 TEST_F(StorageTest, TransactDiscardCreate) {
2009     int rc;
2010     file_handle_t handle;
2011     const char* fname = "test_transact_discard_create_excl";
2012 
2013     // delete test file just in case
2014     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2015 
2016     // create file (without commit)
2017     rc = storage_open_file(
2018             ss, &handle, fname,
2019             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE, 0);
2020     ASSERT_EQ(0, rc);
2021 
2022     // close it
2023     storage_close_file(handle);
2024 
2025     // open it again without create and without commit (expect success)
2026     rc = storage_open_file(ss, &handle, fname, 0, 0);
2027     ASSERT_EQ(0, rc);
2028 
2029     // close it
2030     storage_close_file(handle);
2031 
2032     // abort current transaction
2033     rc = storage_end_transaction(ss, false);
2034     ASSERT_EQ(0, rc);
2035 
2036     // open it again without create without commit (expect not found)
2037     rc = storage_open_file(ss, &handle, fname, 0, 0);
2038     ASSERT_EQ(ERR_NOT_FOUND, rc);
2039 
2040     // cleanup
2041     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2042 
2043 test_abort:;
2044 }
2045 
TEST_F(StorageTest,TransactCommitWrites)2046 TEST_F(StorageTest, TransactCommitWrites) {
2047     int rc;
2048     file_handle_t handle;
2049     file_handle_t handle_aux;
2050     size_t blk = 2048;
2051     size_t exp_len = 32 * 1024;
2052     storage_off_t fsize = (storage_off_t)(-1);
2053     const char* fname = "test_transact_commit_writes";
2054 
2055     // open create truncate file (with commit)
2056     rc = storage_open_file(
2057             ss, &handle, fname,
2058             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2059             STORAGE_OP_COMPLETE);
2060     ASSERT_EQ(0, rc);
2061 
2062     // open the same file in aux session
2063     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2064     ASSERT_EQ(0, rc);
2065 
2066     // check file size, it should be 0
2067     rc = storage_get_file_size(handle_aux, &fsize);
2068     ASSERT_EQ(0, rc);
2069     ASSERT_EQ((storage_off_t)0, fsize);
2070 
2071     // write data in primary session (without commit)
2072     rc = WritePattern(handle, 0, exp_len / 2, blk, false);
2073     ASSERT_EQ((int)exp_len / 2, rc);
2074 
2075     // write more data in primary (without commit)
2076     rc = WritePattern(handle, exp_len / 2, exp_len / 2, blk, false);
2077     ASSERT_EQ((int)exp_len / 2, rc);
2078 
2079     // check file size in aux session, it should still be 0
2080     rc = storage_get_file_size(handle_aux, &fsize);
2081     ASSERT_EQ(0, rc);
2082     ASSERT_EQ((storage_off_t)0, fsize);
2083 
2084     // commit current transaction
2085     rc = storage_end_transaction(ss, true);
2086     ASSERT_EQ(0, rc);
2087 
2088     // check file size of aux session, should fail
2089     rc = storage_get_file_size(handle_aux, &fsize);
2090     ASSERT_EQ(ERR_BUSY, rc);
2091 
2092     // abort transaction in aux session to recover
2093     rc = storage_end_transaction(ss_aux, false);
2094     ASSERT_EQ(0, rc);
2095 
2096     // check file size in aux session, it should be exp_len
2097     rc = storage_get_file_size(handle_aux, &fsize);
2098     ASSERT_EQ(0, rc);
2099     ASSERT_EQ((storage_off_t)exp_len, fsize);
2100 
2101     // check file size in primary session, it should be exp_len
2102     rc = storage_get_file_size(handle, &fsize);
2103     ASSERT_EQ(0, rc);
2104     ASSERT_EQ((storage_off_t)exp_len, fsize);
2105 
2106     // check data in primary session
2107     rc = ReadPatternEOF(handle, 0, blk);
2108     ASSERT_EQ((int)exp_len, rc);
2109 
2110     // check data in aux session
2111     rc = ReadPatternEOF(handle_aux, 0, blk);
2112     ASSERT_EQ((int)exp_len, rc);
2113 
2114     // cleanup
2115     storage_close_file(handle);
2116     storage_close_file(handle_aux);
2117     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2118 
2119 test_abort:;
2120 }
2121 
TEST_F(StorageTest,TransactCommitWrites2)2122 TEST_F(StorageTest, TransactCommitWrites2) {
2123     int rc;
2124     file_handle_t handle;
2125     file_handle_t handle_aux;
2126     size_t blk = 2048;
2127     storage_off_t fsize = (storage_off_t)(-1);
2128     const char* fname = "test_transact_commit_writes2";
2129 
2130     // open create truncate file (with commit)
2131     rc = storage_open_file(
2132             ss, &handle, fname,
2133             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2134             STORAGE_OP_COMPLETE);
2135     ASSERT_EQ(0, rc);
2136 
2137     // open the same file in separate session
2138     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2139     ASSERT_EQ(0, rc);
2140 
2141     // check file size
2142     rc = storage_get_file_size(handle, &fsize);
2143     ASSERT_EQ(0, rc);
2144     ASSERT_EQ((storage_off_t)0, fsize);
2145 
2146     rc = storage_get_file_size(handle_aux, &fsize);
2147     ASSERT_EQ(0, rc);
2148     ASSERT_EQ((storage_off_t)0, fsize);
2149 
2150     // discard transaction in aux_session
2151     rc = storage_end_transaction(ss_aux, false);
2152     ASSERT_EQ(0, rc);
2153 
2154     // Fill with zeroes (with commit)
2155     for (uint32_t i = 0; i < 8; i++) {
2156         rc = WriteZeroChunk(handle, i * blk, blk, true);
2157         ASSERT_EQ((int)blk, rc);
2158     }
2159 
2160     // check that test chunks is filled with zeroes
2161     rc = ReadChunk(handle, blk, blk, blk, 0, 0);
2162     ASSERT_EQ((int)blk, rc);
2163 
2164     rc = ReadChunk(handle, 2 * blk, blk, blk, 0, 0);
2165     ASSERT_EQ((int)blk, rc);
2166 
2167     // write test pattern (without commit)
2168     rc = WritePattern(handle, blk, blk, blk, false);
2169     ASSERT_EQ((int)blk, rc);
2170 
2171     // write test pattern (without commit)
2172     rc = WritePattern(handle, 2 * blk, blk, blk, false);
2173     ASSERT_EQ((int)blk, rc);
2174 
2175     // read it back and check pattern
2176     rc = ReadChunk(handle, blk, blk, 0, blk, 0);
2177     ASSERT_EQ((int)blk, rc);
2178 
2179     rc = ReadChunk(handle, 2 * blk, blk, 0, blk, 0);
2180     ASSERT_EQ((int)blk, rc);
2181 
2182     // In aux session it still should be empty
2183     rc = ReadChunk(handle_aux, blk, blk, blk, 0, 0);
2184     ASSERT_EQ((int)blk, rc);
2185 
2186     rc = ReadChunk(handle_aux, 2 * blk, blk, blk, 0, 0);
2187     ASSERT_EQ((int)blk, rc);
2188 
2189     // commit current transaction
2190     rc = storage_end_transaction(ss, true);
2191     ASSERT_EQ(0, rc);
2192 
2193     // read same chunk back in primary session
2194     rc = ReadChunk(handle, blk, blk, 0, blk, 0);
2195     ASSERT_EQ((int)blk, rc);
2196 
2197     rc = ReadChunk(handle, 2 * blk, blk, 0, blk, 0);
2198     ASSERT_EQ((int)blk, rc);
2199 
2200     // read same chunk back in aux session
2201     rc = ReadChunk(handle_aux, blk, blk, 0, blk, 0);
2202     ASSERT_EQ(ERR_BUSY, rc);
2203 
2204     rc = ReadChunk(handle_aux, 2 * blk, blk, 0, blk, 0);
2205     ASSERT_EQ(ERR_BUSY, rc);
2206 
2207     // abort transaction in aux session
2208     rc = storage_end_transaction(ss_aux, false);
2209     ASSERT_EQ(0, rc);
2210 
2211     // read same chunk again in aux session
2212     rc = ReadChunk(handle_aux, blk, blk, 0, blk, 0);
2213     ASSERT_EQ((int)blk, rc);
2214 
2215     rc = ReadChunk(handle_aux, 2 * blk, blk, 0, blk, 0);
2216     ASSERT_EQ((int)blk, rc);
2217 
2218     // cleanup
2219     storage_close_file(handle);
2220     storage_close_file(handle_aux);
2221     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2222 
2223 test_abort:;
2224 }
2225 
TEST_F(StorageTest,TransactCommitSetSize)2226 TEST_F(StorageTest, TransactCommitSetSize) {
2227     int rc;
2228     file_handle_t handle;
2229     file_handle_t handle_aux;
2230     size_t blk = 2048;
2231     size_t exp_len = 32 * 1024;
2232     storage_off_t fsize = (storage_off_t)(-1);
2233     const char* fname = "test_transact_commit_set_size";
2234 
2235     // open create truncate file (with commit)
2236     rc = storage_open_file(
2237             ss, &handle, fname,
2238             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2239             STORAGE_OP_COMPLETE);
2240     ASSERT_EQ(0, rc);
2241 
2242     // open the same file in separate session
2243     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2244     ASSERT_EQ(0, rc);
2245 
2246     // write data (with commit)
2247     rc = WritePattern(handle, 0, exp_len, blk, true);
2248     ASSERT_EQ((int)exp_len, rc);
2249 
2250     // check file size
2251     rc = storage_get_file_size(handle, &fsize);
2252     ASSERT_EQ(0, rc);
2253     ASSERT_EQ((storage_off_t)exp_len, fsize);
2254 
2255     // same in aux session
2256     rc = storage_get_file_size(handle_aux, &fsize);
2257     ASSERT_EQ(0, rc);
2258     ASSERT_EQ((storage_off_t)exp_len, fsize);
2259 
2260     // set file size to half of original (no commit)
2261     rc = storage_set_file_size(handle, (storage_off_t)exp_len / 2, 0);
2262     ASSERT_EQ(0, rc);
2263 
2264     // check file size
2265     rc = storage_get_file_size(handle, &fsize);
2266     ASSERT_EQ(0, rc);
2267     ASSERT_EQ((storage_off_t)exp_len / 2, fsize);
2268 
2269     rc = storage_get_file_size(handle_aux, &fsize);
2270     ASSERT_EQ(0, rc);
2271     ASSERT_EQ((storage_off_t)exp_len, fsize);
2272 
2273     // set file size to 1/3 of original (no commit)
2274     rc = storage_set_file_size(handle, (storage_off_t)exp_len / 3, 0);
2275     ASSERT_EQ(0, rc);
2276 
2277     // check file size
2278     rc = storage_get_file_size(handle, &fsize);
2279     ASSERT_EQ(0, rc);
2280     ASSERT_EQ((storage_off_t)exp_len / 3, fsize);
2281 
2282     rc = storage_get_file_size(handle_aux, &fsize);
2283     ASSERT_EQ(0, rc);
2284     ASSERT_EQ((storage_off_t)exp_len, fsize);
2285 
2286     // commit current transaction
2287     rc = storage_end_transaction(ss, true);
2288     ASSERT_EQ(0, rc);
2289 
2290     // check file size (should be 1/3 of an original size)
2291     rc = storage_get_file_size(handle, &fsize);
2292     ASSERT_EQ(0, rc);
2293     ASSERT_EQ((storage_off_t)exp_len / 3, fsize);
2294 
2295     // check file size from aux session
2296     rc = storage_get_file_size(handle_aux, &fsize);
2297     ASSERT_EQ(ERR_BUSY, rc);
2298 
2299     // abort transaction
2300     rc = storage_end_transaction(ss_aux, false);
2301     ASSERT_EQ(0, rc);
2302 
2303     // check again
2304     rc = storage_get_file_size(handle_aux, &fsize);
2305     ASSERT_EQ(0, rc);
2306     ASSERT_EQ((storage_off_t)exp_len / 3, fsize);
2307 
2308     // write data, increasing file size to exp_len (no commit)
2309     rc = WritePattern(handle, 0, exp_len, blk, false);
2310     ASSERT_EQ((int)exp_len, rc);
2311 
2312     // check file size
2313     rc = storage_get_file_size(handle, &fsize);
2314     ASSERT_EQ(0, rc);
2315     ASSERT_EQ((storage_off_t)exp_len, fsize);
2316 
2317     // abort aux transaction
2318     rc = storage_end_transaction(ss_aux, false);
2319     ASSERT_EQ(0, rc);
2320 
2321     // check file size from aux session
2322     rc = storage_get_file_size(handle_aux, &fsize);
2323     ASSERT_EQ(0, rc);
2324     ASSERT_EQ((storage_off_t)exp_len / 3, fsize);
2325 
2326     // set file size without actually changing size, but ask to commit
2327     rc = storage_set_file_size(handle, (storage_off_t)exp_len,
2328                                STORAGE_OP_COMPLETE);
2329     ASSERT_EQ(0, rc);
2330 
2331     // abort aux transaction
2332     rc = storage_end_transaction(ss_aux, false);
2333     ASSERT_EQ(0, rc);
2334 
2335     // check file size from aux session
2336     rc = storage_get_file_size(handle_aux, &fsize);
2337     ASSERT_EQ(0, rc);
2338     ASSERT_EQ((storage_off_t)exp_len, fsize);
2339 
2340     // cleanup
2341     storage_close_file(handle);
2342     storage_close_file(handle_aux);
2343     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2344 
2345 test_abort:;
2346 }
2347 
TEST_F(StorageTest,TransactCommitDelete)2348 TEST_F(StorageTest, TransactCommitDelete) {
2349     int rc;
2350     file_handle_t handle;
2351     file_handle_t handle_aux;
2352     size_t blk = 2048;
2353     size_t exp_len = 32 * 1024;
2354     const char* fname = "test_transact_commit_delete";
2355 
2356     // open create truncate file (with commit)
2357     rc = storage_open_file(
2358             ss, &handle, fname,
2359             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2360             STORAGE_OP_COMPLETE);
2361     ASSERT_EQ(0, rc);
2362 
2363     // write data (with commit)
2364     rc = WritePattern(handle, 0, exp_len, blk, true);
2365     ASSERT_EQ((int)exp_len, rc);
2366 
2367     // close it
2368     storage_close_file(handle);
2369 
2370     // open the same file in separate session
2371     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2372     ASSERT_EQ(0, rc);
2373     storage_close_file(handle_aux);
2374 
2375     // delete file (without commit)
2376     rc = storage_delete_file(ss, fname, 0);
2377     ASSERT_EQ(0, rc);
2378 
2379     // try to open it (should fail)
2380     rc = storage_open_file(ss, &handle, fname, 0, 0);
2381     ASSERT_EQ(ERR_NOT_FOUND, rc);
2382 
2383     // open the same file in separate session (should be fine)
2384     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2385     ASSERT_EQ(0, rc);
2386     storage_close_file(handle_aux);
2387 
2388     // commit current transaction
2389     rc = storage_end_transaction(ss, true);
2390     ASSERT_EQ(0, rc);
2391 
2392     // try to open it (still fails)
2393     rc = storage_open_file(ss, &handle, fname, 0, 0);
2394     ASSERT_EQ(ERR_NOT_FOUND, rc);
2395 
2396     // open the same file in separate session (should fail)
2397     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2398     ASSERT_EQ(ERR_NOT_FOUND, rc);
2399 
2400 test_abort:;
2401 }
2402 
TEST_F(StorageTest,TransactCommitTruncate)2403 TEST_F(StorageTest, TransactCommitTruncate) {
2404     int rc;
2405     file_handle_t handle;
2406     file_handle_t handle_aux;
2407     size_t blk = 2048;
2408     size_t exp_len = 32 * 1024;
2409     storage_off_t fsize = (storage_off_t)(-1);
2410     const char* fname = "test_transact_commit_truncate";
2411 
2412     // open create truncate file (with commit)
2413     rc = storage_open_file(
2414             ss, &handle, fname,
2415             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2416             STORAGE_OP_COMPLETE);
2417     ASSERT_EQ(0, rc);
2418 
2419     // write data (with commit)
2420     rc = WritePattern(handle, 0, exp_len, blk, true);
2421     ASSERT_EQ((int)exp_len, rc);
2422 
2423     // check file size
2424     rc = storage_get_file_size(handle, &fsize);
2425     ASSERT_EQ(0, rc);
2426     ASSERT_EQ((storage_off_t)exp_len, fsize);
2427 
2428     // close file
2429     storage_close_file(handle);
2430 
2431     // check from different session
2432     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2433     ASSERT_EQ(0, rc);
2434 
2435     rc = storage_get_file_size(handle_aux, &fsize);
2436     ASSERT_EQ(0, rc);
2437     ASSERT_EQ((storage_off_t)exp_len, fsize);
2438 
2439     // open truncate file (without commit)
2440     rc = storage_open_file(ss, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
2441     ASSERT_EQ(0, rc);
2442 
2443     // check file size
2444     rc = storage_get_file_size(handle, &fsize);
2445     ASSERT_EQ(0, rc);
2446     ASSERT_EQ((storage_off_t)0, fsize);
2447 
2448     rc = storage_get_file_size(handle_aux, &fsize);
2449     ASSERT_EQ(0, rc);
2450     ASSERT_EQ((storage_off_t)exp_len, fsize);
2451 
2452     // commit current transaction
2453     rc = storage_end_transaction(ss, true);
2454     ASSERT_EQ(0, rc);
2455 
2456     // check file size (should be 0)
2457     rc = storage_get_file_size(handle, &fsize);
2458     ASSERT_EQ(0, rc);
2459     ASSERT_EQ((storage_off_t)0, fsize);
2460 
2461     // check file size in aux session (should be ERR_BUSY)
2462     rc = storage_get_file_size(handle_aux, &fsize);
2463     ASSERT_EQ(ERR_BUSY, rc);
2464 
2465     // abort transaction in aux session
2466     rc = storage_end_transaction(ss_aux, false);
2467     ASSERT_EQ(0, rc);
2468 
2469     // check again
2470     rc = storage_get_file_size(handle_aux, &fsize);
2471     ASSERT_EQ(0, rc);
2472     ASSERT_EQ((storage_off_t)0, fsize);
2473 
2474     // cleanup
2475     storage_close_file(handle);
2476     storage_close_file(handle_aux);
2477     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2478 
2479 test_abort:;
2480 }
2481 
TEST_F(StorageTest,TransactCommitCreate)2482 TEST_F(StorageTest, TransactCommitCreate) {
2483     int rc;
2484     file_handle_t handle;
2485     file_handle_t handle_aux;
2486     storage_off_t fsize = (storage_off_t)(-1);
2487     const char* fname = "test_transact_commit_create";
2488 
2489     // delete test file just in case
2490     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2491 
2492     // check from different session
2493     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2494     ASSERT_EQ(ERR_NOT_FOUND, rc);
2495 
2496     // create file (without commit)
2497     rc = storage_open_file(
2498             ss, &handle, fname,
2499             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE, 0);
2500     ASSERT_EQ(0, rc);
2501 
2502     // check file size
2503     rc = storage_get_file_size(handle, &fsize);
2504     ASSERT_EQ(0, rc);
2505     ASSERT_EQ((storage_off_t)0, fsize);
2506 
2507     // close file
2508     storage_close_file(handle);
2509 
2510     // check from aux session (should fail)
2511     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2512     ASSERT_EQ(ERR_NOT_FOUND, rc);
2513 
2514     // commit current transaction
2515     rc = storage_end_transaction(ss, true);
2516     ASSERT_EQ(0, rc);
2517 
2518     // check open from normal session
2519     rc = storage_open_file(ss, &handle, fname, 0, 0);
2520     ASSERT_EQ(0, rc);
2521 
2522     // check open from aux session (should succeed)
2523     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2524     ASSERT_EQ(0, rc);
2525 
2526     // cleanup
2527     storage_close_file(handle);
2528     storage_close_file(handle_aux);
2529     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2530 
2531 test_abort:;
2532 }
2533 
TEST_F(StorageTest,TransactCommitCreateMany)2534 TEST_F(StorageTest, TransactCommitCreateMany) {
2535     int rc;
2536     file_handle_t handle1;
2537     file_handle_t handle2;
2538     file_handle_t handle1_aux;
2539     file_handle_t handle2_aux;
2540     storage_off_t fsize = (storage_off_t)(-1);
2541     const char* fname1 = "test_transact_commit_create1";
2542     const char* fname2 = "test_transact_commit_create2";
2543 
2544     // delete test file just in case
2545     storage_delete_file(ss, fname1, STORAGE_OP_COMPLETE);
2546     storage_delete_file(ss, fname2, STORAGE_OP_COMPLETE);
2547 
2548     // create file (without commit)
2549     rc = storage_open_file(
2550             ss, &handle1, fname1,
2551             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE, 0);
2552     ASSERT_EQ(0, rc);
2553 
2554     // create file (without commit)
2555     rc = storage_open_file(
2556             ss, &handle2, fname2,
2557             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE, 0);
2558     ASSERT_EQ(0, rc);
2559 
2560     // check file sizes
2561     rc = storage_get_file_size(handle1, &fsize);
2562     ASSERT_EQ(0, rc);
2563     ASSERT_EQ((storage_off_t)0, fsize);
2564 
2565     rc = storage_get_file_size(handle1, &fsize);
2566     ASSERT_EQ(0, rc);
2567     ASSERT_EQ((storage_off_t)0, fsize);
2568 
2569     // close files
2570     storage_close_file(handle1);
2571     storage_close_file(handle2);
2572 
2573     rc = storage_open_file(ss_aux, &handle1_aux, fname1, 0, 0);
2574     ASSERT_EQ(ERR_NOT_FOUND, rc);
2575 
2576     rc = storage_open_file(ss_aux, &handle2_aux, fname2, 0, 0);
2577     ASSERT_EQ(ERR_NOT_FOUND, rc);
2578 
2579     // commit current transaction
2580     rc = storage_end_transaction(ss, true);
2581     ASSERT_EQ(0, rc);
2582 
2583     // open from primary session
2584     rc = storage_open_file(ss, &handle1, fname1, 0, 0);
2585     ASSERT_EQ(0, rc);
2586 
2587     rc = storage_open_file(ss, &handle2, fname2, 0, 0);
2588     ASSERT_EQ(0, rc);
2589 
2590     // open from aux session
2591     rc = storage_open_file(ss_aux, &handle1_aux, fname1, 0, 0);
2592     ASSERT_EQ(0, rc);
2593 
2594     rc = storage_open_file(ss_aux, &handle2_aux, fname2, 0, 0);
2595     ASSERT_EQ(0, rc);
2596 
2597     // cleanup
2598     storage_close_file(handle1);
2599     storage_close_file(handle1_aux);
2600     storage_delete_file(ss, fname1, STORAGE_OP_COMPLETE);
2601     storage_close_file(handle2);
2602     storage_close_file(handle2_aux);
2603     storage_delete_file(ss, fname2, STORAGE_OP_COMPLETE);
2604 
2605 test_abort:;
2606 }
2607 
TEST_F(StorageTest,TransactCommitWriteMany)2608 TEST_F(StorageTest, TransactCommitWriteMany) {
2609     int rc;
2610     file_handle_t handle1;
2611     file_handle_t handle2;
2612     file_handle_t handle1_aux;
2613     file_handle_t handle2_aux;
2614     size_t blk = 2048;
2615     size_t exp_len1 = 32 * 1024;
2616     size_t exp_len2 = 31 * 1024;
2617     storage_off_t fsize = (storage_off_t)(-1);
2618     const char* fname1 = "test_transact_commit_write_file1";
2619     const char* fname2 = "test_transact_commit_write_file2";
2620 
2621     // open create truncate (with commit)
2622     rc = storage_open_file(
2623             ss, &handle1, fname1,
2624             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2625             STORAGE_OP_COMPLETE);
2626     ASSERT_EQ(0, rc);
2627 
2628     // open create truncate (with commit)
2629     rc = storage_open_file(
2630             ss, &handle2, fname2,
2631             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2632             STORAGE_OP_COMPLETE);
2633     ASSERT_EQ(0, rc);
2634 
2635     // open same files from aux session
2636     rc = storage_open_file(ss_aux, &handle1_aux, fname1, 0, 0);
2637     ASSERT_EQ(0, rc);
2638 
2639     rc = storage_open_file(ss_aux, &handle2_aux, fname2, 0, 0);
2640     ASSERT_EQ(0, rc);
2641 
2642     // file1: fill file with pattern (without commit)
2643     rc = WritePattern(handle1, 0, exp_len1, blk, false);
2644     ASSERT_EQ((int)exp_len1, rc);
2645 
2646     // file2: fill file with pattern (without commit)
2647     rc = WritePattern(handle2, 0, exp_len2, blk, false);
2648     ASSERT_EQ((int)exp_len2, rc);
2649 
2650     // check file size, it should be exp_len1
2651     rc = storage_get_file_size(handle1, &fsize);
2652     ASSERT_EQ(0, rc);
2653     ASSERT_EQ((storage_off_t)exp_len1, fsize);
2654 
2655     // check file size, it should be exp_len2
2656     rc = storage_get_file_size(handle2, &fsize);
2657     ASSERT_EQ(0, rc);
2658     ASSERT_EQ((storage_off_t)exp_len2, fsize);
2659 
2660     // check file sizes from aux session (should be 0)
2661     rc = storage_get_file_size(handle1_aux, &fsize);
2662     ASSERT_EQ(0, rc);
2663     ASSERT_EQ((storage_off_t)0, fsize);
2664 
2665     rc = storage_get_file_size(handle2_aux, &fsize);
2666     ASSERT_EQ(0, rc);
2667     ASSERT_EQ((storage_off_t)0, fsize);
2668 
2669     // commit transaction
2670     rc = storage_end_transaction(ss, true);
2671     ASSERT_EQ(0, rc);
2672 
2673     // check file size, it should be exp_len1
2674     rc = storage_get_file_size(handle1, &fsize);
2675     ASSERT_EQ(0, rc);
2676     ASSERT_EQ((storage_off_t)exp_len1, fsize);
2677 
2678     // check file size, it should be exp_len2
2679     rc = storage_get_file_size(handle2, &fsize);
2680     ASSERT_EQ(0, rc);
2681     ASSERT_EQ((storage_off_t)exp_len2, fsize);
2682 
2683     // from aux session
2684     rc = storage_get_file_size(handle1_aux, &fsize);
2685     ASSERT_EQ(ERR_BUSY, rc);
2686 
2687     rc = storage_end_transaction(ss_aux, false);
2688     ASSERT_EQ(0, rc);
2689 
2690     rc = storage_get_file_size(handle1_aux, &fsize);
2691     ASSERT_EQ(0, rc);
2692     ASSERT_EQ((storage_off_t)exp_len1, fsize);
2693 
2694     rc = storage_get_file_size(handle2_aux, &fsize);
2695     ASSERT_EQ(0, rc);
2696     ASSERT_EQ((storage_off_t)exp_len2, fsize);
2697 
2698     // check data
2699     rc = ReadPatternEOF(handle1, 0, blk);
2700     ASSERT_EQ((int)exp_len1, rc);
2701 
2702     rc = ReadPatternEOF(handle2, 0, blk);
2703     ASSERT_EQ((int)exp_len2, rc);
2704 
2705     rc = ReadPatternEOF(handle1_aux, 0, blk);
2706     ASSERT_EQ((int)exp_len1, rc);
2707 
2708     rc = ReadPatternEOF(handle2_aux, 0, blk);
2709     ASSERT_EQ((int)exp_len2, rc);
2710 
2711     // cleanup
2712     storage_close_file(handle1);
2713     storage_close_file(handle1_aux);
2714     storage_delete_file(ss, fname1, STORAGE_OP_COMPLETE);
2715     storage_close_file(handle2);
2716     storage_close_file(handle2_aux);
2717     storage_delete_file(ss, fname2, STORAGE_OP_COMPLETE);
2718 
2719 test_abort:;
2720 }
2721 
TEST_F(StorageTest,TransactCommitDeleteCreate)2722 TEST_F(StorageTest, TransactCommitDeleteCreate) {
2723     int rc;
2724     file_handle_t handle;
2725     file_handle_t handle_aux;
2726     size_t blk = 2048;
2727     size_t exp_len = 32 * 1024;
2728     storage_off_t fsize = (storage_off_t)(-1);
2729     const char* fname = "test_transact_delete_create";
2730 
2731     // open create truncate file (with commit)
2732     rc = storage_open_file(
2733             ss, &handle, fname,
2734             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2735             STORAGE_OP_COMPLETE);
2736     ASSERT_EQ(0, rc);
2737 
2738     // write data (with commit)
2739     rc = WritePattern(handle, 0, exp_len, blk, true);
2740     ASSERT_EQ((int)exp_len, rc);
2741 
2742     // close it
2743     storage_close_file(handle);
2744 
2745     // delete file (without commit)
2746     rc = storage_delete_file(ss, fname, 0);
2747     ASSERT_EQ(0, rc);
2748 
2749     // try to open it (should fail)
2750     rc = storage_open_file(ss, &handle, fname, 0, 0);
2751     ASSERT_EQ(ERR_NOT_FOUND, rc);
2752 
2753     // try to open it in aux session (should succeed)
2754     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2755     ASSERT_EQ(0, rc);
2756 
2757     // create file with the same name (no commit)
2758     rc = storage_open_file(
2759             ss, &handle, fname,
2760             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE, 0);
2761     ASSERT_EQ(0, rc);
2762 
2763     // write half of data (with commit)
2764     rc = WritePattern(handle, 0, exp_len / 2, blk, true);
2765     ASSERT_EQ((int)exp_len / 2, rc);
2766 
2767     // check file size (should be half)
2768     rc = storage_get_file_size(handle, &fsize);
2769     ASSERT_EQ(0, rc);
2770     ASSERT_EQ((storage_off_t)exp_len / 2, fsize);
2771 
2772     // commit transaction
2773     rc = storage_end_transaction(ss, true);
2774     ASSERT_EQ(0, rc);
2775 
2776     // check data
2777     rc = ReadPatternEOF(handle, 0, blk);
2778     ASSERT_EQ((int)exp_len / 2, rc);
2779 
2780     // check from aux session
2781     rc = storage_get_file_size(handle_aux, &fsize);
2782     ASSERT_EQ(ERR_NOT_VALID, rc);
2783 
2784     // abort trunsaction
2785     rc = storage_end_transaction(ss_aux, false);
2786     ASSERT_EQ(0, rc);
2787 
2788     // and try again
2789     rc = storage_get_file_size(handle_aux, &fsize);
2790     ASSERT_EQ(ERR_NOT_VALID, rc);
2791 
2792     // close file and reopen it again
2793     storage_close_file(handle_aux);
2794     rc = storage_open_file(ss_aux, &handle_aux, fname, 0, 0);
2795     ASSERT_EQ(0, rc);
2796 
2797     rc = storage_get_file_size(handle_aux, &fsize);
2798     ASSERT_EQ(0, rc);
2799     ASSERT_EQ((storage_off_t)exp_len / 2, fsize);
2800 
2801     rc = ReadPatternEOF(handle_aux, 0, blk);
2802     ASSERT_EQ((int)exp_len / 2, rc);
2803 
2804     // cleanup
2805     storage_close_file(handle);
2806     storage_close_file(handle_aux);
2807     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2808 
2809 test_abort:;
2810 }
2811 
TEST_F(StorageTest,TransactRewriteExistingTruncate)2812 TEST_F(StorageTest, TransactRewriteExistingTruncate) {
2813     int rc;
2814     file_handle_t handle;
2815     size_t blk = 2048;
2816     const char* fname = "test_transact_rewrite_existing_truncate";
2817 
2818     // open create truncate file (with commit)
2819     rc = storage_open_file(
2820             ss, &handle, fname,
2821             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2822             STORAGE_OP_COMPLETE);
2823     ASSERT_EQ(0, rc);
2824 
2825     // close it
2826     storage_close_file(handle);
2827 
2828     // up
2829     for (uint32_t i = 1; i < 32; i++) {
2830         // open truncate (no commit)
2831         rc = storage_open_file(ss, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE,
2832                                0);
2833         ASSERT_EQ(0, rc);
2834 
2835         // write data (with commit)
2836         rc = WritePattern(handle, 0, i * blk, blk, true);
2837         ASSERT_EQ((int)(i * blk), rc);
2838 
2839         // close
2840         storage_close_file(handle);
2841     }
2842 
2843     // down
2844     for (uint32_t i = 1; i < 32; i++) {
2845         // open truncate (no commit)
2846         rc = storage_open_file(ss, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE,
2847                                0);
2848         ASSERT_EQ(0, rc);
2849 
2850         // write data (with commit)
2851         rc = WritePattern(handle, 0, (32 - i) * blk, blk, true);
2852         ASSERT_EQ((int)((32 - i) * blk), rc);
2853 
2854         // close
2855         storage_close_file(handle);
2856     }
2857 
2858     // cleanup
2859     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2860 
2861 test_abort:;
2862 }
2863 
TEST_F(StorageTest,TransactRewriteExistingSetSize)2864 TEST_F(StorageTest, TransactRewriteExistingSetSize) {
2865     int rc;
2866     file_handle_t handle;
2867     size_t blk = 2048;
2868     const char* fname = "test_transact_rewrite_existing_set_size";
2869 
2870     // open create truncate file (with commit)
2871     rc = storage_open_file(
2872             ss, &handle, fname,
2873             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2874             STORAGE_OP_COMPLETE);
2875     ASSERT_EQ(0, rc);
2876 
2877     // close it
2878     storage_close_file(handle);
2879 
2880     // up
2881     for (unsigned int i = 1; i < 32; i++) {
2882         // open truncate (no commit)
2883         rc = storage_open_file(ss, &handle, fname, 0, 0);
2884         ASSERT_EQ(0, rc);
2885 
2886         // write data (with commit)
2887         rc = WritePattern(handle, 0, i * blk, blk, false);
2888         ASSERT_EQ((int)(i * blk), rc);
2889 
2890         // update size (with commit)
2891         rc = storage_set_file_size(handle, i * blk, STORAGE_OP_COMPLETE);
2892         ASSERT_EQ(0, rc);
2893 
2894         // close
2895         storage_close_file(handle);
2896     }
2897 
2898     // down
2899     for (unsigned int i = 1; i < 32; i++) {
2900         // open trancate (no commit)
2901         rc = storage_open_file(ss, &handle, fname, 0, 0);
2902         ASSERT_EQ(0, rc);
2903 
2904         // write data (with commit)
2905         rc = WritePattern(handle, 0, (32 - i) * blk, blk, false);
2906         ASSERT_EQ((int)((32 - i) * blk), rc);
2907 
2908         // update size (with commit)
2909         rc = storage_set_file_size(handle, (32 - i) * blk, STORAGE_OP_COMPLETE);
2910         ASSERT_EQ(0, rc);
2911 
2912         // close
2913         storage_close_file(handle);
2914     }
2915 
2916     // cleanup
2917     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2918 
2919 test_abort:;
2920 }
2921 
TEST_F(StorageTest,TransactResumeAfterNonFatalError)2922 TEST_F(StorageTest, TransactResumeAfterNonFatalError) {
2923     int rc;
2924     file_handle_t handle;
2925     file_handle_t handle1;
2926     size_t blk = 2048;
2927     size_t exp_len = 32 * 1024;
2928     storage_off_t fsize = (storage_off_t)(-1);
2929     const char* fname = "test_transact_resume_writes";
2930 
2931     // open create truncate file (with commit)
2932     rc = storage_open_file(
2933             ss, &handle, fname,
2934             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
2935             STORAGE_OP_COMPLETE);
2936     ASSERT_EQ(0, rc);
2937 
2938     // write (without commit)
2939     rc = WritePattern(handle, 0, exp_len / 2, blk, false);
2940     ASSERT_EQ((int)exp_len / 2, rc);
2941 
2942     // issue some commands that should fail with non-fatal errors
2943 
2944     // read past end of file
2945     uint32_t val = 0xDEADBEEF;
2946     rc = storage_read(handle, exp_len / 2 + 1, &val, sizeof(val));
2947     ASSERT_EQ(ERR_NOT_VALID, rc);
2948 
2949     // open non existing file
2950     rc = storage_open_file(ss, &handle1, "foo", STORAGE_FILE_OPEN_TRUNCATE,
2951                            STORAGE_OP_COMPLETE);
2952     ASSERT_EQ(ERR_NOT_FOUND, rc);
2953 
2954     // delete non-existing file
2955     rc = storage_delete_file(ss, "foo", STORAGE_OP_COMPLETE);
2956     ASSERT_EQ(ERR_NOT_FOUND, rc);
2957 
2958     // then resume writinga (without commit)
2959     rc = WritePattern(handle, exp_len / 2, exp_len / 2, blk, false);
2960     ASSERT_EQ((int)exp_len / 2, rc);
2961 
2962     // commit current transaction
2963     rc = storage_end_transaction(ss, true);
2964     ASSERT_EQ(0, rc);
2965 
2966     // check file size, it should be exp_len
2967     rc = storage_get_file_size(handle, &fsize);
2968     ASSERT_EQ(0, rc);
2969     ASSERT_EQ((storage_off_t)exp_len, fsize);
2970 
2971     // check data
2972     rc = ReadPatternEOF(handle, 0, blk);
2973     ASSERT_EQ((int)exp_len, rc);
2974 
2975     // cleanup
2976     storage_close_file(handle);
2977     storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
2978 
2979 test_abort:;
2980 }
2981 
2982 /*
2983  * Test that every API that should allow checkpointing does (when provisioning
2984  * is enabled)
2985  */
TEST_F(StorageTest,ENABLED_ON_EMULATOR_ONLY (CheckpointApis))2986 TEST_F(StorageTest, ENABLED_ON_EMULATOR_ONLY(CheckpointApis)) {
2987     int rc;
2988     file_handle_t handle;
2989     size_t blk = 2048;
2990     size_t len = 32 * blk;
2991     const char* fname = "test_checkpoint_create";
2992     const char* new_fname = "test_checkpoint_move";
2993 
2994     if (!system_state_provisioning_allowed()) {
2995         trusty_unittest_printf(
2996                 "[  SKIPPED ] CheckpointApis - Provisioning is not allowed\n");
2997         return;
2998     }
2999 
3000     /* We don't allow OP_CHECKPOINT without STORAGE_OP_COMPLETE */
3001     rc = storage_open_file(
3002             ss, &handle, fname,
3003             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
3004             STORAGE_OP_CHECKPOINT);
3005     ASSERT_EQ(ERR_NOT_VALID, rc);
3006 
3007     /* open create truncate file (with checkpoint) */
3008     rc = storage_open_file(
3009             ss, &handle, fname,
3010             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
3011             STORAGE_OP_COMPLETE | STORAGE_OP_CHECKPOINT);
3012     ASSERT_EQ(0, rc);
3013 
3014     /* move the file and checkpoint */
3015     rc = storage_move_file(
3016             ss, handle, fname, new_fname,
3017             STORAGE_FILE_MOVE_CREATE | STORAGE_FILE_MOVE_OPEN_FILE,
3018             STORAGE_OP_COMPLETE | STORAGE_OP_CHECKPOINT);
3019     ASSERT_EQ(0, rc);
3020 
3021     /* write to the file and checkpoint */
3022     rc = WritePatternExt(handle, 0, len, blk,
3023                          STORAGE_OP_COMPLETE | STORAGE_OP_CHECKPOINT);
3024     ASSERT_EQ((int)len, rc);
3025 
3026     rc = ReadPattern(handle, 0, len, blk);
3027     ASSERT_EQ((int)len, rc);
3028 
3029     /* cleanup */
3030     storage_close_file(handle);
3031 
3032     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
3033     ASSERT_EQ(ERR_NOT_FOUND, rc);
3034 
3035     rc = storage_delete_file(ss, new_fname,
3036                              STORAGE_OP_COMPLETE | STORAGE_OP_CHECKPOINT);
3037     ASSERT_EQ(0, rc);
3038 
3039 test_abort:;
3040 }
3041 
TEST_F(StorageTest,ENABLED_ON_EMULATOR_ONLY (CheckpointRequiresProvisioningAllowed))3042 TEST_F(StorageTest,
3043        ENABLED_ON_EMULATOR_ONLY(CheckpointRequiresProvisioningAllowed)) {
3044     int rc;
3045     file_handle_t handle;
3046     const char* fname = "test_checkpoint_create";
3047     const char* new_fname = "test_checkpoint_move";
3048 
3049     if (system_state_provisioning_allowed()) {
3050         trusty_unittest_printf(
3051                 "[  SKIPPED ] CheckpointRequiresProvisioningAllowed - "
3052                 "Provisioning is allowed\n");
3053         return;
3054     }
3055 
3056     /* We don't allow OP_CHECKPOINT without STORAGE_OP_COMPLETE */
3057     rc = storage_open_file(
3058             ss, &handle, fname,
3059             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
3060             STORAGE_OP_CHECKPOINT);
3061     ASSERT_EQ(ERR_NOT_VALID, rc);
3062 
3063     /* open create truncate file (with checkpoint) */
3064     rc = storage_open_file(
3065             ss, &handle, fname,
3066             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
3067             STORAGE_OP_COMPLETE | STORAGE_OP_CHECKPOINT);
3068     ASSERT_EQ(ERR_NOT_ALLOWED, rc);
3069 
3070     /* move the file and checkpoint */
3071     rc = storage_move_file(
3072             ss, handle, fname, new_fname,
3073             STORAGE_FILE_MOVE_CREATE | STORAGE_FILE_MOVE_OPEN_FILE,
3074             STORAGE_OP_COMPLETE | STORAGE_OP_CHECKPOINT);
3075     ASSERT_EQ(ERR_NOT_ALLOWED, rc);
3076 
3077     rc = storage_delete_file(ss, fname, STORAGE_OP_COMPLETE);
3078     ASSERT_EQ(ERR_NOT_FOUND, rc);
3079 
3080     rc = storage_delete_file(ss, new_fname,
3081                              STORAGE_OP_COMPLETE | STORAGE_OP_CHECKPOINT);
3082     ASSERT_EQ(ERR_NOT_ALLOWED, rc);
3083 
3084 test_abort:;
3085 }
3086 #endif
3087 
3088 #define RUN_MODE_ALL NULL
3089 #define RUN_MODE_INIT_NO_COMMIT_SMALL "StorageInitNoCommitSmallTest"
3090 #define RUN_MODE_INIT_NO_COMMIT_LARGE "StorageInitNoCommitLargeTest"
3091 #define RUN_MODE_INIT_NO_COMMIT_CLEANUP "StorageInitNoCommitClenupTest"
3092 #define RUN_MODE_INIT "StorageInitTest"
3093 #define RUN_MODE_CHECK "StorageCheckTest"
3094 #define RUN_MODE_CLEAN "StorageCleanTest"
3095 
run_all_tests(const char * port,const char * suite)3096 static bool run_all_tests(const char* port, const char* suite) {
3097     int rc;
3098     storage_session_t session;
3099 
3100     TLOGI("SS-unittest: %s: waiting for server\n", port);
3101     do {
3102         rc = storage_open_session(&session, port);
3103         if (rc < 0) {
3104             TLOGE("failed (%d) to connect to storage server - retrying\n", rc);
3105 #ifndef STORAGE_FAKE
3106             trusty_nanosleep(0, 0, 1000000);
3107 #endif
3108         }
3109 
3110     } while (rc < 0);
3111     storage_close_session(session);
3112 
3113     storage_test_client_port = port;
3114 
3115     return RUN_ALL_SUITE_TESTS(suite);
3116 }
3117 
3118 #ifdef STORAGE_FAKE
3119 
main(void)3120 int main(void) {
3121     bool passed = run_all_tests(STORAGE_CLIENT_TD_PORT, RUN_MODE_ALL);
3122     //  run_all_tests(STORAGE_CLIENT_TDEA_PORT, RUN_MODE_ALL);
3123     //  run_all_tests(STORAGE_CLIENT_TP_PORT, RUN_MODE_ALL);
3124     return passed ? 0 : 1;
3125 }
3126 
3127 #else
3128 
3129 struct storage_unittest {
3130     struct unittest unittest;
3131     const char* port;
3132     const char* run_mode;
3133 };
3134 
run_test(struct unittest * test)3135 static bool run_test(struct unittest* test) {
3136     struct storage_unittest* storage_test =
3137             containerof(test, struct storage_unittest, unittest);
3138     return run_all_tests(storage_test->port, storage_test->run_mode);
3139 }
3140 
3141 #define PORT_BASE "com.android.storage-unittest."
3142 
3143 #define DEFINE_STORAGE_UNIT_TEST(fs, fs_name, run_mode_val, run_mode_name) \
3144     {                                                                      \
3145         .unittest =                                                        \
3146                 {                                                          \
3147                         .port_name = PORT_BASE fs_name run_mode_name,      \
3148                         .run_test = run_test,                              \
3149                 },                                                         \
3150         .port = (fs), .run_mode = (run_mode_val),                          \
3151     }
3152 
3153 #define DEFINE_STORAGE_UNIT_TESTS_FS(fs, fs_name)                              \
3154     DEFINE_STORAGE_UNIT_TEST((fs), fs_name, RUN_MODE_ALL, ""),                 \
3155             DEFINE_STORAGE_UNIT_TEST((fs), fs_name,                            \
3156                                      RUN_MODE_INIT_NO_COMMIT_SMALL,            \
3157                                      ".initnocommitsmall"),                    \
3158             DEFINE_STORAGE_UNIT_TEST((fs), fs_name,                            \
3159                                      RUN_MODE_INIT_NO_COMMIT_LARGE,            \
3160                                      ".initnocommitlarge"),                    \
3161             DEFINE_STORAGE_UNIT_TEST((fs), fs_name,                            \
3162                                      RUN_MODE_INIT_NO_COMMIT_CLEANUP,          \
3163                                      ".initnocommitcleanup"),                  \
3164             DEFINE_STORAGE_UNIT_TEST((fs), fs_name, RUN_MODE_INIT, ".init"),   \
3165             DEFINE_STORAGE_UNIT_TEST((fs), fs_name, RUN_MODE_CHECK, ".check"), \
3166             DEFINE_STORAGE_UNIT_TEST((fs), fs_name, RUN_MODE_CLEAN, ".clean")
3167 
main(void)3168 int main(void) {
3169     static struct storage_unittest storage_unittests[] = {
3170             DEFINE_STORAGE_UNIT_TESTS_FS(STORAGE_CLIENT_NSP_PORT, "nsp"),
3171             DEFINE_STORAGE_UNIT_TESTS_FS(STORAGE_CLIENT_TD_PORT, "td"),
3172             DEFINE_STORAGE_UNIT_TESTS_FS(STORAGE_CLIENT_TDP_PORT, "tdp"),
3173             DEFINE_STORAGE_UNIT_TESTS_FS(STORAGE_CLIENT_TDEA_PORT, "tdea"),
3174             DEFINE_STORAGE_UNIT_TESTS_FS(STORAGE_CLIENT_TP_PORT, "tp"),
3175     };
3176     static struct unittest* unittests[countof(storage_unittests)];
3177 
3178     for (size_t i = 0; i < countof(storage_unittests); i++) {
3179         unittests[i] = &storage_unittests[i].unittest;
3180     }
3181 
3182     return unittest_main(unittests, countof(unittests));
3183 }
3184 
3185 #endif
3186