// Copyright 2017 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 "remoting/base/oauth_token_getter_proxy.h" #include "base/bind.h" #include "base/callback.h" #include "base/callback_helpers.h" #include "base/memory/weak_ptr.h" #include "base/run_loop.h" #include "base/test/task_environment.h" #include "base/threading/thread.h" #include "base/threading/thread_checker.h" #include "base/threading/thread_task_runner_handle.h" #include "testing/gtest/include/gtest/gtest.h" namespace remoting { namespace { OAuthTokenGetter::TokenCallback GetDoNothingTokenCallback() { return base::DoNothing(); } class FakeOAuthTokenGetter : public OAuthTokenGetter { public: FakeOAuthTokenGetter(); FakeOAuthTokenGetter(const FakeOAuthTokenGetter&) = delete; FakeOAuthTokenGetter& operator=(const FakeOAuthTokenGetter&) = delete; ~FakeOAuthTokenGetter() override; void ResolveCallback(Status status, const std::string& user_email, const std::string& access_token); void ExpectInvalidateCache(); // OAuthTokenGetter overrides. void CallWithToken(TokenCallback on_access_token) override; void InvalidateCache() override; base::WeakPtr GetWeakPtr(); private: TokenCallback on_access_token_; bool invalidate_cache_expected_ = false; THREAD_CHECKER(thread_checker_); base::WeakPtrFactory weak_factory_{this}; }; FakeOAuthTokenGetter::FakeOAuthTokenGetter() { DETACH_FROM_THREAD(thread_checker_); } FakeOAuthTokenGetter::~FakeOAuthTokenGetter() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!invalidate_cache_expected_); } void FakeOAuthTokenGetter::ResolveCallback(Status status, const std::string& user_email, const std::string& access_token) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!on_access_token_.is_null()); std::move(on_access_token_).Run(status, user_email, access_token); } void FakeOAuthTokenGetter::ExpectInvalidateCache() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); ASSERT_FALSE(invalidate_cache_expected_); invalidate_cache_expected_ = true; } void FakeOAuthTokenGetter::CallWithToken(TokenCallback on_access_token) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); on_access_token_ = std::move(on_access_token); } void FakeOAuthTokenGetter::InvalidateCache() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); ASSERT_TRUE(invalidate_cache_expected_); invalidate_cache_expected_ = false; } base::WeakPtr FakeOAuthTokenGetter::GetWeakPtr() { return weak_factory_.GetWeakPtr(); } } // namespace class OAuthTokenGetterProxyTest : public testing::Test { public: OAuthTokenGetterProxyTest() = default; OAuthTokenGetterProxyTest(const OAuthTokenGetterProxyTest&) = delete; OAuthTokenGetterProxyTest& operator=(const OAuthTokenGetterProxyTest&) = delete; ~OAuthTokenGetterProxyTest() override = default; // testing::Test overrides. void SetUp() override; void TearDown() override; protected: void TestCallWithTokenOnRunnerThread(OAuthTokenGetter::Status status, const std::string& user_email, const std::string& access_token); void TestCallWithTokenOnMainThread(OAuthTokenGetter::Status status, const std::string& user_email, const std::string& access_token); void ExpectInvalidateCache(); void InvalidateTokenGetter(); base::Thread runner_thread_{"runner_thread"}; std::unique_ptr token_getter_; std::unique_ptr proxy_; private: struct TokenCallbackResult { OAuthTokenGetter::Status status; std::string user_email; std::string access_token; }; void TestCallWithTokenImpl(OAuthTokenGetter::Status status, const std::string& user_email, const std::string& access_token); void OnTokenReceived(OAuthTokenGetter::Status status, const std::string& user_email, const std::string& access_token); std::unique_ptr expected_callback_result_; base::test::SingleThreadTaskEnvironment task_environment_; }; void OAuthTokenGetterProxyTest::SetUp() { token_getter_ = std::make_unique(); runner_thread_.Start(); proxy_ = std::make_unique( token_getter_->GetWeakPtr(), runner_thread_.task_runner()); } void OAuthTokenGetterProxyTest::TearDown() { InvalidateTokenGetter(); proxy_.reset(); runner_thread_.FlushForTesting(); ASSERT_FALSE(expected_callback_result_); } void OAuthTokenGetterProxyTest::TestCallWithTokenOnRunnerThread( OAuthTokenGetter::Status status, const std::string& user_email, const std::string& access_token) { runner_thread_.task_runner()->PostTask( FROM_HERE, base::BindOnce(&OAuthTokenGetterProxyTest::TestCallWithTokenImpl, base::Unretained(this), OAuthTokenGetter::Status::AUTH_ERROR, "email3", "token3")); runner_thread_.FlushForTesting(); } void OAuthTokenGetterProxyTest::TestCallWithTokenOnMainThread( OAuthTokenGetter::Status status, const std::string& user_email, const std::string& access_token) { TestCallWithTokenImpl(status, user_email, access_token); runner_thread_.FlushForTesting(); base::RunLoop().RunUntilIdle(); } void OAuthTokenGetterProxyTest::ExpectInvalidateCache() { ASSERT_NE(nullptr, token_getter_.get()); runner_thread_.task_runner()->PostTask( FROM_HERE, base::BindOnce(&FakeOAuthTokenGetter::ExpectInvalidateCache, token_getter_->GetWeakPtr())); } void OAuthTokenGetterProxyTest::InvalidateTokenGetter() { if (token_getter_) { runner_thread_.task_runner()->DeleteSoon(FROM_HERE, token_getter_.release()); } } void OAuthTokenGetterProxyTest::TestCallWithTokenImpl( OAuthTokenGetter::Status status, const std::string& user_email, const std::string& access_token) { ASSERT_FALSE(expected_callback_result_); expected_callback_result_ = std::make_unique(); expected_callback_result_->status = status; expected_callback_result_->user_email = user_email; expected_callback_result_->access_token = access_token; proxy_->CallWithToken(base::BindOnce( &OAuthTokenGetterProxyTest::OnTokenReceived, base::Unretained(this))); runner_thread_.task_runner()->PostTask( FROM_HERE, base::BindOnce(&FakeOAuthTokenGetter::ResolveCallback, token_getter_->GetWeakPtr(), status, user_email, access_token)); } void OAuthTokenGetterProxyTest::OnTokenReceived( OAuthTokenGetter::Status status, const std::string& user_email, const std::string& access_token) { ASSERT_TRUE(expected_callback_result_); EXPECT_EQ(expected_callback_result_->status, status); EXPECT_EQ(expected_callback_result_->user_email, user_email); EXPECT_EQ(expected_callback_result_->access_token, access_token); expected_callback_result_.reset(); } TEST_F(OAuthTokenGetterProxyTest, CallWithTokenOnMainThread) { TestCallWithTokenOnMainThread(OAuthTokenGetter::Status::SUCCESS, "email1", "token1"); TestCallWithTokenOnMainThread(OAuthTokenGetter::Status::NETWORK_ERROR, "email2", "token2"); } TEST_F(OAuthTokenGetterProxyTest, CallWithTokenOnRunnerThread) { TestCallWithTokenOnRunnerThread(OAuthTokenGetter::Status::AUTH_ERROR, "email3", "token3"); TestCallWithTokenOnRunnerThread(OAuthTokenGetter::Status::SUCCESS, "email4", "token4"); } TEST_F(OAuthTokenGetterProxyTest, InvalidateCacheOnMainThread) { ExpectInvalidateCache(); proxy_->InvalidateCache(); runner_thread_.FlushForTesting(); } TEST_F(OAuthTokenGetterProxyTest, InvalidateCacheOnRunnerThread) { ExpectInvalidateCache(); runner_thread_.task_runner()->PostTask( FROM_HERE, base::BindOnce(&OAuthTokenGetterProxy::InvalidateCache, base::Unretained(proxy_.get()))); runner_thread_.FlushForTesting(); } TEST_F( OAuthTokenGetterProxyTest, CallWithTokenOnMainThreadAfterTokenGetterDestroyed_callsSilentlyDropped) { InvalidateTokenGetter(); proxy_->CallWithToken(GetDoNothingTokenCallback()); runner_thread_.FlushForTesting(); } TEST_F( OAuthTokenGetterProxyTest, CallWithTokenOnRunnerThreadAfterTokenGetterDestroyed_callsSilentlyDropped) { InvalidateTokenGetter(); runner_thread_.task_runner()->PostTask( FROM_HERE, base::BindOnce(&OAuthTokenGetterProxy::CallWithToken, base::Unretained(proxy_.get()), GetDoNothingTokenCallback())); runner_thread_.FlushForTesting(); } TEST_F( OAuthTokenGetterProxyTest, InvalidateCacheOnMainThreadAfterTokenGetterDestroyed_callsSilentlyDropped) { InvalidateTokenGetter(); proxy_->InvalidateCache(); runner_thread_.FlushForTesting(); } TEST_F( OAuthTokenGetterProxyTest, InvalidateCacheOnRunnerThreadAfterTokenGetterDestroyed_callsSilentlyDropped) { InvalidateTokenGetter(); runner_thread_.task_runner()->PostTask( FROM_HERE, base::BindOnce(&OAuthTokenGetterProxy::InvalidateCache, base::Unretained(proxy_.get()))); runner_thread_.FlushForTesting(); } } // namespace remoting