Home | History | Annotate | Download | only in test
      1 // Copyright (c) 2012 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 <stdarg.h>
      6 #include <string.h>
      7 
      8 #include "base/android/path_utils.h"
      9 #include "base/files/file_path.h"
     10 #include "base/logging.h"
     11 #include "base/memory/singleton.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/message_loop/message_pump_android.h"
     14 #include "base/path_service.h"
     15 #include "base/synchronization/waitable_event.h"
     16 
     17 namespace {
     18 
     19 struct RunState {
     20   RunState(base::MessagePump::Delegate* delegate, int run_depth)
     21       : delegate(delegate),
     22         run_depth(run_depth),
     23         should_quit(false) {
     24   }
     25 
     26   base::MessagePump::Delegate* delegate;
     27 
     28   // Used to count how many Run() invocations are on the stack.
     29   int run_depth;
     30 
     31   // Used to flag that the current Run() invocation should return ASAP.
     32   bool should_quit;
     33 };
     34 
     35 RunState* g_state = NULL;
     36 
     37 // A singleton WaitableEvent wrapper so we avoid a busy loop in
     38 // MessagePumpForUIStub. Other platforms use the native event loop which blocks
     39 // when there are no pending messages.
     40 class Waitable {
     41  public:
     42    static Waitable* GetInstance() {
     43      return Singleton<Waitable>::get();
     44    }
     45 
     46    // Signals that there are more work to do.
     47    void Signal() {
     48      waitable_event_.Signal();
     49    }
     50 
     51    // Blocks until more work is scheduled.
     52    void Block() {
     53      waitable_event_.Wait();
     54    }
     55 
     56    void Quit() {
     57      g_state->should_quit = true;
     58      Signal();
     59    }
     60 
     61  private:
     62   friend struct DefaultSingletonTraits<Waitable>;
     63 
     64   Waitable()
     65       : waitable_event_(false, false) {
     66   }
     67 
     68   base::WaitableEvent waitable_event_;
     69 
     70   DISALLOW_COPY_AND_ASSIGN(Waitable);
     71 };
     72 
     73 // The MessagePumpForUI implementation for test purpose.
     74 class MessagePumpForUIStub : public base::MessagePumpForUI {
     75   virtual ~MessagePumpForUIStub() {}
     76 
     77   virtual void Start(base::MessagePump::Delegate* delegate) OVERRIDE {
     78     NOTREACHED() << "The Start() method shouldn't be called in test, using"
     79         " Run() method should be used.";
     80   }
     81 
     82   virtual void Run(base::MessagePump::Delegate* delegate) OVERRIDE {
     83     // The following was based on message_pump_glib.cc, except we're using a
     84     // WaitableEvent since there are no native message loop to use.
     85     RunState state(delegate, g_state ? g_state->run_depth + 1 : 1);
     86 
     87     RunState* previous_state = g_state;
     88     g_state = &state;
     89 
     90     bool more_work_is_plausible = true;
     91 
     92     for (;;) {
     93       if (!more_work_is_plausible) {
     94         Waitable::GetInstance()->Block();
     95         if (g_state->should_quit)
     96           break;
     97       }
     98 
     99       more_work_is_plausible = g_state->delegate->DoWork();
    100       if (g_state->should_quit)
    101         break;
    102 
    103       base::TimeTicks delayed_work_time;
    104       more_work_is_plausible |=
    105           g_state->delegate->DoDelayedWork(&delayed_work_time);
    106       if (g_state->should_quit)
    107         break;
    108 
    109       if (more_work_is_plausible)
    110         continue;
    111 
    112       more_work_is_plausible = g_state->delegate->DoIdleWork();
    113       if (g_state->should_quit)
    114         break;
    115 
    116       more_work_is_plausible |= !delayed_work_time.is_null();
    117     }
    118 
    119     g_state = previous_state;
    120   }
    121 
    122   virtual void Quit() OVERRIDE {
    123     Waitable::GetInstance()->Quit();
    124   }
    125 
    126   virtual void ScheduleWork() OVERRIDE {
    127     Waitable::GetInstance()->Signal();
    128   }
    129 
    130   virtual void ScheduleDelayedWork(
    131       const base::TimeTicks& delayed_work_time) OVERRIDE {
    132     Waitable::GetInstance()->Signal();
    133   }
    134 };
    135 
    136 base::MessagePump* CreateMessagePumpForUIStub() {
    137   return new MessagePumpForUIStub();
    138 };
    139 
    140 // Provides the test path for DIR_MODULE and DIR_ANDROID_APP_DATA.
    141 bool GetTestProviderPath(int key, base::FilePath* result) {
    142   switch (key) {
    143     case base::DIR_MODULE: {
    144       return base::android::GetExternalStorageDirectory(result);
    145     }
    146     case base::DIR_ANDROID_APP_DATA: {
    147       // For tests, app data is put in external storage.
    148       return base::android::GetExternalStorageDirectory(result);
    149     }
    150     default:
    151       return false;
    152   }
    153 }
    154 
    155 void InitPathProvider(int key) {
    156   base::FilePath path;
    157   // If failed to override the key, that means the way has not been registered.
    158   if (GetTestProviderPath(key, &path) && !PathService::Override(key, path))
    159     PathService::RegisterProvider(&GetTestProviderPath, key, key + 1);
    160 }
    161 
    162 }  // namespace
    163 
    164 namespace base {
    165 
    166 void InitAndroidTestLogging() {
    167   logging::LoggingSettings settings;
    168   settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
    169   logging::InitLogging(settings);
    170   // To view log output with IDs and timestamps use "adb logcat -v threadtime".
    171   logging::SetLogItems(false,    // Process ID
    172                        false,    // Thread ID
    173                        false,    // Timestamp
    174                        false);   // Tick count
    175 }
    176 
    177 void InitAndroidTestPaths() {
    178   InitPathProvider(DIR_MODULE);
    179   InitPathProvider(DIR_ANDROID_APP_DATA);
    180 }
    181 
    182 void InitAndroidTestMessageLoop() {
    183   if (!MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIStub))
    184     LOG(INFO) << "MessagePumpForUIFactory already set, unable to override.";
    185 }
    186 
    187 void InitAndroidTest() {
    188   InitAndroidTestLogging();
    189   InitAndroidTestPaths();
    190   InitAndroidTestMessageLoop();
    191 }
    192 }  // namespace base
    193