diff options
author | Konstantin Varlamov <var-const@users.noreply.github.com> | 2018-05-07 12:22:57 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-07 12:22:57 -0400 |
commit | 38824e721ebaa3f50e443e1ea4b47d34030e4703 (patch) | |
tree | b4a7f806b52f40d85fb92e571c216acaeba2fdc3 /Firestore/core/test/firebase/firestore/util/async_tests_util.h | |
parent | 04a28fce81c737b6505e6c542a14d8529c9f891d (diff) |
C++ migration: add AsyncQueue, the C++ version of FSTDispatchQueue (#1176)
AsyncQueue is a queue that executes given operations asynchronously,
enforcing that only a single operation is executing at any given time,
and that in-progress operations don't spawn more operations. The actual
execution is delegated to a platform-specific executor. Executor is an
interface for a FIFO queue that executes given operations serially. Two
implementations of Executor, one using libdispatch and the other using
C++11 standard library, are provided.
AsyncQueue is not used anywhere in the code base at this point.
Diffstat (limited to 'Firestore/core/test/firebase/firestore/util/async_tests_util.h')
-rw-r--r-- | Firestore/core/test/firebase/firestore/util/async_tests_util.h | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/Firestore/core/test/firebase/firestore/util/async_tests_util.h b/Firestore/core/test/firebase/firestore/util/async_tests_util.h new file mode 100644 index 0000000..422745b --- /dev/null +++ b/Firestore/core/test/firebase/firestore/util/async_tests_util.h @@ -0,0 +1,90 @@ +/* + * Copyright 2018 Google + * + * 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 + * + * http://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. + */ + +#ifndef FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_UTIL_ASYNC_TESTS_UTIL_H_ +#define FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_UTIL_ASYNC_TESTS_UTIL_H_ + +#include <chrono> // NOLINT(build/c++11) +#include <cstdlib> +#include <future> // NOLINT(build/c++11) + +#include "gtest/gtest.h" + +namespace firebase { +namespace firestore { +namespace util { + +inline std::chrono::time_point<std::chrono::system_clock, + std::chrono::milliseconds> +now() { + return std::chrono::time_point_cast<std::chrono::milliseconds>( + std::chrono::system_clock::now()); +} + +constexpr auto kTimeout = std::chrono::seconds(5); + +// Waits for the future to become ready and returns whether it timed out. +inline bool Await(const std::future<void>& future, + const std::chrono::milliseconds timeout = kTimeout) { + return future.wait_for(timeout) == std::future_status::ready; +} + +// Unfortunately, the future returned from std::async blocks in its destructor +// until the async call is finished. If the function called from std::async is +// buggy and hangs forever, the future's destructor will also hang forever. To +// avoid all tests freezing, the only thing to do is to abort (which skips +// destructors). +inline void Abort() { + ADD_FAILURE(); + std::abort(); +} + +// Calls std::abort if the future times out. +inline void AbortOnTimeout(const std::future<void>& future) { + if (!Await(future, kTimeout)) { + Abort(); + } +} + +// The macro calls AbortOnTimeout, but preserves stack trace. +#define ABORT_ON_TIMEOUT(future) \ + do { \ + SCOPED_TRACE("Async operation timed out, aborting..."); \ + AbortOnTimeout(future); \ + } while (0) + +class TestWithTimeoutMixin { + public: + TestWithTimeoutMixin() : signal_finished{[] {}} { + } + + // Googletest doesn't contain built-in functionality to block until an async + // operation completes, and there is no timeout by default. Work around both + // by resolving a packaged_task in the async operation and blocking on the + // associated future (with timeout). + bool WaitForTestToFinish(const std::chrono::seconds timeout = kTimeout) { + return signal_finished.get_future().wait_for(timeout) == + std::future_status::ready; + } + + std::packaged_task<void()> signal_finished; +}; + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_TEST_FIREBASE_FIRESTORE_UTIL_ASYNC_TESTS_UTIL_H_ |