Chromium Code Reviews| Index: net/base/priority_dispatch_unittest.cc |
| diff --git a/net/base/priority_dispatch_unittest.cc b/net/base/priority_dispatch_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5d20321ad275ad3984392dff5d3efd1e70212bdf |
| --- /dev/null |
| +++ b/net/base/priority_dispatch_unittest.cc |
| @@ -0,0 +1,275 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include <ctype.h> |
| +#include <string> |
| + |
| +#include "base/compiler_specific.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/memory/scoped_vector.h" |
| +#include "net/base/priority_dispatch.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace net { |
| + |
| +namespace { |
| + |
| +class PriorityDispatchTest : public testing::Test { |
| + public: |
| + // A job that appends |data| to |log| when started, toupper(|data|) when |
| + // 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.
|
| + class TestJob : public PriorityDispatch::Job { |
| + public: |
| + TestJob(PriorityDispatchTest* test, char data, RequestPriority priority) |
| + : test_(test), data_(data), priority_(priority), running_(false) {} |
| + |
| + // 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.
|
| + PriorityDispatch::Job* this_job() { |
| + return this; |
| + } |
| + |
| + void Add() { |
| + EXPECT_TRUE(handle_.is_null()); |
| + EXPECT_FALSE(running_); |
| + size_t num_queued = dispatch().num_queued_jobs(); |
| + size_t num_running = dispatch().num_running_jobs(); |
| + |
| + handle_ = dispatch().Add(this, priority_); |
| + |
| + if (handle_.is_null()) { |
| + EXPECT_EQ(num_queued, dispatch().num_queued_jobs()); |
| + if (running_) { |
| + EXPECT_EQ(num_running + 1, dispatch().num_running_jobs()); |
| + } else { |
| + // This job got evicted on Add. |
| + EXPECT_EQ(num_running, dispatch().num_running_jobs()); |
| + } |
| + } else { |
| + EXPECT_FALSE(running_); |
| + EXPECT_EQ(priority_, handle_.priority()); |
| + EXPECT_EQ(this_job(), handle_.value()); |
| + EXPECT_EQ(num_running, dispatch().num_running_jobs()); |
| + } |
| + } |
| + |
| + void Update(RequestPriority priority) { |
| + EXPECT_FALSE(running_); |
| + ASSERT_FALSE(handle_.is_null()); |
| + size_t num_queued = dispatch().num_queued_jobs(); |
| + size_t num_running = dispatch().num_running_jobs(); |
| + |
| + handle_ = dispatch().Update(handle_, priority); |
| + |
| + if (handle_.is_null()) { |
| + EXPECT_TRUE(running_); |
| + EXPECT_EQ(num_queued - 1, dispatch().num_queued_jobs()); |
| + EXPECT_EQ(num_running + 1, dispatch().num_running_jobs()); |
| + } else { |
| + EXPECT_FALSE(running_); |
| + EXPECT_EQ(priority, handle_.priority()); |
| + EXPECT_EQ(this_job(), handle_.value()); |
| + EXPECT_EQ(num_queued, dispatch().num_queued_jobs()); |
| + EXPECT_EQ(num_running, dispatch().num_running_jobs()); |
| + } |
| + } |
| + |
| + void Cancel() { |
| + EXPECT_FALSE(running_); |
| + ASSERT_FALSE(handle_.is_null()); |
| + size_t num_queued = dispatch().num_queued_jobs(); |
| + |
| + dispatch().Cancel(handle_); |
| + |
| + EXPECT_EQ(num_queued - 1, dispatch().num_queued_jobs()); |
| + handle_ = PriorityDispatch::Handle(); |
| + } |
| + |
| + void Finish() { |
| + EXPECT_TRUE(running_); |
| + running_ = false; |
| + test_->log_.append(1u, '.'); |
| + |
| + dispatch().OnJobFinished(); |
| + } |
| + |
| + // PriorityDispatch::Job interface |
| + virtual void Start() OVERRIDE { |
| + EXPECT_FALSE(running_); |
| + handle_ = PriorityDispatch::Handle(); |
| + running_ = true; |
| + test_->log_.append(1u, data_); |
| + } |
| + |
| + virtual void OnEvicted() OVERRIDE { |
| + EXPECT_FALSE(running_); |
| + handle_ = PriorityDispatch::Handle(); |
| + test_->log_.append(1u, toupper(data_)); |
| + } |
| + |
| + private: |
| + PriorityDispatch& dispatch() { return *(test_->dispatch_); } |
| + |
| + PriorityDispatchTest* test_; |
| + |
| + char data_; |
| + RequestPriority priority_; |
| + |
| + PriorityDispatch::Handle handle_; |
| + bool running_; |
| + }; |
| + |
| + protected: |
| + 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.
|
| + |
| + void Prepare(const PriorityDispatch::Limits& limits, size_t max_queued) { |
| + dispatch_.reset(new PriorityDispatch(limits, max_queued)); |
| + } |
| + |
| + TestJob* AddJob(char data, RequestPriority priority) { |
| + TestJob* job = new TestJob(this, data, priority); |
| + jobs_.push_back(job); |
| + job->Add(); |
| + return job; |
| + } |
| + |
| + void Expect(std::string log) { |
| + EXPECT_EQ(0u, dispatch_->num_queued_jobs()); |
| + EXPECT_EQ(0u, dispatch_->num_running_jobs()); |
| + EXPECT_EQ(log, log_); |
| + log_.clear(); |
| + } |
| + |
| + std::string log_; |
| + scoped_ptr<PriorityDispatch> dispatch_; |
| + ScopedVector<TestJob> jobs_; |
| +}; |
| + |
| +TEST_F(PriorityDispatchTest, AddAFIFO) { |
| + // Allow only one running job. |
| + PriorityDispatch::Limits limits = {{0, 0, 0, 0, 1}}; |
| + Prepare(limits, 1000u); |
| + |
| + TestJob* job_a = AddJob('a', IDLE); |
| + TestJob* job_b = AddJob('b', IDLE); |
| + TestJob* job_c = AddJob('c', IDLE); |
| + TestJob* job_d = AddJob('d', IDLE); |
| + |
| + job_a->Finish(); |
| + job_b->Finish(); |
| + job_c->Finish(); |
| + job_d->Finish(); |
| + |
| + Expect("a.b.c.d."); |
| +} |
| + |
| +TEST_F(PriorityDispatchTest, AddPriority) { |
| + PriorityDispatch::Limits limits = {{0, 0, 0, 0, 1}}; |
| + Prepare(limits, 1000u); |
| + |
| + TestJob* job_a = AddJob('a', IDLE); |
| + TestJob* job_b = AddJob('b', MEDIUM); |
| + TestJob* job_c = AddJob('c', HIGHEST); |
| + TestJob* job_d = AddJob('d', HIGHEST); |
| + TestJob* job_e = AddJob('e', MEDIUM); |
| + |
| + job_a->Finish(); |
| + job_c->Finish(); |
| + job_d->Finish(); |
| + job_b->Finish(); |
| + job_e->Finish(); |
| + |
| + Expect("a.c.d.b.e."); |
| +} |
| + |
| +TEST_F(PriorityDispatchTest, EnforceLimits) { |
| + PriorityDispatch::Limits limits = {{2, 0, 1, 0, 2}}; |
| + Prepare(limits, 1000u); |
| + |
| + TestJob* job_a = AddJob('a', IDLE); |
| + TestJob* job_b = AddJob('b', IDLE); |
| + TestJob* job_c = AddJob('c', LOWEST); |
| + TestJob* job_d = AddJob('d', LOW); |
| + TestJob* job_e = AddJob('e', MEDIUM); |
| + TestJob* job_f = AddJob('f', HIGHEST); |
| + TestJob* job_g = AddJob('g', HIGHEST); |
| + TestJob* job_h = AddJob('h', HIGHEST); |
| + |
| + EXPECT_EQ(5u, dispatch_->num_running_jobs()); |
| + EXPECT_EQ(3u, dispatch_->num_queued_jobs()); |
| + |
| + job_a->Finish(); // Releases h. |
| + job_b->Finish(); |
| + job_d->Finish(); |
| + job_f->Finish(); // Releases e. |
| + job_g->Finish(); |
| + job_h->Finish(); // Releases c. |
| + job_e->Finish(); |
| + job_c->Finish(); |
| + |
| + Expect("abdfg.h...e..c.."); |
| +} |
| + |
| +TEST_F(PriorityDispatchTest, Update) { |
| + PriorityDispatch::Limits limits = {{0, 0, 0, 0, 1}}; |
| + Prepare(limits, 1000u); |
| + |
| + TestJob* job_a = AddJob('a', IDLE); |
| + TestJob* job_b = AddJob('b', MEDIUM); |
| + TestJob* job_c = AddJob('c', HIGHEST); |
| + TestJob* job_d = AddJob('d', HIGHEST); |
| + |
| + job_b->Update(HIGHEST); |
| + job_c->Update(MEDIUM); |
| + |
| + job_a->Finish(); |
| + job_d->Finish(); |
| + job_b->Finish(); |
| + job_c->Finish(); |
| + |
| + Expect("a.d.b.c."); |
| +} |
| + |
| +TEST_F(PriorityDispatchTest, Cancel) { |
| + PriorityDispatch::Limits limits = {{0, 0, 0, 0, 1}}; |
| + Prepare(limits, 1000u); |
| + |
| + TestJob* job_a = AddJob('a', IDLE); |
| + TestJob* job_b = AddJob('b', IDLE); |
| + TestJob* job_c = AddJob('c', IDLE); |
| + TestJob* job_d = AddJob('d', IDLE); |
| + TestJob* job_e = AddJob('e', IDLE); |
| + |
| + job_b->Cancel(); |
| + job_d->Cancel(); |
| + |
| + job_a->Finish(); |
| + job_c->Finish(); |
| + job_e->Finish(); |
| + |
| + Expect("a.c.e."); |
| +} |
| + |
| +TEST_F(PriorityDispatchTest, Evict) { |
| + PriorityDispatch::Limits limits = {{0, 0, 0, 0, 1}}; |
| + Prepare(limits, 2u); |
| + |
| + // Note that the eviction order is by OldestLowest. |
| + TestJob* job_a = AddJob('a', LOW); |
| + AddJob('b', LOW); |
| + AddJob('c', LOW); |
| + TestJob* job_d = AddJob('d', LOW); // Evicts b. |
| + TestJob* job_e = AddJob('e', HIGHEST); // Evicts c. |
| + AddJob('f', IDLE); // Evicts self. |
| + |
| + job_a->Finish(); |
| + job_e->Finish(); |
| + job_d->Finish(); |
| + |
| + Expect("aBCF.e.d."); |
| +} |
| + |
| +} // namespace |
| + |
| +} // namespace net |
| + |