1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <algorithm>
6#include "android_webview/browser/global_tile_manager.h"
7#include "android_webview/browser/global_tile_manager_client.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
10namespace {
11// This should be the same as the one defined global_tile_manager.cc
12const size_t kNumTilesLimit = 450;
13const size_t kDefaultNumTiles = 150;
14
15}  // namespace
16
17using android_webview::GlobalTileManager;
18using android_webview::GlobalTileManagerClient;
19using content::SynchronousCompositorMemoryPolicy;
20using testing::Test;
21
22class MockGlobalTileManagerClient : public GlobalTileManagerClient {
23 public:
24  virtual SynchronousCompositorMemoryPolicy GetMemoryPolicy() const OVERRIDE {
25    return memory_policy_;
26  }
27
28  virtual void SetMemoryPolicy(SynchronousCompositorMemoryPolicy new_policy,
29                               bool effective_immediately) OVERRIDE {
30    memory_policy_ = new_policy;
31  }
32
33  MockGlobalTileManagerClient() {
34    tile_request_.num_resources_limit = kDefaultNumTiles;
35    key_ = GlobalTileManager::GetInstance()->PushBack(this);
36  }
37
38  virtual ~MockGlobalTileManagerClient() {
39    GlobalTileManager::GetInstance()->Remove(key_);
40  }
41
42  SynchronousCompositorMemoryPolicy GetTileRequest() { return tile_request_; }
43  GlobalTileManager::Key GetKey() { return key_; }
44
45 private:
46  SynchronousCompositorMemoryPolicy memory_policy_;
47  SynchronousCompositorMemoryPolicy tile_request_;
48  GlobalTileManager::Key key_;
49};
50
51class GlobalTileManagerTest : public Test {
52 public:
53  virtual void SetUp() {}
54
55  GlobalTileManager* manager() { return GlobalTileManager::GetInstance(); }
56};
57
58TEST_F(GlobalTileManagerTest, RequestTilesUnderLimit) {
59  MockGlobalTileManagerClient clients[2];
60
61  for (size_t i = 0; i < 2; i++) {
62    manager()->RequestTiles(clients[i].GetTileRequest(), clients[i].GetKey());
63    manager()->DidUse(clients[i].GetKey());
64
65    // Ensure clients get what they asked for when the manager is under tile
66    // limit.
67    EXPECT_EQ(clients[i].GetMemoryPolicy().num_resources_limit,
68              kDefaultNumTiles);
69  }
70}
71
72TEST_F(GlobalTileManagerTest, EvictHappensWhenOverLimit) {
73  MockGlobalTileManagerClient clients[4];
74
75  for (size_t i = 0; i < 4; i++) {
76    manager()->RequestTiles(clients[i].GetTileRequest(), clients[i].GetKey());
77    manager()->DidUse(clients[i].GetKey());
78  }
79
80  size_t total_tiles = 0;
81  for (size_t i = 0; i < 4; i++) {
82    total_tiles += clients[i].GetMemoryPolicy().num_resources_limit;
83  }
84
85  // Ensure that eviction happened and kept the total number of tiles within
86  // kNumTilesLimit.
87  EXPECT_LE(total_tiles, kNumTilesLimit);
88}
89
90TEST_F(GlobalTileManagerTest, RandomizedStressRequests) {
91  MockGlobalTileManagerClient clients[100];
92  size_t index[100];
93  for (size_t i = 0; i < 100; i++) {
94    index[i] = i;
95  }
96
97  // Fix the seed so that tests are reproducible.
98  std::srand(1);
99  // Simulate a random request order of clients.
100  std::random_shuffle(&index[0], &index[99]);
101
102  for (size_t i = 0; i < 100; i++) {
103    size_t j = index[i];
104    manager()->RequestTiles(clients[j].GetTileRequest(), clients[j].GetKey());
105    manager()->DidUse(clients[j].GetKey());
106  }
107
108  size_t total_tiles = 0;
109  for (size_t i = 0; i < 100; i++) {
110    total_tiles += clients[i].GetMemoryPolicy().num_resources_limit;
111  }
112
113  // Ensure that eviction happened and kept the total number of tiles within
114  // kNumTilesLimit.
115  EXPECT_LE(total_tiles, kNumTilesLimit);
116}
117
118TEST_F(GlobalTileManagerTest, FixedOrderedRequests) {
119  MockGlobalTileManagerClient clients[10];
120
121  // 10 clients requesting resources in a fixed order. Do that for 5 rounds.
122  for (int round = 0; round < 5; round++) {
123    for (size_t i = 0; i < 10; i++) {
124      manager()->RequestTiles(clients[i].GetTileRequest(), clients[i].GetKey());
125      manager()->DidUse(clients[i].GetKey());
126    }
127  }
128
129  // Ensure that the total tiles are divided evenly among all clients.
130  for (size_t i = 0; i < 10; i++) {
131    EXPECT_EQ(clients[i].GetMemoryPolicy().num_resources_limit,
132              kNumTilesLimit / 10);
133  }
134}
135
136TEST_F(GlobalTileManagerTest, FixedOrderedRequestsWithInactiveClients) {
137  MockGlobalTileManagerClient clients[20];
138
139  // 20 clients request resources.
140  for (size_t i = 0; i < 20; i++) {
141    manager()->RequestTiles(clients[i].GetTileRequest(), clients[i].GetKey());
142    manager()->DidUse(clients[i].GetKey());
143  }
144
145  // Now the last 10 clients become inactive. Only the first 10 clients remain
146  // active resource requesters.
147  // 10 clients requesting resources in a fixed order. Do that for 5 rounds.
148  for (int round = 0; round < 5; round++) {
149    for (size_t i = 0; i < 10; i++) {
150      manager()->RequestTiles(clients[i].GetTileRequest(), clients[i].GetKey());
151      manager()->DidUse(clients[i].GetKey());
152    }
153  }
154
155  // Ensure that the total tiles are divided evenly among all clients.
156  for (size_t i = 0; i < 10; i++) {
157    EXPECT_EQ(clients[i].GetMemoryPolicy().num_resources_limit,
158              kNumTilesLimit / 10);
159  }
160
161  // Ensure that the inactive tiles are evicted.
162  for (size_t i = 11; i < 20; i++) {
163    EXPECT_EQ(clients[i].GetMemoryPolicy().num_resources_limit, 0u);
164  }
165}
166