- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / contacts / gdata_contacts_service_unittest.cc
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/google_apis/dummy_auth_service.h"
15 #include "chrome/browser/google_apis/test_util.h"
16 #include "chrome/browser/google_apis/time_util.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/test/test_browser_thread.h"
21 #include "content/public/test/test_utils.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