Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ios / net / cookies / cookie_store_ios_unittest.mm
blob39e30db204de21c6010941414d2897fc2fa85dea
1 // Copyright 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.
5 #include "ios/net/cookies/cookie_store_ios.h"
7 #import <Foundation/Foundation.h>
9 #include "base/bind_helpers.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/sys_string_conversions.h"
12 #import "net/base/mac/url_conversions.h"
13 #include "net/cookies/cookie_store_unittest.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 namespace {
17 // Clears the underlying NSHTTPCookieStorage.
18 void ClearCookies() {
19   NSHTTPCookieStorage* store = [NSHTTPCookieStorage sharedHTTPCookieStorage];
20   [store setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
21   NSArray* cookies = [store cookies];
22   for (NSHTTPCookie* cookie in cookies)
23     [store deleteCookie:cookie];
24   EXPECT_EQ(0u, [[store cookies] count]);
26 }  // namespace
28 namespace net {
30 struct CookieStoreIOSTestTraits {
31   static net::CookieStore* Create() {
32     ClearCookies();
33     CookieStoreIOS* store = new CookieStoreIOS(nullptr);
34     store->synchronization_state_ = CookieStoreIOS::SYNCHRONIZED;
35     return store;
36   }
38   static const bool is_cookie_monster = false;
39   static const bool supports_http_only = false;
40   static const bool supports_non_dotted_domains = false;
41   static const bool preserves_trailing_dots = false;
42   static const bool filters_schemes = false;
43   static const bool has_path_prefix_bug = true;
44   static const int creation_time_granularity_in_ms = 1000;
46   base::MessageLoop loop_;
49 struct InactiveCookieStoreIOSTestTraits {
50   static scoped_refptr<net::CookieStore> Create() {
51     return new CookieStoreIOS(nullptr);
52   }
54   static const bool is_cookie_monster = false;
55   static const bool supports_http_only = false;
56   static const bool supports_non_dotted_domains = true;
57   static const bool preserves_trailing_dots = true;
58   static const bool filters_schemes = false;
59   static const bool has_path_prefix_bug = false;
60   static const int creation_time_granularity_in_ms = 0;
62   base::MessageLoop loop_;
65 // RoundTripTestCookieStore is un-synchronized and re-synchronized after all
66 // cookie operations. This means all system cookies are converted to Chrome
67 // cookies and converted back.
68 // The purpose of this class is to test that cookie conversions do not break the
69 // cookie store.
70 class RoundTripTestCookieStore : public net::CookieStore {
71  public:
72   RoundTripTestCookieStore()
73       : store_(new CookieStoreIOS(nullptr)),
74         dummy_store_(new CookieStoreIOS(nullptr)) {
75     CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
76   }
78   // Inherited CookieStore methods.
79   void SetCookieWithOptionsAsync(const GURL& url,
80                                  const std::string& cookie_line,
81                                  const net::CookieOptions& options,
82                                  const SetCookiesCallback& callback) override {
83     RoundTrip();
84     store_->SetCookieWithOptionsAsync(url, cookie_line, options, callback);
85   }
87   void GetCookiesWithOptionsAsync(const GURL& url,
88                                   const net::CookieOptions& options,
89                                   const GetCookiesCallback& callback) override {
90     RoundTrip();
91     store_->GetCookiesWithOptionsAsync(url, options, callback);
92   }
94   void GetAllCookiesForURLAsync(
95       const GURL& url,
96       const GetCookieListCallback& callback) override {
97     RoundTrip();
98     store_->GetAllCookiesForURLAsync(url, callback);
99   }
101   void DeleteCookieAsync(const GURL& url,
102                          const std::string& cookie_name,
103                          const base::Closure& callback) override {
104     RoundTrip();
105     store_->DeleteCookieAsync(url, cookie_name, callback);
106   }
108   net::CookieMonster* GetCookieMonster() override { return nullptr; }
110   void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
111                                     const base::Time& delete_end,
112                                     const DeleteCallback& callback) override {
113     RoundTrip();
114     store_->DeleteAllCreatedBetweenAsync(delete_begin, delete_end, callback);
115   }
117   void DeleteAllCreatedBetweenForHostAsync(
118       const base::Time delete_begin,
119       const base::Time delete_end,
120       const GURL& url,
121       const DeleteCallback& callback) override {
122     RoundTrip();
123     store_->DeleteAllCreatedBetweenForHostAsync(delete_begin, delete_end, url,
124                                                 callback);
125   }
127   void DeleteSessionCookiesAsync(const DeleteCallback& callback) override {
128     RoundTrip();
129     store_->DeleteSessionCookiesAsync(callback);
130   }
132   scoped_ptr<CookieStore::CookieChangedSubscription> AddCallbackForCookie(
133       const GURL& url,
134       const std::string& name,
135       const CookieChangedCallback& callback) override {
136     return scoped_ptr<CookieStore::CookieChangedSubscription>();
137   }
139  protected:
140   ~RoundTripTestCookieStore() override { store_->UnSynchronize(); }
142  private:
143   void RoundTrip() {
144     CookieStoreIOS::SwitchSynchronizedStore(store_.get(), dummy_store_.get());
145     // Check that the system store is empty, because it is synchronized with
146     // |dummy_store_| which is empty.
147     NSHTTPCookieStorage* store = [NSHTTPCookieStorage sharedHTTPCookieStorage];
148     EXPECT_EQ(0u, [[store cookies] count]);
149     CookieStoreIOS::SwitchSynchronizedStore(dummy_store_.get(), store_.get());
150   }
152   scoped_refptr<CookieStoreIOS> store_;
153   // |dummy_store_| is not directly used, but is needed to make |store_|
154   // inactive.
155   scoped_refptr<CookieStoreIOS> dummy_store_;
158 struct RoundTripTestCookieStoreTraits {
159   static scoped_refptr<net::CookieStore> Create() {
160     ClearCookies();
161     return new RoundTripTestCookieStore();
162   }
164   static const bool is_cookie_monster = false;
165   static const bool supports_http_only = false;
166   static const bool supports_non_dotted_domains = false;
167   static const bool preserves_trailing_dots = false;
168   static const bool filters_schemes = false;
169   static const bool has_path_prefix_bug = true;
170   static const int creation_time_granularity_in_ms = 1000;
173 }  // namespace net
175 namespace net {
177 INSTANTIATE_TYPED_TEST_CASE_P(CookieStoreIOS,
178                               CookieStoreTest,
179                               CookieStoreIOSTestTraits);
181 INSTANTIATE_TYPED_TEST_CASE_P(InactiveCookieStoreIOS,
182                               CookieStoreTest,
183                               InactiveCookieStoreIOSTestTraits);
185 INSTANTIATE_TYPED_TEST_CASE_P(RoundTripTestCookieStore,
186                               CookieStoreTest,
187                               RoundTripTestCookieStoreTraits);
189 }  // namespace net
191 namespace {
193 // Test net::CookieMonster::PersistentCookieStore allowing to control when the
194 // initialization completes.
195 class TestPersistentCookieStore
196     : public net::CookieMonster::PersistentCookieStore {
197  public:
198   TestPersistentCookieStore()
199       : kTestCookieURL("http://foo.google.com/bar"), flushed_(false) {}
201   // Runs the completion callback with a "a=b" cookie.
202   void RunLoadedCallback() {
203     std::vector<net::CanonicalCookie*> cookies;
204     net::CookieOptions options;
205     options.set_include_httponly();
206     cookies.push_back(net::CanonicalCookie::Create(kTestCookieURL, "a=b",
207                                                    base::Time::Now(), options));
208     // Some canonical cookies cannot be converted into System cookies, for
209     // example if value is not valid utf8. Such cookies are ignored.
210     net::CanonicalCookie* bad_canonical_cookie = new net::CanonicalCookie(
211         kTestCookieURL, "name", "\x81r\xe4\xbd\xa0\xe5\xa5\xbd", "domain",
212         "path/",
213         base::Time(),  // creation
214         base::Time(),  // expires
215         base::Time(),  // last_access
216         false,         // secure
217         false,         // httponly
218         false,         // first_party_only
219         net::COOKIE_PRIORITY_DEFAULT);
220     cookies.push_back(bad_canonical_cookie);
221     loaded_callback_.Run(cookies);
222   }
224   bool flushed() { return flushed_; }
226  private:
227   // net::CookieMonster::PersistentCookieStore implementation:
228   void Load(const LoadedCallback& loaded_callback) override {
229     loaded_callback_ = loaded_callback;
230   }
232   void LoadCookiesForKey(const std::string& key,
233                          const LoadedCallback& loaded_callback) override {
234     loaded_callback_ = loaded_callback;
235   }
237   void AddCookie(const net::CanonicalCookie& cc) override {}
238   void UpdateCookieAccessTime(const net::CanonicalCookie& cc) override {}
239   void DeleteCookie(const net::CanonicalCookie& cc) override {}
240   void SetForceKeepSessionState() override {}
241   void Flush(const base::Closure& callback) override { flushed_ = true; }
243  private:
244   ~TestPersistentCookieStore() override {}
246   const GURL kTestCookieURL;
247   LoadedCallback loaded_callback_;
248   bool flushed_;
251 // Helper callback to be passed to CookieStore::GetCookiesWithOptionsAsync().
252 class GetCookieCallback {
253  public:
254   GetCookieCallback() : did_run_(false) {}
256   // Returns true if the callback has been run.
257   bool did_run() { return did_run_; }
259   // Returns the parameter of the callback.
260   const std::string& cookie_line() { return cookie_line_; }
262   void Run(const std::string& cookie_line) {
263     ASSERT_FALSE(did_run_);
264     did_run_ = true;
265     cookie_line_ = cookie_line;
266   }
268  private:
269   bool did_run_;
270   std::string cookie_line_;
273 // Helper callback to be passed to CookieStore::GetAllCookiesForURLAsync().
274 class GetAllCookiesCallback {
275  public:
276   GetAllCookiesCallback() : did_run_(false) {}
278   // Returns true if the callback has been run.
279   bool did_run() { return did_run_; }
281   // Returns the parameter of the callback.
282   const net::CookieList& cookie_list() { return cookie_list_; }
284   void Run(const net::CookieList& cookie_list) {
285     ASSERT_FALSE(did_run_);
286     did_run_ = true;
287     cookie_list_ = cookie_list;
288   }
290  private:
291   bool did_run_;
292   net::CookieList cookie_list_;
295 namespace {
297 void RecordCookieChanges(std::vector<net::CanonicalCookie>* out_cookies,
298                          std::vector<bool>* out_removes,
299                          const net::CanonicalCookie& cookie,
300                          bool removed) {
301   DCHECK(out_cookies);
302   out_cookies->push_back(cookie);
303   if (out_removes)
304     out_removes->push_back(removed);
307 void IgnoreBoolean(bool ignored) {
310 void IgnoreString(const std::string& ignored) {
313 }  // namespace
315 class CookieStoreIOSWithBackend : public testing::Test {
316  public:
317   CookieStoreIOSWithBackend()
318       : kTestCookieURL("http://foo.google.com/bar"),
319         kTestCookieURL2("http://foo.google.com/baz"),
320         kTestCookieURL3("http://foo.google.com"),
321         kTestCookieURL4("http://bar.google.com/bar") {
322     backend_ = new TestPersistentCookieStore;
323     store_ = new net::CookieStoreIOS(backend_.get());
324     net::CookieStoreIOS::SetCookiePolicy(net::CookieStoreIOS::ALLOW);
325     cookie_changed_callback_ = store_->AddCallbackForCookie(
326         kTestCookieURL, "abc",
327         base::Bind(&RecordCookieChanges, &cookies_changed_, &cookies_removed_));
328   }
330   ~CookieStoreIOSWithBackend() override {}
332   // Gets the cookies. |callback| will be called on completion.
333   void GetCookies(const net::CookieStore::GetCookiesCallback& callback) {
334     net::CookieOptions options;
335     options.set_include_httponly();
336     store_->GetCookiesWithOptionsAsync(kTestCookieURL, options, callback);
337   }
339   // Sets a cookie.
340   void SetCookie(const std::string& cookie_line) {
341     net::CookieOptions options;
342     options.set_include_httponly();
343     store_->SetCookieWithOptionsAsync(kTestCookieURL, cookie_line, options,
344                                       base::Bind(&IgnoreBoolean));
345     net::CookieStoreIOS::NotifySystemCookiesChanged();
346     // Wait until the flush is posted.
347     base::MessageLoop::current()->RunUntilIdle();
348   }
350   void SetSystemCookie(const GURL& url,
351                        const std::string& name,
352                        const std::string& value) {
353     NSHTTPCookieStorage* storage =
354         [NSHTTPCookieStorage sharedHTTPCookieStorage];
355     [storage setCookie:[NSHTTPCookie cookieWithProperties:@{
356       NSHTTPCookiePath : base::SysUTF8ToNSString(url.path()),
357       NSHTTPCookieName : base::SysUTF8ToNSString(name),
358       NSHTTPCookieValue : base::SysUTF8ToNSString(value),
359       NSHTTPCookieDomain : base::SysUTF8ToNSString(url.host()),
360     }]];
361     net::CookieStoreIOS::NotifySystemCookiesChanged();
362     base::MessageLoop::current()->RunUntilIdle();
363   }
365   void DeleteSystemCookie(const GURL& gurl, const std::string& name) {
366     NSHTTPCookieStorage* storage =
367         [NSHTTPCookieStorage sharedHTTPCookieStorage];
368     NSURL* nsurl = net::NSURLWithGURL(gurl);
369     NSArray* cookies = [storage cookiesForURL:nsurl];
370     for (NSHTTPCookie* cookie in cookies) {
371       if (cookie.name.UTF8String == name) {
372         [storage deleteCookie:cookie];
373         break;
374       }
375     }
376     net::CookieStoreIOS::NotifySystemCookiesChanged();
377     base::MessageLoop::current()->RunUntilIdle();
378   }
380  protected:
381   const GURL kTestCookieURL;
382   const GURL kTestCookieURL2;
383   const GURL kTestCookieURL3;
384   const GURL kTestCookieURL4;
386   base::MessageLoop loop_;
387   scoped_refptr<TestPersistentCookieStore> backend_;
388   scoped_refptr<net::CookieStoreIOS> store_;
389   scoped_ptr<net::CookieStore::CookieChangedSubscription>
390       cookie_changed_callback_;
391   std::vector<net::CanonicalCookie> cookies_changed_;
392   std::vector<bool> cookies_removed_;
395 }  // namespace
397 namespace net {
399 TEST_F(CookieStoreIOSWithBackend, SetCookieCallsHookWhenNotSynchronized) {
400   ClearCookies();
401   SetCookie("abc=def");
402   EXPECT_EQ(0U, cookies_changed_.size());
403   EXPECT_EQ(0U, cookies_removed_.size());
404   backend_->RunLoadedCallback();
405   base::MessageLoop::current()->RunUntilIdle();
406   EXPECT_EQ(1U, cookies_changed_.size());
407   EXPECT_EQ(1U, cookies_removed_.size());
408   EXPECT_EQ("abc", cookies_changed_[0].Name());
409   EXPECT_EQ("def", cookies_changed_[0].Value());
410   EXPECT_FALSE(cookies_removed_[0]);
412   // Replacing an existing cookie is actually a two-phase delete + set
413   // operation, so we get an extra notification.
414   SetCookie("abc=ghi");
415   EXPECT_EQ(3U, cookies_changed_.size());
416   EXPECT_EQ(3U, cookies_removed_.size());
417   EXPECT_EQ("abc", cookies_changed_[1].Name());
418   EXPECT_EQ("def", cookies_changed_[1].Value());
419   EXPECT_TRUE(cookies_removed_[1]);
420   EXPECT_EQ("abc", cookies_changed_[2].Name());
421   EXPECT_EQ("ghi", cookies_changed_[2].Value());
422   EXPECT_FALSE(cookies_removed_[2]);
424   store_->UnSynchronize();
427 TEST_F(CookieStoreIOSWithBackend, SetCookieCallsHookWhenSynchronized) {
428   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
429   GetCookies(base::Bind(&IgnoreString));
430   backend_->RunLoadedCallback();
431   base::MessageLoop::current()->RunUntilIdle();
432   ClearCookies();
433   SetCookie("abc=def");
434   EXPECT_EQ(1U, cookies_changed_.size());
435   EXPECT_EQ(1U, cookies_removed_.size());
436   EXPECT_EQ("abc", cookies_changed_[0].Name());
437   EXPECT_EQ("def", cookies_changed_[0].Value());
438   EXPECT_FALSE(cookies_removed_[0]);
440   SetCookie("abc=ghi");
441   EXPECT_EQ(3U, cookies_changed_.size());
442   EXPECT_EQ(3U, cookies_removed_.size());
443   EXPECT_EQ("abc", cookies_changed_[1].Name());
444   EXPECT_EQ("def", cookies_changed_[1].Value());
445   EXPECT_TRUE(cookies_removed_[1]);
446   EXPECT_EQ("abc", cookies_changed_[2].Name());
447   EXPECT_EQ("ghi", cookies_changed_[2].Value());
448   EXPECT_FALSE(cookies_removed_[2]);
449   DeleteSystemCookie(kTestCookieURL, "abc");
451   store_->UnSynchronize();
454 TEST_F(CookieStoreIOSWithBackend, DeleteCallsHook) {
455   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
456   GetCookies(base::Bind(&IgnoreString));
457   backend_->RunLoadedCallback();
458   base::MessageLoop::current()->RunUntilIdle();
459   ClearCookies();
460   SetCookie("abc=def");
461   EXPECT_EQ(1U, cookies_changed_.size());
462   EXPECT_EQ(1U, cookies_removed_.size());
463   store_->DeleteCookieAsync(kTestCookieURL, "abc",
464                             base::Bind(&IgnoreBoolean, false));
465   CookieStoreIOS::NotifySystemCookiesChanged();
466   base::MessageLoop::current()->RunUntilIdle();
467   store_->UnSynchronize();
470 TEST_F(CookieStoreIOSWithBackend, SameValueDoesNotCallHook) {
471   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
472   GetCookieCallback callback;
473   GetCookies(base::Bind(&IgnoreString));
474   backend_->RunLoadedCallback();
475   base::MessageLoop::current()->RunUntilIdle();
476   ClearCookies();
477   SetCookie("abc=def");
478   EXPECT_EQ(1U, cookies_changed_.size());
479   SetCookie("abc=def");
480   EXPECT_EQ(1U, cookies_changed_.size());
481   store_->UnSynchronize();
484 TEST(CookieStoreIOS, GetAllCookiesForURLAsync) {
485   base::MessageLoop loop;
486   const GURL kTestCookieURL("http://foo.google.com/bar");
487   ClearCookies();
488   scoped_refptr<CookieStoreIOS> cookie_store(new CookieStoreIOS(nullptr));
489   CookieStoreIOS::SwitchSynchronizedStore(nullptr, cookie_store.get());
490   // Add a cookie.
491   net::CookieOptions options;
492   options.set_include_httponly();
493   cookie_store->SetCookieWithOptionsAsync(
494       kTestCookieURL, "a=b", options, net::CookieStore::SetCookiesCallback());
495   // Disallow cookies.
496   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::BLOCK);
497   // No cookie in the system store.
498   NSHTTPCookieStorage* system_store =
499       [NSHTTPCookieStorage sharedHTTPCookieStorage];
500   EXPECT_EQ(0u, [[system_store cookies] count]);
501   // Flushing should not have any effect.
502   cookie_store->Flush(base::Closure());
503   // Check we can get the cookie even though cookies are disabled.
504   GetAllCookiesCallback callback;
505   cookie_store->GetAllCookiesForURLAsync(
506       kTestCookieURL,
507       base::Bind(&GetAllCookiesCallback::Run, base::Unretained(&callback)));
508   EXPECT_TRUE(callback.did_run());
509   EXPECT_EQ(1u, callback.cookie_list().size());
510   net::CanonicalCookie cookie = callback.cookie_list()[0];
511   EXPECT_EQ("a", cookie.Name());
512   EXPECT_EQ("b", cookie.Value());
513   // Re-enable cookies.
514   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::ALLOW);
515   // Cookie is back in the system store.
516   EXPECT_EQ(1u, [[system_store cookies] count]);
517   cookie_store->UnSynchronize();
520 // Tests that cookies can be read before the backend is loaded.
521 TEST_F(CookieStoreIOSWithBackend, NotSynchronized) {
522   // Start fetching the cookie.
523   GetCookieCallback callback;
524   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
525   // Backend loading completes.
526   backend_->RunLoadedCallback();
527   EXPECT_TRUE(callback.did_run());
528   EXPECT_EQ("a=b", callback.cookie_line());
531 // Tests that cookies can be read before synchronization is complete.
532 TEST_F(CookieStoreIOSWithBackend, Synchronizing) {
533   // Start synchronization.
534   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
535   GetCookieCallback callback;
536   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
537   // Backend loading completes (end of synchronization).
538   backend_->RunLoadedCallback();
539   EXPECT_TRUE(callback.did_run());
540   EXPECT_EQ("a=b", callback.cookie_line());
541   store_->UnSynchronize();
544 // Tests that cookies can be read before synchronization is complete, when
545 // triggered by a change in cookie policy.
546 TEST_F(CookieStoreIOSWithBackend, SynchronizingAfterPolicyChange) {
547   ClearCookies();
548   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::BLOCK);
549   // SwitchSynchronizedStore() does nothing when cookies are blocked.
550   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
551   // Start synchronization by allowing cookies.
552   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::ALLOW);
553   GetCookieCallback callback;
554   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
555   // Backend loading completes (end of synchronization).
556   backend_->RunLoadedCallback();
557   EXPECT_TRUE(callback.did_run());
558   EXPECT_EQ("a=b", callback.cookie_line());
559   store_->UnSynchronize();
562 // Tests that Synchronization can be "aborted" (i.e. the cookie store is
563 // unsynchronized while synchronization is in progress).
564 TEST_F(CookieStoreIOSWithBackend, SyncThenUnsync) {
565   ClearCookies();
566   scoped_refptr<CookieStoreIOS> dummy_store = new CookieStoreIOS(nullptr);
567   // Switch back and forth before synchronization can complete.
568   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
569   CookieStoreIOS::SwitchSynchronizedStore(store_.get(), dummy_store.get());
570   backend_->RunLoadedCallback();
571   // No cookie leak in the system store.
572   NSHTTPCookieStorage* store = [NSHTTPCookieStorage sharedHTTPCookieStorage];
573   EXPECT_EQ(0u, [[store cookies] count]);
574   // No cookie lost.
575   GetCookieCallback callback;
576   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
577   EXPECT_TRUE(callback.did_run());
578   EXPECT_EQ("a=b", callback.cookie_line());
579   dummy_store->UnSynchronize();
582 // Tests that Synchronization can be "aborted" while there are pending tasks
583 // (i.e. the cookie store is unsynchronized while synchronization is in progress
584 // and there are pending tasks).
585 TEST_F(CookieStoreIOSWithBackend, SyncThenUnsyncWithPendingTasks) {
586   ClearCookies();
587   scoped_refptr<CookieStoreIOS> dummy_store = new CookieStoreIOS(nullptr);
588   // Start synchornization.
589   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
590   // Create a pending task while synchronization is in progress.
591   GetCookieCallback callback;
592   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
593   // Cancel the synchronization.
594   CookieStoreIOS::SwitchSynchronizedStore(store_.get(), dummy_store.get());
595   // Synchronization completes after being cancelled.
596   backend_->RunLoadedCallback();
597   // The task is not lost.
598   EXPECT_TRUE(callback.did_run());
599   EXPECT_EQ("a=b", callback.cookie_line());
600   dummy_store->UnSynchronize();
603 TEST_F(CookieStoreIOSWithBackend, ChangePolicyOnceDuringSynchronization) {
604   // Start synchronization.
605   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
606   // Toggle cookie policy to trigger another synchronization while the first one
607   // is still in progress.
608   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::BLOCK);
609   // Backend loading completes (end of synchronization).
610   backend_->RunLoadedCallback();
611   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::ALLOW);
612   GetCookieCallback callback;
613   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
614   EXPECT_TRUE(callback.did_run());
615   EXPECT_EQ("a=b", callback.cookie_line());
616   store_->UnSynchronize();
619 TEST_F(CookieStoreIOSWithBackend,
620        ChangePolicyDuringSynchronizationWithPendingTask) {
621   // Start synchronization.
622   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
623   // Create a pending task while synchronization is in progress.
624   GetCookieCallback callback;
625   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
626   // Toggle cookie policy to trigger another synchronization while the first one
627   // is still in progress.
628   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::BLOCK);
629   // Backend loading completes (end of synchronization).
630   backend_->RunLoadedCallback();
631   EXPECT_TRUE(callback.did_run());
632   EXPECT_EQ("a=b", callback.cookie_line());
633   store_->UnSynchronize();
636 TEST_F(CookieStoreIOSWithBackend, ChangePolicyTwiceDuringSynchronization) {
637   // Start synchronization.
638   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
639   // Toggle cookie policy to trigger another synchronization while the first one
640   // is still in progress.
641   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::BLOCK);
642   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::ALLOW);
643   // Backend loading completes (end of synchronization).
644   backend_->RunLoadedCallback();
645   GetCookieCallback callback;
646   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
647   EXPECT_TRUE(callback.did_run());
648   EXPECT_EQ("a=b", callback.cookie_line());
649   store_->UnSynchronize();
652 TEST_F(CookieStoreIOSWithBackend, UnSynchronizeBeforeLoadComplete) {
653   ClearCookies();
654   // Switch back and forth before synchronization can complete.
655   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
656   store_->UnSynchronize();
657   backend_->RunLoadedCallback();
658   // No cookie lost.
659   GetCookieCallback callback;
660   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
661   EXPECT_TRUE(callback.did_run());
662   EXPECT_EQ("a=b", callback.cookie_line());
665 TEST_F(CookieStoreIOSWithBackend, UnSynchronize) {
666   ClearCookies();
667   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
668   backend_->RunLoadedCallback();
669   store_->UnSynchronize();
670   // No cookie lost.
671   GetCookieCallback callback;
672   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
673   EXPECT_TRUE(callback.did_run());
674   EXPECT_EQ("a=b", callback.cookie_line());
677 TEST_F(CookieStoreIOSWithBackend, FlushOnUnSynchronize) {
678   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
679   EXPECT_FALSE(backend_->flushed());
680   store_->UnSynchronize();
681   EXPECT_TRUE(backend_->flushed());
684 TEST_F(CookieStoreIOSWithBackend, FlushOnSwitch) {
685   scoped_refptr<CookieStoreIOS> dummy_store = new CookieStoreIOS(nullptr);
686   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
687   EXPECT_FALSE(backend_->flushed());
688   CookieStoreIOS::SwitchSynchronizedStore(store_.get(), dummy_store.get());
689   EXPECT_TRUE(backend_->flushed());
690   dummy_store->UnSynchronize();
693 TEST_F(CookieStoreIOSWithBackend, FlushOnCookieChanged) {
694   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
695   store_->set_flush_delay_for_testing(base::TimeDelta());
696   backend_->RunLoadedCallback();
697   EXPECT_FALSE(backend_->flushed());
699   // Set a cookie an check that it triggers a flush.
700   SetCookie("x=y");
701   EXPECT_TRUE(backend_->flushed());
703   store_->UnSynchronize();
706 TEST_F(CookieStoreIOSWithBackend, ManualFlush) {
707   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
708   backend_->RunLoadedCallback();
709   EXPECT_FALSE(backend_->flushed());
711   // The store should be flushed even if it is not dirty.
712   store_->Flush(base::Closure());
713   EXPECT_TRUE(backend_->flushed());
715   store_->UnSynchronize();
718 TEST_F(CookieStoreIOSWithBackend, FlushOnPolicyChange) {
719   // Start synchronization.
720   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
721   // Toggle cookie policy to trigger a flush.
722   EXPECT_FALSE(backend_->flushed());
723   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::BLOCK);
724   EXPECT_TRUE(backend_->flushed());
725   store_->UnSynchronize();
726   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::ALLOW);
729 TEST_F(CookieStoreIOSWithBackend, NoInitialNotifyWithNoCookie) {
730   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
731   std::vector<net::CanonicalCookie> cookies;
732   store_->AddCallbackForCookie(
733       kTestCookieURL, "abc",
734       base::Bind(&RecordCookieChanges, &cookies, nullptr));
735   EXPECT_EQ(0U, cookies.size());
736   store_->UnSynchronize();
739 TEST_F(CookieStoreIOSWithBackend, NoInitialNotifyWithSystemCookie) {
740   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
741   SetSystemCookie(kTestCookieURL, "abc", "def");
742   std::vector<net::CanonicalCookie> cookies;
743   store_->AddCallbackForCookie(
744       kTestCookieURL, "abc",
745       base::Bind(&RecordCookieChanges, &cookies, nullptr));
746   EXPECT_EQ(0U, cookies.size());
747   DeleteSystemCookie(kTestCookieURL, "abc");
748   store_->UnSynchronize();
751 TEST_F(CookieStoreIOSWithBackend, NotifyOnAdd) {
752   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
753   backend_->RunLoadedCallback();
754   std::vector<net::CanonicalCookie> cookies;
755   std::vector<bool> removes;
756   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
757       store_->AddCallbackForCookie(
758           kTestCookieURL, "abc",
759           base::Bind(&RecordCookieChanges, &cookies, &removes));
760   EXPECT_EQ(0U, cookies.size());
761   EXPECT_EQ(0U, removes.size());
762   SetSystemCookie(kTestCookieURL, "abc", "def");
763   EXPECT_EQ(1U, cookies.size());
764   EXPECT_EQ(1U, removes.size());
765   EXPECT_EQ("abc", cookies[0].Name());
766   EXPECT_EQ("def", cookies[0].Value());
767   EXPECT_FALSE(removes[0]);
769   SetSystemCookie(kTestCookieURL, "ghi", "jkl");
770   EXPECT_EQ(1U, cookies.size());
771   EXPECT_EQ(1U, removes.size());
773   DeleteSystemCookie(kTestCookieURL, "abc");
774   DeleteSystemCookie(kTestCookieURL, "ghi");
775   store_->UnSynchronize();
778 TEST_F(CookieStoreIOSWithBackend, NotifyOnChange) {
779   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
780   backend_->RunLoadedCallback();
781   std::vector<net::CanonicalCookie> cookies;
782   std::vector<bool> removes;
783   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
784       store_->AddCallbackForCookie(
785           kTestCookieURL, "abc",
786           base::Bind(&RecordCookieChanges, &cookies, &removes));
787   EXPECT_EQ(0U, cookies.size());
788   SetSystemCookie(kTestCookieURL, "abc", "def");
789   EXPECT_EQ(1U, cookies.size());
790   SetSystemCookie(kTestCookieURL, "abc", "ghi");
791   EXPECT_EQ(3U, cookies.size());
792   EXPECT_EQ(3U, removes.size());
793   EXPECT_EQ("abc", cookies[1].Name());
794   EXPECT_EQ("def", cookies[1].Value());
795   EXPECT_TRUE(removes[1]);
796   EXPECT_EQ("abc", cookies[2].Name());
797   EXPECT_EQ("ghi", cookies[2].Value());
798   EXPECT_FALSE(removes[2]);
800   DeleteSystemCookie(kTestCookieURL, "abc");
801   store_->UnSynchronize();
804 TEST_F(CookieStoreIOSWithBackend, NotifyOnDelete) {
805   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
806   backend_->RunLoadedCallback();
807   std::vector<net::CanonicalCookie> cookies;
808   std::vector<bool> removes;
809   SetSystemCookie(kTestCookieURL, "abc", "def");
810   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
811       store_->AddCallbackForCookie(
812           kTestCookieURL, "abc",
813           base::Bind(&RecordCookieChanges, &cookies, &removes));
814   EXPECT_EQ(0U, cookies.size());
815   DeleteSystemCookie(kTestCookieURL, "abc");
816   EXPECT_EQ(1U, cookies.size());
817   EXPECT_EQ(1U, removes.size());
818   EXPECT_TRUE(removes[0]);
819   SetSystemCookie(kTestCookieURL, "abc", "def");
820   EXPECT_EQ(2U, cookies.size());
821   EXPECT_EQ(2U, removes.size());
822   EXPECT_FALSE(removes[1]);
823   DeleteSystemCookie(kTestCookieURL, "abc");
824   store_->UnSynchronize();
827 TEST_F(CookieStoreIOSWithBackend, NoNotifyOnNoChange) {
828   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
829   backend_->RunLoadedCallback();
830   std::vector<net::CanonicalCookie> cookies;
831   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
832       store_->AddCallbackForCookie(
833           kTestCookieURL, "abc",
834           base::Bind(&RecordCookieChanges, &cookies, nullptr));
835   EXPECT_EQ(0U, cookies.size());
836   SetSystemCookie(kTestCookieURL, "abc", "def");
837   EXPECT_EQ(1U, cookies.size());
838   SetSystemCookie(kTestCookieURL, "abc", "def");
839   EXPECT_EQ(1U, cookies.size());
840   DeleteSystemCookie(kTestCookieURL, "abc");
841   store_->UnSynchronize();
844 TEST_F(CookieStoreIOSWithBackend, MultipleNotifies) {
845   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
846   backend_->RunLoadedCallback();
847   std::vector<net::CanonicalCookie> cookies;
848   std::vector<net::CanonicalCookie> cookies2;
849   std::vector<net::CanonicalCookie> cookies3;
850   std::vector<net::CanonicalCookie> cookies4;
851   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
852       store_->AddCallbackForCookie(
853           kTestCookieURL, "abc",
854           base::Bind(&RecordCookieChanges, &cookies, nullptr));
855   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle2 =
856       store_->AddCallbackForCookie(
857           kTestCookieURL2, "abc",
858           base::Bind(&RecordCookieChanges, &cookies2, nullptr));
859   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle3 =
860       store_->AddCallbackForCookie(
861           kTestCookieURL3, "abc",
862           base::Bind(&RecordCookieChanges, &cookies3, nullptr));
863   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle4 =
864       store_->AddCallbackForCookie(
865           kTestCookieURL4, "abc",
866           base::Bind(&RecordCookieChanges, &cookies4, nullptr));
867   SetSystemCookie(kTestCookieURL, "abc", "def");
868   SetSystemCookie(kTestCookieURL2, "abc", "def");
869   SetSystemCookie(kTestCookieURL3, "abc", "def");
870   SetSystemCookie(kTestCookieURL4, "abc", "def");
871   EXPECT_EQ(2U, cookies.size());
872   EXPECT_EQ(2U, cookies2.size());
873   EXPECT_EQ(1U, cookies3.size());
874   EXPECT_EQ(1U, cookies4.size());
875   DeleteSystemCookie(kTestCookieURL, "abc");
876   DeleteSystemCookie(kTestCookieURL2, "abc");
877   DeleteSystemCookie(kTestCookieURL3, "abc");
878   DeleteSystemCookie(kTestCookieURL4, "abc");
879   store_->UnSynchronize();
882 TEST_F(CookieStoreIOSWithBackend, LessSpecificNestedCookie) {
883   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
884   backend_->RunLoadedCallback();
885   std::vector<net::CanonicalCookie> cookies;
886   SetSystemCookie(kTestCookieURL2, "abc", "def");
887   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
888       store_->AddCallbackForCookie(
889           kTestCookieURL2, "abc",
890           base::Bind(&RecordCookieChanges, &cookies, nullptr));
891   EXPECT_EQ(0U, cookies.size());
892   SetSystemCookie(kTestCookieURL3, "abc", "ghi");
893   EXPECT_EQ(1U, cookies.size());
894   DeleteSystemCookie(kTestCookieURL, "abc");
895   store_->UnSynchronize();
898 TEST_F(CookieStoreIOSWithBackend, MoreSpecificNestedCookie) {
899   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
900   backend_->RunLoadedCallback();
901   std::vector<net::CanonicalCookie> cookies;
902   SetSystemCookie(kTestCookieURL3, "abc", "def");
903   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
904       store_->AddCallbackForCookie(
905           kTestCookieURL2, "abc",
906           base::Bind(&RecordCookieChanges, &cookies, nullptr));
907   EXPECT_EQ(0U, cookies.size());
908   SetSystemCookie(kTestCookieURL2, "abc", "ghi");
909   EXPECT_EQ(1U, cookies.size());
910   DeleteSystemCookie(kTestCookieURL, "abc");
911   store_->UnSynchronize();
914 TEST_F(CookieStoreIOSWithBackend, MoreSpecificNestedCookieWithSameValue) {
915   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
916   backend_->RunLoadedCallback();
917   std::vector<net::CanonicalCookie> cookies;
918   SetSystemCookie(kTestCookieURL3, "abc", "def");
919   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
920       store_->AddCallbackForCookie(
921           kTestCookieURL2, "abc",
922           base::Bind(&RecordCookieChanges, &cookies, nullptr));
923   EXPECT_EQ(0U, cookies.size());
924   SetSystemCookie(kTestCookieURL2, "abc", "def");
925   EXPECT_EQ(1U, cookies.size());
926   DeleteSystemCookie(kTestCookieURL, "abc");
927   store_->UnSynchronize();
930 TEST_F(CookieStoreIOSWithBackend, RemoveCallback) {
931   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
932   backend_->RunLoadedCallback();
933   std::vector<net::CanonicalCookie> cookies;
934   SetSystemCookie(kTestCookieURL, "abc", "def");
935   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
936       store_->AddCallbackForCookie(
937           kTestCookieURL, "abc",
938           base::Bind(&RecordCookieChanges, &cookies, nullptr));
939   EXPECT_EQ(0U, cookies.size());
940   SetSystemCookie(kTestCookieURL, "abc", "ghi");
941   EXPECT_EQ(2U, cookies.size());
942   // this deletes the callback
943   handle.reset();
944   SetSystemCookie(kTestCookieURL, "abc", "jkl");
945   EXPECT_EQ(2U, cookies.size());
946   DeleteSystemCookie(kTestCookieURL, "abc");
947   store_->UnSynchronize();
950 }  // namespace net