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