22
22
23
23
#include < array>
24
24
#include < fstream>
25
+ #include < functional>
25
26
#include < iostream>
26
27
#include < memory>
27
28
#include < string>
30
31
#include " Firestore/core/src/util/filesystem.h"
31
32
#include " Firestore/core/src/util/path.h"
32
33
33
- #include " firebase_test_framework.h"
34
34
#include " gtest/gtest.h"
35
35
#include " leveldb/db.h"
36
36
@@ -49,36 +49,109 @@ using ::firebase::firestore::util::Path;
49
49
// with reason "corruption".
50
50
Path CreateLevelDbDatabaseThatUsesSnappyCompression ();
51
51
52
- // This test ensures that we don't accidentally regress having added in Snappy
53
- // compression support (https://github.com/firebase/firebase-ios-sdk/pull/9596).
54
- TEST (LevelDbSnappy, LevelDbHasSnappySupportCompiledIn) {
55
- // Do not run this test on iOS because LevelDb in iOS does not support Snappy.
56
- SKIP_TEST_ON_IOS;
52
+ // Creates and opens a LevelDb database that contains at least one block that
53
+ // is compressed with Snappy compression, then iterates over it, invoking the
54
+ // given callback with the status at each point in the iteration. Once the
55
+ // callback is invoked with a `status` where `status.ok()` is not true, then
56
+ // iteration will stop and the callback will not be invoked again.
57
+ void IterateOverLevelDbDatabaseThatUsesSnappyCompression (
58
+ std::function<void (const leveldb::Status&)>);
57
59
58
- Path leveldb_path = CreateLevelDbDatabaseThatUsesSnappyCompression ();
59
- if (HasFatalFailure ()) return ;
60
+ #if FIREBASE_TESTS_TARGET_DESKTOP
60
61
61
- leveldb::Options options;
62
- options.create_if_missing = false ;
62
+ // Ensure that LevelDb is compiled with Snappy compression support.
63
+ // See https://github.com/firebase/firebase-ios-sdk/pull/9596 for details.
64
+ TEST (LevelDbSnappy, LevelDbSupportsSnappy) {
65
+ IterateOverLevelDbDatabaseThatUsesSnappyCompression (
66
+ [](const leveldb::Status& status) {
67
+ ASSERT_TRUE (status.ok ()) << ConvertStatus (status);
68
+ });
69
+ }
70
+
71
+ #else // FIREBASE_TESTS_TARGET_DESKTOP
72
+
73
+ // Ensure that LevelDb is NOT compiled with Snappy compression support.
74
+ TEST (LevelDbSnappy, LevelDbDoesNotSupportSnappy) {
75
+ bool got_failed_status = false ;
76
+ IterateOverLevelDbDatabaseThatUsesSnappyCompression (
77
+ [&](const leveldb::Status& status) {
78
+ if (!status.ok ()) {
79
+ got_failed_status = true ;
80
+ ASSERT_TRUE (status.IsCorruption ()) << ConvertStatus (status);
81
+ }
82
+ });
63
83
84
+ if (!HasFailure ()) {
85
+ ASSERT_TRUE (got_failed_status)
86
+ << " Reading a Snappy-compressed LevelDb database was successful; "
87
+ " however, it should NOT have been successful "
88
+ " since Snappy support is expected to NOT be available." ;
89
+ }
90
+ }
91
+
92
+ #endif // FIREBASE_TESTS_TARGET_DESKTOP
93
+
94
+ void IterateOverLevelDbDatabaseThatUsesSnappyCompression (
95
+ std::function<void (const leveldb::Status&)> callback) {
64
96
std::unique_ptr<leveldb::DB> db;
65
97
{
98
+ Path leveldb_path = CreateLevelDbDatabaseThatUsesSnappyCompression ();
99
+ if (leveldb_path.empty ()) {
100
+ return ;
101
+ }
102
+
103
+ leveldb::Options options;
104
+ options.create_if_missing = false ;
105
+
66
106
leveldb::DB* db_ptr;
67
107
leveldb::Status status =
68
108
leveldb::DB::Open (options, leveldb_path.ToUtf8String (), &db_ptr);
69
- ASSERT_TRUE (status.ok ());
109
+
110
+ ASSERT_TRUE (status.ok ())
111
+ << " Opening LevelDb database " << leveldb_path.ToUtf8String ()
112
+ << " failed: " << ConvertStatus (status);
113
+
70
114
db.reset (db_ptr);
71
115
}
72
116
73
- // One of the assertions below will fail when LevelDb attempts to read a block
74
- // that is compressed with Snappy and Snappy compression support is not
75
- // compiled in.
76
117
std::unique_ptr<leveldb::Iterator> it (
77
118
db->NewIterator (leveldb::ReadOptions ()));
78
119
for (it->SeekToFirst (); it->Valid (); it->Next ()) {
79
- ASSERT_TRUE (it->status ().ok ()) << ConvertStatus (it->status ());
120
+ callback (it->status ());
121
+ if (!it->status ().ok ()) {
122
+ return ;
123
+ }
124
+ }
125
+
126
+ // Invoke the callback on the final status.
127
+ callback (it->status ());
128
+ }
129
+
130
+ template <typename T>
131
+ void WriteFile (const Path& dir,
132
+ const std::string& file_name,
133
+ const T& data_array) {
134
+ Filesystem* fs = Filesystem::Default ();
135
+ {
136
+ auto status = fs->RecursivelyCreateDir (dir);
137
+ if (!status.ok ()) {
138
+ FAIL () << " Creating directory failed: " << dir.ToUtf8String () << " ("
139
+ << status.error_message () << " )" ;
140
+ }
141
+ }
142
+
143
+ Path file = dir.AppendUtf8 (file_name);
144
+ std::ofstream out_file (file.native_value (), std::ios::binary);
145
+ if (!out_file) {
146
+ FAIL () << " Unable to open file for writing: " << file.ToUtf8String ();
147
+ }
148
+
149
+ out_file.write (reinterpret_cast <const char *>(data_array.data ()),
150
+ data_array.size ());
151
+ out_file.close ();
152
+ if (!out_file) {
153
+ FAIL () << " Writing to file failed: " << file.ToUtf8String ();
80
154
}
81
- ASSERT_TRUE (it->status ().ok ()) << ConvertStatus (it->status ());
82
155
}
83
156
84
157
const std::array<unsigned char , 0x00000165 > LevelDbSnappyFile_000005_ldb{
@@ -196,54 +269,35 @@ const std::array<unsigned char, 0x000000C2> LevelDbSnappyFile_MANIFEST_000084{
196
269
0x04 , 0x0D ,
197
270
};
198
271
199
- template <typename T>
200
- void WriteFile (const Path& dir,
201
- const std::string& file_name,
202
- const T& data_array) {
203
- Filesystem* fs = Filesystem::Default ();
204
- {
205
- auto status = fs->RecursivelyCreateDir (dir);
206
- if (!status.ok ()) {
207
- FAIL () << " Creating directory failed: " << dir.ToUtf8String () << " ("
208
- << status.error_message () << " )" ;
209
- }
210
- }
211
-
212
- Path file = dir.AppendUtf8 (file_name);
213
- std::ofstream out_file (file.native_value (), std::ios::binary);
214
- if (!out_file) {
215
- FAIL () << " Unable to open file for writing: " << file.ToUtf8String ();
216
- }
217
-
218
- out_file.write (reinterpret_cast <const char *>(data_array.data ()),
219
- data_array.size ());
220
- out_file.close ();
221
- if (!out_file) {
222
- FAIL () << " Writing to file failed: " << file.ToUtf8String ();
223
- }
224
- }
225
-
226
272
Path LevelDbDir () {
227
273
Filesystem* fs = Filesystem::Default ();
228
- Path dir = fs->TempDir ().AppendUtf8 (" PersistenceTesting " );
274
+ Path dir = fs->TempDir ().AppendUtf8 (" LevelDbSnappyTest " );
229
275
230
276
// Delete the directory first to ensure isolation between runs.
231
277
auto status = fs->RecursivelyRemove (dir);
232
- EXPECT_TRUE (status.ok ()) << " Failed to clean up leveldb in dir "
278
+ EXPECT_TRUE (status.ok ()) << " Failed to clean up leveldb in directory "
233
279
<< dir.ToUtf8String () << " : " << status.ToString ();
280
+ if (!status.ok ()) {
281
+ return {};
282
+ }
234
283
235
284
return dir;
236
285
}
237
286
238
287
Path CreateLevelDbDatabaseThatUsesSnappyCompression () {
239
288
Path leveldb_dir = LevelDbDir ();
289
+ if (leveldb_dir.empty ()) {
290
+ return {};
291
+ }
292
+
240
293
WriteFile (leveldb_dir, " 000005.ldb" , LevelDbSnappyFile_000005_ldb);
241
294
WriteFile (leveldb_dir, " 000017.ldb" , LevelDbSnappyFile_000017_ldb);
242
295
WriteFile (leveldb_dir, " 000085.ldb" , LevelDbSnappyFile_000085_ldb);
243
296
WriteFile (leveldb_dir, " CURRENT" , LevelDbSnappyFile_CURRENT);
244
297
WriteFile (leveldb_dir, " LOG.old" , LevelDbSnappyFile_LOG_old);
245
298
WriteFile (leveldb_dir, " LOG" , LevelDbSnappyFile_LOG);
246
299
WriteFile (leveldb_dir, " MANIFEST-000084" , LevelDbSnappyFile_MANIFEST_000084);
300
+
247
301
return leveldb_dir;
248
302
}
249
303
0 commit comments