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