[Extensions] Add browser tests for extension web storage data retention [chromium/src : main]

0 views
Skip to first unread message

Simeon Vincent (Gerrit)

unread,
Jun 1, 2026, 6:50:20 PMJun 1
to chromium...@chromium.org, chromium-a...@chromium.org, dullweb...@chromium.org, extension...@chromium.org, msrame...@chromium.org

New activity on the change

Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: I37989af007f05b9fb05da025b03085b2e5c747b0
Gerrit-Change-Number: 7884253
Gerrit-PatchSet: 2
Gerrit-Owner: Simeon Vincent <sim...@chromium.org>
Gerrit-Comment-Date: Mon, 01 Jun 2026 22:50:08 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Simeon Vincent (Gerrit)

unread,
Jun 1, 2026, 7:23:45 PMJun 1
to Justin Lulejian, Chromium LUCI CQ, chromium...@chromium.org, chromium-a...@chromium.org, dullweb...@chromium.org, extension...@chromium.org, msrame...@chromium.org
Attention needed from Justin Lulejian

Simeon Vincent added 1 comment

Patchset-level comments
File-level comment, Patchset 2 (Latest):
Simeon Vincent . resolved

Tim mentioned that you were working on some adjacent Web Platform Tests work. I'd appreciate it if you could take a high level look at this CL to make sure it's in reasonable shape before I reach out to the owners of the systems under test here.

Open in Gerrit

Related details

Attention is currently required from:
  • Justin Lulejian
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: I37989af007f05b9fb05da025b03085b2e5c747b0
Gerrit-Change-Number: 7884253
Gerrit-PatchSet: 2
Gerrit-Owner: Simeon Vincent <sim...@chromium.org>
Gerrit-Reviewer: Justin Lulejian <jlul...@chromium.org>
Gerrit-Reviewer: Simeon Vincent <sim...@chromium.org>
Gerrit-Attention: Justin Lulejian <jlul...@chromium.org>
Gerrit-Comment-Date: Mon, 01 Jun 2026 23:23:34 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Simeon Vincent (Gerrit)

unread,
Jun 3, 2026, 4:59:42 PMJun 3
to Devlin Cronin, Justin Lulejian, Chromium LUCI CQ, chromium...@chromium.org, chromium-a...@chromium.org, dullweb...@chromium.org, extension...@chromium.org, msrame...@chromium.org
Attention needed from Devlin Cronin and Justin Lulejian

Simeon Vincent added 1 comment

Patchset-level comments
Simeon Vincent . resolved

Devlin, please take a look at the overall structure and approach here. Once you're happy with the general shape of the new tests, I'll tag in reviewers for the related systems under test.

Open in Gerrit

Related details

Attention is currently required from:
  • Devlin Cronin
  • Justin Lulejian
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: I37989af007f05b9fb05da025b03085b2e5c747b0
Gerrit-Change-Number: 7884253
Gerrit-PatchSet: 2
Gerrit-Owner: Simeon Vincent <sim...@chromium.org>
Gerrit-Reviewer: Devlin Cronin <rdevlin...@chromium.org>
Gerrit-Reviewer: Justin Lulejian <jlul...@chromium.org>
Gerrit-Reviewer: Simeon Vincent <sim...@chromium.org>
Gerrit-Attention: Devlin Cronin <rdevlin...@chromium.org>
Gerrit-Attention: Justin Lulejian <jlul...@chromium.org>
Gerrit-Comment-Date: Wed, 03 Jun 2026 20:59:29 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Devlin Cronin (Gerrit)

unread,
Jun 4, 2026, 4:17:57 PMJun 4
to Simeon Vincent, Devlin Cronin, Justin Lulejian, Chromium LUCI CQ, chromium...@chromium.org, chromium-a...@chromium.org, dullweb...@chromium.org, extension...@chromium.org, msrame...@chromium.org
Attention needed from Justin Lulejian and Simeon Vincent

Devlin Cronin added 18 comments

Patchset-level comments
Devlin Cronin . resolved

Thanks, Simeon! This is a great start!

File chrome/browser/extensions/browsing_data_test_utils.h
Line 16, Patchset 2 (Latest):void CreateLocalStorageForKey(Profile* profile, const blink::StorageKey& key);
Devlin Cronin . unresolved

nit 1: put these in a namespace, e.g. browsing_data_test_utils
nit 2: add function comments describing what these do

