Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Unified Diff: net/base/host_resolver_impl_unittest.cc

Issue 9572018: [net] Ensure aborted HostResolverImpl::Jobs release slots in the dispatcher. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Reorder: dispatch then Abort. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« net/base/host_resolver_impl.cc ('K') | « net/base/host_resolver_impl.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/base/host_resolver_impl_unittest.cc
diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index 88211ea06e3921feedccf42edce859650f50de62..ebc7fcbf8973d5a302ae60a8e93169131580807f 100644
--- a/net/base/host_resolver_impl_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -15,6 +15,7 @@
#include "base/stringprintf.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
+#include "base/test/test_timeouts.h"
#include "base/time.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
@@ -90,6 +91,45 @@ HostResolver::RequestInfo CreateResolverRequestForAddressFamily(
return info;
}
+// Using WaitingHostResolverProc you can simulate very long lookups.
+class WaitingHostResolverProc : public HostResolverProc {
+ public:
+ explicit WaitingHostResolverProc(HostResolverProc* previous)
+ : HostResolverProc(previous),
+ is_waiting_(false, false),
+ is_signaled_(false, false) {}
+
+ // Waits until a call to |Resolve| is blocked. It is recommended to always
+ // |Wait| before |Signal|, and required if issuing a series of two or more
+ // calls to |Signal|, because |WaitableEvent| does not count the number of
+ // signals.
+ void Wait() {
+ is_waiting_.Wait();
+ }
+
+ // Signals a waiting call to |Resolve|.
+ void Signal() {
+ is_signaled_.Signal();
+ }
+
+ // HostResolverProc methods:
+ virtual int Resolve(const std::string& host,
+ AddressFamily address_family,
+ HostResolverFlags host_resolver_flags,
+ AddressList* addrlist,
+ int* os_error) OVERRIDE {
+ is_waiting_.Signal();
+ is_signaled_.Wait();
+ return ResolveUsingPrevious(host, address_family, host_resolver_flags,
+ addrlist, os_error);
+ }
+
+ private:
+ virtual ~WaitingHostResolverProc() {}
+ base::WaitableEvent is_waiting_;
+ base::WaitableEvent is_signaled_;
+};
+
// A variant of WaitingHostResolverProc that pushes each host mapped into a
// list.
// (and uses a manual-reset event rather than auto-reset).
@@ -143,6 +183,72 @@ class CapturingHostResolverProc : public HostResolverProc {
base::WaitableEvent event_;
};
+// A variant of WaitingHostResolverProc which waits for a specific number of
+// requests.
+class CountingHostResolverProc : public HostResolverProc {
+ public:
+ explicit CountingHostResolverProc(HostResolverProc* previous)
+ : HostResolverProc(previous),
+ num_requests_waiting_(0),
+ num_slots_available_(0),
+ requests_waiting_(&lock_),
+ slots_available_(&lock_) {}
+
+ // Waits until |count| calls to |Resolve| are blocked. Returns false when
+ // timed out.
+ bool WaitFor(unsigned count) {
+ base::AutoLock lock(lock_);
+ base::Time start_time = base::Time::Now();
+ while (num_requests_waiting_ < count) {
+ requests_waiting_.TimedWait(TestTimeouts::action_timeout());
+ if (base::Time::Now() > start_time + TestTimeouts::action_timeout())
+ return false;
+ }
+ return true;
+ }
+
+ // Signals |count| waiting calls to |Resolve|. First come first served.
+ void SignalMultiple(unsigned count) {
+ base::AutoLock lock(lock_);
+ num_slots_available_ += count;
+ slots_available_.Broadcast();
+ }
+
+ // Signals all waiting calls to |Resolve|. Beware of races.
+ void SignalAll() {
+ base::AutoLock lock(lock_);
+ num_slots_available_ += num_requests_waiting_;
+ slots_available_.Broadcast();
+ }
+
+ // HostResolverProc methods:
+ virtual int Resolve(const std::string& host,
+ AddressFamily address_family,
+ HostResolverFlags host_resolver_flags,
+ AddressList* addrlist,
+ int* os_error) OVERRIDE {
+ {
+ base::AutoLock lock(lock_);
+ ++num_requests_waiting_;
+ requests_waiting_.Broadcast();
+ while (!num_slots_available_)
+ slots_available_.Wait();
+ --num_slots_available_;
+ --num_requests_waiting_;
+ }
+ return ResolveUsingPrevious(host, address_family, host_resolver_flags,
+ addrlist, os_error);
+ }
+
+ private:
+ virtual ~CountingHostResolverProc() {}
+ unsigned num_requests_waiting_;
+ unsigned num_slots_available_;
+ base::Lock lock_;
+ base::ConditionVariable requests_waiting_;
+ base::ConditionVariable slots_available_;
+};
+
// This resolver function creates an IPv4 address, whose numeral value
// describes a hash of the requested hostname, and the value of the requested
// address_family.
@@ -467,52 +573,6 @@ TEST_F(HostResolverImplTest, FailedAsynchronousLookup) {
EXPECT_EQ(ERR_DNS_CACHE_MISS, err);
}
-// Using WaitingHostResolverProc you can simulate very long lookups.
-class WaitingHostResolverProc : public HostResolverProc {
- public:
- explicit WaitingHostResolverProc(HostResolverProc* previous)
- : HostResolverProc(previous),
- is_waiting_(false, false),
- is_signaled_(false, false) {}
-
- // If |manual_reset| is true, once Signalled, it will let all Resolve calls
- // proceed.
- WaitingHostResolverProc(HostResolverProc* previous, bool manual_reset)
- : HostResolverProc(previous),
- is_waiting_(false, false),
- is_signaled_(manual_reset, false) {}
-
- // Waits until a call to |Resolve| is blocked. It is recommended to always
- // |Wait| before |Signal|, and required if issuing a series of two or more
- // calls to |Signal|, because |WaitableEvent| does not count the number of
- // signals.
- void Wait() {
- is_waiting_.Wait();
- }
-
- // Signals a waiting call to |Resolve|.
- void Signal() {
- is_signaled_.Signal();
- }
-
- // HostResolverProc methods:
- virtual int Resolve(const std::string& host,
- AddressFamily address_family,
- HostResolverFlags host_resolver_flags,
- AddressList* addrlist,
- int* os_error) OVERRIDE {
- is_waiting_.Signal();
- is_signaled_.Wait();
- return ResolveUsingPrevious(host, address_family, host_resolver_flags,
- addrlist, os_error);
- }
-
- private:
- virtual ~WaitingHostResolverProc() {}
- base::WaitableEvent is_waiting_;
- base::WaitableEvent is_signaled_;
-};
-
TEST_F(HostResolverImplTest, AbortedAsynchronousLookup) {
scoped_refptr<WaitingHostResolverProc> resolver_proc(
new WaitingHostResolverProc(NULL));
@@ -559,8 +619,8 @@ TEST_F(HostResolverImplTest, AbortedAsynchronousLookup) {
NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
NetLog::PHASE_BEGIN);
pos = ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
- NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
- NetLog::PHASE_BEGIN);
+ NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
+ NetLog::PHASE_BEGIN);
// The Request needs to be cancelled. (The Job is "aborted".)
// Don't care about order in which Request, Job and ProcTask end.
@@ -808,6 +868,60 @@ TEST_F(HostResolverImplTest, CancelMultipleRequests) {
MessageLoop::current()->Run();
}
+// Helper class used by HostResolverImplTest.CanceledRequestsReleaseJobSlots.
+class CountingDelegate : public ResolveRequest::Delegate {
+ public:
+ CountingDelegate() : num_completions_(0) {}
+
+ virtual void OnCompleted(ResolveRequest* resolve) OVERRIDE {
+ ++num_completions_;
+ MessageLoop::current()->Quit();
+ }
+
+ unsigned num_completions() const { return num_completions_; }
+
+ private:
+ unsigned num_completions_;
+};
+
+TEST_F(HostResolverImplTest, CanceledRequestsReleaseJobSlots) {
+ scoped_refptr<CountingHostResolverProc> resolver_proc(
+ new CountingHostResolverProc(NULL));
+
+ scoped_ptr<HostResolver> host_resolver(
+ CreateHostResolverImpl(resolver_proc));
+
+ CountingDelegate delegate;
+ std::vector<ResolveRequest*> requests;
+
+ // Fill up the dispatcher and queue.
+ for (unsigned i = 0; i < kMaxJobs + 1; ++i) {
+ std::string hostname = "a_";
+ hostname[1] = 'a' + i;
+ requests.push_back(new ResolveRequest(host_resolver.get(), hostname, 80,
+ &delegate));
+ requests.push_back(new ResolveRequest(host_resolver.get(), hostname, 81,
+ &delegate));
+ }
+
+ EXPECT_TRUE(resolver_proc->WaitFor(kMaxJobs));
+
+ // Cancel all but last two.
+ for (unsigned i = 0; i < requests.size() - 2; ++i) {
+ requests[i]->Cancel();
+ }
+
+ EXPECT_TRUE(resolver_proc->WaitFor(kMaxJobs + 1));
+ EXPECT_EQ(0u, delegate.num_completions());
+
+ resolver_proc->SignalAll();
+
+ while (delegate.num_completions() < 2)
+ MessageLoop::current()->Run();
+
+ MessageLoop::current()->AssertIdle();
+}
+
// Helper class used by HostResolverImplTest.CancelWithinCallback.
class CancelWithinCallbackVerifier : public ResolveRequest::Delegate {
public:
@@ -1185,9 +1299,8 @@ class StartWithinAbortedCallbackVerifier : public ResolveRequest::Delegate {
// Tests that a new Request made from the callback of a previously aborted one
// will not be aborted.
TEST_F(HostResolverImplTest, AbortOnlyExistingRequestsOnIPAddressChange) {
- // Setting |manual_reset| to true so that Signal unblocks all calls.
- scoped_refptr<WaitingHostResolverProc> resolver_proc(
- new WaitingHostResolverProc(CreateCatchAllHostResolverProc(), true));
+ scoped_refptr<CountingHostResolverProc> resolver_proc(
+ new CountingHostResolverProc(CreateCatchAllHostResolverProc()));
scoped_ptr<HostResolver> host_resolver(CreateHostResolverImpl(resolver_proc));
StartWithinAbortedCallbackVerifier verifier1("zzz");
@@ -1198,8 +1311,8 @@ TEST_F(HostResolverImplTest, AbortOnlyExistingRequestsOnIPAddressChange) {
ResolveRequest req2(host_resolver.get(), "eee", 80, &verifier2);
ResolveRequest req3(host_resolver.get(), "ccc", 90, &verifier3);
// The jobs start immediately.
- // Wait until at least one is blocked.
- resolver_proc->Wait();
+ // Wait until all are blocked;
+ resolver_proc->WaitFor(3u);
// Trigger an IP address change.
NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
// This should abort all running jobs.
@@ -1208,7 +1321,7 @@ TEST_F(HostResolverImplTest, AbortOnlyExistingRequestsOnIPAddressChange) {
EXPECT_EQ(ERR_ABORTED, req2.result());
EXPECT_EQ(ERR_ABORTED, req3.result());
// Unblock all calls to proc.
- resolver_proc->Signal();
+ resolver_proc->SignalMultiple(6u);
// Run until the re-started requests finish.
EXPECT_EQ(OK, verifier1.WaitUntilDone());
EXPECT_EQ(OK, verifier2.WaitUntilDone());
« net/base/host_resolver_impl.cc ('K') | « net/base/host_resolver_impl.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698