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

Unified Diff: net/url_request/sdch_dictionary_fetcher_unittest.cc

Issue 864923002: In SdchDictionaryFetcher, don't set state when scheduling if loop is active. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Result of git cl format. Created 5 years, 11 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
Index: net/url_request/sdch_dictionary_fetcher_unittest.cc
diff --git a/net/url_request/sdch_dictionary_fetcher_unittest.cc b/net/url_request/sdch_dictionary_fetcher_unittest.cc
index 69adfed768007007729b1ca202d4475987266e87..25bf98ee330e8c60090a756784b2b6d83a7830d2 100644
--- a/net/url_request/sdch_dictionary_fetcher_unittest.cc
+++ b/net/url_request/sdch_dictionary_fetcher_unittest.cc
@@ -7,6 +7,7 @@
#include <string>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/thread_task_runner_handle.h"
@@ -18,6 +19,18 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+// Local test infrastructure
+// * URLRequestSpecifiedResponseJob: A URLRequestJob that returns
+// a different but derivable response for each URL (used for all
+// url requests in this file). The class provides interfaces to
+// signal whenever the total number of jobs transitions to zero.
+// * SdchDictionaryFetcherTest: Registers a callback with the above
+// class, and provides blocking interfaces for a transition to zero jobs.
+// Contains an SdchDictionaryFetcher, and tracks fetcher dictionary
+// addition callbacks.
mmenke 2015/01/21 21:33:57 Class level are generally be put just above the cl
Randy Smith (Not in Mondays) 2015/01/22 19:04:40 Hmmm. I can do that, and if you really want me to
mmenke 2015/01/22 19:58:33 Rather than tell you twice, which is something I p
Randy Smith (Not in Mondays) 2015/01/24 23:21:01 Thinking about it, the thing I care the most about
mmenke 2015/01/26 16:06:06 Works for me.
+// Most tests schedule a dictionary fetch, wait for no jobs outstanding,
+// then test that the fetch results are as expected.
+
namespace net {
static const char* kSampleBufferContext = "This is a sample buffer.";
@@ -27,7 +40,9 @@ class URLRequestSpecifiedResponseJob : public URLRequestSimpleJob {
public:
URLRequestSpecifiedResponseJob(URLRequest* request,
NetworkDelegate* network_delegate)
- : URLRequestSimpleJob(request, network_delegate) {}
+ : URLRequestSimpleJob(request, network_delegate) {
+ ++jobs_outstanding_;
+ }
static void AddUrlHandler() {
net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
@@ -58,8 +73,24 @@ class URLRequestSpecifiedResponseJob : public URLRequestSimpleJob {
static int jobs_requested() { return jobs_requested_; }
+ // |*callback| will be invoked when the total number of outstanding
+ // jobs drops to zero.
+ // Ownership of |*callback| remains with caller; |*callback|
+ // must be kept alive as long as this variable has a pointer to
+ // it.
+ static void SetSignalOnNoJobs(base::Closure* callback) {
+ signal_on_no_jobs_ = callback;
+ }
+
+ static int jobs_outstanding() { return jobs_outstanding_; }
+
private:
- ~URLRequestSpecifiedResponseJob() override{};
+ ~URLRequestSpecifiedResponseJob() override {
+ --jobs_outstanding_;
+ if (jobs_outstanding_ == 0 && signal_on_no_jobs_)
+ signal_on_no_jobs_->Run();
+ }
+
int GetData(std::string* mime_type,
std::string* charset,
std::string* data,
@@ -69,11 +100,17 @@ class URLRequestSpecifiedResponseJob : public URLRequestSimpleJob {
return OK;
}
+ static base::Closure* signal_on_no_jobs_;
static int jobs_requested_;
+ static int jobs_outstanding_;
mmenke 2015/01/21 21:33:57 I'd advise against using non-const static variable
Randy Smith (Not in Mondays) 2015/01/22 19:04:39 Good point, and maybe I'm just having a braino, bu
mmenke 2015/01/22 19:58:33 I'm fine with avoiding RunUntilIdle, like this (I'
mmenke 2015/01/24 17:01:24 And a quick followup... If keeping around an unow
Randy Smith (Not in Mondays) 2015/01/24 23:21:01 I'm good with your original suggestion, and it did
};
+base::Closure* URLRequestSpecifiedResponseJob::signal_on_no_jobs_(nullptr);
+
int URLRequestSpecifiedResponseJob::jobs_requested_(0);
+int URLRequestSpecifiedResponseJob::jobs_outstanding_(0);
+
class SdchDictionaryFetcherTest : public ::testing::Test {
public:
struct DictionaryAdditions {
@@ -85,17 +122,26 @@ class SdchDictionaryFetcherTest : public ::testing::Test {
GURL dictionary_url;
};
- SdchDictionaryFetcherTest() {
+ SdchDictionaryFetcherTest()
+ : waiting_for_no_jobs_(false),
+ run_loop_(nullptr),
+ no_jobs_seen_callback_(
+ base::Bind(&SdchDictionaryFetcherTest::NotifyNoJobs,
+ base::Unretained(this))) {
URLRequestSpecifiedResponseJob::AddUrlHandler();
context_.reset(new TestURLRequestContext);
fetcher_.reset(new SdchDictionaryFetcher(
context_.get(),
base::Bind(&SdchDictionaryFetcherTest::OnDictionaryFetched,
base::Unretained(this))));
+ URLRequestSpecifiedResponseJob::SetSignalOnNoJobs(
+ // Callback will be reset before destruction completion.
+ &no_jobs_seen_callback_);
}
~SdchDictionaryFetcherTest() override {
URLRequestSpecifiedResponseJob::RemoveUrlHandler();
+ URLRequestSpecifiedResponseJob::SetSignalOnNoJobs(nullptr);
}
void OnDictionaryFetched(const std::string& dictionary_text,
@@ -125,18 +171,41 @@ class SdchDictionaryFetcherTest : public ::testing::Test {
return GURL(gurl_string);
}
+ // Block until there are no outstanding URLRequestSpecifiedResponseJobs.
+ void WaitForNoJobs() {
+ if (URLRequestSpecifiedResponseJob::jobs_outstanding() == 0)
+ return;
+
+ base::RunLoop run_loop;
+ run_loop_ = &run_loop;
mmenke 2015/01/21 21:33:57 Suggest just a scoped_ptr<RunLoop> in the class -
Randy Smith (Not in Mondays) 2015/01/22 19:04:40 Done.
+ DCHECK(!waiting_for_no_jobs_);
+ waiting_for_no_jobs_ = true;
+ run_loop.Run();
+ run_loop_ = nullptr;
+ waiting_for_no_jobs_ = false;
+ }
+
private:
+ void NotifyNoJobs() {
+ if (waiting_for_no_jobs_)
mmenke 2015/01/21 21:33:57 Any case where this is not the same as run_loop_ !
Randy Smith (Not in Mondays) 2015/01/22 19:04:40 CL history I should have cleaned up--I used to hav
+ run_loop_->Quit();
+ }
+
+ bool waiting_for_no_jobs_;
+ base::RunLoop* run_loop_;
+
scoped_ptr<TestURLRequestContext> context_;
scoped_ptr<SdchDictionaryFetcher> fetcher_;
std::vector<DictionaryAdditions> dictionary_additions;
+ base::Closure no_jobs_seen_callback_;
};
// Schedule a fetch and make sure it happens.
TEST_F(SdchDictionaryFetcherTest, Basic) {
GURL dictionary_url(PathToGurl("dictionary"));
fetcher()->Schedule(dictionary_url);
+ WaitForNoJobs();
- base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, JobsRequested());
std::vector<DictionaryAdditions> additions;
GetDictionaryAdditions(&additions);
@@ -152,7 +221,7 @@ TEST_F(SdchDictionaryFetcherTest, Multiple) {
fetcher()->Schedule(dictionary_url);
fetcher()->Schedule(dictionary_url);
fetcher()->Schedule(dictionary_url);
- base::RunLoop().RunUntilIdle();
+ WaitForNoJobs();
EXPECT_EQ(1, JobsRequested());
std::vector<DictionaryAdditions> additions;
@@ -173,9 +242,30 @@ TEST_F(SdchDictionaryFetcherTest, Cancel) {
fetcher()->Schedule(dictionary_url_2);
fetcher()->Schedule(dictionary_url_3);
fetcher()->Cancel();
- base::RunLoop().RunUntilIdle();
+ WaitForNoJobs();
// Synchronous execution may have resulted in a single job being scheduled.
EXPECT_GE(1, JobsRequested());
}
+
+// Attempt to confuse the fetcher loop processing by scheduling a
+// dictionary addition while another fetch is in process.
+TEST_F(SdchDictionaryFetcherTest, LoopRace) {
+ GURL dictionary_url(PathToGurl("dictionary"));
+ GURL dictionary1_url(PathToGurl("dictionary1"));
+ fetcher()->Schedule(dictionary_url);
+ fetcher()->Schedule(dictionary1_url);
+ WaitForNoJobs();
+
+ EXPECT_EQ(2, JobsRequested());
+ std::vector<DictionaryAdditions> additions;
+ GetDictionaryAdditions(&additions);
+ ASSERT_EQ(2u, additions.size());
+ EXPECT_EQ(
+ URLRequestSpecifiedResponseJob::ExpectedResponseForURL(dictionary_url),
+ additions[0].dictionary_text);
+ EXPECT_EQ(
+ URLRequestSpecifiedResponseJob::ExpectedResponseForURL(dictionary1_url),
+ additions[1].dictionary_text);
+}
}
mmenke 2015/01/21 21:33:57 // net (And there should be a linebreak before the
Randy Smith (Not in Mondays) 2015/01/22 19:04:39 Whoops. Done.
« net/url_request/sdch_dictionary_fetcher.cc ('K') | « net/url_request/sdch_dictionary_fetcher.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698