File chrome/browser/extensions/browsing_data_test_utils.cc
Line 14, Patchset 2 (Latest):// #include "testing/gtest/include/gtest/gtest.h" // Not required?
Devlin Cronin . unresolved

clean up unused includes

Line 46, Patchset 2 (Latest): auto it = std::ranges::find_if(
usage_infos, [&key](const storage::mojom::StorageUsageInfoPtr& info) {
return info->storage_key == key;
});
return it != usage_infos.end();
Devlin Cronin . unresolved

nit: simpler to use std::ranges::any_of (though I know this was largely cut-and-paste)

File chrome/browser/extensions/extension_web_storage_durability_browsertest.cc
Line 5, Patchset 2 (Latest):// This file contains tests that verify how web storage (local storage,
Devlin Cronin . unresolved

nit: prefer placing this lower -- maybe below the static assert, or maybe above the test fixture definition (around line 64)

Line 61, Patchset 2 (Latest): req.onerror = () => { resolve() };
Devlin Cronin . unresolved

should this throw an error? It seems like we shouldn't expect errors from IDB

Line 74, Patchset 2 (Latest): // web origin handling.
Devlin Cronin . unresolved

nit: function comments should be descriptive, rather than imperative. "Retrieves the storage..."

Line 79, Patchset 2 (Latest): // Retrieve the storage key of the text extension
Devlin Cronin . unresolved

nit: comments should end in a period

Line 80, Patchset 2 (Latest): static blink::StorageKey GetExtStorageKey(const Extension* extension) {
Devlin Cronin . unresolved

nit: avoid uncommon abbreviations in the code -- prefer "Extension"

Line 82, Patchset 2 (Latest): return blink::StorageKey::CreateFirstParty(url::Origin::Create(ext_url));
Devlin Cronin . unresolved

nit: simpler: `extension->origin()`

Line 101, Patchset 2 (Latest): return nullptr;
Devlin Cronin . unresolved

nit: add something like `ADD_FAILURE() << "Failed to load extension."`

Line 118, Patchset 2 (Latest): content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(
[](storage::QuotaManager* qm,
scoped_refptr<base::SequencedTaskRunner> reply_runner,
std::set<storage::BucketLocator>* result,
base::OnceClosure quit) {
qm->GetEvictionBuckets(
INT64_MAX,
base::BindPostTask(
std::move(reply_runner),
base::BindOnce(
[](std::set<storage::BucketLocator>* result,
base::OnceClosure quit,
const std::set<storage::BucketLocator>& buckets) {
*result = buckets;
std::move(quit).Run();
},
result, std::move(quit))));
},
base::Unretained(qm), std::move(ui_runner), &result,
run_loop.QuitClosure()));
Devlin Cronin . unresolved

nit: let's pull these two lambdas into separate variables to help reduce some of the callback nesting here

Line 193, Patchset 2 (Latest):// TODO(simeonv): Add packaged apps to the test. See
Devlin Cronin . unresolved

packaged apps are very, very deprecated. We shouldn't be adding them anywhere

