1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
// 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 "chrome/browser/search_engines/template_url_model_test_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/threading/thread.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// A Task used to coordinate when the database has finished processing
// requests. See note in BlockTillServiceProcessesRequests for details.
//
// When Run() schedules a QuitTask on the message loop it was created with.
class QuitTask2 : public Task {
public:
QuitTask2() : main_loop_(MessageLoop::current()) {}
virtual void Run() {
main_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
private:
MessageLoop* main_loop_;
};
// Blocks the caller until thread has finished servicing all pending
// requests.
static void WaitForThreadToProcessRequests(BrowserThread::ID identifier) {
// Schedule a task on the thread that is processed after all
// pending requests on the thread.
BrowserThread::PostTask(identifier, FROM_HERE, new QuitTask2());
// Run the current message loop. QuitTask2, when run, invokes Quit,
// which unblocks this.
MessageLoop::current()->Run();
}
} // namespace
// Subclass the TestingProfile so that it can return a WebDataService.
class TemplateURLModelTestingProfile : public TestingProfile {
public:
TemplateURLModelTestingProfile()
: TestingProfile(),
db_thread_(BrowserThread::DB),
io_thread_(BrowserThread::IO) {
}
void SetUp();
void TearDown();
// Starts the I/O thread. This isn't done automatically because not every test
// needs this.
void StartIOThread() {
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_IO;
io_thread_.StartWithOptions(options);
}
virtual WebDataService* GetWebDataService(ServiceAccessType access) {
return service_.get();
}
private:
scoped_refptr<WebDataService> service_;
ScopedTempDir temp_dir_;
BrowserThread db_thread_;
BrowserThread io_thread_;
};
// Trivial subclass of TemplateURLModel that records the last invocation of
// SetKeywordSearchTermsForURL.
class TestingTemplateURLModel : public TemplateURLModel {
public:
explicit TestingTemplateURLModel(Profile* profile)
: TemplateURLModel(profile) {
}
string16 GetAndClearSearchTerm() {
string16 search_term;
search_term.swap(search_term_);
return search_term;
}
protected:
virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url,
const GURL& url,
const string16& term) {
search_term_ = term;
}
private:
string16 search_term_;
DISALLOW_COPY_AND_ASSIGN(TestingTemplateURLModel);
};
void TemplateURLModelTestingProfile::SetUp() {
db_thread_.Start();
// Make unique temp directory.
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
FilePath path = temp_dir_.path().AppendASCII("TestDataService.db");
service_ = new WebDataService;
ASSERT_TRUE(service_->InitWithPath(path));
}
void TemplateURLModelTestingProfile::TearDown() {
// Clear the request context so it will get deleted. This should be done
// before shutting down the I/O thread to avoid memory leaks.
ResetRequestContext();
// Wait for the delete of the request context to happen.
if (io_thread_.IsRunning())
TemplateURLModelTestUtil::BlockTillIOThreadProcessesRequests();
// The I/O thread must be shutdown before the DB thread.
io_thread_.Stop();
// Clean up the test directory.
if (service_.get())
service_->Shutdown();
// Note that we must ensure the DB thread is stopped after WDS
// shutdown (so it can commit pending transactions) but before
// deleting the test profile directory, otherwise we may not be
// able to delete it due to an open transaction.
db_thread_.Stop();
}
TemplateURLModelTestUtil::TemplateURLModelTestUtil()
: ui_thread_(BrowserThread::UI, &message_loop_),
changed_count_(0) {
}
TemplateURLModelTestUtil::~TemplateURLModelTestUtil() {
}
void TemplateURLModelTestUtil::SetUp() {
profile_.reset(new TemplateURLModelTestingProfile());
profile_->SetUp();
profile_->SetTemplateURLModel(new TestingTemplateURLModel(profile_.get()));
profile_->GetTemplateURLModel()->AddObserver(this);
}
void TemplateURLModelTestUtil::TearDown() {
if (profile_.get()) {
profile_->TearDown();
profile_.reset();
}
TemplateURLRef::SetGoogleBaseURL(NULL);
// Flush the message loop to make Purify happy.
message_loop_.RunAllPending();
}
void TemplateURLModelTestUtil::OnTemplateURLModelChanged() {
changed_count_++;
}
int TemplateURLModelTestUtil::GetObserverCount() {
return changed_count_;
}
void TemplateURLModelTestUtil::ResetObserverCount() {
changed_count_ = 0;
}
void TemplateURLModelTestUtil::BlockTillServiceProcessesRequests() {
WaitForThreadToProcessRequests(BrowserThread::DB);
}
void TemplateURLModelTestUtil::BlockTillIOThreadProcessesRequests() {
WaitForThreadToProcessRequests(BrowserThread::IO);
}
void TemplateURLModelTestUtil::VerifyLoad() {
ASSERT_FALSE(model()->loaded());
model()->Load();
BlockTillServiceProcessesRequests();
EXPECT_EQ(1, GetObserverCount());
ResetObserverCount();
}
void TemplateURLModelTestUtil::ChangeModelToLoadState() {
model()->ChangeToLoadedState();
// Initialize the web data service so that the database gets updated with
// any changes made.
model()->service_ = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
}
void TemplateURLModelTestUtil::ClearModel() {
profile_->SetTemplateURLModel(NULL);
}
void TemplateURLModelTestUtil::ResetModel(bool verify_load) {
profile_->SetTemplateURLModel(new TestingTemplateURLModel(profile_.get()));
model()->AddObserver(this);
changed_count_ = 0;
if (verify_load)
VerifyLoad();
}
string16 TemplateURLModelTestUtil::GetAndClearSearchTerm() {
return
static_cast<TestingTemplateURLModel*>(model())->GetAndClearSearchTerm();
}
void TemplateURLModelTestUtil::SetGoogleBaseURL(
const std::string& base_url) const {
TemplateURLRef::SetGoogleBaseURL(new std::string(base_url));
NotificationService::current()->Notify(NotificationType::GOOGLE_URL_UPDATED,
NotificationService::AllSources(),
NotificationService::NoDetails());
}
WebDataService* TemplateURLModelTestUtil::GetWebDataService() {
return profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
}
TemplateURLModel* TemplateURLModelTestUtil::model() const {
return profile_->GetTemplateURLModel();
}
TestingProfile* TemplateURLModelTestUtil::profile() const {
return profile_.get();
}
void TemplateURLModelTestUtil::StartIOThread() {
profile_->StartIOThread();
}
|