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