chromium/net/cookies/cookie_monster_unittest.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif

#include "net/cookies/cookie_monster.h"

#include <stdint.h>

#include <algorithm>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/containers/queue.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_samples.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "cookie_partition_key.h"
#include "net/base/features.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/canonical_cookie_test_helpers.h"
#include "net/cookies/cookie_change_dispatcher.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_inclusion_status.h"
#include "net/cookies/cookie_monster_store_test.h"  // For CookieStore mock
#include "net/cookies/cookie_partition_key.h"
#include "net/cookies/cookie_store.h"
#include "net/cookies/cookie_store_change_unittest.h"
#include "net/cookies/cookie_store_test_callbacks.h"
#include "net/cookies/cookie_store_test_helpers.h"
#include "net/cookies/cookie_store_unittest.h"
#include "net/cookies/cookie_util.h"
#include "net/cookies/parsed_cookie.h"
#include "net/cookies/test_cookie_access_delegate.h"
#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_util.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/third_party/mozilla/url_parse.h"
#include "url/url_constants.h"

namespace net {

Time;
CookieDeletionInfo;

namespace {

ElementsAre;

// False means 'less than or equal', so we test both ways for full equal.
MATCHER_P(CookieEquals, expected, "") {}

MATCHER_P2(MatchesCookieNameDomain, name, domain, "") {}

MATCHER_P4(MatchesCookieNameValueCreationExpiry,
           name,
           value,
           creation,
           expiry,
           "") {}

const char kTopLevelDomainPlus1[] =;
const char kTopLevelDomainPlus2[] =;
const char kTopLevelDomainPlus2Secure[] =;
const char kTopLevelDomainPlus3[] =;
const char kOtherDomain[] =;

struct CookieMonsterTestTraits {};

INSTANTIATE_TYPED_TEST_SUITE_P();
INSTANTIATE_TYPED_TEST_SUITE_P();
INSTANTIATE_TYPED_TEST_SUITE_P();
INSTANTIATE_TYPED_TEST_SUITE_P();

template <typename T>
class CookieMonsterTestBase : public CookieStoreTest<T> {};

CookieMonsterTest;

class CookieMonsterTestGarbageCollectionObc
    : public CookieMonsterTest,
      public testing::WithParamInterface<std::tuple<bool, bool>> {};

CookieMonsterTestPriorityGarbageCollectionObc;

struct CookiesInputInfo {};

}  // namespace

// This test suite verifies the task deferral behaviour of the CookieMonster.
// Specifically, for each asynchronous method, verify that:
// 1. invoking it on an uninitialized cookie store causes the store to begin
//    chain-loading its backing data or loading data for a specific domain key
//    (eTLD+1).
// 2. The initial invocation does not complete until the loading completes.
// 3. Invocations after the loading has completed complete immediately.
class DeferredCookieTaskTest : public CookieMonsterTest {};

TEST_F(DeferredCookieTaskTest, DeferredGetCookieList) {}

TEST_F(DeferredCookieTaskTest, DeferredSetCookie) {}

TEST_F(DeferredCookieTaskTest, DeferredSetAllCookies) {}

TEST_F(DeferredCookieTaskTest, DeferredGetAllCookies) {}

TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlCookies) {}

TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlWithOptionsCookies) {}

TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCookies) {}

TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCreatedInTimeRangeCookies) {}

TEST_F(DeferredCookieTaskTest,
       DeferredDeleteAllWithPredicateCreatedInTimeRangeCookies) {}

TEST_F(DeferredCookieTaskTest, DeferredDeleteMatchingCookies) {}

TEST_F(DeferredCookieTaskTest, DeferredDeleteCanonicalCookie) {}

TEST_F(DeferredCookieTaskTest, DeferredDeleteSessionCookies) {}

// Verify that a series of queued tasks are executed in order upon loading of
// the backing store and that new tasks received while the queued tasks are
// being dispatched go to the end of the queue.
TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) {}

TEST_F(CookieMonsterTest, TestCookieDeleteAll) {}

TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedInTimeRangeTimestamps) {}

TEST_F(CookieMonsterTest,
       TestCookieDeleteAllCreatedInTimeRangeTimestampsWithInfo) {}

TEST_F(CookieMonsterTest, TestCookieDeleteMatchingCookies) {}

