1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_function.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extensions_quota_service.h"
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "testing/gtest/include/gtest/gtest.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottusing base::TimeDelta;
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeTicks;
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef QuotaLimitHeuristic::Bucket Bucket;
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef QuotaLimitHeuristic::Config Config;
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef QuotaLimitHeuristic::BucketList BucketList;
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef ExtensionsQuotaService::TimedLimit TimedLimit;
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef ExtensionsQuotaService::SustainedLimit SustainedLimit;
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const Config kFrozenConfig = { 0, TimeDelta::FromDays(0) };
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const Config k2PerMinute = { 2, TimeDelta::FromMinutes(1) };
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const Config k20PerHour = { 20, TimeDelta::FromHours(1) };
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const TimeTicks kStartTime = TimeTicks();
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const TimeTicks k1MinuteAfterStart =
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    kStartTime + TimeDelta::FromMinutes(1);
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass Mapper : public QuotaLimitHeuristic::BucketMapper {
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Mapper() {}
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual ~Mapper() { STLDeleteValues(&buckets_); }
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void GetBucketsForArgs(const ListValue* args, BucketList* buckets) {
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < args->GetSize(); i++) {
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int id;
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ASSERT_TRUE(args->GetInteger(i, &id));
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (buckets_.find(id) == buckets_.end())
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        buckets_[id] = new Bucket();
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      buckets->push_back(buckets_[id]);
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typedef std::map<int, Bucket*> BucketMap;
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BucketMap buckets_;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(Mapper);
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass MockMapper : public QuotaLimitHeuristic::BucketMapper {
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void GetBucketsForArgs(const ListValue* args, BucketList* buckets) {}
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass MockFunction : public ExtensionFunction {
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit MockFunction(const std::string& name) { set_name(name); }
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void SetArgs(const ListValue* args) {}
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual const std::string GetError() { return std::string(); }
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual const std::string GetResult() { return std::string(); }
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Run() {}
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass TimedLimitMockFunction : public MockFunction {
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit TimedLimitMockFunction(const std::string& name)
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : MockFunction(name) {}
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void GetQuotaLimitHeuristics(
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      QuotaLimitHeuristics* heuristics) const {
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    heuristics->push_back(new TimedLimit(k2PerMinute, new Mapper()));
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ChainedLimitsMockFunction : public MockFunction {
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit ChainedLimitsMockFunction(const std::string& name)
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : MockFunction(name) {}
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void GetQuotaLimitHeuristics(
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      QuotaLimitHeuristics* heuristics) const {
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No more than 2 per minute sustained over 5 minutes.
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    heuristics->push_back(new SustainedLimit(TimeDelta::FromMinutes(5),
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        k2PerMinute, new Mapper()));
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No more than 20 per hour.
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    heuristics->push_back(new TimedLimit(k20PerHour, new Mapper()));
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass FrozenMockFunction : public MockFunction {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit FrozenMockFunction(const std::string& name) : MockFunction(name) {}
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void GetQuotaLimitHeuristics(
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      QuotaLimitHeuristics* heuristics) const {
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    heuristics->push_back(new TimedLimit(kFrozenConfig, new Mapper()));
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ExtensionsQuotaServiceTest : public testing::Test {
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionsQuotaServiceTest()
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : extension_a_("a"), extension_b_("b"), extension_c_("c") {}
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void SetUp() {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    service_.reset(new ExtensionsQuotaService());
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void TearDown() {
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    service_.reset();
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected:
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string extension_a_;
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string extension_b_;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string extension_c_;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<ExtensionsQuotaService> service_;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass QuotaLimitHeuristicTest : public testing::Test {
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static void DoMoreThan2PerMinuteFor5Minutes(const TimeTicks& start_time,
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              QuotaLimitHeuristic* lim,
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              Bucket* b,
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              int an_unexhausted_minute) {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0; i < 5; i++) {
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Perform one operation in each minute.
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int m = i * 60;
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXPECT_TRUE(lim->Apply(b, start_time + TimeDelta::FromSeconds(10 + m)));
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXPECT_TRUE(b->has_tokens());
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (i == an_unexhausted_minute)
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;  // Don't exhaust all tokens this minute.
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXPECT_TRUE(lim->Apply(b, start_time + TimeDelta::FromSeconds(15 + m)));
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXPECT_FALSE(b->has_tokens());
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // These are OK because we haven't exhausted all buckets.
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXPECT_TRUE(lim->Apply(b, start_time + TimeDelta::FromSeconds(20 + m)));
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXPECT_FALSE(b->has_tokens());
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXPECT_TRUE(lim->Apply(b, start_time + TimeDelta::FromSeconds(50 + m)));
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXPECT_FALSE(b->has_tokens());
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(QuotaLimitHeuristicTest, Timed) {
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimedLimit lim(k2PerMinute, new MockMapper());
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Bucket b;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  b.Reset(k2PerMinute, kStartTime);
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(lim.Apply(&b, kStartTime));
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(b.has_tokens());
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(lim.Apply(&b, kStartTime + TimeDelta::FromSeconds(30)));
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(b.has_tokens());
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(lim.Apply(&b,  k1MinuteAfterStart));
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  b.Reset(k2PerMinute, kStartTime);
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(lim.Apply(&b, k1MinuteAfterStart - TimeDelta::FromSeconds(1)));
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(lim.Apply(&b, k1MinuteAfterStart));
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(lim.Apply(&b, k1MinuteAfterStart + TimeDelta::FromSeconds(1)));
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(lim.Apply(&b, k1MinuteAfterStart + TimeDelta::FromSeconds(2)));
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(lim.Apply(&b, k1MinuteAfterStart + TimeDelta::FromSeconds(3)));
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(QuotaLimitHeuristicTest, Sustained) {
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SustainedLimit lim(TimeDelta::FromMinutes(5), k2PerMinute, new MockMapper());
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Bucket bucket;
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bucket.Reset(k2PerMinute, kStartTime);
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DoMoreThan2PerMinuteFor5Minutes(kStartTime, &lim, &bucket, -1);
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This straw breaks the camel's back.
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(lim.Apply(&bucket, kStartTime + TimeDelta::FromMinutes(6)));
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The heuristic resets itself on a safe request.
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(lim.Apply(&bucket, kStartTime + TimeDelta::FromDays(1)));
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Do the same as above except don't exhaust final bucket.
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bucket.Reset(k2PerMinute, kStartTime);
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DoMoreThan2PerMinuteFor5Minutes(kStartTime, &lim, &bucket, -1);
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(lim.Apply(&bucket, kStartTime + TimeDelta::FromMinutes(7)));
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Do the same as above except don't exhaust the 3rd (w.l.o.g) bucket.
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bucket.Reset(k2PerMinute, kStartTime);
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DoMoreThan2PerMinuteFor5Minutes(kStartTime, &lim, &bucket, 3);
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the 3rd bucket were exhausted, this would fail (see first test).
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(lim.Apply(&bucket, kStartTime + TimeDelta::FromMinutes(6)));
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ExtensionsQuotaServiceTest, NoHeuristic) {
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<MockFunction> f(new MockFunction("foo"));
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_a_, f, &args, kStartTime));
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ExtensionsQuotaServiceTest, FrozenHeuristic) {
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<MockFunction> f(new FrozenMockFunction("foo"));
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(new FundamentalValue(1));
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_a_, f, &args, kStartTime));
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ExtensionsQuotaServiceTest, SingleHeuristic) {
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<MockFunction> f(new TimedLimitMockFunction("foo"));
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(new FundamentalValue(1));
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_a_, f, &args, kStartTime));
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_a_, f, &args,
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kStartTime + TimeDelta::FromSeconds(10)));
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_a_, f, &args,
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kStartTime + TimeDelta::FromSeconds(15)));
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args2;
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args2.Append(new FundamentalValue(1));
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args2.Append(new FundamentalValue(2));
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_b_, f, &args2, kStartTime));
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_b_, f, &args2,
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kStartTime + TimeDelta::FromSeconds(10)));
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeDelta peace = TimeDelta::FromMinutes(30);
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_b_, f, &args, kStartTime + peace));
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_b_, f, &args,
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kStartTime + peace + TimeDelta::FromSeconds(10)));
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_b_, f, &args2,
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kStartTime + peace + TimeDelta::FromSeconds(15)));
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Test that items are independent.
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args3;
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args3.Append(new FundamentalValue(3));
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_c_, f, &args, kStartTime));
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_c_, f, &args3,
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kStartTime + TimeDelta::FromSeconds(10)));
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_c_, f, &args,
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kStartTime + TimeDelta::FromSeconds(15)));
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_c_, f, &args3,
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kStartTime + TimeDelta::FromSeconds(20)));
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_c_, f, &args,
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kStartTime + TimeDelta::FromSeconds(25)));
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_c_, f, &args3,
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kStartTime + TimeDelta::FromSeconds(30)));
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ExtensionsQuotaServiceTest, ChainedHeuristics) {
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<MockFunction> f(new ChainedLimitsMockFunction("foo"));
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args.Append(new FundamentalValue(1));
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // First, test that the low limit can be avoided but the higher one is hit.
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // One event per minute for 20 minutes comes in under the sustained limit,
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // but is equal to the timed limit.
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < 20; i++) {
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_TRUE(service_->Assess(extension_a_, f, &args,
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                kStartTime + TimeDelta::FromSeconds(10 + i * 60)));
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This will bring us to 21 events in an hour, which is a violation.
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_a_, f, &args,
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kStartTime + TimeDelta::FromMinutes(30)));
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now, check that we can still hit the lower limit.
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < 5; i++) {
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_TRUE(service_->Assess(extension_b_, f, &args,
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                kStartTime + TimeDelta::FromSeconds(10 + i * 60)));
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_TRUE(service_->Assess(extension_b_, f, &args,
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                kStartTime + TimeDelta::FromSeconds(15 + i * 60)));
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXPECT_TRUE(service_->Assess(extension_b_, f, &args,
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                kStartTime + TimeDelta::FromSeconds(20 + i * 60)));
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_b_, f, &args,
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kStartTime + TimeDelta::FromMinutes(6)));
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ExtensionsQuotaServiceTest, MultipleFunctionsDontInterfere) {
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<MockFunction> f(new TimedLimitMockFunction("foo"));
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<MockFunction> g(new TimedLimitMockFunction("bar"));
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args_f;
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue args_g;
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args_f.Append(new FundamentalValue(1));
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  args_g.Append(new FundamentalValue(2));
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_a_, f, &args_f, kStartTime));
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_a_, g, &args_g, kStartTime));
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_a_, f, &args_f,
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kStartTime + TimeDelta::FromSeconds(10)));
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_a_, g, &args_g,
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kStartTime + TimeDelta::FromSeconds(10)));
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_a_, f, &args_f,
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kStartTime + TimeDelta::FromSeconds(15)));
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_a_, g, &args_g,
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kStartTime + TimeDelta::FromSeconds(15)));
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ExtensionsQuotaServiceTest, ViolatorsWillBeViolators) {
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<MockFunction> f(new TimedLimitMockFunction("foo"));
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<MockFunction> g(new TimedLimitMockFunction("bar"));
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue arg;
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  arg.Append(new FundamentalValue(1));
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_a_, f, &arg, kStartTime));
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(service_->Assess(extension_a_, f, &arg,
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kStartTime + TimeDelta::FromSeconds(10)));
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_a_, f, &arg,
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kStartTime + TimeDelta::FromSeconds(15)));
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't allow this extension to use quota limited functions even if they
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // wait a while.
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_a_, f, &arg,
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kStartTime + TimeDelta::FromDays(1)));
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(service_->Assess(extension_a_, g, &arg,
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               kStartTime + TimeDelta::FromDays(1)));
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
305