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