OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "chrome/browser/chromeos/contacts/gdata_contacts_service.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/files/file_path.h" | |
9 #include "base/message_loop/message_loop.h" | |
10 #include "base/strings/stringprintf.h" | |
11 #include "base/time/time.h" | |
12 #include "chrome/browser/chromeos/contacts/contact.pb.h" | |
13 #include "chrome/browser/chromeos/contacts/contact_test_util.h" | |
14 #include "chrome/browser/ui/browser.h" | |
15 #include "chrome/test/base/in_process_browser_test.h" | |
16 #include "content/public/browser/browser_thread.h" | |
17 #include "content/public/test/test_browser_thread.h" | |
18 #include "content/public/test/test_utils.h" | |
19 #include "google_apis/drive/dummy_auth_service.h" | |
20 #include "google_apis/drive/test_util.h" | |
21 #include "google_apis/drive/time_util.h" | |
22 #include "net/test/embedded_test_server/embedded_test_server.h" | |
23 #include "net/test/embedded_test_server/http_request.h" | |
24 #include "net/test/embedded_test_server/http_response.h" | |
25 #include "net/url_request/url_request_test_util.h" | |
26 #include "testing/gtest/include/gtest/gtest.h" | |
27 #include "ui/gfx/size.h" | |
28 | |
29 using content::BrowserThread; | |
30 | |
31 namespace contacts { | |
32 namespace { | |
33 | |
34 // Filename of JSON feed containing contact groups. | |
35 const char kGroupsFeedFilename[] = "/groups.json"; | |
36 | |
37 // Width and height of /photo.png on the test server. | |
38 const int kPhotoSize = 48; | |
39 | |
40 // Initializes |contact| using the passed-in values. | |
41 void InitContact(const std::string& contact_id, | |
42 const std::string& rfc_3339_update_time, | |
43 bool deleted, | |
44 const std::string& full_name, | |
45 const std::string& given_name, | |
46 const std::string& additional_name, | |
47 const std::string& family_name, | |
48 const std::string& name_prefix, | |
49 const std::string& name_suffix, | |
50 contacts::Contact* contact) { | |
51 DCHECK(contact); | |
52 contact->set_contact_id(contact_id); | |
53 base::Time update_time; | |
54 CHECK(google_apis::util::GetTimeFromString( | |
55 rfc_3339_update_time, &update_time)) | |
56 << "Unable to parse time \"" << rfc_3339_update_time << "\""; | |
57 contact->set_update_time(update_time.ToInternalValue()); | |
58 contact->set_deleted(deleted); | |
59 contact->set_full_name(full_name); | |
60 contact->set_given_name(given_name); | |
61 contact->set_additional_name(additional_name); | |
62 contact->set_family_name(family_name); | |
63 contact->set_name_prefix(name_prefix); | |
64 contact->set_name_suffix(name_suffix); | |
65 } | |
66 | |
67 class GDataContactsServiceTest : public testing::Test { | |
68 public: | |
69 GDataContactsServiceTest() | |
70 : ui_thread_(content::BrowserThread::UI, &message_loop_), | |
71 io_thread_(content::BrowserThread::IO), | |
72 download_was_successful_(false) { | |
73 } | |
74 | |
75 virtual void SetUp() OVERRIDE { | |
76 io_thread_.StartIOThread(); | |
77 request_context_getter_ = new net::TestURLRequestContextGetter( | |
78 content::BrowserThread::GetMessageLoopProxyForThread( | |
79 content::BrowserThread::IO)); | |
80 | |
81 test_server_.reset(new net::test_server::EmbeddedTestServer); | |
82 ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady()); | |
83 test_server_->RegisterRequestHandler( | |
84 base::Bind(&GDataContactsServiceTest::HandleDownloadRequest, | |
85 base::Unretained(this))); | |
86 service_.reset(new GDataContactsService(request_context_getter_.get(), | |
87 new google_apis::DummyAuthService)); | |
88 service_->set_rewrite_photo_url_callback_for_testing( | |
89 base::Bind(&GDataContactsServiceTest::RewritePhotoUrl, | |
90 base::Unretained(this))); | |
91 service_->set_groups_feed_url_for_testing( | |
92 test_server_->GetURL(kGroupsFeedFilename)); | |
93 service_->set_photo_download_timer_interval_for_testing( | |
94 base::TimeDelta::FromMilliseconds(10)); | |
95 } | |
96 | |
97 virtual void TearDown() OVERRIDE { | |
98 EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete()); | |
99 test_server_.reset(); | |
100 request_context_getter_ = NULL; | |
101 service_.reset(); | |
102 } | |
103 | |
104 protected: | |
105 // Downloads contacts from |feed_filename| (within the chromeos/gdata/contacts | |
106 // test data directory). |min_update_time| is appended to the URL and the | |
107 // resulting contacts are swapped into |contacts|. Returns false if the | |
108 // download failed. | |
109 bool Download(const std::string& feed_filename, | |
110 const base::Time& min_update_time, | |
111 scoped_ptr<ScopedVector<contacts::Contact> >* contacts) { | |
112 DCHECK(contacts); | |
113 service_->set_contacts_feed_url_for_testing( | |
114 test_server_->GetURL(feed_filename)); | |
115 service_->DownloadContacts( | |
116 base::Bind(&GDataContactsServiceTest::OnSuccess, | |
117 base::Unretained(this)), | |
118 base::Bind(&GDataContactsServiceTest::OnFailure, | |
119 base::Unretained(this)), | |
120 min_update_time); | |
121 content::RunMessageLoop(); | |
122 contacts->swap(downloaded_contacts_); | |
123 return download_was_successful_; | |
124 } | |
125 | |
126 scoped_ptr<GDataContactsService> service_; | |
127 scoped_ptr<net::test_server::EmbeddedTestServer> test_server_; | |
128 | |
129 private: | |
130 // Rewrites |original_url|, a photo URL from a contacts feed, to instead point | |
131 // at a file on |test_server_|. | |
132 std::string RewritePhotoUrl(const std::string& original_url) { | |
133 return test_server_->GetURL(GURL(original_url).path()).spec(); | |
134 } | |
135 | |
136 // Handles success for Download(). | |
137 void OnSuccess(scoped_ptr<ScopedVector<contacts::Contact> > contacts) { | |
138 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
139 download_was_successful_ = true; | |
140 downloaded_contacts_.swap(contacts); | |
141 base::MessageLoop::current()->Quit(); | |
142 } | |
143 | |
144 // Handles failure for Download(). | |
145 void OnFailure() { | |
146 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
147 download_was_successful_ = false; | |
148 downloaded_contacts_.reset(new ScopedVector<contacts::Contact>()); | |
149 base::MessageLoop::current()->Quit(); | |
150 } | |
151 | |
152 // Handles a request for downloading a file. Reads a requested file and | |
153 // returns the content. | |
154 scoped_ptr<net::test_server::HttpResponse> HandleDownloadRequest( | |
155 const net::test_server::HttpRequest& request) { | |
156 // Requested url must not contain a query string. | |
157 scoped_ptr<net::test_server::BasicHttpResponse> result = | |
158 google_apis::test_util::CreateHttpResponseFromFile( | |
159 google_apis::test_util::GetTestFilePath( | |
160 std::string("chromeos/gdata/contacts") + request.relative_url)); | |
161 return result.PassAs<net::test_server::HttpResponse>(); | |
162 } | |
163 | |
164 base::MessageLoopForUI message_loop_; | |
165 content::TestBrowserThread ui_thread_; | |
166 content::TestBrowserThread io_thread_; | |
167 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_; | |
168 | |
169 // Was the last download successful? Used to pass the result back from | |
170 // OnSuccess() and OnFailure() to Download(). | |
171 bool download_was_successful_; | |
172 | |
173 // Used to pass downloaded contacts back to Download(). | |
174 scoped_ptr<ScopedVector<contacts::Contact> > downloaded_contacts_; | |
175 }; | |
176 | |
177 } // namespace | |
178 | |
179 // Test that we report failure for feeds that are broken in various ways. | |
180 TEST_F(GDataContactsServiceTest, BrokenFeeds) { | |
181 scoped_ptr<ScopedVector<contacts::Contact> > contacts; | |
182 EXPECT_FALSE(Download("/some_bogus_file", base::Time(), &contacts)); | |
183 EXPECT_FALSE(Download("/empty.txt", base::Time(), &contacts)); | |
184 EXPECT_FALSE(Download("/not_json.txt", base::Time(), &contacts)); | |
185 EXPECT_FALSE(Download("/not_dictionary.json", base::Time(), &contacts)); | |
186 EXPECT_FALSE(Download("/no_feed.json", base::Time(), &contacts)); | |
187 EXPECT_FALSE(Download("/no_category.json", base::Time(), &contacts)); | |
188 EXPECT_FALSE(Download("/wrong_category.json", base::Time(), &contacts)); | |
189 | |
190 // Missing photos should be allowed, though (as this can occur in production). | |
191 EXPECT_TRUE(Download("/feed_photo_404.json", base::Time(), &contacts)); | |
192 ASSERT_EQ(static_cast<size_t>(1), contacts->size()); | |
193 EXPECT_FALSE((*contacts)[0]->has_raw_untrusted_photo()); | |
194 | |
195 // We should report failure when we're unable to download the contact group | |
196 // feed. | |
197 service_->clear_cached_my_contacts_group_id_for_testing(); | |
198 service_->set_groups_feed_url_for_testing( | |
199 test_server_->GetURL("/404")); | |
200 EXPECT_FALSE(Download("/feed.json", base::Time(), &contacts)); | |
201 EXPECT_TRUE(service_->cached_my_contacts_group_id_for_testing().empty()); | |
202 | |
203 // We should also fail when the "My Contacts" group isn't listed in the group | |
204 // feed. | |
205 service_->clear_cached_my_contacts_group_id_for_testing(); | |
206 service_->set_groups_feed_url_for_testing( | |
207 test_server_->GetURL("/groups_no_my_contacts.json")); | |
208 EXPECT_FALSE(Download("/feed.json", base::Time(), &contacts)); | |
209 EXPECT_TRUE(service_->cached_my_contacts_group_id_for_testing().empty()); | |
210 } | |
211 | |
212 // Check that we're able to download an empty feed and a normal-looking feed | |
213 // with two regular contacts and one deleted one. | |
214 TEST_F(GDataContactsServiceTest, Download) { | |
215 scoped_ptr<ScopedVector<contacts::Contact> > contacts; | |
216 EXPECT_TRUE(Download("/no_entries.json", base::Time(), &contacts)); | |
217 EXPECT_TRUE(contacts->empty()); | |
218 | |
219 EXPECT_TRUE(Download("/feed.json", base::Time(), &contacts)); | |
220 | |
221 // Check that we got the group ID for the "My Contacts" group that's hardcoded | |
222 // in the groups feed. | |
223 EXPECT_EQ( | |
224 "http://www.google.com/m8/feeds/groups/test.user%40gmail.com/base/6", | |
225 service_->cached_my_contacts_group_id_for_testing()); | |
226 | |
227 // All of these expected values are hardcoded in the feed. | |
228 scoped_ptr<contacts::Contact> contact1(new contacts::Contact); | |
229 InitContact("http://example.com/1", | |
230 "2012-06-04T15:53:36.023Z", | |
231 false, "Joe Contact", "Joe", "", "Contact", "", "", | |
232 contact1.get()); | |
233 contacts::test::SetPhoto(gfx::Size(kPhotoSize, kPhotoSize), contact1.get()); | |
234 contacts::test::AddEmailAddress( | |
235 "joe.contact@gmail.com", | |
236 contacts::Contact_AddressType_Relation_OTHER, "", true, contact1.get()); | |
237 contacts::test::AddPostalAddress( | |
238 "345 Spear St\nSan Francisco CA 94105", | |
239 contacts::Contact_AddressType_Relation_HOME, "", false, contact1.get()); | |
240 | |
241 scoped_ptr<contacts::Contact> contact2(new contacts::Contact); | |
242 InitContact("http://example.com/2", | |
243 "2012-06-21T16:20:13.208Z", | |
244 false, "Dr. Jane Liz Doe Sr.", "Jane", "Liz", "Doe", "Dr.", "Sr.", | |
245 contact2.get()); | |
246 contacts::test::AddEmailAddress( | |
247 "jane.doe@gmail.com", | |
248 contacts::Contact_AddressType_Relation_HOME, "", true, contact2.get()); | |
249 contacts::test::AddEmailAddress( | |
250 "me@privacy.net", | |
251 contacts::Contact_AddressType_Relation_WORK, "", false, contact2.get()); | |
252 contacts::test::AddEmailAddress( | |
253 "foo@example.org", | |
254 contacts::Contact_AddressType_Relation_OTHER, "Fake", false, | |
255 contact2.get()); | |
256 contacts::test::AddPhoneNumber( | |
257 "123-456-7890", | |
258 contacts::Contact_AddressType_Relation_MOBILE, "", false, | |
259 contact2.get()); | |
260 contacts::test::AddPhoneNumber( | |
261 "234-567-8901", | |
262 contacts::Contact_AddressType_Relation_OTHER, "grandcentral", false, | |
263 contact2.get()); | |
264 contacts::test::AddPostalAddress( | |
265 "100 Elm St\nSan Francisco, CA 94110", | |
266 contacts::Contact_AddressType_Relation_HOME, "", false, contact2.get()); | |
267 contacts::test::AddInstantMessagingAddress( | |
268 "foo@example.org", | |
269 contacts::Contact_InstantMessagingAddress_Protocol_GOOGLE_TALK, | |
270 contacts::Contact_AddressType_Relation_OTHER, "", false, | |
271 contact2.get()); | |
272 contacts::test::AddInstantMessagingAddress( | |
273 "12345678", | |
274 contacts::Contact_InstantMessagingAddress_Protocol_ICQ, | |
275 contacts::Contact_AddressType_Relation_OTHER, "", false, | |
276 contact2.get()); | |
277 | |
278 scoped_ptr<contacts::Contact> contact3(new contacts::Contact); | |
279 InitContact("http://example.com/3", | |
280 "2012-07-23T23:07:06.133Z", | |
281 true, "", "", "", "", "", "", | |
282 contact3.get()); | |
283 | |
284 EXPECT_EQ(contacts::test::VarContactsToString( | |
285 3, contact1.get(), contact2.get(), contact3.get()), | |
286 contacts::test::ContactsToString(*contacts)); | |
287 } | |
288 | |
289 // Download a feed containing more photos than we're able to download in | |
290 // parallel to check that we still end up with all the photos. | |
291 TEST_F(GDataContactsServiceTest, ParallelPhotoDownload) { | |
292 // The feed used for this test contains 8 contacts. | |
293 const int kNumContacts = 8; | |
294 service_->set_max_photo_downloads_per_second_for_testing(6); | |
295 scoped_ptr<ScopedVector<contacts::Contact> > contacts; | |
296 EXPECT_TRUE(Download("/feed_multiple_photos.json", base::Time(), &contacts)); | |
297 ASSERT_EQ(static_cast<size_t>(kNumContacts), contacts->size()); | |
298 | |
299 ScopedVector<contacts::Contact> expected_contacts; | |
300 for (int i = 0; i < kNumContacts; ++i) { | |
301 contacts::Contact* contact = new contacts::Contact; | |
302 InitContact(base::StringPrintf("http://example.com/%d", i + 1), | |
303 "2012-06-04T15:53:36.023Z", | |
304 false, "", "", "", "", "", "", contact); | |
305 contacts::test::SetPhoto(gfx::Size(kPhotoSize, kPhotoSize), contact); | |
306 expected_contacts.push_back(contact); | |
307 } | |
308 EXPECT_EQ(contacts::test::ContactsToString(expected_contacts), | |
309 contacts::test::ContactsToString(*contacts)); | |
310 } | |
311 | |
312 TEST_F(GDataContactsServiceTest, UnicodeStrings) { | |
313 scoped_ptr<ScopedVector<contacts::Contact> > contacts; | |
314 EXPECT_TRUE(Download("/feed_unicode.json", base::Time(), &contacts)); | |
315 | |
316 // All of these expected values are hardcoded in the feed. | |
317 scoped_ptr<contacts::Contact> contact1(new contacts::Contact); | |
318 InitContact("http://example.com/1", "2012-06-04T15:53:36.023Z", | |
319 false, "\xE5\xAE\x89\xE8\x97\xA4\x20\xE5\xBF\xA0\xE9\x9B\x84", | |
320 "\xE5\xBF\xA0\xE9\x9B\x84", "", "\xE5\xAE\x89\xE8\x97\xA4", | |
321 "", "", contact1.get()); | |
322 scoped_ptr<contacts::Contact> contact2(new contacts::Contact); | |
323 InitContact("http://example.com/2", "2012-06-21T16:20:13.208Z", | |
324 false, "Bob Smith", "Bob", "", "Smith", "", "", | |
325 contact2.get()); | |
326 EXPECT_EQ(contacts::test::VarContactsToString( | |
327 2, contact1.get(), contact2.get()), | |
328 contacts::test::ContactsToString(*contacts)); | |
329 } | |
330 | |
331 } // namespace contacts | |
OLD | NEW |