blob: ad12e14ac941501ade6d0d5eb89d43d13f839f90 [file] [log] [blame]
// 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_SUITE_P(PersistentCookieStoreIOS,
CookieStoreTest,
PersistentCookieStoreIOSTestTraits);
INSTANTIATE_TYPED_TEST_SUITE_P(PersistentCookieStoreIOS,
CookieStoreChangeGlobalTest,
PersistentCookieStoreIOSTestTraits);
INSTANTIATE_TYPED_TEST_SUITE_P(PersistentCookieStoreIOS,
CookieStoreChangeUrlTest,
PersistentCookieStoreIOSTestTraits);
INSTANTIATE_TYPED_TEST_SUITE_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