blob: c836bf5d0e268d5015d72b5abf2d1b07b669c83b [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/webid/delegation/email_verifier_impl.h"
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/webid/delegation/email_verification_request.h"
#include "content/public/browser/webid/email_verifier.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::NiceMock;
using ::testing::Optional;
namespace content::webid {
class MockEmailVerificationRequest : public EmailVerificationRequest {
public:
explicit MockEmailVerificationRequest(RenderFrameHost& rfh)
: EmailVerificationRequest(
nullptr,
nullptr,
static_cast<RenderFrameHostImpl&>(rfh).GetSafeRef()) {}
~MockEmailVerificationRequest() override { Destroy(); }
MOCK_METHOD(void, Destroy, (), ());
MOCK_METHOD(void,
Send,
(const std::string&,
const std::string&,
EmailVerifier::OnEmailVerifiedCallback));
};
class MockRequestBuilder {
public:
MOCK_METHOD(std::unique_ptr<EmailVerificationRequest>, Run, ());
};
class EmailVerifierImplTest : public RenderViewHostTestHarness {
public:
EmailVerifierImplTest() = default;
~EmailVerifierImplTest() override = default;
};
TEST_F(EmailVerifierImplTest, TestSingleRequest) {
auto request =
std::make_unique<testing::StrictMock<MockEmailVerificationRequest>>(
*main_rfh());
auto* request_ptr = request.get();
MockRequestBuilder builder;
EXPECT_CALL(builder, Run)
.WillOnce(testing::Return(testing::ByMove(std::move(request))));
EmailVerifierImpl verifier(base::BindRepeating(&MockRequestBuilder::Run,
base::Unretained(&builder)));
EXPECT_CALL(*request_ptr, Send("test@example.com", "nonce", _))
.WillOnce(testing::WithArgs<2>(
[&](EmailVerifier::OnEmailVerifiedCallback callback) {
std::move(callback).Run("token");
}));
EXPECT_CALL(*request_ptr, Destroy());
base::MockCallback<EmailVerifier::OnEmailVerifiedCallback> cb;
EXPECT_CALL(cb, Run(Optional<std::string>("token")));
verifier.Verify("test@example.com", "nonce", cb.Get());
}
TEST_F(EmailVerifierImplTest, TestTwoConcurrentRequests) {
auto request1 =
std::make_unique<testing::StrictMock<MockEmailVerificationRequest>>(
*main_rfh());
auto* request_ptr1 = request1.get();
auto request2 =
std::make_unique<testing::StrictMock<MockEmailVerificationRequest>>(
*main_rfh());
auto* request_ptr2 = request2.get();
MockRequestBuilder builder;
EXPECT_CALL(builder, Run)
.WillOnce(testing::Return(testing::ByMove(std::move(request1))))
.WillOnce(testing::Return(testing::ByMove(std::move(request2))));
EmailVerifierImpl verifier(base::BindRepeating(&MockRequestBuilder::Run,
base::Unretained(&builder)));
// Set up expectations and capture callbacks for the two requests.
EmailVerifier::OnEmailVerifiedCallback callback1;
EXPECT_CALL(*request_ptr1, Send("test1@example.com", "nonce1", _))
.WillOnce(testing::WithArgs<2>(
[&](EmailVerifier::OnEmailVerifiedCallback callback) {
callback1 = std::move(callback);
}));
EmailVerifier::OnEmailVerifiedCallback callback2;
EXPECT_CALL(*request_ptr2, Send("test2@example.com", "nonce2", _))
.WillOnce(testing::WithArgs<2>(
[&](EmailVerifier::OnEmailVerifiedCallback callback) {
callback2 = std::move(callback);
}));
// Make the concurrent calls to Verify.
base::MockCallback<EmailVerifier::OnEmailVerifiedCallback> cb1;
verifier.Verify("test1@example.com", "nonce1", cb1.Get());
base::MockCallback<EmailVerifier::OnEmailVerifiedCallback> cb2;
verifier.Verify("test2@example.com", "nonce2", cb2.Get());
ASSERT_TRUE(callback1);
ASSERT_TRUE(callback2);
// Set up expectations for the final callbacks and object destruction.
EXPECT_CALL(*request_ptr1, Destroy());
EXPECT_CALL(*request_ptr2, Destroy());
EXPECT_CALL(cb1, Run(Optional<std::string>("token1")));
EXPECT_CALL(cb2, Run(Optional<std::string>("token2")));
// Complete in reverse order to test concurrency.
std::move(callback2).Run("token2");
std::move(callback1).Run("token1");
}
} // namespace content::webid