|  | // 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/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::Deserialize(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 |