// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "platform/impl/windows/scheduled_executor.h" #include #include "platform/impl/windows/test_data.h" #include "gtest/gtest.h" TEST(ScheduledExecutorTests, ExecuteSucceeds) { // Arrange std::string expected(RUNNABLE_0_TEXT.c_str()); std::unique_ptr submittableExecutor = std::make_unique(); std::string output = std::string(); // Container to note threads that ran std::unique_ptr> threadIds = std::make_unique>(); CRITICAL_SECTION crit_sec; InitializeCriticalSection(&crit_sec); threadIds->push_back(GetCurrentThreadId()); // Act submittableExecutor->Execute([&output, &threadIds, &crit_sec]() { EnterCriticalSection(&crit_sec); threadIds->push_back(GetCurrentThreadId()); output.append(RUNNABLE_0_TEXT.c_str()); LeaveCriticalSection(&crit_sec); }); submittableExecutor->Shutdown(); DeleteCriticalSection(&crit_sec); // Assert // We should've run 1 time on the main thread, and 1 times on the // workerThread ASSERT_EQ(threadIds->size(), 2); // We should still be on the main thread ASSERT_EQ(GetCurrentThreadId(), threadIds->at(0)); // We should've run all runnables on the worker thread ASSERT_EQ(output, expected); } TEST(ScheduledExecutorTests, ScheduleSucceeds) { // Arrange std::string expected(RUNNABLE_0_TEXT.c_str()); std::unique_ptr submittableExecutor = std::make_unique(); std::string output = std::string(); // Container to note threads that ran std::unique_ptr> threadIds = std::make_unique>(); CRITICAL_SECTION crit_sec; InitializeCriticalSection(&crit_sec); threadIds->push_back(GetCurrentThreadId()); std::chrono::system_clock::time_point timeNow = std::chrono::system_clock::now(); std::chrono::system_clock::time_point timeExecuted; // Act submittableExecutor->Schedule( [&output, &threadIds, &timeExecuted, &crit_sec]() { EnterCriticalSection(&crit_sec); timeExecuted = std::chrono::system_clock::now(); threadIds->push_back(GetCurrentThreadId()); output.append(RUNNABLE_0_TEXT.c_str()); LeaveCriticalSection(&crit_sec); }, absl::Milliseconds(50)); SleepEx(100, true); // Yield the thread submittableExecutor->Shutdown(); DeleteCriticalSection(&crit_sec); auto difference = std::chrono::duration_cast( timeExecuted - timeNow) .count(); // Assert // We should've run 1 time on the main thread, and 1 times on the // workerThread ASSERT_TRUE(difference >= 50) << "difference was: " << difference; ASSERT_TRUE(difference < 100) << "difference was: " << difference; ASSERT_EQ(threadIds->size(), 2); // We should still be on the main thread ASSERT_EQ(GetCurrentThreadId(), threadIds->at(0)); // We should've run all runnables on the worker thread ASSERT_EQ(output, expected); } TEST(ScheduledExecutorTests, CancelSucceeds) { // Arrange std::string expected(""); std::unique_ptr submittableExecutor = std::make_unique(); std::string output = std::string(); // Container to note threads that ran std::unique_ptr> threadIds = std::make_unique>(); threadIds->push_back(GetCurrentThreadId()); // Act auto cancelable = submittableExecutor->Schedule( [&output, &threadIds]() { threadIds->push_back(GetCurrentThreadId()); output.append(RUNNABLE_0_TEXT.c_str()); }, absl::Milliseconds(1000)); SleepEx(100, true); // Yield the thread auto actual = cancelable->Cancel(); submittableExecutor->Shutdown(); // Assert ASSERT_TRUE(actual); ASSERT_EQ(threadIds->size(), 1); // We should still be on the main thread ASSERT_EQ(GetCurrentThreadId(), threadIds->at(0)); // We should've run all runnables on the worker thread ASSERT_EQ(output, expected); } TEST(ScheduledExecutorTests, CancelAfterStartedFails) { // Arrange std::string expected(RUNNABLE_0_TEXT.c_str()); std::unique_ptr submittableExecutor = std::make_unique(); std::string output = std::string(); // Container to note threads that ran std::unique_ptr> threadIds = std::make_unique>(); CRITICAL_SECTION crit_sec; InitializeCriticalSection(&crit_sec); threadIds->push_back(GetCurrentThreadId()); // Act auto cancelable = submittableExecutor->Schedule( [&output, &threadIds, &crit_sec]() { EnterCriticalSection(&crit_sec); threadIds->push_back(GetCurrentThreadId()); output.append(RUNNABLE_0_TEXT.c_str()); LeaveCriticalSection(&crit_sec); }, absl::Milliseconds(100)); SleepEx(1000, true); // Yield the thread auto actual = cancelable->Cancel(); submittableExecutor->Shutdown(); DeleteCriticalSection(&crit_sec); // Assert ASSERT_FALSE(actual); ASSERT_EQ(threadIds->size(), 2); // We should still be on the main thread ASSERT_EQ(GetCurrentThreadId(), threadIds->at(0)); // We should've run all runnables on the worker thread ASSERT_EQ(output, expected); }