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