| // Copyright 2015 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 <stdint.h> |
| |
| #include "base/test/test_mock_time_task_runner.h" |
| #include "cc/trees/layer_tree_host.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/compositor/compositor_lock.h" |
| |
| using testing::Mock; |
| using testing::_; |
| |
| namespace ui { |
| namespace { |
| |
| // For tests that control time. |
| class CompositorLockTest : public testing::Test { |
| protected: |
| CompositorLockTest() {} |
| ~CompositorLockTest() override {} |
| |
| void SetUp() override { |
| task_runner_ = new base::TestMockTimeTaskRunner; |
| lock_manager_ = std::make_unique<CompositorLockManager>(task_runner_); |
| } |
| |
| base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); } |
| |
| CompositorLockManager* lock_manager() { return lock_manager_.get(); } |
| |
| void DestroyLockManager() { lock_manager_.reset(); } |
| |
| protected: |
| scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
| std::unique_ptr<CompositorLockManager> lock_manager_; |
| bool is_locked_ = false; |
| }; |
| |
| class MockCompositorLockClient : public ui::CompositorLockClient { |
| public: |
| MOCK_METHOD0(CompositorLockTimedOut, void()); |
| }; |
| |
| } // namespace |
| |
| TEST_F(CompositorLockTest, LocksTimeOut) { |
| std::unique_ptr<CompositorLock> lock; |
| |
| base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(100); |
| |
| { |
| testing::StrictMock<MockCompositorLockClient> lock_client; |
| // This lock has a timeout. |
| lock = lock_manager()->GetCompositorLock(&lock_client, timeout, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| EXPECT_CALL(lock_client, CompositorLockTimedOut()).Times(1); |
| task_runner()->FastForwardBy(timeout); |
| task_runner()->RunUntilIdle(); |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| } |
| |
| { |
| testing::StrictMock<MockCompositorLockClient> lock_client; |
| // This lock has no timeout. |
| lock = lock_manager()->GetCompositorLock(&lock_client, base::TimeDelta(), |
| nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| EXPECT_CALL(lock_client, CompositorLockTimedOut()).Times(0); |
| task_runner()->FastForwardBy(timeout); |
| task_runner()->RunUntilIdle(); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| } |
| } |
| |
| TEST_F(CompositorLockTest, MultipleLockClients) { |
| testing::StrictMock<MockCompositorLockClient> lock_client1; |
| std::unique_ptr<CompositorLock> lock1; |
| testing::StrictMock<MockCompositorLockClient> lock_client2; |
| std::unique_ptr<CompositorLock> lock2; |
| |
| base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(1); |
| // Both locks are grabbed from the Compositor with a separate client. |
| lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout, nullptr); |
| lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| // Both clients get notified of timeout. |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(1); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| task_runner()->FastForwardBy(timeout); |
| task_runner()->RunUntilIdle(); |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| } |
| |
| TEST_F(CompositorLockTest, ExtendingLifeOfLockDoesntUseDeadClient) { |
| testing::StrictMock<MockCompositorLockClient> lock_client1; |
| std::unique_ptr<CompositorLock> lock1; |
| testing::StrictMock<MockCompositorLockClient> lock_client2; |
| std::unique_ptr<CompositorLock> lock2; |
| |
| base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(1); |
| |
| // One lock is grabbed from the compositor with a client. The other |
| // extends its lifetime past that of the first. |
| lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| |
| // This also locks the compositor and will do so past |lock1| ending. |
| lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout, nullptr); |
| // |lock1| is destroyed, so it won't timeout but |lock2| will. |
| lock1 = nullptr; |
| |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(0); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| task_runner()->FastForwardBy(timeout); |
| task_runner()->RunUntilIdle(); |
| |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| } |
| |
| TEST_F(CompositorLockTest, AddingLocksDoesNotExtendTimeout) { |
| testing::StrictMock<MockCompositorLockClient> lock_client1; |
| std::unique_ptr<CompositorLock> lock1; |
| testing::StrictMock<MockCompositorLockClient> lock_client2; |
| std::unique_ptr<CompositorLock> lock2; |
| |
| base::TimeDelta timeout1 = base::TimeDelta::FromMilliseconds(1); |
| base::TimeDelta timeout2 = base::TimeDelta::FromMilliseconds(10); |
| |
| // The first lock has a short timeout. |
| lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| |
| // The second lock has a longer timeout, but since a lock is active, |
| // the first one is used for both. |
| lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2, nullptr); |
| |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(1); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| task_runner()->FastForwardBy(timeout1); |
| task_runner()->RunUntilIdle(); |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| } |
| |
| TEST_F(CompositorLockTest, AllowAndExtendTimeout) { |
| testing::StrictMock<MockCompositorLockClient> lock_client1; |
| std::unique_ptr<CompositorLock> lock1; |
| testing::StrictMock<MockCompositorLockClient> lock_client2; |
| std::unique_ptr<CompositorLock> lock2; |
| |
| base::TimeDelta timeout1 = base::TimeDelta::FromMilliseconds(1); |
| base::TimeDelta timeout2 = base::TimeDelta::FromMilliseconds(10); |
| |
| // The first lock has a short timeout. |
| lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| |
| // Allow locks to extend timeout. |
| lock_manager()->set_allow_locks_to_extend_timeout(true); |
| // The second lock has a longer timeout, so the second one is used for both. |
| lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2, nullptr); |
| lock_manager()->set_allow_locks_to_extend_timeout(false); |
| |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(0); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(0); |
| task_runner()->FastForwardBy(timeout1); |
| task_runner()->RunUntilIdle(); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(1); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| task_runner()->FastForwardBy(timeout2 - timeout1); |
| task_runner()->RunUntilIdle(); |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| } |
| |
| TEST_F(CompositorLockTest, ExtendingTimeoutStartingCreatedTime) { |
| testing::StrictMock<MockCompositorLockClient> lock_client1; |
| std::unique_ptr<CompositorLock> lock1; |
| testing::StrictMock<MockCompositorLockClient> lock_client2; |
| std::unique_ptr<CompositorLock> lock2; |
| |
| base::TimeDelta timeout1 = base::TimeDelta::FromMilliseconds(5); |
| base::TimeDelta timeout2 = base::TimeDelta::FromMilliseconds(10); |
| |
| // The first lock has a short timeout. |
| lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| |
| base::TimeDelta time_elapse = base::TimeDelta::FromMilliseconds(1); |
| task_runner()->FastForwardBy(time_elapse); |
| task_runner()->RunUntilIdle(); |
| |
| // Allow locks to extend timeout. |
| lock_manager()->set_allow_locks_to_extend_timeout(true); |
| // The second lock has a longer timeout, so the second one is used for both |
| // and start from the time second lock created. |
| lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2, nullptr); |
| lock_manager()->set_allow_locks_to_extend_timeout(false); |
| |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(0); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(0); |
| task_runner()->FastForwardBy(timeout1 - time_elapse); |
| task_runner()->RunUntilIdle(); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(1); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| task_runner()->FastForwardBy(timeout2 - (timeout1 - time_elapse)); |
| task_runner()->RunUntilIdle(); |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| } |
| |
| TEST_F(CompositorLockTest, AllowButNotExtendTimeout) { |
| testing::StrictMock<MockCompositorLockClient> lock_client1; |
| std::unique_ptr<CompositorLock> lock1; |
| testing::StrictMock<MockCompositorLockClient> lock_client2; |
| std::unique_ptr<CompositorLock> lock2; |
| |
| base::TimeDelta timeout1 = base::TimeDelta::FromMilliseconds(10); |
| base::TimeDelta timeout2 = base::TimeDelta::FromMilliseconds(1); |
| |
| // The first lock has a longer timeout. |
| lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| |
| // Allow locks to extend timeout. |
| lock_manager()->set_allow_locks_to_extend_timeout(true); |
| // The second lock has a short timeout, so the first one is used for both. |
| lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2, nullptr); |
| lock_manager()->set_allow_locks_to_extend_timeout(false); |
| |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(0); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(0); |
| task_runner()->FastForwardBy(timeout2); |
| task_runner()->RunUntilIdle(); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(1); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| task_runner()->FastForwardBy(timeout1 - timeout2); |
| task_runner()->RunUntilIdle(); |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| } |
| |
| TEST_F(CompositorLockTest, AllowingExtendDoesNotUseDeadClient) { |
| testing::StrictMock<MockCompositorLockClient> lock_client1; |
| std::unique_ptr<CompositorLock> lock1; |
| testing::StrictMock<MockCompositorLockClient> lock_client2; |
| std::unique_ptr<CompositorLock> lock2; |
| |
| base::TimeDelta timeout1 = base::TimeDelta::FromMilliseconds(1); |
| base::TimeDelta timeout2 = base::TimeDelta::FromMilliseconds(10); |
| |
| lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(1); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(0); |
| task_runner()->FastForwardBy(timeout1); |
| task_runner()->RunUntilIdle(); |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| |
| // Allow locks to extend timeout. |
| lock_manager()->set_allow_locks_to_extend_timeout(true); |
| // |lock1| is timed out already. The second lock can timeout on its own. |
| lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2, nullptr); |
| lock_manager()->set_allow_locks_to_extend_timeout(false); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(0); |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| task_runner()->FastForwardBy(timeout2); |
| task_runner()->RunUntilIdle(); |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| } |
| |
| TEST_F(CompositorLockTest, LockIsDestroyedDoesntTimeout) { |
| base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(1); |
| |
| testing::StrictMock<MockCompositorLockClient> lock_client1; |
| std::unique_ptr<CompositorLock> lock1; |
| lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| // The CompositorLockClient is destroyed when |lock1| is released. |
| lock1 = nullptr; |
| // The client isn't called as a result. |
| EXPECT_CALL(lock_client1, CompositorLockTimedOut()).Times(0); |
| task_runner()->FastForwardBy(timeout); |
| task_runner()->RunUntilIdle(); |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| } |
| |
| TEST_F(CompositorLockTest, TimeoutEndsWhenLockEnds) { |
| testing::StrictMock<MockCompositorLockClient> lock_client1; |
| std::unique_ptr<CompositorLock> lock1; |
| testing::StrictMock<MockCompositorLockClient> lock_client2; |
| std::unique_ptr<CompositorLock> lock2; |
| |
| base::TimeDelta timeout1 = base::TimeDelta::FromMilliseconds(1); |
| base::TimeDelta timeout2 = base::TimeDelta::FromMilliseconds(10); |
| |
| // The first lock has a short timeout. |
| lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| // But the first lock is ended before timeout. |
| lock1 = nullptr; |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| |
| // The second lock has a longer timeout, and it should use that timeout, |
| // since the first lock is done. |
| lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2, nullptr); |
| EXPECT_TRUE(lock_manager()->IsLocked()); |
| |
| { |
| // The second lock doesn't timeout from the first lock which has ended. |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(0); |
| task_runner()->FastForwardBy(timeout1); |
| task_runner()->RunUntilIdle(); |
| } |
| |
| { |
| // The second lock can still timeout on its own though. |
| EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1); |
| task_runner()->FastForwardBy(timeout2 - timeout1); |
| task_runner()->RunUntilIdle(); |
| } |
| |
| EXPECT_FALSE(lock_manager()->IsLocked()); |
| } |
| |
| TEST_F(CompositorLockTest, CompositorLockOutlivesManager) { |
| testing::StrictMock<MockCompositorLockClient> lock_client1; |
| std::unique_ptr<CompositorLock> lock1; |
| |
| lock1 = lock_manager()->GetCompositorLock(&lock_client1, base::TimeDelta(), |
| nullptr); |
| // The compositor is destroyed before the lock. |
| DestroyLockManager(); |
| // This doesn't crash. |
| lock1 = nullptr; |
| } |
| |
| } // namespace ui |