| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/net/cookies/cookie_store_ios_persistent.h" |
| |
| #import <Foundation/Foundation.h> |
| |
| #include <memory> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #import "ios/net/cookies/cookie_store_ios_test_util.h" |
| #include "net/cookies/canonical_cookie_test_helpers.h" |
| #include "net/cookies/cookie_store_change_unittest.h" |
| #include "net/cookies/cookie_store_test_callbacks.h" |
| #include "net/cookies/cookie_store_unittest.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/platform_test.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| namespace net { |
| |
| struct PersistentCookieStoreIOSTestTraits { |
| static std::unique_ptr<net::CookieStore> Create() { |
| return std::make_unique<CookieStoreIOSPersistent>(nullptr, |
| nullptr /* net_log */); |
| } |
| |
| static void DeliverChangeNotifications() { base::RunLoop().RunUntilIdle(); } |
| |
| static const bool is_cookie_monster = false; |
| static const bool supports_http_only = false; |
| static const bool supports_non_dotted_domains = true; |
| static const bool preserves_trailing_dots = true; |
| static const bool filters_schemes = false; |
| static const bool has_path_prefix_bug = false; |
| static const bool forbids_setting_empty_name = false; |
| static const bool supports_global_cookie_tracking = false; |
| // TODO(crbug.com/813931): Fix the bugs uncovered by these tests. |
| static const bool supports_named_cookie_tracking = false; |
| static const bool supports_url_cookie_tracking = false; |
| static const bool supports_multiple_tracking_callbacks = false; |
| static const bool has_exact_change_cause = false; |
| static const bool has_exact_change_ordering = false; |
| static const int creation_time_granularity_in_ms = 0; |
| static const int enforces_prefixes = true; |
| static const bool enforce_strict_secure = false; |
| |
| base::MessageLoop loop_; |
| }; |
| |
| INSTANTIATE_TYPED_TEST_CASE_P(PersistentCookieStoreIOS, |
| CookieStoreTest, |
| PersistentCookieStoreIOSTestTraits); |
| INSTANTIATE_TYPED_TEST_CASE_P(PersistentCookieStoreIOS, |
| CookieStoreChangeGlobalTest, |
| PersistentCookieStoreIOSTestTraits); |
| INSTANTIATE_TYPED_TEST_CASE_P(PersistentCookieStoreIOS, |
| CookieStoreChangeUrlTest, |
| PersistentCookieStoreIOSTestTraits); |
| INSTANTIATE_TYPED_TEST_CASE_P(PersistentCookieStoreIOS, |
| CookieStoreChangeNamedTest, |
| PersistentCookieStoreIOSTestTraits); |
| |
| namespace { |
| |
| // Test fixture to exercise net::CookieStoreIOSPersistent created with |
| // TestPersistentCookieStore back-end and not synchronized with |
| // SystemCookieStore. |
| class CookieStoreIOSPersistentTest : public PlatformTest { |
| public: |
| CookieStoreIOSPersistentTest() |
| : kTestCookieURL("http://foo.google.com/bar"), |
| scoped_cookie_store_ios_client_( |
| std::make_unique<TestCookieStoreIOSClient>()), |
| backend_(new net::TestPersistentCookieStore), |
| store_(std::make_unique<net::CookieStoreIOSPersistent>( |
| backend_.get(), |
| nullptr /* net_log */)) { |
| cookie_change_subscription_ = |
| store_->GetChangeDispatcher().AddCallbackForCookie( |
| kTestCookieURL, "abc", |
| base::BindRepeating(&net::RecordCookieChanges, &cookies_changed_, |
| &cookies_removed_)); |
| } |
| |
| ~CookieStoreIOSPersistentTest() override {} |
| |
| // Gets the cookies. |callback| will be called on completion. |
| void GetCookies(net::CookieStore::GetCookieListCallback callback) { |
| net::CookieOptions options; |
| options.set_include_httponly(); |
| store_->GetCookieListWithOptionsAsync(kTestCookieURL, options, |
| std::move(callback)); |
| } |
| |
| // Sets a cookie. |
| void SetCookie(const std::string& cookie_line) { |
| net::SetCookie(cookie_line, kTestCookieURL, store_.get()); |
| } |
| |
| private: |
| const GURL kTestCookieURL; |
| |
| protected: |
| base::MessageLoop loop_; |
| ScopedTestingCookieStoreIOSClient scoped_cookie_store_ios_client_; |
| scoped_refptr<net::TestPersistentCookieStore> backend_; |
| std::unique_ptr<net::CookieStoreIOS> store_; |
| std::unique_ptr<net::CookieChangeSubscription> cookie_change_subscription_; |
| std::vector<net::CanonicalCookie> cookies_changed_; |
| std::vector<bool> cookies_removed_; |
| }; |
| |
| } // namespace |
| |
| TEST_F(CookieStoreIOSPersistentTest, SetCookieCallsHook) { |
| ClearCookies(); |
| SetCookie("abc=def"); |
| EXPECT_EQ(0U, cookies_changed_.size()); |
| EXPECT_EQ(0U, cookies_removed_.size()); |
| backend_->RunLoadedCallback(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(1U, cookies_changed_.size()); |
| EXPECT_EQ(1U, cookies_removed_.size()); |
| EXPECT_EQ("abc", cookies_changed_[0].Name()); |
| EXPECT_EQ("def", cookies_changed_[0].Value()); |
| EXPECT_FALSE(cookies_removed_[0]); |
| |
| // Replacing an existing cookie is actually a two-phase delete + set |
| // operation, so we get an extra notification. |
| SetCookie("abc=ghi"); |
| EXPECT_EQ(3U, cookies_changed_.size()); |
| EXPECT_EQ(3U, cookies_removed_.size()); |
| EXPECT_EQ("abc", cookies_changed_[1].Name()); |
| EXPECT_EQ("def", cookies_changed_[1].Value()); |
| EXPECT_TRUE(cookies_removed_[1]); |
| EXPECT_EQ("abc", cookies_changed_[2].Name()); |
| EXPECT_EQ("ghi", cookies_changed_[2].Value()); |
| EXPECT_FALSE(cookies_removed_[2]); |
| } |
| |
| // Tests that cookies can be read before the backend is loaded. |
| TEST_F(CookieStoreIOSPersistentTest, NotSynchronized) { |
| // Start fetching the cookie. |
| GetCookieListCallback callback; |
| GetCookies( |
| base::BindOnce(&GetCookieListCallback::Run, base::Unretained(&callback))); |
| // Backend loading completes. |
| backend_->RunLoadedCallback(); |
| EXPECT_THAT(callback.cookies(), MatchesCookieLine("a=b")); |
| } |
| |
| } // namespace net |