Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / ios / net / cookies / cookie_store_ios_unittest.mm
blob311587a0c3272ae8bc9ab937b79521035fe0ea11
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 supports_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 supports_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 supports_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 TEST_F(CookieStoreIOSWithBackend, ChangePolicyOnceDuringSynchronization) {
583   // Start synchronization.
584   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
585   // Toggle cookie policy to trigger another synchronization while the first one
586   // is still in progress.
587   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::BLOCK);
588   // Backend loading completes (end of synchronization).
589   backend_->RunLoadedCallback();
590   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::ALLOW);
591   GetCookieCallback callback;
592   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
593   EXPECT_TRUE(callback.did_run());
594   EXPECT_EQ("a=b", callback.cookie_line());
595   store_->UnSynchronize();
598 TEST_F(CookieStoreIOSWithBackend, ChangePolicyTwiceDuringSynchronization) {
599   // Start synchronization.
600   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
601   // Toggle cookie policy to trigger another synchronization while the first one
602   // is still in progress.
603   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::BLOCK);
604   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::ALLOW);
605   // Backend loading completes (end of synchronization).
606   backend_->RunLoadedCallback();
607   GetCookieCallback callback;
608   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
609   EXPECT_TRUE(callback.did_run());
610   EXPECT_EQ("a=b", callback.cookie_line());
611   store_->UnSynchronize();
614 TEST_F(CookieStoreIOSWithBackend, UnSynchronizeBeforeLoadComplete) {
615   ClearCookies();
616   // Switch back and forth before synchronization can complete.
617   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
618   store_->UnSynchronize();
619   backend_->RunLoadedCallback();
620   // No cookie lost.
621   GetCookieCallback callback;
622   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
623   EXPECT_TRUE(callback.did_run());
624   EXPECT_EQ("a=b", callback.cookie_line());
627 TEST_F(CookieStoreIOSWithBackend, UnSynchronize) {
628   ClearCookies();
629   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
630   backend_->RunLoadedCallback();
631   store_->UnSynchronize();
632   // No cookie lost.
633   GetCookieCallback callback;
634   GetCookies(base::Bind(&GetCookieCallback::Run, base::Unretained(&callback)));
635   EXPECT_TRUE(callback.did_run());
636   EXPECT_EQ("a=b", callback.cookie_line());
639 TEST_F(CookieStoreIOSWithBackend, FlushOnUnSynchronize) {
640   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
641   EXPECT_FALSE(backend_->flushed());
642   store_->UnSynchronize();
643   EXPECT_TRUE(backend_->flushed());
646 TEST_F(CookieStoreIOSWithBackend, FlushOnSwitch) {
647   scoped_refptr<CookieStoreIOS> dummy_store = new CookieStoreIOS(nullptr);
648   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
649   EXPECT_FALSE(backend_->flushed());
650   CookieStoreIOS::SwitchSynchronizedStore(store_.get(), dummy_store.get());
651   EXPECT_TRUE(backend_->flushed());
652   dummy_store->UnSynchronize();
655 TEST_F(CookieStoreIOSWithBackend, FlushOnCookieChanged) {
656   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
657   store_->set_flush_delay_for_testing(base::TimeDelta());
658   backend_->RunLoadedCallback();
659   EXPECT_FALSE(backend_->flushed());
661   // Set a cookie an check that it triggers a flush.
662   SetCookie("x=y");
663   EXPECT_TRUE(backend_->flushed());
665   store_->UnSynchronize();
668 TEST_F(CookieStoreIOSWithBackend, ManualFlush) {
669   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
670   backend_->RunLoadedCallback();
671   EXPECT_FALSE(backend_->flushed());
673   // The store should be flushed even if it is not dirty.
674   store_->Flush(base::Closure());
675   EXPECT_TRUE(backend_->flushed());
677   store_->UnSynchronize();
680 TEST_F(CookieStoreIOSWithBackend, FlushOnPolicyChange) {
681   // Start synchronization.
682   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
683   // Toggle cookie policy to trigger a flush.
684   EXPECT_FALSE(backend_->flushed());
685   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::BLOCK);
686   EXPECT_TRUE(backend_->flushed());
687   store_->UnSynchronize();
688   CookieStoreIOS::SetCookiePolicy(CookieStoreIOS::ALLOW);
691 TEST_F(CookieStoreIOSWithBackend, NoInitialNotifyWithNoCookie) {
692   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
693   std::vector<net::CanonicalCookie> cookies;
694   store_->AddCallbackForCookie(
695       kTestCookieURL, "abc",
696       base::Bind(&RecordCookieChanges, &cookies, nullptr));
697   EXPECT_EQ(0U, cookies.size());
698   store_->UnSynchronize();
701 TEST_F(CookieStoreIOSWithBackend, NoInitialNotifyWithSystemCookie) {
702   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
703   SetSystemCookie(kTestCookieURL, "abc", "def");
704   std::vector<net::CanonicalCookie> cookies;
705   store_->AddCallbackForCookie(
706       kTestCookieURL, "abc",
707       base::Bind(&RecordCookieChanges, &cookies, nullptr));
708   EXPECT_EQ(0U, cookies.size());
709   DeleteSystemCookie(kTestCookieURL, "abc");
710   store_->UnSynchronize();
713 TEST_F(CookieStoreIOSWithBackend, NotifyOnAdd) {
714   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
715   backend_->RunLoadedCallback();
716   std::vector<net::CanonicalCookie> cookies;
717   std::vector<bool> removes;
718   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
719       store_->AddCallbackForCookie(
720           kTestCookieURL, "abc",
721           base::Bind(&RecordCookieChanges, &cookies, &removes));
722   EXPECT_EQ(0U, cookies.size());
723   EXPECT_EQ(0U, removes.size());
724   SetSystemCookie(kTestCookieURL, "abc", "def");
725   EXPECT_EQ(1U, cookies.size());
726   EXPECT_EQ(1U, removes.size());
727   EXPECT_EQ("abc", cookies[0].Name());
728   EXPECT_EQ("def", cookies[0].Value());
729   EXPECT_FALSE(removes[0]);
731   SetSystemCookie(kTestCookieURL, "ghi", "jkl");
732   EXPECT_EQ(1U, cookies.size());
733   EXPECT_EQ(1U, removes.size());
735   DeleteSystemCookie(kTestCookieURL, "abc");
736   DeleteSystemCookie(kTestCookieURL, "ghi");
737   store_->UnSynchronize();
740 TEST_F(CookieStoreIOSWithBackend, NotifyOnChange) {
741   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
742   backend_->RunLoadedCallback();
743   std::vector<net::CanonicalCookie> cookies;
744   std::vector<bool> removes;
745   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
746       store_->AddCallbackForCookie(
747           kTestCookieURL, "abc",
748           base::Bind(&RecordCookieChanges, &cookies, &removes));
749   EXPECT_EQ(0U, cookies.size());
750   SetSystemCookie(kTestCookieURL, "abc", "def");
751   EXPECT_EQ(1U, cookies.size());
752   SetSystemCookie(kTestCookieURL, "abc", "ghi");
753   EXPECT_EQ(3U, cookies.size());
754   EXPECT_EQ(3U, removes.size());
755   EXPECT_EQ("abc", cookies[1].Name());
756   EXPECT_EQ("def", cookies[1].Value());
757   EXPECT_TRUE(removes[1]);
758   EXPECT_EQ("abc", cookies[2].Name());
759   EXPECT_EQ("ghi", cookies[2].Value());
760   EXPECT_FALSE(removes[2]);
762   DeleteSystemCookie(kTestCookieURL, "abc");
763   store_->UnSynchronize();
766 TEST_F(CookieStoreIOSWithBackend, NotifyOnDelete) {
767   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
768   backend_->RunLoadedCallback();
769   std::vector<net::CanonicalCookie> cookies;
770   std::vector<bool> removes;
771   SetSystemCookie(kTestCookieURL, "abc", "def");
772   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
773       store_->AddCallbackForCookie(
774           kTestCookieURL, "abc",
775           base::Bind(&RecordCookieChanges, &cookies, &removes));
776   EXPECT_EQ(0U, cookies.size());
777   DeleteSystemCookie(kTestCookieURL, "abc");
778   EXPECT_EQ(1U, cookies.size());
779   EXPECT_EQ(1U, removes.size());
780   EXPECT_TRUE(removes[0]);
781   SetSystemCookie(kTestCookieURL, "abc", "def");
782   EXPECT_EQ(2U, cookies.size());
783   EXPECT_EQ(2U, removes.size());
784   EXPECT_FALSE(removes[1]);
785   DeleteSystemCookie(kTestCookieURL, "abc");
786   store_->UnSynchronize();
789 TEST_F(CookieStoreIOSWithBackend, NoNotifyOnNoChange) {
790   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
791   backend_->RunLoadedCallback();
792   std::vector<net::CanonicalCookie> cookies;
793   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
794       store_->AddCallbackForCookie(
795           kTestCookieURL, "abc",
796           base::Bind(&RecordCookieChanges, &cookies, nullptr));
797   EXPECT_EQ(0U, cookies.size());
798   SetSystemCookie(kTestCookieURL, "abc", "def");
799   EXPECT_EQ(1U, cookies.size());
800   SetSystemCookie(kTestCookieURL, "abc", "def");
801   EXPECT_EQ(1U, cookies.size());
802   DeleteSystemCookie(kTestCookieURL, "abc");
803   store_->UnSynchronize();
806 TEST_F(CookieStoreIOSWithBackend, MultipleNotifies) {
807   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
808   backend_->RunLoadedCallback();
809   std::vector<net::CanonicalCookie> cookies;
810   std::vector<net::CanonicalCookie> cookies2;
811   std::vector<net::CanonicalCookie> cookies3;
812   std::vector<net::CanonicalCookie> cookies4;
813   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
814       store_->AddCallbackForCookie(
815           kTestCookieURL, "abc",
816           base::Bind(&RecordCookieChanges, &cookies, nullptr));
817   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle2 =
818       store_->AddCallbackForCookie(
819           kTestCookieURL2, "abc",
820           base::Bind(&RecordCookieChanges, &cookies2, nullptr));
821   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle3 =
822       store_->AddCallbackForCookie(
823           kTestCookieURL3, "abc",
824           base::Bind(&RecordCookieChanges, &cookies3, nullptr));
825   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle4 =
826       store_->AddCallbackForCookie(
827           kTestCookieURL4, "abc",
828           base::Bind(&RecordCookieChanges, &cookies4, nullptr));
829   SetSystemCookie(kTestCookieURL, "abc", "def");
830   SetSystemCookie(kTestCookieURL2, "abc", "def");
831   SetSystemCookie(kTestCookieURL3, "abc", "def");
832   SetSystemCookie(kTestCookieURL4, "abc", "def");
833   EXPECT_EQ(2U, cookies.size());
834   EXPECT_EQ(2U, cookies2.size());
835   EXPECT_EQ(1U, cookies3.size());
836   EXPECT_EQ(1U, cookies4.size());
837   DeleteSystemCookie(kTestCookieURL, "abc");
838   DeleteSystemCookie(kTestCookieURL2, "abc");
839   DeleteSystemCookie(kTestCookieURL3, "abc");
840   DeleteSystemCookie(kTestCookieURL4, "abc");
841   store_->UnSynchronize();
844 TEST_F(CookieStoreIOSWithBackend, LessSpecificNestedCookie) {
845   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
846   backend_->RunLoadedCallback();
847   std::vector<net::CanonicalCookie> cookies;
848   SetSystemCookie(kTestCookieURL2, "abc", "def");
849   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
850       store_->AddCallbackForCookie(
851           kTestCookieURL2, "abc",
852           base::Bind(&RecordCookieChanges, &cookies, nullptr));
853   EXPECT_EQ(0U, cookies.size());
854   SetSystemCookie(kTestCookieURL3, "abc", "ghi");
855   EXPECT_EQ(1U, cookies.size());
856   DeleteSystemCookie(kTestCookieURL, "abc");
857   store_->UnSynchronize();
860 TEST_F(CookieStoreIOSWithBackend, MoreSpecificNestedCookie) {
861   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
862   backend_->RunLoadedCallback();
863   std::vector<net::CanonicalCookie> cookies;
864   SetSystemCookie(kTestCookieURL3, "abc", "def");
865   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
866       store_->AddCallbackForCookie(
867           kTestCookieURL2, "abc",
868           base::Bind(&RecordCookieChanges, &cookies, nullptr));
869   EXPECT_EQ(0U, cookies.size());
870   SetSystemCookie(kTestCookieURL2, "abc", "ghi");
871   EXPECT_EQ(1U, cookies.size());
872   DeleteSystemCookie(kTestCookieURL, "abc");
873   store_->UnSynchronize();
876 TEST_F(CookieStoreIOSWithBackend, MoreSpecificNestedCookieWithSameValue) {
877   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
878   backend_->RunLoadedCallback();
879   std::vector<net::CanonicalCookie> cookies;
880   SetSystemCookie(kTestCookieURL3, "abc", "def");
881   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
882       store_->AddCallbackForCookie(
883           kTestCookieURL2, "abc",
884           base::Bind(&RecordCookieChanges, &cookies, nullptr));
885   EXPECT_EQ(0U, cookies.size());
886   SetSystemCookie(kTestCookieURL2, "abc", "def");
887   EXPECT_EQ(1U, cookies.size());
888   DeleteSystemCookie(kTestCookieURL, "abc");
889   store_->UnSynchronize();
892 TEST_F(CookieStoreIOSWithBackend, RemoveCallback) {
893   CookieStoreIOS::SwitchSynchronizedStore(nullptr, store_.get());
894   backend_->RunLoadedCallback();
895   std::vector<net::CanonicalCookie> cookies;
896   SetSystemCookie(kTestCookieURL, "abc", "def");
897   scoped_ptr<net::CookieStore::CookieChangedSubscription> handle =
898       store_->AddCallbackForCookie(
899           kTestCookieURL, "abc",
900           base::Bind(&RecordCookieChanges, &cookies, nullptr));
901   EXPECT_EQ(0U, cookies.size());
902   SetSystemCookie(kTestCookieURL, "abc", "ghi");
903   EXPECT_EQ(2U, cookies.size());
904   // this deletes the callback
905   handle.reset();
906   SetSystemCookie(kTestCookieURL, "abc", "jkl");
907   EXPECT_EQ(2U, cookies.size());
908   DeleteSystemCookie(kTestCookieURL, "abc");
909   store_->UnSynchronize();
912 }  // namespace net