static const base::TimeDelta kLastAccessThreshold =;
static const base::TimeDelta kAccessDelay =;

TEST_F(CookieMonsterTest, TestLastAccess) {}

TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,
       TestHostGarbageCollection) {}

TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,
       TestPriorityAwareGarbageCollectionNonSecure) {}

TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,
       TestPriorityAwareGarbageCollectionSecure) {}

TEST_P(CookieMonsterTestPriorityGarbageCollectionObc,
       TestPriorityAwareGarbageCollectionMixed) {}

// Test that domain cookies are always deleted before host cookies for a given
// {priority, secureness}. In this case, default priority and secure.
TEST_P(CookieMonsterTestGarbageCollectionObc, DomainCookiesPreferred) {}

// Securely set cookies should always be deleted after non-securely set cookies.
TEST_P(CookieMonsterTestGarbageCollectionObc, SecureCookiesPreferred) {}

TEST_F(CookieMonsterTest, TestPartitionedCookiesGarbageCollection_Memory) {}

TEST_F(CookieMonsterTest, TestPartitionedCookiesGarbageCollection_MaxCookies) {}

TEST_F(CookieMonsterTest, SetCookieableSchemes) {}

TEST_F(CookieMonsterTest, SetCookieableSchemes_StoreInitialized) {}

TEST_F(CookieMonsterTest, GetAllCookiesForURL) {}

TEST_F(CookieMonsterTest, GetExcludedCookiesForURL) {}

TEST_F(CookieMonsterTest, GetAllCookiesForURLPathMatching) {}

TEST_F(CookieMonsterTest, GetExcludedCookiesForURLPathMatching) {}

TEST_F(CookieMonsterTest, CookieSorting) {}

TEST_F(CookieMonsterTest, InheritCreationDate) {}

TEST_F(CookieMonsterTest, OverwriteSource) {}

// Check that GetAllCookiesForURL() does not return expired cookies and deletes
// them.
TEST_F(CookieMonsterTest, DeleteExpiredCookiesOnGet) {}

// Test that cookie expiration works correctly when a cookie expires because
// time elapses.
TEST_F(CookieMonsterTest, DeleteExpiredCookiesAfterTimeElapsed) {}

TEST_F(CookieMonsterTest, DeleteExpiredPartitionedCookiesAfterTimeElapsed) {}

// This test is for verifying the fix of https://crbug.com/353034832.
TEST_F(CookieMonsterTest, ExpireSinglePartitionedCookie) {}

TEST_F(CookieMonsterTest, DeleteExpiredAfterTimeElapsed_GetAllCookies) {}

TEST_F(CookieMonsterTest,
       DeleteExpiredPartitionedCookiesAfterTimeElapsed_GetAllCookies) {}

TEST_F(CookieMonsterTest, DeletePartitionedCookie) {}

// Tests importing from a persistent cookie store that contains duplicate
// equivalent cookies. This situation should be handled by removing the
// duplicate cookie (both from the in-memory cache, and from the backing store).
//
// This is a regression test for: http://crbug.com/17855.
TEST_F(CookieMonsterTest, DontImportDuplicateCookies) {}

TEST_F(CookieMonsterTest, DontImportDuplicateCookies_PartitionedCookies) {}

// Tests importing from a persistent cookie store that contains cookies
// with duplicate creation times.  This is OK now, but it still interacts
// with the de-duplication algorithm.
//
// This is a regression test for: http://crbug.com/43188.
TEST_F(CookieMonsterTest, ImportDuplicateCreationTimes) {}

TEST_F(CookieMonsterTest, ImportDuplicateCreationTimes_PartitionedCookies) {}

TEST_F(CookieMonsterTest, PredicateSeesAllCookies) {}

// Mainly a test of GetEffectiveDomain, or more specifically, of the
// expected behavior of GetEffectiveDomain within the CookieMonster.
TEST_F(CookieMonsterTest, GetKey) {}

// Test that cookies transfer from/to the backing store correctly.
// TODO(crbug.com/40188414): Include partitioned cookies in this test when we
// start saving them in the persistent store.
TEST_F(CookieMonsterTest, BackingStoreCommunication) {}

TEST_F(CookieMonsterTest, RestoreDifferentCookieSameCreationTime) {}

