Home | History | Annotate | Download | only in base
      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 "base/bind.h"
      6 #include "base/files/file_path.h"
      7 #include "base/memory/ref_counted.h"
      8 #include "base/scoped_native_library.h"
      9 #include "remoting/base/auto_thread.h"
     10 #include "testing/gtest/include/gtest/gtest.h"
     11 
     12 #if defined(OS_WIN)
     13 #include <objbase.h>
     14 #include "base/win/windows_version.h"
     15 #endif
     16 
     17 namespace {
     18 
     19 const char kThreadName[] = "Test thread";
     20 
     21 void SetFlagTask(bool* success) {
     22   *success = true;
     23 }
     24 
     25 void PostSetFlagTask(
     26     scoped_refptr<base::TaskRunner> task_runner,
     27     bool* success) {
     28   task_runner->PostTask(FROM_HERE, base::Bind(&SetFlagTask, success));
     29 }
     30 
     31 #if defined(OS_WIN)
     32 void CheckComAptTypeTask(APTTYPE* apt_type_out, HRESULT* hresult) {
     33   typedef HRESULT (WINAPI * CoGetApartmentTypeFunc)
     34       (APTTYPE*, APTTYPEQUALIFIER*);
     35 
     36   // CoGetApartmentType requires Windows 7 or above.
     37   if (base::win::GetVersion() < base::win::VERSION_WIN7) {
     38     *hresult = E_NOTIMPL;
     39     return;
     40   }
     41 
     42   // Dynamic link to the API so the same test binary can run on older systems.
     43   base::ScopedNativeLibrary com_library(base::FilePath(L"ole32.dll"));
     44   ASSERT_TRUE(com_library.is_valid());
     45   CoGetApartmentTypeFunc co_get_apartment_type =
     46       static_cast<CoGetApartmentTypeFunc>(
     47           com_library.GetFunctionPointer("CoGetApartmentType"));
     48   ASSERT_TRUE(co_get_apartment_type != NULL);
     49 
     50   APTTYPEQUALIFIER apt_type_qualifier;
     51   *hresult = (*co_get_apartment_type)(apt_type_out, &apt_type_qualifier);
     52 }
     53 #endif
     54 
     55 }  // namespace
     56 
     57 namespace remoting {
     58 
     59 class AutoThreadTest : public testing::Test {
     60  public:
     61   AutoThreadTest() : message_loop_quit_correctly_(false) {
     62   }
     63 
     64   void RunMessageLoop() {
     65     // Release |main_task_runner_|, then run |message_loop_| until other
     66     // references created in tests are gone.  We also post a delayed quit
     67     // task to |message_loop_| so the test will not hang on failure.
     68     main_task_runner_ = NULL;
     69     message_loop_.PostDelayedTask(FROM_HERE,
     70                                   base::MessageLoop::QuitClosure(),
     71                                   base::TimeDelta::FromSeconds(5));
     72     message_loop_.Run();
     73   }
     74 
     75   virtual void SetUp() OVERRIDE {
     76     main_task_runner_ = new AutoThreadTaskRunner(
     77         message_loop_.message_loop_proxy(),
     78         base::Bind(&AutoThreadTest::QuitMainMessageLoop,
     79                    base::Unretained(this)));
     80   }
     81 
     82   virtual void TearDown() OVERRIDE {
     83     // Verify that |message_loop_| was quit by the AutoThreadTaskRunner.
     84     EXPECT_TRUE(message_loop_quit_correctly_);
     85   }
     86 
     87  protected:
     88   void QuitMainMessageLoop() {
     89     message_loop_quit_correctly_ = true;
     90     message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
     91   }
     92 
     93   base::MessageLoop message_loop_;
     94   bool message_loop_quit_correctly_;
     95   scoped_refptr<AutoThreadTaskRunner> main_task_runner_;
     96 };
     97 
     98 TEST_F(AutoThreadTest, StartAndStop) {
     99   // Create an AutoThread joined by our MessageLoop.
    100   scoped_refptr<base::TaskRunner> task_runner =
    101       AutoThread::Create(kThreadName, main_task_runner_);
    102   EXPECT_TRUE(task_runner.get());
    103 
    104   task_runner = NULL;
    105   RunMessageLoop();
    106 }
    107 
    108 TEST_F(AutoThreadTest, ProcessTask) {
    109   // Create an AutoThread joined by our MessageLoop.
    110   scoped_refptr<base::TaskRunner> task_runner =
    111       AutoThread::Create(kThreadName, main_task_runner_);
    112   EXPECT_TRUE(task_runner.get());
    113 
    114   // Post a task to it.
    115   bool success = false;
    116   task_runner->PostTask(FROM_HERE, base::Bind(&SetFlagTask, &success));
    117 
    118   task_runner = NULL;
    119   RunMessageLoop();
    120 
    121   EXPECT_TRUE(success);
    122 }
    123 
    124 TEST_F(AutoThreadTest, ThreadDependency) {
    125   // Create two AutoThreads joined by our MessageLoop.
    126   scoped_refptr<base::TaskRunner> task_runner1 =
    127       AutoThread::Create(kThreadName, main_task_runner_);
    128   EXPECT_TRUE(task_runner1.get());
    129   scoped_refptr<base::TaskRunner> task_runner2 =
    130       AutoThread::Create(kThreadName, main_task_runner_);
    131   EXPECT_TRUE(task_runner2.get());
    132 
    133   // Post a task to thread 1 that will post a task to thread 2.
    134   bool success = false;
    135   task_runner1->PostTask(FROM_HERE,
    136       base::Bind(&PostSetFlagTask, task_runner2, &success));
    137 
    138   task_runner1 = NULL;
    139   task_runner2 = NULL;
    140   RunMessageLoop();
    141 
    142   EXPECT_TRUE(success);
    143 }
    144 
    145 #if defined(OS_WIN)
    146 TEST_F(AutoThreadTest, ThreadWithComMta) {
    147   scoped_refptr<base::TaskRunner> task_runner =
    148       AutoThread::CreateWithLoopAndComInitTypes(kThreadName,
    149                                                 main_task_runner_,
    150                                                 base::MessageLoop::TYPE_DEFAULT,
    151                                                 AutoThread::COM_INIT_MTA);
    152   EXPECT_TRUE(task_runner.get());
    153 
    154   // Post a task to query the COM apartment type.
    155   HRESULT hresult = E_FAIL;
    156   APTTYPE apt_type = APTTYPE_NA;
    157   task_runner->PostTask(FROM_HERE,
    158                         base::Bind(&CheckComAptTypeTask, &apt_type, &hresult));
    159 
    160   task_runner = NULL;
    161   RunMessageLoop();
    162 
    163   // CoGetApartmentType requires Windows 7 or above.
    164   if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
    165     EXPECT_EQ(S_OK, hresult);
    166     EXPECT_EQ(APTTYPE_MTA, apt_type);
    167   } else {
    168     EXPECT_EQ(E_NOTIMPL, hresult);
    169   }
    170 }
    171 
    172 TEST_F(AutoThreadTest, ThreadWithComSta) {
    173   scoped_refptr<base::TaskRunner> task_runner =
    174       AutoThread::CreateWithLoopAndComInitTypes(kThreadName,
    175                                                 main_task_runner_,
    176                                                 base::MessageLoop::TYPE_UI,
    177                                                 AutoThread::COM_INIT_STA);
    178   EXPECT_TRUE(task_runner.get());
    179 
    180   // Post a task to query the COM apartment type.
    181   HRESULT hresult = E_FAIL;
    182   APTTYPE apt_type = APTTYPE_NA;
    183   task_runner->PostTask(FROM_HERE,
    184                         base::Bind(&CheckComAptTypeTask, &apt_type, &hresult));
    185 
    186   task_runner = NULL;
    187   RunMessageLoop();
    188 
    189   // CoGetApartmentType requires Windows 7 or above.
    190   if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
    191     EXPECT_EQ(S_OK, hresult);
    192     // Whether the thread is the "main" STA apartment depends upon previous
    193     // COM activity in this test process, so allow both types here.
    194     EXPECT_TRUE(apt_type == APTTYPE_MAINSTA || apt_type == APTTYPE_STA);
    195   } else {
    196     EXPECT_EQ(E_NOTIMPL, hresult);
    197   }
    198 }
    199 #endif // defined(OS_WIN)
    200 
    201 }  // namespace remoting
    202