910e62b5创建于 1月15日历史提交
// Copyright 2017 The Chromium Authors
// 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/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/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 "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 OAuthTokenInfo& token_info);

  void ExpectInvalidateCache();

  // OAuthTokenGetter overrides.
  void CallWithToken(TokenCallback on_access_token) override;
  void InvalidateCache() override;
  base::WeakPtr<OAuthTokenGetter> GetWeakPtr() override;

  base::WeakPtr<FakeOAuthTokenGetter> GetFakeOAuthTokenGetterWeakPtr();

 private:
  TokenCallback on_access_token_;
  bool invalidate_cache_expected_ = false;

  THREAD_CHECKER(thread_checker_);

  base::WeakPtrFactory<FakeOAuthTokenGetter> 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 OAuthTokenInfo& token_info) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(!on_access_token_.is_null());
  std::move(on_access_token_).Run(status, token_info);
}

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<OAuthTokenGetter> FakeOAuthTokenGetter::GetWeakPtr() {
  return weak_factory_.GetWeakPtr();
}

base::WeakPtr<FakeOAuthTokenGetter>
FakeOAuthTokenGetter::GetFakeOAuthTokenGetterWeakPtr() {
  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 OAuthTokenInfo& token_info);

  void TestCallWithTokenOnMainThread(OAuthTokenGetter::Status status,
                                     const OAuthTokenInfo& token_info);

  void ExpectInvalidateCache();

  void InvalidateTokenGetter();

  base::Thread runner_thread_{"runner_thread"};
  std::unique_ptr<FakeOAuthTokenGetter> token_getter_;
  std::unique_ptr<OAuthTokenGetterProxy> proxy_;

 private:
  struct TokenCallbackResult {
    OAuthTokenGetter::Status status;
    std::string user_email;
    std::string access_token;
  };

  void TestCallWithTokenImpl(OAuthTokenGetter::Status status,
                             const OAuthTokenInfo& token_info);

  void OnTokenReceived(OAuthTokenGetter::Status status,
                       const OAuthTokenInfo& token_info);

  std::unique_ptr<TokenCallbackResult> expected_callback_result_;

  base::test::SingleThreadTaskEnvironment task_environment_;
};

void OAuthTokenGetterProxyTest::SetUp() {
  token_getter_ = std::make_unique<FakeOAuthTokenGetter>();
  runner_thread_.Start();
  proxy_ = std::make_unique<OAuthTokenGetterProxy>(
      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 OAuthTokenInfo& token_info) {
  runner_thread_.task_runner()->PostTask(
      FROM_HERE,
      base::BindOnce(&OAuthTokenGetterProxyTest::TestCallWithTokenImpl,
                     base::Unretained(this),
                     OAuthTokenGetter::Status::AUTH_ERROR, token_info));
  runner_thread_.FlushForTesting();
}

void OAuthTokenGetterProxyTest::TestCallWithTokenOnMainThread(
    OAuthTokenGetter::Status status,
    const OAuthTokenInfo& token_info) {
  TestCallWithTokenImpl(status, token_info);
  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_->GetFakeOAuthTokenGetterWeakPtr()));
}

void OAuthTokenGetterProxyTest::InvalidateTokenGetter() {
  if (token_getter_) {
    runner_thread_.task_runner()->DeleteSoon(FROM_HERE,
                                             token_getter_.release());
  }
}

void OAuthTokenGetterProxyTest::TestCallWithTokenImpl(
    OAuthTokenGetter::Status status,
    const OAuthTokenInfo& token_info) {
  ASSERT_FALSE(expected_callback_result_);
  expected_callback_result_ = std::make_unique<TokenCallbackResult>();
  expected_callback_result_->status = status;
  expected_callback_result_->user_email = token_info.user_email();
  expected_callback_result_->access_token = token_info.access_token();
  proxy_->CallWithToken(base::BindOnce(
      &OAuthTokenGetterProxyTest::OnTokenReceived, base::Unretained(this)));
  runner_thread_.task_runner()->PostTask(
      FROM_HERE, base::BindOnce(&FakeOAuthTokenGetter::ResolveCallback,
                                token_getter_->GetFakeOAuthTokenGetterWeakPtr(),
                                status, token_info));
}

void OAuthTokenGetterProxyTest::OnTokenReceived(
    OAuthTokenGetter::Status status,
    const OAuthTokenInfo& token_info) {
  ASSERT_TRUE(expected_callback_result_);
  EXPECT_EQ(expected_callback_result_->status, status);
  EXPECT_EQ(expected_callback_result_->user_email, token_info.user_email());
  EXPECT_EQ(expected_callback_result_->access_token, token_info.access_token());
  expected_callback_result_.reset();
}

TEST_F(OAuthTokenGetterProxyTest, CallWithTokenOnMainThread) {
  TestCallWithTokenOnMainThread(OAuthTokenGetter::Status::SUCCESS,
                                OAuthTokenInfo("token1", "email1"));
  TestCallWithTokenOnMainThread(OAuthTokenGetter::Status::NETWORK_ERROR,
                                OAuthTokenInfo("token2", "email2"));
}

TEST_F(OAuthTokenGetterProxyTest, CallWithTokenOnRunnerThread) {
  TestCallWithTokenOnRunnerThread(OAuthTokenGetter::Status::AUTH_ERROR,
                                  OAuthTokenInfo("token3", "email3"));
  TestCallWithTokenOnRunnerThread(OAuthTokenGetter::Status::SUCCESS,
                                  OAuthTokenInfo("token4", "email4"));
}

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