TEST_F(CookieMonsterTest, CookieListOrdering) {}

// These garbage collection tests and CookieMonstertest.TestGCTimes (in
// cookie_monster_perftest.cc) are somewhat complementary.  These tests probe
// for whether garbage collection always happens when it should (i.e. that we
// actually get rid of cookies when we should).  The perftest is probing for
// whether garbage collection happens when it shouldn't.  See comments
// before that test for more details.

// Check to make sure that a whole lot of recent cookies doesn't get rid of
// anything after garbage collection is checked for.
TEST_F(CookieMonsterTest, GarbageCollectionKeepsRecentEphemeralCookies) {}

// A whole lot of recent cookies; GC shouldn't happen.
TEST_F(CookieMonsterTest, GarbageCollectionKeepsRecentCookies) {}

// Test case where there are more than kMaxCookies - kPurgeCookies recent
// cookies. All old cookies should be garbage collected, all recent cookies
// kept.
TEST_F(CookieMonsterTest, GarbageCollectionKeepsOnlyRecentCookies) {}

// Test case where there are exactly kMaxCookies - kPurgeCookies recent cookies.
// All old cookies should be deleted.
TEST_F(CookieMonsterTest, GarbageCollectionExactlyAllOldCookiesDeleted) {}

// Test case where there are less than kMaxCookies - kPurgeCookies recent
// cookies. Enough old cookies should be deleted to reach kMaxCookies -
// kPurgeCookies total cookies, but no more. Some old cookies should be kept.
TEST_F(CookieMonsterTest, GarbageCollectionTriggers5) {}

// Tests garbage collection when there are only secure cookies.
// See https://crbug/730000
TEST_F(CookieMonsterTest, GarbageCollectWithSecureCookiesOnly) {}

// Tests that if the main load event happens before the loaded event for a
// particular key, the tasks for that key run first.
TEST_F(CookieMonsterTest, WhileLoadingLoadCompletesBeforeKeyLoadCompletes) {}

// Tests that case that DeleteAll is waiting for load to complete, and then a
// get is queued. The get should wait to run until after all the cookies are
// retrieved, and should return nothing, since all cookies were just deleted.
TEST_F(CookieMonsterTest, WhileLoadingDeleteAllGetForURL) {}

// Tests that a set cookie call sandwiched between two get all cookies, all
// before load completes, affects the first but not the second. The set should
// also not trigger a LoadCookiesForKey (As that could complete only after the
// main load for the store).
TEST_F(CookieMonsterTest, WhileLoadingGetAllSetGetAll) {}

namespace {

void RunClosureOnAllCookiesReceived(base::OnceClosure closure,
                                    const CookieList& cookie_list) {}

}  // namespace

// Tests that if a single cookie task is queued as a result of a task performed
// on all cookies when loading completes, it will be run after any already
// queued tasks.
TEST_F(CookieMonsterTest, CheckOrderOfCookieTaskQueueWhenLoadingCompletes) {}

// Test that FlushStore() is forwarded to the store and callbacks are posted.
TEST_F(CookieMonsterTest, FlushStore) {}

TEST_F(CookieMonsterTest, SetAllCookies) {}

// Check that DeleteAll does flush (as a quick check that flush_count() works).
TEST_F(CookieMonsterTest, DeleteAll) {}

TEST_F(CookieMonsterTest, HistogramCheck) {}

TEST_F(CookieMonsterTest, InvalidExpiryTime) {}

// Test that CookieMonster writes session cookies into the underlying
// CookieStore if the "persist session cookies" option is on.
TEST_F(CookieMonsterTest, PersistSessionCookies) {}

// Test the commands sent to the persistent cookie store.
TEST_F(CookieMonsterTest, PersisentCookieStorageTest) {}

// Test to assure that cookies with control characters are purged appropriately.
// See http://crbug.com/238041 for background.
TEST_F(CookieMonsterTest, ControlCharacterPurge) {}

// Test that cookie source schemes are histogrammed correctly.
TEST_F(CookieMonsterTest, CookieSourceHistogram) {}

// Test that inserting the first cookie for a key and deleting the last cookie
// for a key correctly reflected in the Cookie.NumKeys histogram.
TEST_F(CookieMonsterTest, NumKeysHistogram) {}

TEST_F(CookieMonsterTest, CookieCount2Histogram) {}

