mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
chore: cherry-pick 24293de155 from chromium (#30262)
Co-authored-by: Electron Bot <electron@github.com>
This commit is contained in:
@@ -179,4 +179,5 @@ cherry-pick-e60cc80ff744.patch
|
||||
fix_use-after-free_with_xslt_strip-space.patch
|
||||
cherry-pick-3feda0244490.patch
|
||||
cherry-pick-cd98d7c0dae9.patch
|
||||
replace_first_of_two_waitableevents_in_creditcardaccessmanager.patch
|
||||
cherry-pick-ac9dc1235e28.patch
|
||||
|
||||
@@ -0,0 +1,574 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dominic Battre <battre@chromium.org>
|
||||
Date: Wed, 7 Jul 2021 20:02:45 +0000
|
||||
Subject: Replace first of two WaitableEvents in CreditCardAccessManager
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
(cherry picked from commit 48cf01e4039fecbe119d8223d1f6072aaf44f258)
|
||||
|
||||
Bug: 1214234
|
||||
Change-Id: I38171be7b38982f25abfbb3dff7a41f19a167764
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3001123
|
||||
Reviewed-by: Jared Saul <jsaul@google.com>
|
||||
Commit-Queue: Dominic Battré <battre@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#898237}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3011066
|
||||
Reviewed-by: Dominic Battré <battre@chromium.org>
|
||||
Reviewed-by: Prudhvi Kumar Bommana <pbommana@google.com>
|
||||
Owners-Override: Prudhvi Kumar Bommana <pbommana@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4515@{#1366}
|
||||
Cr-Branched-From: 488fc70865ddaa05324ac00a54a6eb783b4bc41c-refs/heads/master@{#885287}
|
||||
|
||||
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
|
||||
index 3447ad7a30331d3fc31653083f1411784c244198..ed26a8dd8e0e444ec8e37b292c5fbde4ed0bbc91 100644
|
||||
--- a/components/autofill/core/browser/BUILD.gn
|
||||
+++ b/components/autofill/core/browser/BUILD.gn
|
||||
@@ -213,6 +213,8 @@ static_library("browser") {
|
||||
"payments/payments_util.cc",
|
||||
"payments/payments_util.h",
|
||||
"payments/risk_data_loader.h",
|
||||
+ "payments/wait_for_signal_or_timeout.cc",
|
||||
+ "payments/wait_for_signal_or_timeout.h",
|
||||
"payments/strike_database.cc",
|
||||
"payments/strike_database.h",
|
||||
"payments/strike_database_integrator_base.cc",
|
||||
@@ -638,6 +640,7 @@ source_set("unit_tests") {
|
||||
"payments/payments_client_unittest.cc",
|
||||
"payments/payments_service_url_unittest.cc",
|
||||
"payments/payments_util_unittest.cc",
|
||||
+ "payments/wait_for_signal_or_timeout_unittest.cc",
|
||||
"payments/strike_database_integrator_test_strike_database_unittest.cc",
|
||||
"payments/strike_database_unittest.cc",
|
||||
"personal_data_manager_unittest.cc",
|
||||
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc
|
||||
index cbd1018b3dd6c30cec3a92f6e0108fadf7a48dc8..46b143fcc5e1736736e913c8a32f21d15a85be33 100644
|
||||
--- a/components/autofill/core/browser/payments/credit_card_access_manager.cc
|
||||
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "base/task/post_task.h"
|
||||
#include "base/task/task_traits.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
-#include "base/threading/sequenced_task_runner_handle.h"
|
||||
#include "base/time/time.h"
|
||||
#include "build/build_config.h"
|
||||
#include "components/autofill/core/browser/autofill_client.h"
|
||||
@@ -47,12 +46,6 @@ constexpr int64_t kUnmaskDetailsResponseTimeoutMs = 3 * 1000; // 3 sec
|
||||
// Time to wait between multiple calls to GetUnmaskDetails().
|
||||
constexpr int64_t kDelayForGetUnmaskDetails = 3 * 60 * 1000; // 3 min
|
||||
|
||||
-// Used for asynchronously waiting for |event| to be signaled.
|
||||
-bool WaitForEvent(base::WaitableEvent* event) {
|
||||
- event->declare_only_used_while_idle();
|
||||
- return event->TimedWait(
|
||||
- base::TimeDelta::FromMilliseconds(kUnmaskDetailsResponseTimeoutMs));
|
||||
-}
|
||||
} // namespace
|
||||
|
||||
CreditCardAccessManager::CreditCardAccessManager(
|
||||
@@ -65,9 +58,6 @@ CreditCardAccessManager::CreditCardAccessManager(
|
||||
payments_client_(client_->GetPaymentsClient()),
|
||||
personal_data_manager_(personal_data_manager),
|
||||
form_event_logger_(form_event_logger),
|
||||
- ready_to_start_authentication_(
|
||||
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
||||
- base::WaitableEvent::InitialState::NOT_SIGNALED),
|
||||
can_fetch_unmask_details_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
||||
base::WaitableEvent::InitialState::SIGNALED) {
|
||||
}
|
||||
@@ -341,12 +331,10 @@ void CreditCardAccessManager::FetchCreditCard(
|
||||
|
||||
// Wait for |ready_to_start_authentication_| to be signaled by
|
||||
// OnDidGetUnmaskDetails() or until timeout before calling Authenticate().
|
||||
- auto task_runner = base::ThreadPool::CreateTaskRunner({base::MayBlock()});
|
||||
- cancelable_authenticate_task_tracker_.PostTaskAndReplyWithResult(
|
||||
- task_runner.get(), FROM_HERE,
|
||||
- base::BindOnce(&WaitForEvent, &ready_to_start_authentication_),
|
||||
+ ready_to_start_authentication_.OnEventOrTimeOut(
|
||||
base::BindOnce(&CreditCardAccessManager::Authenticate,
|
||||
- weak_ptr_factory_.GetWeakPtr()));
|
||||
+ weak_ptr_factory_.GetWeakPtr()),
|
||||
+ base::TimeDelta::FromMilliseconds(kUnmaskDetailsResponseTimeoutMs));
|
||||
} else {
|
||||
Authenticate(get_unmask_details_returned);
|
||||
}
|
||||
@@ -711,7 +699,6 @@ void CreditCardAccessManager::HandleDialogUserResponse(
|
||||
case WebauthnDialogCallbackType::kVerificationCancelled:
|
||||
// TODO(crbug.com/949269): Add tests and logging for canceling verify
|
||||
// pending dialog.
|
||||
- cancelable_authenticate_task_tracker_.TryCancelAll();
|
||||
payments_client_->CancelRequest();
|
||||
SignalCanFetchUnmaskDetails();
|
||||
ready_to_start_authentication_.Reset();
|
||||
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.h b/components/autofill/core/browser/payments/credit_card_access_manager.h
|
||||
index 6bdf8b8c647f885aad5784f737e117b3a55bd2be..99f6581b7320312776f52383b8e8e3b7845268a8 100644
|
||||
--- a/components/autofill/core/browser/payments/credit_card_access_manager.h
|
||||
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.h
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h"
|
||||
#include "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
|
||||
#include "components/autofill/core/browser/payments/payments_client.h"
|
||||
+#include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h"
|
||||
#include "components/autofill/core/browser/personal_data_manager.h"
|
||||
|
||||
#if !defined(OS_IOS)
|
||||
@@ -295,11 +296,7 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
|
||||
// Resets when PrepareToFetchCreditCard() is called, if not already reset.
|
||||
// Signaled when OnDidGetUnmaskDetails() is called or after timeout.
|
||||
// Authenticate() is called when signaled.
|
||||
- base::WaitableEvent ready_to_start_authentication_;
|
||||
-
|
||||
- // Tracks the Authenticate() task that is signaled by
|
||||
- // |ready_to_start_authentication_|, allowing it to be canceled if necessary.
|
||||
- base::CancelableTaskTracker cancelable_authenticate_task_tracker_;
|
||||
+ WaitForSignalOrTimeout ready_to_start_authentication_;
|
||||
|
||||
// Required to avoid any unnecessary preflight calls to Payments servers.
|
||||
// Initial state is signaled. Resets when PrepareToFetchCreditCard() is
|
||||
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
|
||||
index 68b1b1ccf5ac5c7000c09de4b57932834735aaf6..ecfebce277b3b757b83d7c663b2b753f952cf02e 100644
|
||||
--- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
|
||||
+++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
|
||||
@@ -139,8 +139,23 @@ class CreditCardAccessManagerTest : public testing::Test {
|
||||
public:
|
||||
CreditCardAccessManagerTest()
|
||||
: task_environment_(
|
||||
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME,
|
||||
base::test::TaskEnvironment::MainThreadType::DEFAULT,
|
||||
- base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {}
|
||||
+ base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {
|
||||
+ // Advance the mock clock to 2021-01-01, 00:00:00.000.
|
||||
+ base::Time year_2021;
|
||||
+ CHECK(base::Time::FromUTCExploded({.year = 2021,
|
||||
+ .month = 1,
|
||||
+ .day_of_week = 4,
|
||||
+ .day_of_month = 1,
|
||||
+ .hour = 0,
|
||||
+ .minute = 0,
|
||||
+ .second = 0,
|
||||
+ .millisecond = 0},
|
||||
+ &year_2021));
|
||||
+ task_environment_.AdvanceClock(year_2021 -
|
||||
+ task_environment_.GetMockClock()->Now());
|
||||
+ }
|
||||
|
||||
void SetUp() override {
|
||||
autofill_client_.SetPrefs(test::PrefServiceForTesting());
|
||||
@@ -929,6 +944,7 @@ TEST_F(CreditCardAccessManagerTest,
|
||||
|
||||
ResetFetchCreditCard();
|
||||
credit_card_access_manager_->PrepareToFetchCreditCard();
|
||||
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4));
|
||||
WaitForCallbacks();
|
||||
|
||||
credit_card_access_manager_->FetchCreditCard(local_card,
|
||||
@@ -949,6 +965,7 @@ TEST_F(CreditCardAccessManagerTest,
|
||||
credit_card_access_manager_->PrepareToFetchCreditCard();
|
||||
credit_card_access_manager_->FetchCreditCard(server_card,
|
||||
accessor_->GetWeakPtr());
|
||||
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4));
|
||||
WaitForCallbacks();
|
||||
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
@@ -1022,6 +1039,8 @@ TEST_F(CreditCardAccessManagerTest, Metrics_LoggingTimedOutCvcFallback) {
|
||||
|
||||
// Mock a delayed response.
|
||||
InvokeDelayedGetUnmaskDetailsResponse();
|
||||
+
|
||||
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4));
|
||||
WaitForCallbacks();
|
||||
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
@@ -1043,6 +1062,7 @@ TEST_F(CreditCardAccessManagerTest, Metrics_LoggingTimedOutCvcFallback) {
|
||||
credit_card_access_manager_->PrepareToFetchCreditCard();
|
||||
credit_card_access_manager_->FetchCreditCard(server_card,
|
||||
accessor_->GetWeakPtr());
|
||||
+ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4));
|
||||
WaitForCallbacks();
|
||||
|
||||
histogram_tester.ExpectUniqueSample(
|
||||
diff --git a/components/autofill/core/browser/payments/wait_for_signal_or_timeout.cc b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.cc
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..713a53e0f006e51f5d9bd64466712bf75b3ba095
|
||||
--- /dev/null
|
||||
+++ b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.cc
|
||||
@@ -0,0 +1,78 @@
|
||||
+// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h"
|
||||
+
|
||||
+#include "base/threading/sequenced_task_runner_handle.h"
|
||||
+
|
||||
+WaitForSignalOrTimeout::WaitForSignalOrTimeout() = default;
|
||||
+WaitForSignalOrTimeout::~WaitForSignalOrTimeout() = default;
|
||||
+
|
||||
+void WaitForSignalOrTimeout::Signal() {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
|
||||
+ SignalHandler(/*triggered_by_signal=*/true);
|
||||
+}
|
||||
+
|
||||
+bool WaitForSignalOrTimeout::IsSignaled() const {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
|
||||
+ return state_ == State::kSignalReceived || state_ == State::kDone;
|
||||
+}
|
||||
+
|
||||
+void WaitForSignalOrTimeout::OnEventOrTimeOut(Callback callback,
|
||||
+ base::TimeDelta timeout) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
|
||||
+ switch (state_) {
|
||||
+ case State::kInitialState:
|
||||
+ callback_ = std::move(callback);
|
||||
+ ++generation_id_; // Invalidate previous OnTimeOut tasks.
|
||||
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
|
||||
+ FROM_HERE,
|
||||
+ base::BindOnce(&WaitForSignalOrTimeout::OnTimeOut,
|
||||
+ weak_factory_.GetWeakPtr(), generation_id_),
|
||||
+ timeout);
|
||||
+ break;
|
||||
+
|
||||
+ case State::kSignalReceived:
|
||||
+ state_ = State::kDone;
|
||||
+ std::move(callback).Run(
|
||||
+ /*triggered_by_signal=*/in_state_signal_received_due_to_signal_call_);
|
||||
+ break;
|
||||
+
|
||||
+ case State::kDone:
|
||||
+ Reset();
|
||||
+ OnEventOrTimeOut(std::move(callback), timeout);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void WaitForSignalOrTimeout::Reset() {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
|
||||
+ state_ = State::kInitialState;
|
||||
+ ++generation_id_;
|
||||
+ callback_ = Callback();
|
||||
+}
|
||||
+
|
||||
+void WaitForSignalOrTimeout::OnTimeOut(int generation_id) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
|
||||
+ if (generation_id == generation_id_)
|
||||
+ SignalHandler(/*triggered_by_signal=*/false);
|
||||
+}
|
||||
+
|
||||
+void WaitForSignalOrTimeout::SignalHandler(bool triggered_by_signal) {
|
||||
+ switch (state_) {
|
||||
+ case State::kInitialState:
|
||||
+ if (callback_.is_null()) {
|
||||
+ state_ = State::kSignalReceived;
|
||||
+ in_state_signal_received_due_to_signal_call_ = triggered_by_signal;
|
||||
+ } else {
|
||||
+ state_ = State::kDone;
|
||||
+ std::move(callback_).Run(triggered_by_signal);
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case State::kSignalReceived:
|
||||
+ case State::kDone:
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/components/autofill/core/browser/payments/wait_for_signal_or_timeout.h b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.h
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6b2c451245441f784938e4132e2ab03e7d85f9b6
|
||||
--- /dev/null
|
||||
+++ b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.h
|
||||
@@ -0,0 +1,100 @@
|
||||
+// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_WAIT_FOR_SIGNAL_OR_TIMEOUT_H_
|
||||
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_WAIT_FOR_SIGNAL_OR_TIMEOUT_H_
|
||||
+
|
||||
+#include "base/callback.h"
|
||||
+#include "base/memory/weak_ptr.h"
|
||||
+#include "base/sequence_checker.h"
|
||||
+#include "base/time/time.h"
|
||||
+
|
||||
+// A WaitForSignalOrTimeout waits for Signal() or a time out and calls a
|
||||
+// callback when either of these happens for the first time.
|
||||
+//
|
||||
+// The WaitForSignalOrTimeout is Reset()-able and ensures that the callback will
|
||||
+// be called at most once (unless Reset() resets the state). The
|
||||
+// WaitForSignalOrTimeout can be destroyed at any time without negative
|
||||
+// side-effects. The callback won't be called in this case. If the Signal()
|
||||
+// arrives before a call for OnEventOrTimeOut(), the callback will be called
|
||||
+// immediately. If a second Signal() arrives, nothing happens. The
|
||||
+// WaitForSignalOrTimeout must be used on single task sequence.
|
||||
+//
|
||||
+// This class provides the bare minimum needed for a Payment task. If there are
|
||||
+// more use cases, feel free to spice it up and move it to base/.
|
||||
+class WaitForSignalOrTimeout {
|
||||
+ public:
|
||||
+ // The passed boolean is true if the callback happened by a call of Signal()
|
||||
+ // (as opposed to a timeout).
|
||||
+ using Callback = base::OnceCallback<void(bool)>;
|
||||
+
|
||||
+ WaitForSignalOrTimeout();
|
||||
+ ~WaitForSignalOrTimeout();
|
||||
+ WaitForSignalOrTimeout(const WaitForSignalOrTimeout&) = delete;
|
||||
+ WaitForSignalOrTimeout& operator=(const WaitForSignalOrTimeout&) = delete;
|
||||
+
|
||||
+ // Triggers |callback_| if it has not been called before, or registers that
|
||||
+ // the signal occurred, so that |callback| of OnEventOrTimeOut() can be
|
||||
+ // called immediately.
|
||||
+ void Signal();
|
||||
+
|
||||
+ // Returns whether Signal() was called at least once or a timeout happened,
|
||||
+ // and Reset() has not been called afterwards. Note that this function does
|
||||
+ // not discriminate whether Signal() was called or a timeout happened.
|
||||
+ // The |callback_|'s parameter has this distinction, though.
|
||||
+ bool IsSignaled() const;
|
||||
+
|
||||
+ // Registers the |callback| and calls it immediately if Signal() was called
|
||||
+ // already. Starts a timeout task, so that |callback| is called if no call of
|
||||
+ // Signal() is observed within |timeout|. A previous timeout is replaced by a
|
||||
+ // new one.
|
||||
+ void OnEventOrTimeOut(Callback callback, base::TimeDelta timeout);
|
||||
+
|
||||
+ // Resets the state machine so that no Signal() was observed, no callback is
|
||||
+ // registered and no timeout task is running.
|
||||
+ void Reset();
|
||||
+
|
||||
+ private:
|
||||
+ enum class State {
|
||||
+ // Signal() has not been called, yet.
|
||||
+ kInitialState,
|
||||
+ // Signal() has been called, but callback is not specified.
|
||||
+ kSignalReceived,
|
||||
+ // callback has been called.
|
||||
+ kDone,
|
||||
+ };
|
||||
+
|
||||
+ // Internal callback for the timeout. |generation_id| is a generation counter
|
||||
+ // to ensure that old, delayed timeout tasks are ignored.
|
||||
+ void OnTimeOut(int generation_id);
|
||||
+
|
||||
+ // Handler for Signal() and OnTimeOut(). Calls |callback_| if appropriate.
|
||||
+ // The parameter is true if this function is called via Signal() and false if
|
||||
+ // the function is called via OnTimeOut(). This parameter is passed to
|
||||
+ // callback.
|
||||
+ void SignalHandler(bool triggered_by_signal);
|
||||
+
|
||||
+ State state_ = State::kInitialState;
|
||||
+
|
||||
+ // This variable is only valid if state_ == State::kSignalReceived. It is
|
||||
+ // true if we moved into this state due to a Signal() call, and false if
|
||||
+ // we moved into this state due to an OnTimeOut() call.
|
||||
+ bool in_state_signal_received_due_to_signal_call_;
|
||||
+
|
||||
+ // As the base::ThreadPool does not support cancelable tasks, we just rely on
|
||||
+ // a generation counter. Every time Reset() or OnEventOrTimeOut() are called,
|
||||
+ // the generation id is incremented. If outdated delayed OnTimeOut() tasks
|
||||
+ // trickle in, we recognize them as tasks for which the |generation_id|
|
||||
+ // parameter is less than the current generation_id_ and ignore them.
|
||||
+ int generation_id_ = 0;
|
||||
+
|
||||
+ // Callback to be called in case of a Signal() or a time out.
|
||||
+ Callback callback_;
|
||||
+
|
||||
+ SEQUENCE_CHECKER(my_sequence_checker_);
|
||||
+
|
||||
+ base::WeakPtrFactory<WaitForSignalOrTimeout> weak_factory_{this};
|
||||
+};
|
||||
+
|
||||
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_WAIT_FOR_SIGNAL_OR_TIMEOUT_H_
|
||||
diff --git a/components/autofill/core/browser/payments/wait_for_signal_or_timeout_unittest.cc b/components/autofill/core/browser/payments/wait_for_signal_or_timeout_unittest.cc
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..eda3fd362221cb9c08c893af02ce33a2826c5d6f
|
||||
--- /dev/null
|
||||
+++ b/components/autofill/core/browser/payments/wait_for_signal_or_timeout_unittest.cc
|
||||
@@ -0,0 +1,188 @@
|
||||
+// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h"
|
||||
+
|
||||
+#include "base/test/task_environment.h"
|
||||
+#include "testing/gtest/include/gtest/gtest.h"
|
||||
+
|
||||
+class WaitForSignalOrTimeoutTest : public testing::Test {
|
||||
+ public:
|
||||
+ WaitForSignalOrTimeoutTest() = default;
|
||||
+ ~WaitForSignalOrTimeoutTest() override = default;
|
||||
+
|
||||
+ WaitForSignalOrTimeout::Callback GetCallback() {
|
||||
+ return base::BindOnce(&WaitForSignalOrTimeoutTest::Callback,
|
||||
+ base::Unretained(this));
|
||||
+ }
|
||||
+
|
||||
+ protected:
|
||||
+ void Callback(bool triggered_by_signal) {
|
||||
+ callbacks_++;
|
||||
+ last_callback_triggered_by_signal_ = triggered_by_signal;
|
||||
+ }
|
||||
+
|
||||
+ // Number of observed callbacks.
|
||||
+ int callbacks_ = 0;
|
||||
+
|
||||
+ bool last_callback_triggered_by_signal_ = false;
|
||||
+
|
||||
+ base::test::TaskEnvironment task_env_{
|
||||
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
|
||||
+};
|
||||
+
|
||||
+// WaitForSignalOrTimeout is initialized with a callback and then the Signal()
|
||||
+// happens.
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, InitThenSignal) {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+ wait.Signal();
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_TRUE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ // Another signal call should be ignored.
|
||||
+ wait.Signal();
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+
|
||||
+ // Also the pending timeout should not trigger further callbacks.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35));
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+}
|
||||
+
|
||||
+// A Signal() is registered before the callback.
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, SignalThenInit) {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+
|
||||
+ // Trigger the signal before a callback handler is registered.
|
||||
+ wait.Signal();
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+
|
||||
+ // Once the callback handler is registered, it should be called immediately.
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_TRUE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ // Another signal call should be ignored.
|
||||
+ wait.Signal();
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+
|
||||
+ // Also the pending timeout should not trigger further callbacks.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35));
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+}
|
||||
+
|
||||
+// A timeout occurs before Signal() is called.
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, InitThenTimeout) {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35));
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_FALSE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ // A late signal will be ignored.
|
||||
+ wait.Signal();
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+}
|
||||
+
|
||||
+// The WaitForSignalOrTimeout gets destroyed before a Signal() or timeout
|
||||
+// happens.
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, DestroyedBeforeSignal) {
|
||||
+ {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ }
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35));
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+}
|
||||
+
|
||||
+// The WaitForSignalOrTimeout gets signaled, reset, and signaled again.
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, Reset) {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+ wait.Signal();
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_TRUE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ wait.Reset();
|
||||
+
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+
|
||||
+ // This signal does not trigger a callback because none is registered.
|
||||
+ wait.Signal();
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ // Now the callback happens immediately.
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_EQ(2, callbacks_);
|
||||
+ EXPECT_TRUE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ wait.Reset();
|
||||
+
|
||||
+ // Finally, we simulate a timeout after the reset.
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35));
|
||||
+ EXPECT_EQ(3, callbacks_);
|
||||
+ EXPECT_FALSE(last_callback_triggered_by_signal_);
|
||||
+}
|
||||
+
|
||||
+TEST_F(WaitForSignalOrTimeoutTest, OnEventOrTimeOutCalledTwice) {
|
||||
+ WaitForSignalOrTimeout wait;
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+
|
||||
+ // Wait some time but not long enough for the timeout to trigger.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25));
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+
|
||||
+ // This resets the state machine (currently waiting for a signal or timeout)
|
||||
+ // and starts a new wait.
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+
|
||||
+ // Wait some time but not long enough for the timeout to trigger.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25));
|
||||
+ // The first timeout should not have triggered anything.
|
||||
+ EXPECT_EQ(0, callbacks_);
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+
|
||||
+ // Wait some more time for the second timeout to kick in.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_FALSE(last_callback_triggered_by_signal_);
|
||||
+
|
||||
+ // This resets the state machine (currently in done state) once more and
|
||||
+ // starts a new wait.
|
||||
+ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30));
|
||||
+
|
||||
+ // Wait some time but not long enough for the timeout to trigger.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25));
|
||||
+ // The first timeout should not have triggered anything.
|
||||
+ EXPECT_EQ(1, callbacks_);
|
||||
+ EXPECT_FALSE(wait.IsSignaled());
|
||||
+
|
||||
+ // Wait some more time for the second timeout to kick in.
|
||||
+ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
|
||||
+ EXPECT_EQ(2, callbacks_);
|
||||
+ EXPECT_TRUE(wait.IsSignaled());
|
||||
+ EXPECT_FALSE(last_callback_triggered_by_signal_);
|
||||
+}
|
||||
Reference in New Issue
Block a user