OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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 <ctype.h> |
| 6 #include <string> |
| 7 |
| 8 #include "base/compiler_specific.h" |
| 9 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/memory/scoped_vector.h" |
| 11 #include "net/base/prioritized_dispatcher.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 |
| 14 namespace net { |
| 15 |
| 16 namespace { |
| 17 |
| 18 class PrioritizedDispatcherTest : public testing::Test { |
| 19 public: |
| 20 // A job that appends |data| to |log_| when started, toupper(|data|) when |
| 21 // evicted, and '.' when finished. This is intended to confirm the execution |
| 22 // and eviction order of a sequence of jobs added to the dispatcher. |
| 23 class TestJob : public PrioritizedDispatcher::Job { |
| 24 public: |
| 25 TestJob(PrioritizedDispatcherTest* test, char data, |
| 26 RequestPriority priority) |
| 27 : test_(test), data_(data), priority_(priority), running_(false) {} |
| 28 |
| 29 // MSVS does not accept EXPECT_EQ(this, ...) so wrap it up. |
| 30 PrioritizedDispatcher::Job* this_job() { |
| 31 return this; |
| 32 } |
| 33 |
| 34 void Add() { |
| 35 EXPECT_TRUE(handle_.is_null()); |
| 36 EXPECT_FALSE(running_); |
| 37 size_t num_queued = dispatch().num_queued_jobs(); |
| 38 size_t num_running = dispatch().num_running_jobs(); |
| 39 |
| 40 bool would_evict = dispatch().WouldEvict(priority_); |
| 41 handle_ = dispatch().Add(this, priority_); |
| 42 |
| 43 if (handle_.is_null()) { |
| 44 EXPECT_EQ(num_queued, dispatch().num_queued_jobs()); |
| 45 if (running_) { |
| 46 EXPECT_FALSE(would_evict); |
| 47 EXPECT_EQ(num_running + 1, dispatch().num_running_jobs()); |
| 48 } else { |
| 49 // This job got evicted on Add. |
| 50 EXPECT_TRUE(would_evict); |
| 51 EXPECT_EQ(num_running, dispatch().num_running_jobs()); |
| 52 } |
| 53 } else { |
| 54 EXPECT_FALSE(would_evict); |
| 55 EXPECT_FALSE(running_); |
| 56 EXPECT_EQ(priority_, handle_.priority()); |
| 57 EXPECT_EQ(this_job(), handle_.value()); |
| 58 EXPECT_EQ(num_running, dispatch().num_running_jobs()); |
| 59 } |
| 60 } |
| 61 |
| 62 void Update(RequestPriority priority) { |
| 63 EXPECT_FALSE(running_); |
| 64 ASSERT_FALSE(handle_.is_null()); |
| 65 size_t num_queued = dispatch().num_queued_jobs(); |
| 66 size_t num_running = dispatch().num_running_jobs(); |
| 67 |
| 68 handle_ = dispatch().Update(handle_, priority); |
| 69 |
| 70 if (handle_.is_null()) { |
| 71 EXPECT_TRUE(running_); |
| 72 EXPECT_EQ(num_queued - 1, dispatch().num_queued_jobs()); |
| 73 EXPECT_EQ(num_running + 1, dispatch().num_running_jobs()); |
| 74 } else { |
| 75 EXPECT_FALSE(running_); |
| 76 EXPECT_EQ(priority, handle_.priority()); |
| 77 EXPECT_EQ(this_job(), handle_.value()); |
| 78 EXPECT_EQ(num_queued, dispatch().num_queued_jobs()); |
| 79 EXPECT_EQ(num_running, dispatch().num_running_jobs()); |
| 80 } |
| 81 } |
| 82 |
| 83 void Cancel() { |
| 84 EXPECT_FALSE(running_); |
| 85 ASSERT_FALSE(handle_.is_null()); |
| 86 size_t num_queued = dispatch().num_queued_jobs(); |
| 87 |
| 88 dispatch().Cancel(handle_); |
| 89 |
| 90 EXPECT_EQ(num_queued - 1, dispatch().num_queued_jobs()); |
| 91 handle_ = PrioritizedDispatcher::Handle(); |
| 92 } |
| 93 |
| 94 void Finish() { |
| 95 EXPECT_TRUE(running_); |
| 96 running_ = false; |
| 97 test_->log_.append(1u, '.'); |
| 98 |
| 99 dispatch().OnJobFinished(); |
| 100 } |
| 101 |
| 102 // PriorityDispatch::Job interface |
| 103 virtual void Start() OVERRIDE { |
| 104 EXPECT_FALSE(running_); |
| 105 handle_ = PrioritizedDispatcher::Handle(); |
| 106 running_ = true; |
| 107 test_->log_.append(1u, data_); |
| 108 } |
| 109 |
| 110 virtual void OnEvicted() OVERRIDE { |
| 111 EXPECT_FALSE(running_); |
| 112 handle_ = PrioritizedDispatcher::Handle(); |
| 113 test_->log_.append(1u, toupper(data_)); |
| 114 } |
| 115 |
| 116 private: |
| 117 PrioritizedDispatcher& dispatch() { return *(test_->dispatch_); } |
| 118 |
| 119 PrioritizedDispatcherTest* test_; |
| 120 |
| 121 char data_; |
| 122 RequestPriority priority_; |
| 123 |
| 124 PrioritizedDispatcher::Handle handle_; |
| 125 bool running_; |
| 126 }; |
| 127 |
| 128 protected: |
| 129 void Prepare(const PrioritizedDispatcher::Limits& limits, size_t max_queued) { |
| 130 dispatch_.reset(new PrioritizedDispatcher(limits, max_queued)); |
| 131 } |
| 132 |
| 133 TestJob* AddJob(char data, RequestPriority priority) { |
| 134 TestJob* job = new TestJob(this, data, priority); |
| 135 jobs_.push_back(job); |
| 136 job->Add(); |
| 137 return job; |
| 138 } |
| 139 |
| 140 void Expect(std::string log) { |
| 141 EXPECT_EQ(0u, dispatch_->num_queued_jobs()); |
| 142 EXPECT_EQ(0u, dispatch_->num_running_jobs()); |
| 143 EXPECT_EQ(log, log_); |
| 144 log_.clear(); |
| 145 } |
| 146 |
| 147 std::string log_; |
| 148 scoped_ptr<PrioritizedDispatcher> dispatch_; |
| 149 ScopedVector<TestJob> jobs_; |
| 150 }; |
| 151 |
| 152 TEST_F(PrioritizedDispatcherTest, AddAFIFO) { |
| 153 // Allow only one running job. |
| 154 PrioritizedDispatcher::Limits limits = { 1 }; |
| 155 Prepare(limits, 1000u); |
| 156 |
| 157 TestJob* job_a = AddJob('a', IDLE); |
| 158 TestJob* job_b = AddJob('b', IDLE); |
| 159 TestJob* job_c = AddJob('c', IDLE); |
| 160 TestJob* job_d = AddJob('d', IDLE); |
| 161 |
| 162 job_a->Finish(); |
| 163 job_b->Finish(); |
| 164 job_c->Finish(); |
| 165 job_d->Finish(); |
| 166 |
| 167 Expect("a.b.c.d."); |
| 168 } |
| 169 |
| 170 TEST_F(PrioritizedDispatcherTest, AddPriority) { |
| 171 PrioritizedDispatcher::Limits limits = { 1 }; |
| 172 Prepare(limits, 1000u); |
| 173 |
| 174 TestJob* job_a = AddJob('a', IDLE); |
| 175 TestJob* job_b = AddJob('b', MEDIUM); |
| 176 TestJob* job_c = AddJob('c', HIGHEST); |
| 177 TestJob* job_d = AddJob('d', HIGHEST); |
| 178 TestJob* job_e = AddJob('e', MEDIUM); |
| 179 |
| 180 job_a->Finish(); |
| 181 job_c->Finish(); |
| 182 job_d->Finish(); |
| 183 job_b->Finish(); |
| 184 job_e->Finish(); |
| 185 |
| 186 Expect("a.c.d.b.e."); |
| 187 } |
| 188 |
| 189 TEST_F(PrioritizedDispatcherTest, EnforceLimits) { |
| 190 // Reserve 2 for HIGHEST and 1 for LOW or higher. |
| 191 // This leaves 2 for LOWEST or lower. |
| 192 PrioritizedDispatcher::Limits limits = { 5, { 2, 0, 1 } }; |
| 193 Prepare(limits, 1000u); |
| 194 |
| 195 TestJob* job_a = AddJob('a', IDLE); // Uses unreserved slot. |
| 196 TestJob* job_b = AddJob('b', IDLE); // Uses unreserved slot. |
| 197 TestJob* job_c = AddJob('c', LOWEST); // Must wait. |
| 198 TestJob* job_d = AddJob('d', LOW); // Uses reserved slot. |
| 199 TestJob* job_e = AddJob('e', MEDIUM); // Must wait. |
| 200 TestJob* job_f = AddJob('f', HIGHEST); // Uses reserved slot. |
| 201 TestJob* job_g = AddJob('g', HIGHEST); // Uses reserved slot. |
| 202 TestJob* job_h = AddJob('h', HIGHEST); // Must wait. |
| 203 |
| 204 EXPECT_EQ(5u, dispatch_->num_running_jobs()); |
| 205 EXPECT_EQ(3u, dispatch_->num_queued_jobs()); |
| 206 |
| 207 job_a->Finish(); // Releases h. |
| 208 job_b->Finish(); |
| 209 job_d->Finish(); |
| 210 job_f->Finish(); // Releases e. |
| 211 job_g->Finish(); |
| 212 job_h->Finish(); // Releases c. |
| 213 job_e->Finish(); |
| 214 job_c->Finish(); |
| 215 |
| 216 Expect("abdfg.h...e..c.."); |
| 217 } |
| 218 |
| 219 TEST_F(PrioritizedDispatcherTest, Update) { |
| 220 PrioritizedDispatcher::Limits limits = { 1 }; |
| 221 Prepare(limits, 1000u); |
| 222 |
| 223 TestJob* job_a = AddJob('a', IDLE); |
| 224 TestJob* job_b = AddJob('b', MEDIUM); |
| 225 TestJob* job_c = AddJob('c', HIGHEST); |
| 226 TestJob* job_d = AddJob('d', HIGHEST); |
| 227 |
| 228 job_b->Update(HIGHEST); |
| 229 job_c->Update(MEDIUM); |
| 230 |
| 231 job_a->Finish(); |
| 232 job_d->Finish(); |
| 233 job_b->Finish(); |
| 234 job_c->Finish(); |
| 235 |
| 236 Expect("a.d.b.c."); |
| 237 } |
| 238 |
| 239 TEST_F(PrioritizedDispatcherTest, Cancel) { |
| 240 PrioritizedDispatcher::Limits limits = { 1 }; |
| 241 Prepare(limits, 1000u); |
| 242 |
| 243 TestJob* job_a = AddJob('a', IDLE); |
| 244 TestJob* job_b = AddJob('b', IDLE); |
| 245 TestJob* job_c = AddJob('c', IDLE); |
| 246 TestJob* job_d = AddJob('d', IDLE); |
| 247 TestJob* job_e = AddJob('e', IDLE); |
| 248 |
| 249 job_b->Cancel(); |
| 250 job_d->Cancel(); |
| 251 |
| 252 job_a->Finish(); |
| 253 job_c->Finish(); |
| 254 job_e->Finish(); |
| 255 |
| 256 Expect("a.c.e."); |
| 257 } |
| 258 |
| 259 TEST_F(PrioritizedDispatcherTest, Evict) { |
| 260 PrioritizedDispatcher::Limits limits = { 1 }; |
| 261 Prepare(limits, 2u); |
| 262 |
| 263 // Note that the eviction order is by OldestLowest. |
| 264 TestJob* job_a = AddJob('a', LOW); |
| 265 AddJob('b', LOW); |
| 266 AddJob('c', LOW); |
| 267 TestJob* job_d = AddJob('d', LOW); // Evicts b. |
| 268 TestJob* job_e = AddJob('e', HIGHEST); // Evicts c. |
| 269 AddJob('f', IDLE); // Evicts self. |
| 270 |
| 271 job_a->Finish(); |
| 272 job_e->Finish(); |
| 273 job_d->Finish(); |
| 274 |
| 275 Expect("aBCF.e.d."); |
| 276 } |
| 277 |
| 278 } // namespace |
| 279 |
| 280 } // namespace net |
| 281 |
OLD | NEW |