Line 199, Patchset 2 (Latest): ChromeBrowsingData_DefaultOriginTypes) {
Devlin Cronin . unresolved

for these, please add test comments briefly describing what they do. Your ones above the tests above are great.

Line 214, Patchset 2 (Latest): EXPECT_FALSE(api_test_utils::RunFunctionAndReturnSingleResult(
Devlin Cronin . unresolved

optional: I'd maybe lean towards using the browser data remover code directly instead of going through the extension API, unless you explicitly wanted to exercise "another extension calls chrome.browsingData.remove()" -- in which case, I'd suggest having a second extension directly, rather than anonymously invoking the function. But I don't feel terribly strongly.

Line 217, Patchset 2 (Latest): usage_infos = GetLocalStorage(profile());
EXPECT_TRUE(UsageInfosHasStorageKey(usage_infos, ext_key));
EXPECT_FALSE(UsageInfosHasStorageKey(usage_infos, web_key));
Devlin Cronin . unresolved

Food for thought: for all these tests, I would personally lean towards having them be more end-to-end-y, testing behavior from the extensions POV. In particular, I would lean towards something like:

  • Set a variable in local storage in JS
  • Maybe-clear
  • Fetch variable from local storage in JS
  • Expect variable present or not

If you wanted to go that route, BackgroundScriptExecutor is probably your friend.

That's a bit more clear as to the implication of this, and IMO is more robust than checking that there is a storage key (which is origin-based, and less obvious about the data actually stored in it).

WDYT?

Line 391, Patchset 2 (Latest): for (const auto& entry : *model) {
url::Origin entry_origin =
BrowsingDataModel::GetOriginForDataKey(*entry.data_key);
EXPECT_NE(entry_origin, ext_origin)
<< "Extension origin unexpectedly found in BrowsingDataModel: "
<< entry_origin;
}
Devlin Cronin . unresolved

code coverage indicates the body of this is never being reached -- so model is empty. Is that expected?

Line 416, Patchset 2 (Latest):
base::RunLoop run_loop;
profile()->GetDefaultStoragePartition()->ClearData(
content::StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE, ext_key,
base::Time(), base::Time::Max(), run_loop.QuitClosure());
run_loop.Run();
Devlin Cronin . unresolved

nit: might be more clear to pull this out into a helper function

Open in Gerrit

Related details

Attention is currently required from:
  • Justin Lulejian
  • Simeon Vincent
Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I37989af007f05b9fb05da025b03085b2e5c747b0
    Gerrit-Change-Number: 7884253
    Gerrit-PatchSet: 2
    Gerrit-Owner: Simeon Vincent <sim...@chromium.org>
    Gerrit-Reviewer: Devlin Cronin <rdevlin...@chromium.org>
    Gerrit-Reviewer: Justin Lulejian <jlul...@chromium.org>
    Gerrit-Reviewer: Simeon Vincent <sim...@chromium.org>
    Gerrit-Attention: Justin Lulejian <jlul...@chromium.org>
    Gerrit-Attention: Simeon Vincent <sim...@chromium.org>
    Gerrit-Comment-Date: Thu, 04 Jun 2026 20:17:42 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Simeon Vincent (Gerrit)

    unread,
    Jun 11, 2026, 4:54:57 PMJun 11
    to Devlin Cronin, Justin Lulejian, Chromium LUCI CQ, chromium...@chromium.org, chromium-a...@chromium.org, dullweb...@chromium.org, extension...@chromium.org, msrame...@chromium.org
    Attention needed from Devlin Cronin and Justin Lulejian

    Simeon Vincent added 18 comments

    Patchset-level comments
    File-level comment, Patchset 2:
    Simeon Vincent . resolved

    This this patchset addresses most of the feedback on the CL. I'm going to tackle refactoring the [`browserData.remove` tests feedback](https://chromium-review.googlesource.com/c/chromium/src/+/7884253/comment/7c899c56_8156213a/) in a follow-up.

    File chrome/browser/extensions/browsing_data_test_utils.h
    Line 16, Patchset 2:void CreateLocalStorageForKey(Profile* profile, const blink::StorageKey& key);
    Devlin Cronin . resolved

    nit 1: put these in a namespace, e.g. browsing_data_test_utils
    nit 2: add function comments describing what these do

    Simeon Vincent

    Acknowledged

    File chrome/browser/extensions/browsing_data_test_utils.cc
    Line 14, Patchset 2:// #include "testing/gtest/include/gtest/gtest.h" // Not required?
    Devlin Cronin . resolved

    clean up unused includes

    Simeon Vincent

    I shouldn't have commented these out.

    • `testing/gtest/include/gtest/gtest.h` is used by `ASSERT_TRUE` and `ASSERT_FALSE` statements
    • `third_party/blink/public/common/storage_key/storage_key.h` is used by `blink::StorageKey`

    I did another pass on the includes and added a couple of files for resources that were previously used but not directly included.

    Line 46, Patchset 2: auto it = std::ranges::find_if(

    usage_infos, [&key](const storage::mojom::StorageUsageInfoPtr& info) {
    return info->storage_key == key;
    });
    return it != usage_infos.end();
    Devlin Cronin . resolved

    nit: simpler to use std::ranges::any_of (though I know this was largely cut-and-paste)

    Simeon Vincent

    Acknowledged

    File chrome/browser/extensions/extension_web_storage_durability_browsertest.cc
    Line 5, Patchset 2:// This file contains tests that verify how web storage (local storage,
    Devlin Cronin . resolved

    nit: prefer placing this lower -- maybe below the static assert, or maybe above the test fixture definition (around line 64)

    Simeon Vincent

    Acknowledged. I opted to move it after the `static_assert` rather than just above the text fixture because I figured this was describing the contents of the file rather than that specific fixture.

    Line 61, Patchset 2: req.onerror = () => { resolve() };
    Devlin Cronin . resolved

    should this throw an error? It seems like we shouldn't expect errors from IDB

    Simeon Vincent

    Acknowledged

    Line 74, Patchset 2: // web origin handling.
    Devlin Cronin . resolved

    nit: function comments should be descriptive, rather than imperative. "Retrieves the storage..."

    Simeon Vincent

    I've updated this comment and the comments on other methods in this class.

    Line 79, Patchset 2: // Retrieve the storage key of the text extension
    Devlin Cronin . resolved

    nit: comments should end in a period

    Simeon Vincent

    Acknowledged

    Line 80, Patchset 2: static blink::StorageKey GetExtStorageKey(const Extension* extension) {
    Devlin Cronin . resolved

    nit: avoid uncommon abbreviations in the code -- prefer "Extension"

    Simeon Vincent

    Acknowledged. Renamed to `GetExtensionStorageKey`.

    Line 82, Patchset 2: return blink::StorageKey::CreateFirstParty(url::Origin::Create(ext_url));
    Devlin Cronin . resolved

    nit: simpler: `extension->origin()`

    Simeon Vincent

    Acknowledged

    Line 101, Patchset 2: return nullptr;
    Devlin Cronin . resolved

    nit: add something like `ADD_FAILURE() << "Failed to load extension."`

    Simeon Vincent

    Acknowledged

    Line 118, Patchset 2: content::GetIOThreadTaskRunner({})->PostTask(

    FROM_HERE,
    base::BindOnce(
    [](storage::QuotaManager* qm,
    scoped_refptr<base::SequencedTaskRunner> reply_runner,
    std::set<storage::BucketLocator>* result,
    base::OnceClosure quit) {
    qm->GetEvictionBuckets(
    INT64_MAX,
    base::BindPostTask(
    std::move(reply_runner),
    base::BindOnce(
    [](std::set<storage::BucketLocator>* result,
    base::OnceClosure quit,
    const std::set<storage::BucketLocator>& buckets) {
    *result = buckets;
    std::move(quit).Run();
    },
    result, std::move(quit))));
    },
    base::Unretained(qm), std::move(ui_runner), &result,
    run_loop.QuitClosure()));
    Devlin Cronin . resolved

    nit: let's pull these two lambdas into separate variables to help reduce some of the callback nesting here

    Simeon Vincent

    Acknowledged

    Line 193, Patchset 2:// TODO(simeonv): Add packaged apps to the test. See
    Devlin Cronin . resolved

    packaged apps are very, very deprecated. We shouldn't be adding them anywhere

    Simeon Vincent

    Acknowledged. I've removed this TODO.

    Line 199, Patchset 2: ChromeBrowsingData_DefaultOriginTypes) {
    Devlin Cronin . resolved

    for these, please add test comments briefly describing what they do. Your ones above the tests above are great.

    Simeon Vincent

    Acknowledged

    Line 214, Patchset 2: EXPECT_FALSE(api_test_utils::RunFunctionAndReturnSingleResult(
    Devlin Cronin . unresolved

    optional: I'd maybe lean towards using the browser data remover code directly instead of going through the extension API, unless you explicitly wanted to exercise "another extension calls chrome.browsingData.remove()" -- in which case, I'd suggest having a second extension directly, rather than anonymously invoking the function. But I don't feel terribly strongly.

    Simeon Vincent

    Makes sense to me.

    Line 217, Patchset 2: usage_infos = GetLocalStorage(profile());
    EXPECT_TRUE(UsageInfosHasStorageKey(usage_infos, ext_key));
    EXPECT_FALSE(UsageInfosHasStorageKey(usage_infos, web_key));
    Devlin Cronin . unresolved

    Food for thought: for all these tests, I would personally lean towards having them be more end-to-end-y, testing behavior from the extensions POV. In particular, I would lean towards something like:

    • Set a variable in local storage in JS
    • Maybe-clear
    • Fetch variable from local storage in JS
    • Expect variable present or not

    If you wanted to go that route, BackgroundScriptExecutor is probably your friend.

    That's a bit more clear as to the implication of this, and IMO is more robust than checking that there is a storage key (which is origin-based, and less obvious about the data actually stored in it).

    WDYT?

    Simeon Vincent

    That makes sense. My main hestiation is that it's not clear how to implement this in a browsertest, since serviceworkers don't have access to Local Storage, which is currently being used in the test.

    I'll take a shot at it in my next patchset.

    Line 391, Patchset 2: for (const auto& entry : *model) {

    url::Origin entry_origin =
    BrowsingDataModel::GetOriginForDataKey(*entry.data_key);
    EXPECT_NE(entry_origin, ext_origin)
    << "Extension origin unexpectedly found in BrowsingDataModel: "
    << entry_origin;
    }
    Devlin Cronin . resolved

    code coverage indicates the body of this is never being reached -- so model is empty. Is that expected?

    Simeon Vincent

    Yes, but in retrospect that's a bit odd. I've updated the test to also include a web origin to ensure that the model isn't empty.


    base::RunLoop run_loop;
    profile()->GetDefaultStoragePartition()->ClearData(
    content::StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE, ext_key,
    base::Time(), base::Time::Max(), run_loop.QuitClosure());
    run_loop.Run();
    Devlin Cronin . resolved

    nit: might be more clear to pull this out into a helper function

    Simeon Vincent

    Acknowledged. This has been moved into a new "ClearStorageKeyFromDefaultStoragePartition" helper.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Devlin Cronin
    • Justin Lulejian
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: I37989af007f05b9fb05da025b03085b2e5c747b0
    Gerrit-Change-Number: 7884253
    Gerrit-PatchSet: 2
    Gerrit-Owner: Simeon Vincent <sim...@chromium.org>
    Gerrit-Reviewer: Devlin Cronin <rdevlin...@chromium.org>
    Gerrit-Reviewer: Justin Lulejian <jlul...@chromium.org>
    Gerrit-Reviewer: Simeon Vincent <sim...@chromium.org>
    Gerrit-Attention: Devlin Cronin <rdevlin...@chromium.org>
    Gerrit-Attention: Justin Lulejian <jlul...@chromium.org>
    Gerrit-Comment-Date: Thu, 11 Jun 2026 20:54:40 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Devlin Cronin <rdevlin...@chromium.org>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Simeon Vincent (Gerrit)

    unread,
    Jun 13, 2026, 3:53:28 AM (13 days ago) Jun 13
    to Devlin Cronin, Justin Lulejian, Chromium LUCI CQ, chromium...@chromium.org, chromium-a...@chromium.org, dullweb...@chromium.org, extension...@chromium.org, msrame...@chromium.org
    Attention needed from Devlin Cronin and Justin Lulejian

    Simeon Vincent added 2 comments

    File chrome/browser/extensions/extension_web_storage_durability_browsertest.cc
    Line 214, Patchset 2: EXPECT_FALSE(api_test_utils::RunFunctionAndReturnSingleResult(
    Devlin Cronin . resolved

    optional: I'd maybe lean towards using the browser data remover code directly instead of going through the extension API, unless you explicitly wanted to exercise "another extension calls chrome.browsingData.remove()" -- in which case, I'd suggest having a second extension directly, rather than anonymously invoking the function. But I don't feel terribly strongly.

    Simeon Vincent

    Makes sense to me.

    Simeon Vincent

    Addressed in patchset 7.

    Line 217, Patchset 2: usage_infos = GetLocalStorage(profile());
    EXPECT_TRUE(UsageInfosHasStorageKey(usage_infos, ext_key));
    EXPECT_FALSE(UsageInfosHasStorageKey(usage_infos, web_key));
    Devlin Cronin . resolved

    Food for thought: for all these tests, I would personally lean towards having them be more end-to-end-y, testing behavior from the extensions POV. In particular, I would lean towards something like:

    • Set a variable in local storage in JS
    • Maybe-clear
    • Fetch variable from local storage in JS
    • Expect variable present or not

    If you wanted to go that route, BackgroundScriptExecutor is probably your friend.

    That's a bit more clear as to the implication of this, and IMO is more robust than checking that there is a storage key (which is origin-based, and less obvious about the data actually stored in it).

    WDYT?

    Simeon Vincent

    That makes sense. My main hestiation is that it's not clear how to implement this in a browsertest, since serviceworkers don't have access to Local Storage, which is currently being used in the test.

    I'll take a shot at it in my next patchset.

    Simeon Vincent

    Addressed in patchset 7.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Devlin Cronin
    • Justin Lulejian
    Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement is not satisfiedCode-Owners
      • requirement is not satisfiedCode-Review
      • requirement is not satisfiedReview-Enforcement
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: I37989af007f05b9fb05da025b03085b2e5c747b0
      Gerrit-Change-Number: 7884253
      Gerrit-PatchSet: 7
      Gerrit-Owner: Simeon Vincent <sim...@chromium.org>
      Gerrit-Reviewer: Devlin Cronin <rdevlin...@chromium.org>
      Gerrit-Reviewer: Justin Lulejian <jlul...@chromium.org>
      Gerrit-Reviewer: Simeon Vincent <sim...@chromium.org>
      Gerrit-Attention: Devlin Cronin <rdevlin...@chromium.org>
      Gerrit-Attention: Justin Lulejian <jlul...@chromium.org>
      Gerrit-Comment-Date: Sat, 13 Jun 2026 07:53:06 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Comment-In-Reply-To: Devlin Cronin <rdevlin...@chromium.org>
      Comment-In-Reply-To: Simeon Vincent <sim...@chromium.org>
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy

      Justin Lulejian (Gerrit)

      unread,
      Jun 18, 2026, 4:57:53 PM (8 days ago) Jun 18
      to Simeon Vincent, Devlin Cronin, Chromium LUCI CQ, chromium...@chromium.org, chromium-a...@chromium.org, dullweb...@chromium.org, extension...@chromium.org, msrame...@chromium.org
      Attention needed from Devlin Cronin and Simeon Vincent

      Justin Lulejian added 10 comments

      Patchset-level comments
      File-level comment, Patchset 8 (Latest):
      Justin Lulejian . resolved

      Hi Simeon! Thanks for sending this. Did an initial pass. Apologies this didn't show up in my review notifications for some reason.

      File chrome/browser/extensions/browsing_data_test_utils.h
      Line 20, Patchset 8 (Latest):// Initialize a minimal localStorage area for |key| in |profile|'s default
      Justin Lulejian . unresolved

      ```suggestion
      // Initialize a minimal localStorage area for `key` in `profile`'s default
      ```

      here and elsewhere.

      File chrome/browser/extensions/browsing_data_test_utils.cc
      Line 29, Patchset 8 (Latest): area->Put({'k', 'e', 'y'}, {'v', 'a', 'l', 'u', 'e'}, std::nullopt,
      Justin Lulejian . unresolved
      ```suggestion
      area->Put({'k', 'e', 'y'}, {'v', 'a', 'l', 'u', 'e'},/*<param>=*/std::nullopt,
      ```
      File chrome/browser/extensions/extension_web_storage_durability_browsertest.cc
      Line 58, Patchset 8 (Latest):constexpr char kBackgroundInitIdb[] = R"(
      new Promise(resolve => {
      const req = indexedDB.open('test-db', 1);
      req.onsuccess = () => { req.result.close(); resolve(); };
      req.onerror = () => { chrome.test.fail("IDB Error: " + err.toString()); };
      }).then(() => chrome.test.sendMessage('idb-ready'));
      )";
      Justin Lulejian . unresolved

      Since only used in `LoadTestExtensionWithIdb` we can move this there?

      Line 125, Patchset 8 (Latest): void BrowsingDataRemoverCallRemove(const Extension* extension,
      const std::string& options_json,
      const std::string& data_types_json) {
      const std::string& script =
      "chrome.browsingData.remove(" + options_json + ", " + data_types_json +
      ", () => chrome.test.sendScriptResult('done'));";

      base::Value value = BackgroundScriptExecutor::ExecuteScript(
      profile(), extension->id(), script,
      BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
      }
      Justin Lulejian . unresolved

      A bit of a nit, but I don't see the 'done' being validated.

      ```suggestion
      bool BrowsingDataRemoverCallRemove(const Extension* extension,
      const std::string& options_json,
      const std::string& data_types_json) {
      const std::string& script =
      "chrome.browsingData.remove(" + options_json + ", " + data_types_json +
      ", () => chrome.test.sendScriptResult('done'));";
          base::Value value = BackgroundScriptExecutor::ExecuteScript(
      profile(), extension->id(), script,
      BackgroundScriptExecutor::ResultCapture::kSendScriptResult);

      return value == "done";
      }
      ```

      Then usage:

      ```
      bool data_removed = BrowsingDataRemoverCallRemove(...);
      ASSERT_TRUE(data_removed);
      ```

      Line 139, Patchset 8 (Latest): R"(setTimeout(async () => {
      Justin Lulejian . unresolved

      Is the wrapping `setTimeout` actually necessary?

      Line 170, Patchset 8 (Latest): // Retrieve a set of buckets that QuotaManagerImpl can delete when under
      Justin Lulejian . unresolved
      ```suggestion
      // Retrieve a set of buckets that `QuotaManagerImpl` can delete when under
      ```

      here and other places where comments refer to code symbols to be consistent with the rest of the comments.

      Line 173, Patchset 8 (Latest): storage::QuotaManager* qm =
      profile()->GetDefaultStoragePartition()->GetQuotaManager();
      std::set<storage::BucketLocator> result;
      base::RunLoop run_loop;

      scoped_refptr<base::SequencedTaskRunner> ui_runner =
      base::SequencedTaskRunner::GetCurrentDefault();

      auto on_got_eviction_buckets = base::BindOnce(

      [](std::set<storage::BucketLocator>* result, base::OnceClosure quit,
      const std::set<storage::BucketLocator>& buckets) {
      *result = buckets;
      std::move(quit).Run();
      },
      &result, run_loop.QuitClosure());

      auto get_eviction_buckets = base::BindOnce(

      [](storage::QuotaManager* qm,
      scoped_refptr<base::SequencedTaskRunner> reply_runner,
      base::OnceCallback<void(const std::set<storage::BucketLocator>&)>
      on_got) {
      qm->GetEvictionBuckets(
      INT64_MAX,
      base::BindPostTask(std::move(reply_runner), std::move(on_got)));

      },
      base::Unretained(qm), std::move(ui_runner),
      Justin Lulejian . unresolved

      Is it possible to pass `qm` as a scoped_refptr?

      ```suggestion
      scoped_refptr<storage::QuotaManager> qm =
      base::WrapRefCounted(profile()->GetDefaultStoragePartition()->GetQuotaManager());
      std::set<storage::BucketLocator> result;
      base::RunLoop run_loop;
          scoped_refptr<base::SequencedTaskRunner> ui_runner =
      base::SequencedTaskRunner::GetCurrentDefault();
          auto on_got_eviction_buckets = base::BindOnce(

      [](std::set<storage::BucketLocator>* result, base::OnceClosure quit,
      const std::set<storage::BucketLocator>& buckets) {
      *result = buckets;
      std::move(quit).Run();
      },
              &result, run_loop.QuitClosure());
          auto get_eviction_buckets = base::BindOnce(

      [](storage::QuotaManager* qm,
      scoped_refptr<base::SequencedTaskRunner> reply_runner,
                 base::OnceCallback<void(const std::set<storage::BucketLocator>&)>
      on_got) {
      qm->GetEvictionBuckets(
      INT64_MAX,
      base::BindPostTask(std::move(reply_runner), std::move(on_got)));
      },
      qm, std::move(ui_runner),
      ```
      Line 204, Patchset 8 (Latest): run_loop.Run();
      Justin Lulejian . unresolved

      wrap waits with `SCOPED_TRACE("<what is being waited for>")` so that if the test fails/flakes later the future reviewer will get more immediate context.

      Line 480, Patchset 8 (Latest):IN_PROC_BROWSER_TEST_F(ExtensionWebStorageDurabilityTest, GetLocalStorageData) {
      Justin Lulejian . unresolved

      ```suggestion
      IN_PROC_BROWSER_TEST_F(ExtensionWebStorageDurabilityTest, StoragePartitionClearData_ExtensionWithUnlimitedStorage) {
      ```

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Devlin Cronin
      • Simeon Vincent
      Submit Requirements:
        • requirement satisfiedCode-Coverage
        • requirement is not satisfiedCode-Owners
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: chromium/src
        Gerrit-Branch: main
        Gerrit-Change-Id: I37989af007f05b9fb05da025b03085b2e5c747b0
        Gerrit-Change-Number: 7884253
        Gerrit-PatchSet: 8
        Gerrit-Owner: Simeon Vincent <sim...@chromium.org>
        Gerrit-Reviewer: Devlin Cronin <rdevlin...@chromium.org>
        Gerrit-Reviewer: Justin Lulejian <jlul...@chromium.org>
        Gerrit-Reviewer: Simeon Vincent <sim...@chromium.org>
        Gerrit-Attention: Devlin Cronin <rdevlin...@chromium.org>
        Gerrit-Attention: Simeon Vincent <sim...@chromium.org>
        Gerrit-Comment-Date: Thu, 18 Jun 2026 20:57:41 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: No
        satisfied_requirement
        unsatisfied_requirement
        open
        diffy

        Devlin Cronin (Gerrit)

        unread,
        Jun 25, 2026, 3:55:09 PM (15 hours ago) Jun 25
        to Simeon Vincent, Devlin Cronin, Justin Lulejian, Chromium LUCI CQ, chromium...@chromium.org, chromium-a...@chromium.org, dullweb...@chromium.org, extension...@chromium.org, msrame...@chromium.org
        Attention needed from Simeon Vincent

        Devlin Cronin added 8 comments

        Patchset-level comments
        Devlin Cronin . resolved

        Thanks, Simeon!

        File chrome/browser/extensions/browsing_data_test_utils.cc
        Line 46, Patchset 2: auto it = std::ranges::find_if(
        usage_infos, [&key](const storage::mojom::StorageUsageInfoPtr& info) {
        return info->storage_key == key;
        });
        return it != usage_infos.end();
        Devlin Cronin . unresolved

        nit: simpler to use std::ranges::any_of (though I know this was largely cut-and-paste)

        Simeon Vincent

        Acknowledged

        Devlin Cronin

        General note: "Acknowledged" is usually used for "There was no action taken, but I read the comment". "Done" is used for "I changed the code as requested".

        (So for this comment now, "Acknowledged" makes sense : ))

        File chrome/browser/extensions/extension_web_storage_durability_browsertest.cc
        Line 128, Patchset 8 (Latest): const std::string& script =

        "chrome.browsingData.remove(" + options_json + ", " + data_types_json +
        ", () => chrome.test.sendScriptResult('done'));";
        Devlin Cronin . unresolved
        nit1: prefer composing with base::StringPrintf() instead of +.
        nit2: prefer promises?
        ```
        static constexpr char kScriptTemplate =
        "chrome.browsingData.remove(%s, %s).then(() => chrome.test.sendScriptResult('done'));";
        std::string script = base::StringPrintf(kScriptTemplate, options_json.c_str(), data_types_json.c_str());
        ```
        Line 173, Patchset 8 (Latest): storage::QuotaManager* qm =
        Devlin Cronin . unresolved

        avoid uncommon abbreviations. Let's just spell out quota_manager.

        Devlin Cronin

        Not likely any need to, since this is all local and "synchronous" in a test-only file.

        Instead, I'd just drop the Unretained()s. They're not necessary.

        Line 270, Patchset 8 (Latest):// calls `chrome.browsingData()` with default `originTypes`.
        Devlin Cronin . unresolved

        chrome.browsingData.remove()?

        Line 374, Patchset 8 (Latest): auto usageInfo = utils::GetLocalStorageInfo(profile());
        Devlin Cronin . unresolved

        usage_info

        Line 444, Patchset 8 (Latest): // Verify that the extension origin doesn't own any entries in the model.

        for (const auto& entry : *model) {
        url::Origin entry_origin =
        BrowsingDataModel::GetOriginForDataKey(*entry.data_key);
        EXPECT_NE(entry_origin, ext_origin)
        << "Extension origin unexpectedly found in BrowsingDataModel: "
        << entry_origin;
        }
        Devlin Cronin . unresolved

        given the above, we know there's only one entry here -- let's just flip the EXPECT_EQ to ASSERT_EQ and then access the only element directly instead of having a for-loop

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Simeon Vincent
        Submit Requirements:
        • requirement satisfiedCode-Coverage
        • requirement is not satisfiedCode-Owners
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: chromium/src
        Gerrit-Branch: main
        Gerrit-Change-Id: I37989af007f05b9fb05da025b03085b2e5c747b0
        Gerrit-Change-Number: 7884253
        Gerrit-PatchSet: 8
        Gerrit-Owner: Simeon Vincent <sim...@chromium.org>
        Gerrit-Reviewer: Devlin Cronin <rdevlin...@chromium.org>
        Gerrit-Reviewer: Justin Lulejian <jlul...@chromium.org>
        Gerrit-Reviewer: Simeon Vincent <sim...@chromium.org>
        Gerrit-Attention: Simeon Vincent <sim...@chromium.org>
        Gerrit-Comment-Date: Thu, 25 Jun 2026 19:54:56 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: No
        Comment-In-Reply-To: Devlin Cronin <rdevlin...@chromium.org>
        Comment-In-Reply-To: Justin Lulejian <jlul...@chromium.org>
        Comment-In-Reply-To: Simeon Vincent <sim...@chromium.org>
        satisfied_requirement
        unsatisfied_requirement
        open
        diffy
        Reply all
        Reply to author
        Forward
        0 new messages