Home | History | Annotate | Download | only in leveldatabase
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/file_util.h"
      6 #include "base/files/file.h"
      7 #include "base/files/file_enumerator.h"
      8 #include "base/files/file_path.h"
      9 #include "base/files/scoped_temp_dir.h"
     10 #include "base/test/test_suite.h"
     11 #include "env_chromium_stdio.h"
     12 #if defined(OS_WIN)
     13 #include "env_chromium_win.h"
     14 #endif
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 #include "third_party/leveldatabase/env_idb.h"
     17 #include "third_party/leveldatabase/src/include/leveldb/db.h"
     18 
     19 using namespace leveldb_env;
     20 using namespace leveldb;
     21 
     22 #define FPL FILE_PATH_LITERAL
     23 
     24 TEST(ErrorEncoding, OnlyAMethod) {
     25   const MethodID in_method = kSequentialFileRead;
     26   const Status s = MakeIOError("Somefile.txt", "message", in_method);
     27   MethodID method;
     28   int error = -75;
     29   EXPECT_EQ(METHOD_ONLY,
     30             ParseMethodAndError(s.ToString().c_str(), &method, &error));
     31   EXPECT_EQ(in_method, method);
     32   EXPECT_EQ(-75, error);
     33 }
     34 
     35 TEST(ErrorEncoding, FileError) {
     36   const MethodID in_method = kWritableFileClose;
     37   const base::File::Error fe = base::File::FILE_ERROR_INVALID_OPERATION;
     38   const Status s = MakeIOError("Somefile.txt", "message", in_method, fe);
     39   MethodID method;
     40   int error;
     41   EXPECT_EQ(METHOD_AND_PFE,
     42             ParseMethodAndError(s.ToString().c_str(), &method, &error));
     43   EXPECT_EQ(in_method, method);
     44   EXPECT_EQ(fe, error);
     45 }
     46 
     47 TEST(ErrorEncoding, Errno) {
     48   const MethodID in_method = kWritableFileFlush;
     49   const int some_errno = ENOENT;
     50   const Status s =
     51       MakeIOError("Somefile.txt", "message", in_method, some_errno);
     52   MethodID method;
     53   int error;
     54   EXPECT_EQ(METHOD_AND_ERRNO,
     55             ParseMethodAndError(s.ToString().c_str(), &method, &error));
     56   EXPECT_EQ(in_method, method);
     57   EXPECT_EQ(some_errno, error);
     58 }
     59 
     60 #if defined(OS_WIN)
     61 TEST(ErrorEncoding, ErrnoWin32) {
     62   const MethodID in_method = kWritableFileFlush;
     63   const DWORD some_errno = ERROR_FILE_NOT_FOUND;
     64   const Status s =
     65       MakeIOErrorWin("Somefile.txt", "message", in_method, some_errno);
     66   MethodID method;
     67   int error;
     68   EXPECT_EQ(METHOD_AND_ERRNO,
     69             ParseMethodAndError(s.ToString().c_str(), &method, &error));
     70   EXPECT_EQ(in_method, method);
     71   EXPECT_EQ(some_errno, error);
     72 }
     73 #endif
     74 
     75 TEST(ErrorEncoding, NoEncodedMessage) {
     76   Status s = Status::IOError("Some message", "from leveldb itself");
     77   MethodID method = kRandomAccessFileRead;
     78   int error = 4;
     79   EXPECT_EQ(NONE, ParseMethodAndError(s.ToString().c_str(), &method, &error));
     80   EXPECT_EQ(kRandomAccessFileRead, method);
     81   EXPECT_EQ(4, error);
     82 }
     83 
     84 template <typename T>
     85 class MyEnv : public T {
     86  public:
     87   MyEnv() : directory_syncs_(0) {}
     88   int directory_syncs() { return directory_syncs_; }
     89 
     90  protected:
     91   virtual void DidSyncDir(const std::string& fname) {
     92     ++directory_syncs_;
     93     ChromiumEnv::DidSyncDir(fname);
     94   }
     95 
     96  private:
     97   int directory_syncs_;
     98 };
     99 
    100 template <typename T>
    101 class ChromiumEnvMultiPlatformTests : public ::testing::Test {
    102  public:
    103 };
    104 
    105 #if defined(OS_WIN)
    106 typedef ::testing::Types<ChromiumEnvStdio, ChromiumEnvWin> ChromiumEnvMultiPlatformTestsTypes;
    107 #else
    108 typedef ::testing::Types<ChromiumEnvStdio> ChromiumEnvMultiPlatformTestsTypes;
    109 #endif
    110 TYPED_TEST_CASE(ChromiumEnvMultiPlatformTests, ChromiumEnvMultiPlatformTestsTypes);
    111 
    112 TYPED_TEST(ChromiumEnvMultiPlatformTests, DirectorySyncing) {
    113   MyEnv<TypeParam> env;
    114 
    115   base::ScopedTempDir dir;
    116   ASSERT_TRUE(dir.CreateUniqueTempDir());
    117   base::FilePath dir_path = dir.path();
    118   std::string some_data = "some data";
    119   Slice data = some_data;
    120 
    121   std::string manifest_file_name =
    122       FilePathToString(dir_path.Append(FILE_PATH_LITERAL("MANIFEST-001")));
    123   WritableFile* manifest_file_ptr;
    124   Status s = env.NewWritableFile(manifest_file_name, &manifest_file_ptr);
    125   EXPECT_TRUE(s.ok());
    126   scoped_ptr<WritableFile> manifest_file(manifest_file_ptr);
    127   manifest_file->Append(data);
    128   EXPECT_EQ(0, env.directory_syncs());
    129   manifest_file->Append(data);
    130   EXPECT_EQ(0, env.directory_syncs());
    131 
    132   std::string sst_file_name =
    133       FilePathToString(dir_path.Append(FILE_PATH_LITERAL("000003.sst")));
    134   WritableFile* sst_file_ptr;
    135   s = env.NewWritableFile(sst_file_name, &sst_file_ptr);
    136   EXPECT_TRUE(s.ok());
    137   scoped_ptr<WritableFile> sst_file(sst_file_ptr);
    138   sst_file->Append(data);
    139   EXPECT_EQ(0, env.directory_syncs());
    140 
    141   manifest_file->Append(data);
    142   EXPECT_EQ(1, env.directory_syncs());
    143   manifest_file->Append(data);
    144   EXPECT_EQ(1, env.directory_syncs());
    145 }
    146 
    147 int CountFilesWithExtension(const base::FilePath& dir,
    148                             const base::FilePath::StringType& extension) {
    149   int matching_files = 0;
    150   base::FileEnumerator dir_reader(
    151       dir, false, base::FileEnumerator::FILES);
    152   for (base::FilePath fname = dir_reader.Next(); !fname.empty();
    153        fname = dir_reader.Next()) {
    154     if (fname.MatchesExtension(extension))
    155       matching_files++;
    156   }
    157   return matching_files;
    158 }
    159 
    160 bool GetFirstLDBFile(const base::FilePath& dir, base::FilePath* ldb_file) {
    161   base::FileEnumerator dir_reader(
    162       dir, false, base::FileEnumerator::FILES);
    163   for (base::FilePath fname = dir_reader.Next(); !fname.empty();
    164        fname = dir_reader.Next()) {
    165     if (fname.MatchesExtension(FPL(".ldb"))) {
    166       *ldb_file = fname;
    167       return true;
    168     }
    169   }
    170   return false;
    171 }
    172 
    173 TEST(ChromiumEnv, BackupTables) {
    174   Options options;
    175   options.create_if_missing = true;
    176   options.env = IDBEnv();
    177 
    178   base::ScopedTempDir scoped_temp_dir;
    179   ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
    180   base::FilePath dir = scoped_temp_dir.path();
    181 
    182   DB* db;
    183   Status status = DB::Open(options, dir.AsUTF8Unsafe(), &db);
    184   EXPECT_TRUE(status.ok()) << status.ToString();
    185   status = db->Put(WriteOptions(), "key", "value");
    186   EXPECT_TRUE(status.ok()) << status.ToString();
    187   Slice a = "a";
    188   Slice z = "z";
    189   db->CompactRange(&a, &z);
    190   int ldb_files = CountFilesWithExtension(dir, FPL(".ldb"));
    191   int bak_files = CountFilesWithExtension(dir, FPL(".bak"));
    192   EXPECT_GT(ldb_files, 0);
    193   EXPECT_EQ(ldb_files, bak_files);
    194   base::FilePath ldb_file;
    195   EXPECT_TRUE(GetFirstLDBFile(dir, &ldb_file));
    196   delete db;
    197   EXPECT_TRUE(base::DeleteFile(ldb_file, false));
    198   EXPECT_EQ(ldb_files - 1, CountFilesWithExtension(dir, FPL(".ldb")));
    199 
    200   // The ldb file deleted above should be restored in Open.
    201   status = leveldb::DB::Open(options, dir.AsUTF8Unsafe(), &db);
    202   EXPECT_TRUE(status.ok()) << status.ToString();
    203   std::string value;
    204   status = db->Get(ReadOptions(), "key", &value);
    205   EXPECT_TRUE(status.ok()) << status.ToString();
    206   EXPECT_EQ("value", value);
    207   delete db;
    208 
    209   // Ensure that deleting an ldb file also deletes its backup.
    210   int orig_ldb_files = CountFilesWithExtension(dir, FPL(".ldb"));
    211   EXPECT_GT(ldb_files, 0);
    212   EXPECT_EQ(ldb_files, bak_files);
    213   EXPECT_TRUE(GetFirstLDBFile(dir, &ldb_file));
    214   options.env->DeleteFile(ldb_file.AsUTF8Unsafe());
    215   ldb_files = CountFilesWithExtension(dir, FPL(".ldb"));
    216   bak_files = CountFilesWithExtension(dir, FPL(".bak"));
    217   EXPECT_EQ(orig_ldb_files - 1, ldb_files);
    218   EXPECT_EQ(bak_files, ldb_files);
    219 }
    220 
    221 TEST(ChromiumEnv, GetChildrenEmptyDir) {
    222   base::ScopedTempDir scoped_temp_dir;
    223   ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
    224   base::FilePath dir = scoped_temp_dir.path();
    225 
    226   Env* env = IDBEnv();
    227   std::vector<std::string> result;
    228   leveldb::Status status = env->GetChildren(dir.AsUTF8Unsafe(), &result);
    229   EXPECT_TRUE(status.ok());
    230   EXPECT_EQ(0U, result.size());
    231 }
    232 
    233 TEST(ChromiumEnv, GetChildrenPriorResults) {
    234   base::ScopedTempDir scoped_temp_dir;
    235   ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
    236   base::FilePath dir = scoped_temp_dir.path();
    237 
    238   base::FilePath new_file_dir = dir.Append(FPL("tmp_file"));
    239   FILE* f = fopen(new_file_dir.AsUTF8Unsafe().c_str(), "w");
    240   if (f) {
    241     fputs("Temp file contents", f);
    242     fclose(f);
    243   }
    244 
    245   Env* env = IDBEnv();
    246   std::vector<std::string> result;
    247   leveldb::Status status = env->GetChildren(dir.AsUTF8Unsafe(), &result);
    248   EXPECT_TRUE(status.ok());
    249   EXPECT_EQ(1U, result.size());
    250 
    251   // And a second time should also return one result
    252   status = env->GetChildren(dir.AsUTF8Unsafe(), &result);
    253   EXPECT_TRUE(status.ok());
    254   EXPECT_EQ(1U, result.size());
    255 }
    256 
    257 int main(int argc, char** argv) { return base::TestSuite(argc, argv).Run(); }
    258