webrtc_m130/test/wait_until.h
Evan Shrubsole 1d2f30b8b9 Add utility WaitUntil for testing for an eventual condition
This replaces the WaitUntilCondition function that was used in the
peer_connection_encodings_integrationtest previously. Along with that it
adds tests and improved error message printing.

As a drive-by, matchers were added for RTCError as these are the return
type of this utility function.

Bug: webrtc:381524905
Change-Id: If7ff18692396d3996b5b289f2d2c92520226003e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/369980
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Evan Shrubsole <eshr@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43494}
2024-12-04 13:51:30 +00:00

93 lines
2.9 KiB
C++

/*
* Copyright 2024 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef TEST_WAIT_UNTIL_H_
#define TEST_WAIT_UNTIL_H_
#include <string>
#include "absl/base/nullability.h"
#include "api/rtc_error.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "rtc_base/checks.h"
#include "rtc_base/thread.h"
#include "system_wrappers/include/clock.h"
#include "test/gmock.h"
#include "test/wait_until_internal.h" // IWYU pragma: private
namespace webrtc {
struct WaitUntilSettings {
// The maximum time to wait for the condition to be met.
TimeDelta timeout = TimeDelta::Seconds(5);
// The interval between polling the condition.
TimeDelta polling_interval = TimeDelta::Millis(1);
// The clock to use for timing.
absl::Nullable<SimulatedClock*> clock = nullptr;
// Name of the result to be used in the error message.
std::string result_name = "result";
};
// Runs a function `fn`, which returns a result, until `matcher` matches the
// result.
//
// The function is called repeatedly until the result matches the matcher or the
// timeout is reached. If the matcher matches the result, the result is
// returned. Otherwise, an error is returned.
//
// Example:
//
// int counter = 0;
// RTCErrorOr<int> result = Waituntil([&] { return ++counter; }, Eq(3))
// EXPECT_THAT(result, IsOkAndHolds(3));
template <typename Fn, typename Matcher>
auto WaitUntil(const Fn& fn, Matcher matcher, WaitUntilSettings settings = {})
-> RTCErrorOr<decltype(fn())> {
if (!settings.clock) {
RTC_CHECK(rtc::Thread::Current()) << "A current thread is required. An "
"rtc::AutoThread can work for tests.";
}
absl::Nonnull<Clock*> clock =
settings.clock ? settings.clock : Clock::GetRealTimeClock();
Timestamp start = clock->CurrentTime();
do {
auto result = fn();
if (testing::Value(result, matcher)) {
return result;
}
if (settings.clock) {
settings.clock->AdvanceTime(settings.polling_interval);
} else {
rtc::Thread::Current()->ProcessMessages(0);
rtc::Thread::Current()->SleepMs(settings.polling_interval.ms());
}
} while (clock->CurrentTime() < start + settings.timeout);
// One more try after the last sleep. This failure will contain the error
// message.
auto result = fn();
testing::StringMatchResultListener listener;
if (wait_until_internal::ExplainMatchResult(matcher, result, &listener,
settings.result_name)) {
return result;
}
return RTCError(RTCErrorType::INTERNAL_ERROR, listener.str());
}
} // namespace webrtc
#endif // TEST_WAIT_UNTIL_H_