TEST_F(CookieMonsterTest, CookieJarSizeHistograms) {}

TEST_F(CookieMonsterTest, PartitionedCookieHistograms) {}

TEST_F(CookieMonsterTest, MaxSameSiteNoneCookiesPerKey) {}

// Test that localhost URLs can set and get secure cookies, even if
// non-cryptographic.
TEST_F(CookieMonsterTest, SecureCookieLocalhost) {}

TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) {}

TEST_F(CookieMonsterTest,
       MaybeDeleteEquivalentCookieAndUpdateStatus_PartitionedCookies) {}

// Tests whether cookies that vary based on their source scheme/port are
// overwritten correctly depending on the state of the origin-bound feature
// flags.
class CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus
    : public CookieMonsterTest {};

// Scheme binding disabled.
// Port binding disabled.
// Cookies that differ only in their scheme and/or port should overwrite the
// preexisting cookies.
TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,
       NoSchemeNoPort) {}

// Scheme binding enabled.
// Port binding disabled.
// Cookies that differ in scheme are separate, cookies that differ only by
// port should be overwritten.
TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,
       YesSchemeNoPort) {}

// Scheme binding disabled.
// Port binding enabled.
// Cookies that differ only by scheme and Domain cookies that differ only by
// port should be overwritten. Host cookies that differ only by port are
// separate.
TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,
       NoSchemeYesPort) {}

// Scheme binding enabled.
// Port binding enabled.
// Cookies that differ by port or scheme are separate. Except for Domain cookies
// which will be overwritten if they differ only by port.
TEST_F(CookieMonsterTest_MaybeDeleteEquivalentCookieAndUpdateStatus,
       YesSchemeYesPort) {}

// Tests that only the correct set of (potentially duplicate) cookies are loaded
// from the backend store depending on the state of the origin-bound feature
// flags.
class CookieMonsterTest_StoreLoadedCookies : public CookieMonsterTest {};

// Scheme binding disabled.
// Port binding disabled.
// Only 2 cookies, the most recently created, should exist.
TEST_F(CookieMonsterTest_StoreLoadedCookies, NoSchemeNoPort) {}

// Scheme binding enabled.
// Port binding disabled.
// 4 Cookies should exist.
TEST_F(CookieMonsterTest_StoreLoadedCookies, YesSchemeNoPort) {}

// Scheme binding disabled.
// Port binding enabled.
// 3 Cookies should exist.
TEST_F(CookieMonsterTest_StoreLoadedCookies, NoSchemeYesPort) {}

// Scheme binding enabled.
// Port binding enabled.
// 5 Cookies should exist.
TEST_F(CookieMonsterTest_StoreLoadedCookies, YesSchemeYesPort) {}

// Test skipping a cookie in MaybeDeleteEquivalentCookieAndUpdateStatus for
// multiple reasons (Secure and HttpOnly).
TEST_F(CookieMonsterTest, SkipDontOverwriteForMultipleReasons) {}

// Test that when we check for equivalent cookies, we don't remove any if the
// cookie should not be set.
TEST_F(CookieMonsterTest, DontDeleteEquivalentCookieIfSetIsRejected) {}

TEST_F(CookieMonsterTest, SetSecureCookies) {}

// Tests the behavior of "Leave Secure Cookies Alone" in
// MaybeDeleteEquivalentCookieAndUpdateStatus().
// Check domain-match criterion: If either cookie domain matches the other,
// don't set the insecure cookie.
TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_DomainMatch) {}

// Tests the behavior of "Leave Secure Cookies Alone" in
// MaybeDeleteEquivalentCookieAndUpdateStatus().
// Check path-match criterion: If the new cookie is for the same path or a
// subdirectory of the preexisting cookie's path, don't set the new cookie.
TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_PathMatch) {}

// Tests for behavior for strict secure cookies.
TEST_F(CookieMonsterTest, EvictSecureCookies) {}

// Tests that strict secure cookies doesn't trip equivalent cookie checks
// accidentally. Regression test for https://crbug.com/569943.
TEST_F(CookieMonsterTest, EquivalentCookies) {}

TEST_F(CookieMonsterTest, SetCanonicalCookieDoesNotBlockForLoadAll) {}

