Home | History | Annotate | Download | only in crash_cache
      1 // Copyright (c) 2006-2008 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 // This command-line program generates the set of files needed for the crash-
      6 // cache unit tests (DiskCacheTest,CacheBackend_Recover*). This program only
      7 // works properly on debug mode, because the crash functionality is not compiled
      8 // on release builds of the cache.
      9 
     10 #include <string>
     11 
     12 #include "base/at_exit.h"
     13 #include "base/command_line.h"
     14 #include "base/file_util.h"
     15 #include "base/logging.h"
     16 #include "base/message_loop.h"
     17 #include "base/path_service.h"
     18 #include "base/process_util.h"
     19 #include "base/string_util.h"
     20 
     21 #include "net/disk_cache/backend_impl.h"
     22 #include "net/disk_cache/disk_cache.h"
     23 #include "net/disk_cache/disk_cache_test_util.h"
     24 #include "net/disk_cache/rankings.h"
     25 
     26 using base::Time;
     27 
     28 enum Errors {
     29   GENERIC = -1,
     30   ALL_GOOD = 0,
     31   INVALID_ARGUMENT = 1,
     32   CRASH_OVERWRITE,
     33   NOT_REACHED
     34 };
     35 
     36 using disk_cache::RankCrashes;
     37 
     38 // Starts a new process, to generate the files.
     39 int RunSlave(RankCrashes action) {
     40   FilePath exe;
     41   PathService::Get(base::FILE_EXE, &exe);
     42 
     43   CommandLine cmdline(exe);
     44   cmdline.AppendLooseValue(ASCIIToWide(IntToString(action)));
     45 
     46   base::ProcessHandle handle;
     47   if (!base::LaunchApp(cmdline, false, false, &handle)) {
     48     printf("Unable to run test %d\n", action);
     49     return GENERIC;
     50   }
     51 
     52   int exit_code;
     53 
     54   if (!base::WaitForExitCode(handle, &exit_code)) {
     55     printf("Unable to get return code, test %d\n", action);
     56     return GENERIC;
     57   }
     58   if (ALL_GOOD != exit_code)
     59     printf("Test %d failed, code %d\n", action, exit_code);
     60 
     61   return exit_code;
     62 }
     63 
     64 // Main loop for the master process.
     65 int MasterCode() {
     66   for (int i = disk_cache::NO_CRASH + 1; i < disk_cache::MAX_CRASH; i++) {
     67     int ret = RunSlave(static_cast<RankCrashes>(i));
     68     if (ALL_GOOD != ret)
     69       return ret;
     70   }
     71 
     72   return ALL_GOOD;
     73 }
     74 
     75 // -----------------------------------------------------------------------
     76 
     77 extern RankCrashes g_rankings_crash;
     78 const char* kCrashEntryName = "the first key";
     79 
     80 // Creates the destinaton folder for this run, and returns it on full_path.
     81 bool CreateTargetFolder(const FilePath& path, RankCrashes action,
     82                         FilePath* full_path) {
     83   const char* folders[] = {
     84     "",
     85     "insert_empty1",
     86     "insert_empty2",
     87     "insert_empty3",
     88     "insert_one1",
     89     "insert_one2",
     90     "insert_one3",
     91     "insert_load1",
     92     "insert_load2",
     93     "remove_one1",
     94     "remove_one2",
     95     "remove_one3",
     96     "remove_one4",
     97     "remove_head1",
     98     "remove_head2",
     99     "remove_head3",
    100     "remove_head4",
    101     "remove_tail1",
    102     "remove_tail2",
    103     "remove_tail3",
    104     "remove_load1",
    105     "remove_load2",
    106     "remove_load3"
    107   };
    108   COMPILE_ASSERT(arraysize(folders) == disk_cache::MAX_CRASH, sync_folders);
    109   DCHECK(action > disk_cache::NO_CRASH && action < disk_cache::MAX_CRASH);
    110 
    111   *full_path = path.AppendASCII(folders[action]);
    112 
    113   if (file_util::PathExists(*full_path))
    114     return false;
    115 
    116   return file_util::CreateDirectory(*full_path);
    117 }
    118 
    119 // Generates the files for an empty and one item cache.
    120 int SimpleInsert(const FilePath& path, RankCrashes action) {
    121   disk_cache::Backend* cache = disk_cache::CreateCacheBackend(path, false, 0,
    122                                                               net::DISK_CACHE);
    123   if (!cache || cache->GetEntryCount())
    124     return GENERIC;
    125 
    126   const char* test_name = "some other key";
    127 
    128   if (action <= disk_cache::INSERT_EMPTY_3) {
    129     test_name = kCrashEntryName;
    130     g_rankings_crash = action;
    131   }
    132 
    133   disk_cache::Entry* entry;
    134   if (!cache->CreateEntry(test_name, &entry))
    135     return GENERIC;
    136 
    137   entry->Close();
    138 
    139   DCHECK(action <= disk_cache::INSERT_ONE_3);
    140   g_rankings_crash = action;
    141   test_name = kCrashEntryName;
    142 
    143   if (!cache->CreateEntry(test_name, &entry))
    144     return GENERIC;
    145 
    146   return NOT_REACHED;
    147 }
    148 
    149 // Generates the files for a one item cache, and removing the head.
    150 int SimpleRemove(const FilePath& path, RankCrashes action) {
    151   DCHECK(action >= disk_cache::REMOVE_ONE_1);
    152   DCHECK(action <= disk_cache::REMOVE_TAIL_3);
    153 
    154   disk_cache::Backend* cache = disk_cache::CreateCacheBackend(path, false, 0,
    155                                                               net::DISK_CACHE);
    156   if (!cache || cache->GetEntryCount())
    157     return GENERIC;
    158 
    159   disk_cache::Entry* entry;
    160   if (!cache->CreateEntry(kCrashEntryName, &entry))
    161     return GENERIC;
    162 
    163   entry->Close();
    164 
    165   if (action >= disk_cache::REMOVE_TAIL_1) {
    166     if (!cache->CreateEntry("some other key", &entry))
    167       return GENERIC;
    168 
    169     entry->Close();
    170   }
    171 
    172   if (!cache->OpenEntry(kCrashEntryName, &entry))
    173     return GENERIC;
    174 
    175   g_rankings_crash = action;
    176   entry->Doom();
    177   entry->Close();
    178 
    179   return NOT_REACHED;
    180 }
    181 
    182 int HeadRemove(const FilePath& path, RankCrashes action) {
    183   DCHECK(action >= disk_cache::REMOVE_HEAD_1);
    184   DCHECK(action <= disk_cache::REMOVE_HEAD_4);
    185 
    186   disk_cache::Backend* cache = disk_cache::CreateCacheBackend(path, false, 0,
    187                                                               net::DISK_CACHE);
    188   if (!cache || cache->GetEntryCount())
    189     return GENERIC;
    190 
    191   disk_cache::Entry* entry;
    192   if (!cache->CreateEntry("some other key", &entry))
    193     return GENERIC;
    194 
    195   entry->Close();
    196   if (!cache->CreateEntry(kCrashEntryName, &entry))
    197     return GENERIC;
    198 
    199   entry->Close();
    200 
    201   if (!cache->OpenEntry(kCrashEntryName, &entry))
    202     return GENERIC;
    203 
    204   g_rankings_crash = action;
    205   entry->Doom();
    206   entry->Close();
    207 
    208   return NOT_REACHED;
    209 }
    210 
    211 // Generates the files for insertion and removals on heavy loaded caches.
    212 int LoadOperations(const FilePath& path, RankCrashes action) {
    213   DCHECK(action >= disk_cache::INSERT_LOAD_1);
    214 
    215   // Work with a tiny index table (16 entries)
    216   disk_cache::BackendImpl* cache =
    217       new disk_cache::BackendImpl(path, 0xf);
    218   if (!cache || !cache->SetMaxSize(0x100000) || !cache->Init() ||
    219       cache->GetEntryCount())
    220     return GENERIC;
    221 
    222   int seed = static_cast<int>(Time::Now().ToInternalValue());
    223   srand(seed);
    224 
    225   disk_cache::Entry* entry;
    226   for (int i = 0; i < 100; i++) {
    227     std::string key = GenerateKey(true);
    228     if (!cache->CreateEntry(key, &entry))
    229       return GENERIC;
    230     entry->Close();
    231     if (50 == i && action >= disk_cache::REMOVE_LOAD_1) {
    232       if (!cache->CreateEntry(kCrashEntryName, &entry))
    233         return GENERIC;
    234       entry->Close();
    235     }
    236   }
    237 
    238   if (action <= disk_cache::INSERT_LOAD_2) {
    239     g_rankings_crash = action;
    240 
    241     if (!cache->CreateEntry(kCrashEntryName, &entry))
    242       return GENERIC;
    243   }
    244 
    245   if (!cache->OpenEntry(kCrashEntryName, &entry))
    246     return GENERIC;
    247 
    248   g_rankings_crash = action;
    249 
    250   entry->Doom();
    251   entry->Close();
    252 
    253   return NOT_REACHED;
    254 }
    255 
    256 // Main function on the child process.
    257 int SlaveCode(const FilePath& path, RankCrashes action) {
    258   MessageLoop message_loop;
    259 
    260   FilePath full_path;
    261   if (!CreateTargetFolder(path, action, &full_path)) {
    262     printf("Destination folder found, please remove it.\n");
    263     return CRASH_OVERWRITE;
    264   }
    265 
    266   if (action <= disk_cache::INSERT_ONE_3)
    267     return SimpleInsert(full_path, action);
    268 
    269   if (action <= disk_cache::INSERT_LOAD_2)
    270     return LoadOperations(full_path, action);
    271 
    272   if (action <= disk_cache::REMOVE_ONE_4)
    273     return SimpleRemove(full_path, action);
    274 
    275   if (action <= disk_cache::REMOVE_HEAD_4)
    276     return HeadRemove(full_path, action);
    277 
    278   if (action <= disk_cache::REMOVE_TAIL_3)
    279     return SimpleRemove(full_path, action);
    280 
    281   if (action <= disk_cache::REMOVE_LOAD_3)
    282     return LoadOperations(full_path, action);
    283 
    284   return NOT_REACHED;
    285 }
    286 
    287 // -----------------------------------------------------------------------
    288 
    289 int main(int argc, const char* argv[]) {
    290   // Setup an AtExitManager so Singleton objects will be destructed.
    291   base::AtExitManager at_exit_manager;
    292 
    293   if (argc < 2)
    294     return MasterCode();
    295 
    296   char* end;
    297   RankCrashes action = static_cast<RankCrashes>(strtol(argv[1], &end, 0));
    298   if (action <= disk_cache::NO_CRASH || action >= disk_cache::MAX_CRASH) {
    299     printf("Invalid action\n");
    300     return INVALID_ARGUMENT;
    301   }
    302 
    303   FilePath path;
    304   PathService::Get(base::DIR_SOURCE_ROOT, &path);
    305   path = path.AppendASCII("net");
    306   path = path.AppendASCII("data");
    307   path = path.AppendASCII("cache_tests");
    308   path = path.AppendASCII("new_crashes");
    309 
    310   return SlaveCode(path, action);
    311 }
    312