Allow only one bookmark to be added for multiple fast starring
[chromium-blink-merge.git] / extensions / browser / quota_service_unittest.cc
blobc5b7812433b506ba2a0684f3d431423c1c7f1961
1 // Copyright 2013 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.
5 #include "base/message_loop/message_loop.h"
6 #include "base/process/process.h"
7 #include "base/stl_util.h"
8 #include "base/strings/string_util.h"
9 #include "content/public/test/test_browser_thread.h"
10 #include "extensions/browser/extension_function.h"
11 #include "extensions/browser/quota_service.h"
12 #include "testing/gtest/include/gtest/gtest.h"
14 using base::TimeDelta;
15 using base::TimeTicks;
16 using content::BrowserThread;
18 namespace extensions {
20 typedef QuotaLimitHeuristic::Bucket Bucket;
21 typedef QuotaLimitHeuristic::Config Config;
22 typedef QuotaLimitHeuristic::BucketList BucketList;
23 typedef QuotaService::TimedLimit TimedLimit;
25 namespace {
27 const char kGenericName[] = "name";
28 const Config kFrozenConfig = {0, TimeDelta::FromDays(0)};
29 const Config k2PerMinute = {2, TimeDelta::FromMinutes(1)};
30 const Config k20PerHour = {20, TimeDelta::FromHours(1)};
31 const TimeTicks kStartTime = TimeTicks();
32 const TimeTicks k1MinuteAfterStart = kStartTime + TimeDelta::FromMinutes(1);
34 class Mapper : public QuotaLimitHeuristic::BucketMapper {
35 public:
36 Mapper() {}
37 ~Mapper() override { STLDeleteValues(&buckets_); }
38 void GetBucketsForArgs(const base::ListValue* args,
39 BucketList* buckets) override {
40 for (size_t i = 0; i < args->GetSize(); i++) {
41 int id;
42 ASSERT_TRUE(args->GetInteger(i, &id));
43 if (buckets_.find(id) == buckets_.end())
44 buckets_[id] = new Bucket();
45 buckets->push_back(buckets_[id]);
49 private:
50 typedef std::map<int, Bucket*> BucketMap;
51 BucketMap buckets_;
52 DISALLOW_COPY_AND_ASSIGN(Mapper);
55 class MockMapper : public QuotaLimitHeuristic::BucketMapper {
56 public:
57 void GetBucketsForArgs(const base::ListValue* args,
58 BucketList* buckets) override {}
61 class MockFunction : public ExtensionFunction {
62 public:
63 explicit MockFunction(const char* name) { set_name(name); }
65 void SetArgs(const base::ListValue* args) override {}
66 std::string GetError() const override { return std::string(); }
67 void SetError(const std::string& error) override {}
68 void Destruct() const override { delete this; }
69 ResponseAction Run() override { return RespondLater(); }
70 void SendResponse(bool) override {}
72 protected:
73 ~MockFunction() override {}
76 class TimedLimitMockFunction : public MockFunction {
77 public:
78 explicit TimedLimitMockFunction(const char* name) : MockFunction(name) {}
79 void GetQuotaLimitHeuristics(
80 QuotaLimitHeuristics* heuristics) const override {
81 heuristics->push_back(
82 new TimedLimit(k2PerMinute, new Mapper(), kGenericName));
85 private:
86 ~TimedLimitMockFunction() override {}
89 class FrozenMockFunction : public MockFunction {
90 public:
91 explicit FrozenMockFunction(const char* name) : MockFunction(name) {}
92 void GetQuotaLimitHeuristics(
93 QuotaLimitHeuristics* heuristics) const override {
94 heuristics->push_back(
95 new TimedLimit(kFrozenConfig, new Mapper(), kGenericName));
98 private:
99 ~FrozenMockFunction() override {}
101 } // namespace
103 class QuotaServiceTest : public testing::Test {
104 public:
105 QuotaServiceTest()
106 : extension_a_("a"),
107 extension_b_("b"),
108 extension_c_("c"),
109 loop_(),
110 ui_thread_(BrowserThread::UI, &loop_) {}
111 void SetUp() override { service_.reset(new QuotaService()); }
112 void TearDown() override {
113 loop_.RunUntilIdle();
114 service_.reset();
117 protected:
118 std::string extension_a_;
119 std::string extension_b_;
120 std::string extension_c_;
121 scoped_ptr<QuotaService> service_;
122 base::MessageLoop loop_;
123 content::TestBrowserThread ui_thread_;
126 class QuotaLimitHeuristicTest : public testing::Test {
127 public:
128 static void DoMoreThan2PerMinuteFor5Minutes(const TimeTicks& start_time,
129 QuotaLimitHeuristic* lim,
130 Bucket* b,
131 int an_unexhausted_minute) {
132 for (int i = 0; i < 5; i++) {
133 // Perform one operation in each minute.
134 int m = i * 60;
135 EXPECT_TRUE(lim->Apply(b, start_time + TimeDelta::FromSeconds(10 + m)));
136 EXPECT_TRUE(b->has_tokens());
138 if (i == an_unexhausted_minute)
139 continue; // Don't exhaust all tokens this minute.
141 EXPECT_TRUE(lim->Apply(b, start_time + TimeDelta::FromSeconds(15 + m)));
142 EXPECT_FALSE(b->has_tokens());
144 // These are OK because we haven't exhausted all buckets.
145 EXPECT_TRUE(lim->Apply(b, start_time + TimeDelta::FromSeconds(20 + m)));
146 EXPECT_FALSE(b->has_tokens());
147 EXPECT_TRUE(lim->Apply(b, start_time + TimeDelta::FromSeconds(50 + m)));
148 EXPECT_FALSE(b->has_tokens());
153 TEST_F(QuotaLimitHeuristicTest, Timed) {
154 TimedLimit lim(k2PerMinute, new MockMapper(), kGenericName);
155 Bucket b;
157 b.Reset(k2PerMinute, kStartTime);
158 EXPECT_TRUE(lim.Apply(&b, kStartTime));
159 EXPECT_TRUE(b.has_tokens());
160 EXPECT_TRUE(lim.Apply(&b, kStartTime + TimeDelta::FromSeconds(30)));
161 EXPECT_FALSE(b.has_tokens());
162 EXPECT_FALSE(lim.Apply(&b, k1MinuteAfterStart));
164 b.Reset(k2PerMinute, kStartTime);
165 EXPECT_TRUE(lim.Apply(&b, k1MinuteAfterStart - TimeDelta::FromSeconds(1)));
166 EXPECT_TRUE(lim.Apply(&b, k1MinuteAfterStart));
167 EXPECT_TRUE(lim.Apply(&b, k1MinuteAfterStart + TimeDelta::FromSeconds(1)));
168 EXPECT_TRUE(lim.Apply(&b, k1MinuteAfterStart + TimeDelta::FromSeconds(2)));
169 EXPECT_FALSE(lim.Apply(&b, k1MinuteAfterStart + TimeDelta::FromSeconds(3)));
172 TEST_F(QuotaServiceTest, NoHeuristic) {
173 scoped_refptr<MockFunction> f(new MockFunction("foo"));
174 base::ListValue args;
175 EXPECT_EQ("", service_->Assess(extension_a_, f.get(), &args, kStartTime));
178 TEST_F(QuotaServiceTest, FrozenHeuristic) {
179 scoped_refptr<MockFunction> f(new FrozenMockFunction("foo"));
180 base::ListValue args;
181 args.Append(new base::FundamentalValue(1));
182 EXPECT_NE("", service_->Assess(extension_a_, f.get(), &args, kStartTime));
185 TEST_F(QuotaServiceTest, SingleHeuristic) {
186 scoped_refptr<MockFunction> f(new TimedLimitMockFunction("foo"));
187 base::ListValue args;
188 args.Append(new base::FundamentalValue(1));
189 EXPECT_EQ("", service_->Assess(extension_a_, f.get(), &args, kStartTime));
190 EXPECT_EQ("",
191 service_->Assess(extension_a_,
192 f.get(),
193 &args,
194 kStartTime + TimeDelta::FromSeconds(10)));
195 EXPECT_NE("",
196 service_->Assess(extension_a_,
197 f.get(),
198 &args,
199 kStartTime + TimeDelta::FromSeconds(15)));
201 base::ListValue args2;
202 args2.Append(new base::FundamentalValue(1));
203 args2.Append(new base::FundamentalValue(2));
204 EXPECT_EQ("", service_->Assess(extension_b_, f.get(), &args2, kStartTime));
205 EXPECT_EQ("",
206 service_->Assess(extension_b_,
207 f.get(),
208 &args2,
209 kStartTime + TimeDelta::FromSeconds(10)));
211 TimeDelta peace = TimeDelta::FromMinutes(30);
212 EXPECT_EQ("",
213 service_->Assess(extension_b_, f.get(), &args, kStartTime + peace));
214 EXPECT_EQ("",
215 service_->Assess(extension_b_,
216 f.get(),
217 &args,
218 kStartTime + peace + TimeDelta::FromSeconds(10)));
219 EXPECT_NE("",
220 service_->Assess(extension_b_,
221 f.get(),
222 &args2,
223 kStartTime + peace + TimeDelta::FromSeconds(15)));
225 // Test that items are independent.
226 base::ListValue args3;
227 args3.Append(new base::FundamentalValue(3));
228 EXPECT_EQ("", service_->Assess(extension_c_, f.get(), &args, kStartTime));
229 EXPECT_EQ("",
230 service_->Assess(extension_c_,
231 f.get(),
232 &args3,
233 kStartTime + TimeDelta::FromSeconds(10)));
234 EXPECT_EQ("",
235 service_->Assess(extension_c_,
236 f.get(),
237 &args,
238 kStartTime + TimeDelta::FromSeconds(15)));
239 EXPECT_EQ("",
240 service_->Assess(extension_c_,
241 f.get(),
242 &args3,
243 kStartTime + TimeDelta::FromSeconds(20)));
244 EXPECT_NE("",
245 service_->Assess(extension_c_,
246 f.get(),
247 &args,
248 kStartTime + TimeDelta::FromSeconds(25)));
249 EXPECT_NE("",
250 service_->Assess(extension_c_,
251 f.get(),
252 &args3,
253 kStartTime + TimeDelta::FromSeconds(30)));
256 TEST_F(QuotaServiceTest, MultipleFunctionsDontInterfere) {
257 scoped_refptr<MockFunction> f(new TimedLimitMockFunction("foo"));
258 scoped_refptr<MockFunction> g(new TimedLimitMockFunction("bar"));
260 base::ListValue args_f;
261 base::ListValue args_g;
262 args_f.Append(new base::FundamentalValue(1));
263 args_g.Append(new base::FundamentalValue(2));
265 EXPECT_EQ("", service_->Assess(extension_a_, f.get(), &args_f, kStartTime));
266 EXPECT_EQ("", service_->Assess(extension_a_, g.get(), &args_g, kStartTime));
267 EXPECT_EQ("",
268 service_->Assess(extension_a_,
269 f.get(),
270 &args_f,
271 kStartTime + TimeDelta::FromSeconds(10)));
272 EXPECT_EQ("",
273 service_->Assess(extension_a_,
274 g.get(),
275 &args_g,
276 kStartTime + TimeDelta::FromSeconds(10)));
277 EXPECT_NE("",
278 service_->Assess(extension_a_,
279 f.get(),
280 &args_f,
281 kStartTime + TimeDelta::FromSeconds(15)));
282 EXPECT_NE("",
283 service_->Assess(extension_a_,
284 g.get(),
285 &args_g,
286 kStartTime + TimeDelta::FromSeconds(15)));
289 TEST_F(QuotaServiceTest, ViolatorsWillBeForgiven) {
290 scoped_refptr<MockFunction> f(new TimedLimitMockFunction("foo"));
291 base::ListValue arg;
292 arg.Append(new base::FundamentalValue(1));
293 EXPECT_EQ("", service_->Assess(extension_a_, f.get(), &arg, kStartTime));
294 EXPECT_EQ("",
295 service_->Assess(extension_a_,
296 f.get(),
297 &arg,
298 kStartTime + TimeDelta::FromSeconds(10)));
299 EXPECT_NE("",
300 service_->Assess(extension_a_,
301 f.get(),
302 &arg,
303 kStartTime + TimeDelta::FromSeconds(15)));
305 // Waiting a while will give the extension access to the function again.
306 EXPECT_EQ("", service_->Assess(extension_a_, f.get(), &arg,
307 kStartTime + TimeDelta::FromDays(1)));
309 // And lose it again soon after.
310 EXPECT_EQ("", service_->Assess(extension_a_, f.get(), &arg,
311 kStartTime + TimeDelta::FromDays(1) +
312 TimeDelta::FromSeconds(10)));
313 EXPECT_NE("", service_->Assess(extension_a_, f.get(), &arg,
314 kStartTime + TimeDelta::FromDays(1) +
315 TimeDelta::FromSeconds(15)));
317 // Going further over quota should continue to fail within this time period,
318 // but still all restored later.
319 EXPECT_NE("", service_->Assess(extension_a_, f.get(), &arg,
320 kStartTime + TimeDelta::FromDays(1) +
321 TimeDelta::FromSeconds(20)));
322 EXPECT_NE("", service_->Assess(extension_a_, f.get(), &arg,
323 kStartTime + TimeDelta::FromDays(1) +
324 TimeDelta::FromSeconds(25)));
326 // Like now.
327 EXPECT_EQ("", service_->Assess(extension_a_, f.get(), &arg,
328 kStartTime + TimeDelta::FromDays(2)));
331 } // namespace extensions