chromium/content/browser/android/scoped_surface_request_manager_unittest.cc

// Copyright 2016 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/android/scoped_surface_request_manager.h"

#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "content/public/test/browser_task_environment.h"
#include "gpu/command_buffer/service/mock_texture_owner.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/android/scoped_java_surface.h"
#include "ui/gl/android/surface_texture.h"

namespace content {

class ScopedSurfaceRequestManagerUnitTest : public testing::Test {
 public:
  ScopedSurfaceRequestManagerUnitTest() {
    manager_ = ScopedSurfaceRequestManager::GetInstance();

    // The need to reset the callbacks because the
    // ScopedSurfaceRequestManager's lifetime outlive the tests.
    manager_->clear_requests_for_testing();

    last_received_request_ = 0;
    dummy_token_ = base::UnguessableToken::CreateForTesting(123, 456);

    mock_texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
        0, nullptr, nullptr);
  }

  ScopedSurfaceRequestManagerUnitTest(
      const ScopedSurfaceRequestManagerUnitTest&) = delete;
  ScopedSurfaceRequestManagerUnitTest& operator=(
      const ScopedSurfaceRequestManagerUnitTest&) = delete;

  ScopedSurfaceRequestManager::ScopedSurfaceRequestCB CreateNoopCallback() {
    return base::BindOnce(&ScopedSurfaceRequestManagerUnitTest::DummyCallback,
                          base::Unretained(this));
  }

  ScopedSurfaceRequestManager::ScopedSurfaceRequestCB CreateLoggingCallback() {
    return base::BindOnce(&ScopedSurfaceRequestManagerUnitTest::LoggingCallback,
                          base::Unretained(this), kSpecificCallbackId);
  }

  // No-op callback.
  void DummyCallback(gl::ScopedJavaSurface surface) {}

  // Callback that updates |last_received_request_| to allow differentiation
  // between callback instances in tests.
  void LoggingCallback(int request_id, gl::ScopedJavaSurface surface) {
    last_received_request_ = request_id;
  }

  scoped_refptr<NiceMock<gpu::MockTextureOwner>> mock_texture_owner;

  int last_received_request_;
  const int kSpecificCallbackId = 1357;
  base::UnguessableToken dummy_token_;

  raw_ptr<ScopedSurfaceRequestManager> manager_;

  content::BrowserTaskEnvironment task_environment_;
};

// Makes sure we can successfully register a callback.
TEST_F(ScopedSurfaceRequestManagerUnitTest, RegisterRequest_ShouldSucceed) {
  EXPECT_EQ(0, manager_->request_count_for_testing());

  base::UnguessableToken token =
      manager_->RegisterScopedSurfaceRequest(CreateNoopCallback());

  EXPECT_EQ(1, manager_->request_count_for_testing());
  EXPECT_FALSE(token.is_empty());
}

// Makes sure we can successfully register multiple callbacks, and that they
// return distinct request tokens.
TEST_F(ScopedSurfaceRequestManagerUnitTest,
       RegisterMultipleRequests_ShouldSucceed) {
  base::UnguessableToken token1 =
      manager_->RegisterScopedSurfaceRequest(CreateNoopCallback());
  base::UnguessableToken token2 =
      manager_->RegisterScopedSurfaceRequest(CreateNoopCallback());

  EXPECT_EQ(2, manager_->request_count_for_testing());
  EXPECT_NE(token1, token2);
}

// Makes sure GetInstance() is idempotent/that the class is a proper singleton.
TEST_F(ScopedSurfaceRequestManagerUnitTest, VerifySingleton_ShouldSucceed) {
  EXPECT_EQ(manager_, ScopedSurfaceRequestManager::GetInstance());
}

// Makes sure we can unregister a callback after registering it.
TEST_F(ScopedSurfaceRequestManagerUnitTest,
       GetRegisteredRequest_ShouldSucceed) {
  base::UnguessableToken token =
      manager_->RegisterScopedSurfaceRequest(CreateNoopCallback());
  EXPECT_EQ(1, manager_->request_count_for_testing());

  manager_->UnregisterScopedSurfaceRequest(token);

  EXPECT_EQ(0, manager_->request_count_for_testing());
}

// Makes sure that unregistering a callback only affects the specified callback.
TEST_F(ScopedSurfaceRequestManagerUnitTest,
       GetRegisteredRequestFromMultipleRequests_ShouldSucceed) {
  base::UnguessableToken token =
      manager_->RegisterScopedSurfaceRequest(CreateNoopCallback());
  manager_->RegisterScopedSurfaceRequest(CreateNoopCallback());
  EXPECT_EQ(2, manager_->request_count_for_testing());

  manager_->UnregisterScopedSurfaceRequest(token);

  EXPECT_EQ(1, manager_->request_count_for_testing());
}

// Makes sure that unregistration is a noop permitted when there are no
// registered requests.
TEST_F(ScopedSurfaceRequestManagerUnitTest,
       UnregisteredRequest_ShouldReturnNullCallback) {
  manager_->UnregisterScopedSurfaceRequest(dummy_token_);

  EXPECT_EQ(0, manager_->request_count_for_testing());
}

// Makes sure that unregistering an invalid |request_token| doesn't affect
// other registered callbacks.
TEST_F(ScopedSurfaceRequestManagerUnitTest,
       GetUnregisteredRequestFromMultipleRequests_ShouldReturnNullCallback) {
  manager_->RegisterScopedSurfaceRequest(CreateNoopCallback());

  manager_->UnregisterScopedSurfaceRequest(dummy_token_);

  EXPECT_EQ(1, manager_->request_count_for_testing());
}

// Makes sure that trying to fulfill a request for an invalid |request_token|
// does nothing, and does not affect other callbacks.
TEST_F(ScopedSurfaceRequestManagerUnitTest,
       FulfillUnregisteredRequest_ShouldDoNothing) {
  manager_->RegisterScopedSurfaceRequest(CreateLoggingCallback());

  manager_->FulfillScopedSurfaceRequest(
      dummy_token_, mock_texture_owner->CreateJavaSurface());

  EXPECT_EQ(1, manager_->request_count_for_testing());
  EXPECT_NE(kSpecificCallbackId, last_received_request_);
}

// Makes sure that trying to fulfill a request fulfills the right request, and
// does not affect other registered requests.
TEST_F(ScopedSurfaceRequestManagerUnitTest,
       FulfillRegisteredRequest_ShouldSucceed) {
  base::UnguessableToken specific_token =
      manager_->RegisterScopedSurfaceRequest(CreateLoggingCallback());

  const uint64_t kOtherCallbackId = 5678;
  manager_->RegisterScopedSurfaceRequest(
      base::BindOnce(&ScopedSurfaceRequestManagerUnitTest::LoggingCallback,
                     base::Unretained(this), kOtherCallbackId));

  manager_->FulfillScopedSurfaceRequest(
      specific_token, mock_texture_owner->CreateJavaSurface());

  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(1, manager_->request_count_for_testing());
  EXPECT_EQ(kSpecificCallbackId, last_received_request_);
}

// Makes sure that the ScopedSurfaceRequestConduit implementation properly
// fulfills requests.
TEST_F(ScopedSurfaceRequestManagerUnitTest,
       ForwardSurfaceOwner_ShouldFulfillRequest) {
  base::UnguessableToken token =
      manager_->RegisterScopedSurfaceRequest(CreateLoggingCallback());

  manager_->ForwardSurfaceOwnerForSurfaceRequest(token,
                                                 mock_texture_owner.get());

  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(0, manager_->request_count_for_testing());
  EXPECT_EQ(kSpecificCallbackId, last_received_request_);
}

}  // Content