TEST_F(CookieMonsterTest, DeleteDuplicateCTime) {}

TEST_F(CookieMonsterTest, DeleteCookieWithInheritedTimestamps) {}

TEST_F(CookieMonsterTest, RejectCreatedSameSiteCookieOnSet) {}

TEST_F(CookieMonsterTest, RejectCreatedSecureCookieOnSet) {}

TEST_F(CookieMonsterTest, RejectCreatedHttpOnlyCookieOnSet) {}

// Test that SameSite=None requires Secure.
TEST_F(CookieMonsterTest, CookiesWithoutSameSiteMustBeSecure) {}

class CookieMonsterNotificationTest : public CookieMonsterTest {};

void RecordCookieChanges(std::vector<CanonicalCookie>* out_cookies,
                         std::vector<CookieChangeCause>* out_causes,
                         const CookieChangeInfo& change) {}

// Tests that there are no changes emitted for cookie loading, but there are
// changes emitted for other operations.
TEST_F(CookieMonsterNotificationTest, NoNotificationOnLoad) {}

class CookieMonsterLegacyCookieAccessTest : public CookieMonsterTest {};

TEST_F(CookieMonsterLegacyCookieAccessTest, SetLegacyNoSameSiteCookie) {}

TEST_F(CookieMonsterLegacyCookieAccessTest, GetLegacyNoSameSiteCookie) {}

TEST_F(CookieMonsterLegacyCookieAccessTest,
       SetLegacySameSiteNoneInsecureCookie) {}

TEST_F(CookieMonsterLegacyCookieAccessTest,
       GetLegacySameSiteNoneInsecureCookie) {}

TEST_F(CookieMonsterTest, IsCookieSentToSamePortThatSetIt) {}

TEST_F(CookieMonsterTest, CookieDomainSetHistogram) {}

TEST_F(CookieMonsterTest, CookiePortReadHistogram) {}

TEST_F(CookieMonsterTest, CookiePortSetHistogram) {}

TEST_F(CookieMonsterTest, CookiePortReadDiffersFromSetHistogram) {}

TEST_F(CookieMonsterTest, CookieSourceSchemeNameHistogram) {}

class FirstPartySetEnabledCookieMonsterTest : public CookieMonsterTest {};

TEST_F(FirstPartySetEnabledCookieMonsterTest, RecordsPeriodicFPSSizes) {}

TEST_F(CookieMonsterTest, GetAllCookiesForURLNonce) {}

TEST_F(CookieMonsterTest, SiteHasCookieInOtherPartition) {}

// Test that domain cookies which shadow origin cookies are excluded when scheme
// binding is enabled.
TEST_F(CookieMonsterTest, FilterCookiesWithOptionsExcludeShadowingDomains) {}

// Test that domain cookies which shadow origin cookies have warnings when
// scheme binding is disabled.
TEST_F(CookieMonsterTest, FilterCookiesWithOptionsWarnShadowingDomains) {}

// This test sets a cookie (only checked using IsCanonicalForFromStorage)
// that's 300 days old and expires in 800 days. It checks that this cookie was
// stored, and then update it. It checks that the updated cookie has the
// creation and expiry dates expected.
TEST_F(CookieMonsterTest, FromStorageCookieCreated300DaysAgoThenUpdatedNow) {}

// This test sets a cookie (only checked using IsCanonicalForFromStorage)
// that's 500 days old and expires in 800 days. It checks that this cookie was
// stored, and then update it. It checks that the updated cookie has the
// creation and expiry dates expected.
TEST_F(CookieMonsterTest, FromStorageCookieCreated500DaysAgoThenUpdatedNow) {}

// This test sets a cookie (checked using IsCanonical) that's 300 days old and
// expires in 800 days. It checks that this cookie was stored, and then update
// it. It checks that the updated cookie has the creation and expiry dates
// expected.
TEST_F(CookieMonsterTest, SanitizedCookieCreated300DaysAgoThenUpdatedNow) {}

// This test sets a cookie (checked using IsCanonical) that's 500 days old and
// expires in 800 days. It checks that this cookie was stored, and then update
// it. It checks that the updated cookie has the creation and expiry dates
// expected.
TEST_F(CookieMonsterTest, SanitizedCookieCreated500DaysAgoThenUpdatedNow) {}

INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();

}  // namespace net