#include <stdint.h>
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.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 {
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(); }
base::OnceClosure CreateReleaseCallback() {
return base::BindOnce(
[](CompositorLockTest* self) { self->num_releases_++; },
base::Unretained(this));
}
protected:
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
std::unique_ptr<CompositorLockManager> lock_manager_;
bool is_locked_ = false;
uint32_t num_releases_ = 0u;
};
class MockCompositorLockClient : public ui::CompositorLockClient {
public:
MOCK_METHOD0(CompositorLockTimedOut, void());
};
}
TEST_F(CompositorLockTest, LocksTimeOut) {
std::unique_ptr<CompositorLock> lock;
base::TimeDelta timeout = base::Milliseconds(100);
{
testing::StrictMock<MockCompositorLockClient> lock_client;
lock = lock_manager()->GetCompositorLock(&lock_client, timeout,
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
EXPECT_CALL(lock_client, CompositorLockTimedOut()).Times(1);
task_runner()->FastForwardBy(timeout);
task_runner()->RunUntilIdle();
EXPECT_FALSE(lock_manager()->IsLocked());
EXPECT_EQ(1u, num_releases_);
}
{
testing::StrictMock<MockCompositorLockClient> lock_client;
lock = lock_manager()->GetCompositorLock(&lock_client, base::TimeDelta(),
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
EXPECT_CALL(lock_client, CompositorLockTimedOut()).Times(0);
task_runner()->FastForwardBy(timeout);
task_runner()->RunUntilIdle();
EXPECT_TRUE(lock_manager()->IsLocked());
EXPECT_EQ(1u, num_releases_);
}
}
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::Milliseconds(1);
lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout,
CreateReleaseCallback());
lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout,
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
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());
EXPECT_EQ(2u, num_releases_);
}
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::Milliseconds(1);
lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout,
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout,
CreateReleaseCallback());
lock1 = nullptr;
EXPECT_EQ(1u, num_releases_);
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());
EXPECT_EQ(2u, num_releases_);
}
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::Milliseconds(1);
base::TimeDelta timeout2 = base::Milliseconds(10);
lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1,
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2,
CreateReleaseCallback());
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());
EXPECT_EQ(2u, num_releases_);
}
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::Milliseconds(1);
base::TimeDelta timeout2 = base::Milliseconds(10);
lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1,
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
lock_manager()->set_allow_locks_to_extend_timeout(true);
lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2,
CreateReleaseCallback());
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_EQ(0u, num_releases_);
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());
EXPECT_EQ(2u, num_releases_);
}
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::Milliseconds(5);
base::TimeDelta timeout2 = base::Milliseconds(10);
lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1,
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
base::TimeDelta time_elapse = base::Milliseconds(1);
task_runner()->FastForwardBy(time_elapse);
task_runner()->RunUntilIdle();
lock_manager()->set_allow_locks_to_extend_timeout(true);
lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2,
CreateReleaseCallback());
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_EQ(0u, num_releases_);
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());
EXPECT_EQ(2u, num_releases_);
}
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::Milliseconds(10);
base::TimeDelta timeout2 = base::Milliseconds(1);
lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1,
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
lock_manager()->set_allow_locks_to_extend_timeout(true);
lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2,
CreateReleaseCallback());
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_EQ(0u, num_releases_);
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());
EXPECT_EQ(2u, num_releases_);
}
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::Milliseconds(1);
base::TimeDelta timeout2 = base::Milliseconds(10);
lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1,
CreateReleaseCallback());
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());
EXPECT_EQ(1u, num_releases_);
lock_manager()->set_allow_locks_to_extend_timeout(true);
lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2,
CreateReleaseCallback());
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());
EXPECT_EQ(2u, num_releases_);
}
TEST_F(CompositorLockTest, LockIsDestroyedDoesntTimeout) {
base::TimeDelta timeout = base::Milliseconds(1);
testing::StrictMock<MockCompositorLockClient> lock_client1;
std::unique_ptr<CompositorLock> lock1;
lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout,
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
lock1 = nullptr;
EXPECT_EQ(1u, num_releases_);
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::Milliseconds(1);
base::TimeDelta timeout2 = base::Milliseconds(10);
lock1 = lock_manager()->GetCompositorLock(&lock_client1, timeout1,
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
lock1 = nullptr;
EXPECT_FALSE(lock_manager()->IsLocked());
EXPECT_EQ(1u, num_releases_);
lock2 = lock_manager()->GetCompositorLock(&lock_client2, timeout2,
CreateReleaseCallback());
EXPECT_TRUE(lock_manager()->IsLocked());
{
EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(0);
task_runner()->FastForwardBy(timeout1);
task_runner()->RunUntilIdle();
}
{
EXPECT_CALL(lock_client2, CompositorLockTimedOut()).Times(1);
task_runner()->FastForwardBy(timeout2 - timeout1);
task_runner()->RunUntilIdle();
}
EXPECT_FALSE(lock_manager()->IsLocked());
EXPECT_EQ(2u, num_releases_);
}
TEST_F(CompositorLockTest, CompositorLockOutlivesManager) {
testing::StrictMock<MockCompositorLockClient> lock_client1;
std::unique_ptr<CompositorLock> lock1;
lock1 = lock_manager()->GetCompositorLock(&lock_client1, base::TimeDelta(),
CreateReleaseCallback());
DestroyLockManager();
lock1 = nullptr;
EXPECT_EQ(1u, num_releases_);
}
}