Home | History | Annotate | Download | only in apps
      1 // Copyright 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 <algorithm>
      6 
      7 #include "base/rand_util.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "base/time/time.h"
     10 #include "chrome/browser/apps/ephemeral_app_service.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 namespace {
     14 
     15 // Generate a time N number of days before the reference time.
     16 // The generated time can be randomized.
     17 base::Time GetPastTime(const base::Time& reference_time,
     18                        int days_before,
     19                        bool randomize_time = false) {
     20   base::Time generated_time =
     21       reference_time - base::TimeDelta::FromDays(days_before);
     22 
     23   // Add an hour so that the time is well within the number of days before.
     24   generated_time += base::TimeDelta::FromHours(1);
     25 
     26   // Add a random number of seconds between 0 - 10 hours.
     27   if (randomize_time)
     28     generated_time += base::TimeDelta::FromSeconds(base::RandInt(0, 36000));
     29 
     30   return generated_time;
     31 }
     32 
     33 }  // namespace
     34 
     35 class EphemeralAppServiceTest : public testing::Test {
     36  protected:
     37   typedef EphemeralAppService::LaunchTimeAppMap LaunchTimeAppMap;
     38 
     39   EphemeralAppServiceTest() {}
     40   virtual ~EphemeralAppServiceTest() {}
     41 
     42   void RunTest(int ephemeral_app_count,
     43                const LaunchTimeAppMap& launch_times,
     44                const std::set<std::string>& expected_removed_ids) {
     45     std::set<std::string> remove_app_ids;
     46     EphemeralAppService::GetAppsToRemove(ephemeral_app_count,
     47                                          launch_times,
     48                                          &remove_app_ids);
     49     EXPECT_EQ(expected_removed_ids, remove_app_ids);
     50   }
     51 
     52   void RunTestCheckLRU(int ephemeral_app_count,
     53                        LaunchTimeAppMap& launch_times,
     54                        int expected_removed_count) {
     55     std::set<std::string> remove_app_ids;
     56     EphemeralAppService::GetAppsToRemove(ephemeral_app_count,
     57                                          launch_times,
     58                                          &remove_app_ids);
     59     EXPECT_EQ(expected_removed_count, (int) remove_app_ids.size());
     60 
     61     // Move the launch times of removed apps to another map.
     62     LaunchTimeAppMap removed_apps;
     63     for (LaunchTimeAppMap::iterator it = launch_times.begin();
     64          it != launch_times.end(); ) {
     65       if (remove_app_ids.find(it->second) != remove_app_ids.end()) {
     66         removed_apps.insert(*it);
     67         launch_times.erase(it++);
     68       } else {
     69         ++it;
     70       }
     71     }
     72 
     73     if (launch_times.empty())
     74       return;
     75 
     76     // Verify that the removed apps have launch times earlier than or equal to
     77     // all retained apps. We can actually just compare with the first entry in
     78     // |launch_times| but will make no implementation assumptions.
     79     for (LaunchTimeAppMap::const_iterator removed = removed_apps.begin();
     80          removed != removed_apps.end(); ++removed) {
     81       for (LaunchTimeAppMap::iterator retained = launch_times.begin();
     82          retained != launch_times.end(); ++retained) {
     83         EXPECT_LE(removed->first, retained->first);
     84       }
     85     }
     86   }
     87 
     88   // Generate X app launch times, N days before the reference time.
     89   // If |generated_ids| is not NULL, the generated app IDs will be added
     90   // to the set.
     91   void GenerateLaunchTimes(const base::Time& reference_time,
     92                            int days_before,
     93                            int count,
     94                            LaunchTimeAppMap* launch_times,
     95                            std::set<std::string>* generated_ids = NULL) {
     96     for (int i = 0; i < count; ++i) {
     97       std::string app_id = base::IntToString(launch_times->size());
     98       launch_times->insert(std::make_pair(
     99           GetPastTime(reference_time, days_before, true),
    100           app_id));
    101 
    102       if (generated_ids)
    103         generated_ids->insert(app_id);
    104     }
    105   }
    106 
    107   // Add inactive apps that should always be removed by garbage collection.
    108   void AddInactiveApps(const base::Time& reference_time,
    109                        int count,
    110                        LaunchTimeAppMap* launch_times,
    111                        std::set<std::string>* generated_ids = NULL) {
    112     GenerateLaunchTimes(reference_time,
    113                         EphemeralAppService::kAppInactiveThreshold + 1,
    114                         count,
    115                         launch_times,
    116                         generated_ids);
    117   }
    118 
    119   // Add recently launched apps that should NOT be removed by garbage
    120   // collection regardless of the number of cached ephemeral apps.
    121   void AddRecentlyLaunchedApps(const base::Time& reference_time,
    122                                int count,
    123                                LaunchTimeAppMap* launch_times,
    124                                std::set<std::string>* generated_ids = NULL) {
    125     GenerateLaunchTimes(reference_time,
    126                         EphemeralAppService::kAppKeepThreshold,
    127                         count,
    128                         launch_times,
    129                         generated_ids);
    130   }
    131 
    132   // Add apps launched between the kAppInactiveThreshold and kAppKeepThreshold,
    133   // which may or may not be removed by garbage collection depending on the
    134   // number of ephemeral apps in the cache.
    135   void AddIntermediateApps(const base::Time& reference_time,
    136                            int count,
    137                            LaunchTimeAppMap* launch_times,
    138                            std::set<std::string>* generated_ids = NULL) {
    139     int days_before = base::RandInt(EphemeralAppService::kAppKeepThreshold + 1,
    140                                     EphemeralAppService::kAppInactiveThreshold);
    141     GenerateLaunchTimes(reference_time,
    142                         days_before,
    143                         count,
    144                         launch_times,
    145                         generated_ids);
    146   }
    147 };
    148 
    149 // Verify that inactive apps are removed even if the cache has not reached
    150 // capacity.
    151 // Test case: | inactive |
    152 // Expected output: All inactive apps removed.
    153 TEST_F(EphemeralAppServiceTest, RemoveInactiveApps) {
    154   base::Time time_now = base::Time::Now();
    155   LaunchTimeAppMap launch_times;
    156   std::set<std::string> expected_removed_ids;
    157 
    158   AddInactiveApps(
    159       time_now,
    160       EphemeralAppService::kMaxEphemeralAppsCount / 5,
    161       &launch_times,
    162       &expected_removed_ids);
    163   RunTest(launch_times.size(), launch_times, expected_removed_ids);
    164 }
    165 
    166 // Verify that inactive apps are removed even if the cache has not reached
    167 // capacity.
    168 // Test case: | inactive | intermediate | recently launched |
    169 // Expected output: All inactive apps removed, other apps retained.
    170 TEST_F(EphemeralAppServiceTest, RemoveInactiveAppsKeepOthers) {
    171   base::Time time_now = base::Time::Now();
    172   LaunchTimeAppMap launch_times;
    173   std::set<std::string> expected_removed_ids;
    174 
    175   AddInactiveApps(
    176       time_now,
    177       EphemeralAppService::kMaxEphemeralAppsCount / 5,
    178       &launch_times,
    179       &expected_removed_ids);
    180   AddIntermediateApps(
    181       time_now,
    182       EphemeralAppService::kMaxEphemeralAppsCount / 5,
    183       &launch_times);
    184   AddRecentlyLaunchedApps(
    185       time_now,
    186       EphemeralAppService::kMaxEphemeralAppsCount / 5,
    187       &launch_times);
    188   RunTest(launch_times.size(), launch_times, expected_removed_ids);
    189 }
    190 
    191 // Verify that recently launched apps will not be removed, even when the cache
    192 // overflows.
    193 // Test case: | recently launched |
    194 // Expected output: All recently launched apps retained.
    195 TEST_F(EphemeralAppServiceTest, KeepRecentLaunch) {
    196   base::Time time_now = base::Time::Now();
    197   LaunchTimeAppMap launch_times;
    198 
    199   AddRecentlyLaunchedApps(
    200       time_now,
    201       3,
    202       &launch_times);
    203   RunTest(launch_times.size(), launch_times, std::set<std::string>());
    204 
    205   AddRecentlyLaunchedApps(
    206       time_now,
    207       EphemeralAppService::kMaxEphemeralAppsCount,
    208       &launch_times); // overflow
    209   RunTest(launch_times.size(), launch_times, std::set<std::string>());
    210 }
    211 
    212 // Verify that recently launched apps will not be removed, even when the cache
    213 // overflows.
    214 // Test case: | intermediate (overflow) | recently launched (overflow) |
    215 // Expected output: All recently launched apps retained, intermediate apps
    216 // removed.
    217 TEST_F(EphemeralAppServiceTest, KeepRecentLaunchRemoveOthers) {
    218   base::Time time_now = base::Time::Now();
    219   LaunchTimeAppMap launch_times;
    220   std::set<std::string> expected_removed_ids;
    221 
    222   AddRecentlyLaunchedApps(
    223       time_now,
    224       EphemeralAppService::kMaxEphemeralAppsCount + 3,
    225       &launch_times); // overflow
    226   AddIntermediateApps(
    227       time_now,
    228       3,
    229       &launch_times,
    230       &expected_removed_ids); // overflow
    231   RunTest(launch_times.size(), launch_times, expected_removed_ids);
    232 }
    233 
    234 // Verify that the LRU algorithm is implemented correctly.
    235 // Test case: | intermediate (overflow) |
    236 // Expected output: The least recently launched apps are removed.
    237 TEST_F(EphemeralAppServiceTest, RemoveOverflow) {
    238   base::Time time_now = base::Time::Now();
    239   LaunchTimeAppMap launch_times;
    240 
    241   const int kOverflow = 3;
    242   AddIntermediateApps(
    243       time_now,
    244       EphemeralAppService::kMaxEphemeralAppsCount + kOverflow,
    245       &launch_times); // overflow
    246   RunTestCheckLRU(launch_times.size(), launch_times, kOverflow);
    247 }
    248 
    249 // Verify that GetAppsToRemove() takes into account the number of running apps,
    250 // since they are not included in the launch times.
    251 // Test case: | intermediate (overflow) | running apps |
    252 // Expected output: The least recently launched apps are removed.
    253 TEST_F(EphemeralAppServiceTest, RemoveOverflowWithRunningApps) {
    254   base::Time time_now = base::Time::Now();
    255   LaunchTimeAppMap launch_times;
    256 
    257   const int kRunningApps = 3;
    258   AddIntermediateApps(
    259       time_now,
    260       EphemeralAppService::kMaxEphemeralAppsCount,
    261       &launch_times);  // overflow
    262   RunTestCheckLRU(
    263       launch_times.size() + kRunningApps,
    264       launch_times,
    265       kRunningApps);
    266 }
    267