Home | History | Annotate | Download | only in power
      1 // Copyright 2014 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 "chrome/browser/chromeos/power/renderer_freezer.h"
      6 
      7 #include <string>
      8 
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/run_loop.h"
     11 #include "chromeos/dbus/dbus_thread_manager.h"
     12 #include "chromeos/dbus/fake_power_manager_client.h"
     13 #include "testing/gtest/include/gtest/gtest-death-test.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace chromeos {
     17 
     18 namespace {
     19 // Class that delegates used in testing can inherit from to record calls that
     20 // are made by the code being tested.
     21 class ActionRecorder {
     22  public:
     23   ActionRecorder() {}
     24   virtual ~ActionRecorder() {}
     25 
     26   // Returns a comma-separated string describing the actions that were
     27   // requested since the previous call to GetActions() (i.e. results are
     28   // non-repeatable).
     29   std::string GetActions() {
     30     std::string actions = actions_;
     31     actions_.clear();
     32     return actions;
     33   }
     34 
     35  protected:
     36   // Appends |new_action| to |actions_|, using a comma as a separator if
     37   // other actions are already listed.
     38   void AppendAction(const std::string& new_action) {
     39     if (!actions_.empty())
     40       actions_ += ",";
     41     actions_ += new_action;
     42   }
     43 
     44  private:
     45   // Comma-separated list of actions that have been performed.
     46   std::string actions_;
     47 
     48   DISALLOW_COPY_AND_ASSIGN(ActionRecorder);
     49 };
     50 
     51 // Actions that can be returned by TestDelegate::GetActions().
     52 const char kFreezeRenderers[] = "freeze_renderers";
     53 const char kThawRenderers[] = "thaw_renderers";
     54 const char kNoActions[] = "";
     55 
     56 // Test implementation of RendererFreezer::Delegate that records the actions it
     57 // was asked to perform.
     58 class TestDelegate : public RendererFreezer::Delegate, public ActionRecorder {
     59  public:
     60   TestDelegate()
     61       : can_freeze_renderers_(true),
     62         freeze_renderers_result_(true),
     63         thaw_renderers_result_(true) {}
     64 
     65   virtual ~TestDelegate() {}
     66 
     67   // RendererFreezer::Delegate overrides.
     68   virtual bool FreezeRenderers() OVERRIDE {
     69     AppendAction(kFreezeRenderers);
     70 
     71     return freeze_renderers_result_;
     72   }
     73   virtual bool ThawRenderers() OVERRIDE {
     74     AppendAction(kThawRenderers);
     75 
     76     return thaw_renderers_result_;
     77   }
     78   virtual bool CanFreezeRenderers() OVERRIDE { return can_freeze_renderers_; }
     79 
     80   void set_freeze_renderers_result(bool result) {
     81     freeze_renderers_result_ = result;
     82   }
     83 
     84   void set_thaw_renderers_result(bool result) {
     85     thaw_renderers_result_ = result;
     86   }
     87 
     88   // Sets whether the delegate is capable of freezing renderers.  This also
     89   // changes |freeze_renderers_result_| and |thaw_renderers_result_|.
     90   void set_can_freeze_renderers(bool can_freeze) {
     91     can_freeze_renderers_ = can_freeze;
     92 
     93     // If the delegate cannot freeze renderers, then the result of trying to do
     94     // so will be false.
     95     freeze_renderers_result_ = can_freeze;
     96     thaw_renderers_result_ = can_freeze;
     97   }
     98 
     99  private:
    100   bool can_freeze_renderers_;
    101   bool freeze_renderers_result_;
    102   bool thaw_renderers_result_;
    103 
    104   DISALLOW_COPY_AND_ASSIGN(TestDelegate);
    105 };
    106 
    107 }  // namespace
    108 
    109 class RendererFreezerTest : public testing::Test {
    110  public:
    111   RendererFreezerTest()
    112       : power_manager_client_(new FakePowerManagerClient()),
    113         test_delegate_(new TestDelegate()) {
    114     DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
    115         scoped_ptr<PowerManagerClient>(power_manager_client_));
    116   }
    117 
    118   virtual ~RendererFreezerTest() {
    119     renderer_freezer_.reset();
    120 
    121     DBusThreadManager::Shutdown();
    122   }
    123 
    124   void Init() {
    125     renderer_freezer_.reset(new RendererFreezer(
    126         scoped_ptr<RendererFreezer::Delegate>(test_delegate_)));
    127   }
    128 
    129  protected:
    130   FakePowerManagerClient* power_manager_client_;
    131   TestDelegate* test_delegate_;
    132 
    133   scoped_ptr<RendererFreezer> renderer_freezer_;
    134 
    135  private:
    136   base::MessageLoop message_loop_;
    137   DISALLOW_COPY_AND_ASSIGN(RendererFreezerTest);
    138 };
    139 
    140 // Tests that the RendererFreezer freezes renderers on suspend and thaws them on
    141 // resume.
    142 TEST_F(RendererFreezerTest, SuspendResume) {
    143   Init();
    144 
    145   power_manager_client_->SendSuspendImminent();
    146 
    147   // The RendererFreezer should have grabbed an asynchronous callback and done
    148   // nothing else.
    149   EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks());
    150   EXPECT_EQ(kNoActions, test_delegate_->GetActions());
    151 
    152   // The RendererFreezer should eventually freeze the renderers and run the
    153   // callback.
    154   base::RunLoop().RunUntilIdle();
    155   EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks());
    156   EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions());
    157 
    158   // The renderers should be thawed when we resume.
    159   power_manager_client_->SendSuspendDone();
    160   EXPECT_EQ(kThawRenderers, test_delegate_->GetActions());
    161 }
    162 
    163 // Tests that the RendereFreezer doesn't freeze renderers if the suspend attempt
    164 // was canceled before it had a chance to complete.
    165 TEST_F(RendererFreezerTest, SuspendCanceled) {
    166   Init();
    167 
    168   // We shouldn't do anything yet.
    169   power_manager_client_->SendSuspendImminent();
    170   EXPECT_EQ(kNoActions, test_delegate_->GetActions());
    171 
    172   // If a suspend gets canceled for any reason, we should see a SuspendDone().
    173   power_manager_client_->SendSuspendDone();
    174 
    175   // We shouldn't try to freeze the renderers now.
    176   base::RunLoop().RunUntilIdle();
    177   EXPECT_EQ(kNoActions, test_delegate_->GetActions());
    178 }
    179 
    180 // Tests that the renderer freezer does nothing if the delegate cannot freeze
    181 // renderers.
    182 TEST_F(RendererFreezerTest, DelegateCannotFreezeRenderers) {
    183   test_delegate_->set_can_freeze_renderers(false);
    184   Init();
    185 
    186   power_manager_client_->SendSuspendImminent();
    187 
    188   // The RendererFreezer should not have grabbed a callback or done anything
    189   // else.
    190   EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks());
    191   EXPECT_EQ(kNoActions, test_delegate_->GetActions());
    192 
    193   // There should be nothing in the message loop.
    194   base::RunLoop().RunUntilIdle();
    195   EXPECT_EQ(kNoActions, test_delegate_->GetActions());
    196 
    197   // Nothing happens on resume.
    198   power_manager_client_->SendSuspendDone();
    199   EXPECT_EQ(kNoActions, test_delegate_->GetActions());
    200 }
    201 
    202 // Tests that the RendererFreezer does nothing on resume if the freezing
    203 // operation was unsuccessful.
    204 TEST_F(RendererFreezerTest, ErrorFreezingRenderers) {
    205   Init();
    206   test_delegate_->set_freeze_renderers_result(false);
    207 
    208   power_manager_client_->SendSuspendImminent();
    209   EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks());
    210 
    211   // The freezing operation should fail, but we should still report readiness.
    212   base::RunLoop().RunUntilIdle();
    213   EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions());
    214   EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks());
    215 
    216   // Since the delegate reported that the freezing was unsuccessful, don't do
    217   // anything on resume.
    218   power_manager_client_->SendSuspendDone();
    219   EXPECT_EQ(kNoActions, test_delegate_->GetActions());
    220 }
    221 
    222 #if defined(GTEST_HAS_DEATH_TEST)
    223 // Tests that the RendererFreezer crashes the browser if the freezing operation
    224 // was successful but the thawing operation failed.
    225 TEST_F(RendererFreezerTest, ErrorThawingRenderers) {
    226   Init();
    227   test_delegate_->set_thaw_renderers_result(false);
    228 
    229   power_manager_client_->SendSuspendImminent();
    230   base::RunLoop().RunUntilIdle();
    231   EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions());
    232 
    233   EXPECT_DEATH(power_manager_client_->SendSuspendDone(), "Unable to thaw");
    234 }
    235 #endif  // GTEST_HAS_DEATH_TEST
    236 
    237 }  // namespace chromeos
    238