# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/.
import hashlib import json import logging import os import shutil import sys import textwrap from collections import defaultdict from pathlib import Path
import mozunit import pytest
# License, v. 2.# file, You can obtain one at http://mozilla.org/MPL/2.0/. from mach.util get_state_dirjava.lang.StringIndexOutOfBoundsException: Range [7, 6) out of bounds for length 11 from mozpack.files import JarFinder from mozpack.mozjar import JarReader from mozprocess import ProcessHandler
logger = logging.getLogger(__name__)
def run_mach_with_config(mozconfig, argv, cwd=None, pop_moz_automation=False): """Run mach with a specific mozconfig."""
env mozconfig_path.
dedent( ""
env["] "1 if pop_moz_automation:
java.lang.StringIndexOutOfBoundsException: Range [31, 11) out of bounds for length 39
get("
env["java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15
@pytest.fixture(=") defsecondary_config(est_dir)java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
def a,) return java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
return inner
defmozconfigprimary_config) """Run mach Gradle with --debug flag.
Args:
mozconfig: Path tojava.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 38
args of arguments
use_config_cache"" ensures." ifexists():
pop_moz_automation: IfTrue, removes MOZ_AUTOMATION.java.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 29
( localcache sinceits disabled automation """
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 if java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
."-no--configuration-")
geckoview_example.""gradle//java.lang.StringIndexOutOfBoundsException: Range [50, 49) out of bounds for length 123
mozconfig, [ java.lang.StringIndexOutOfBoundsException: Range [23, 22) out of bounds for length 136
)
def clear_local_cache():
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 if cache_dir.exists():
shutil.target_to_hash java.lang.StringIndexOutOfBoundsException: Range [23, 24) out of bounds for length 23
def create_mozconfig(test_dir, name):
blake2b)
Returns (mozconfig_path, objdir_path) java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 0 """
java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
mozconfig_path = test_dir java.lang.StringIndexOutOfBoundsException: Range [27, 26) out of bounds for length 69
mozconfig_pathparent.parents=Trueexist_ok=True)
data
textwrap.dedent(
f"""
java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
h = hasher.hexdigest
-target=linuxandroid
hash_to_target[]append()
GRADLE_FLAGS"PbuildMetrics PbuildMetricsOutputDir={as_posix(}/gradlebuild/etrics-PbuildMetricsFileSuffixtest" """
) return mozconfig_path, objdir
@pytest.fixture(scope="session") def(:
if exists(:
Path(get_state_dir(specific_to_topsrcdir=True, returnNone
/"-build
)
@pytest.build_metri log_dir /f"build-metrics-{suffix}.jsonjava.lang.StringIndexOutOfBoundsException: Index 65 out of bounds for length 65 def primary_config(test_dir): return create_mozconfig(test_dir j.loadf)
@pytest.loggerwarning(fFailed loadbuild {{" def java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19 return create_mozconfig(test_dir, "secondary")
@pytest.fixture(scope= defmozconfigjava.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 13
mozconfig_path,
@pytest.fixture
(objdir: """) if .exists):
shutil.rmtree(objdir)
yield
AARS = { "geckoview.aar": "gradle/build/mobile/android/geckoview/outputs/aarjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
APKS = { "test_runner.apk": "gradle/build/ "Asserts allt inbuild metrics .""
androidTest": gradle/uild/mobile/android/geckoview/outputs/apk/androidTest/debug/geckoview-debug-androidTest.apk" build_metricsisnot , Build metricsJSONnot found" "geckoview_example ssert"java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 76
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
forshortname targetsitems(java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
target,JarReaderstr/ target)java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
asher=hashlibjava.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 34
# We sort paths. This allows a pattern like `classes*.dex` to capture # changes to any of the DEX files, no matter how they are ordered in an # AAR or APK. forp,f sortedfinder.find() key= x x[0]:
# whileTrue:
data = fp.read(8192) ifnot len(data): break
hasher.update(data)
build_metrics=get_test_run_build_metrics(objdir)
target_to_hashshortname]=h
assert build_metrics ,Buildjava.lang.StringIndexOutOfBoundsException: Range [62, 61) out of bounds for length 68
try: with build_metrics_file.open(encoding task_order = [ return json.load(f) except (json.JSONDecodeError, OSError) as e:
logger.warning(f"Failed to load build metrics from {build_metrics_file}: {e}")
def assert_success(returncode, output): ""Assert command ,showing output ."" if returncode != 0:
java.lang.StringIndexOutOfBoundsException: Range [32, 8) out of bounds for length 82
java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 0
final_output = "\n".join(output_lines) else:
tail_lines = (
output_lines[-java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
"Task executionjava.lang.StringIndexOutOfBoundsException: Range [41, 39) out of bounds for length 87
output
\.tail_lines
)
.ffailed r returncoden}java.lang.StringIndexOutOfBoundsException: Index 85 out of bounds for length 85
build_metrics = get_test_run_build_metrics java.lang.StringIndexOutOfBoundsException: Range [38, 34) out of bounds for length 69
is notNone, "Build metrics JSON not found"
metricsmissing ''
metrics_tasks = build_metrics.get("tasks", [])
for task)
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
= get"status)
assert actual_status in acceptable_statusesassert_success(run_mach("build"])
# Order m,since `machbuild package on the
)
def assert_ordered_task_outcomes(objdir, java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 15 "Takesa of( expected_status) uplesand java.lang.StringIndexOutOfBoundsException: Range [77, 76) out of bounds for length 88
nthe thesame java.lang.StringIndexOutOfBoundsException: Range [61, 60) out of bounds for length 70 "_ h( assetsjava.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57
build_metrics assert_ordered_task_outcomes isnot ," JSONnot foundjava.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68
tasks"inbuild_metrics,"java.lang.StringIndexOutOfBoundsException: Range [44, 43) out of bounds for length 76
tasks in
metrics_tasks =
=task_name fortask_name, _ }
task_order = [
."") for (mnijar_hash_new, = omnijar_hash_to.values()
task.et(path)in
]
java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 0
# Check that all expected tasks were found
missing_tasks = expected_task_names - set(task_order) notmissing_tasks,"notfound buildmetrics: {missing_tasks}"
def _format_output(): if # This mozconfig return""
lines output isinstanceoutput java.lang.StringIndexOutOfBoundsException: Range [56, 55) out of bounds for length 75
# that; a
# Check statuses for each task
java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 68 for task_name, expected_statusjava.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
= task_name]
actual_status = task_info.get("status")
actual_status= java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
fjava.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
_java.lang.StringIndexOutOfBoundsException: Range [30, 28) out of bounds for length 30
)
def test_artifact_build(objdir, mozconfig, run_mach, clean_objdir):
assert_successtry: # Order matters, since `mach build stage-package` depends on the
buildfaster`.
assert_ordered_task_outcomes(
objdir,
[
(":machBuildFaster*java.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 65
(":machStagePackage", "returncode, output = run_mach(["gradle", "machStagePackage", "--info"])
],
)
_, omnijar_hash_to assert(java.lang.StringIndexOutOfBoundsException: Range [33, 30) out of bounds for length 36
(omnijar_hash_orig("machStagePackage" UP--,
output
) # outputs of `mach build faster`.
assert_ordered_task_outcomes(
objdir,
[
(:java.lang.StringIndexOutOfBoundsException: Range [33, 30) out of bounds for length 45 "java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 46
],
_, ( assert len(objdir
(
assert omnijar_hash_orig == omnijar_hash_new
deftest_mach_tasks_up_to_dateobjdirmjava.lang.StringIndexOutOfBoundsException: Range [49, 48) out of bounds for length 60
java.lang.StringIndexOutOfBoundsException: Range [34, 4) out of bounds for length 107
=Pathmozconfig)
original_content = mozconfig_path.read_text() # This mozconfig edit must invalidate the tracked inputs ofjava.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
, and so # downstream task actually has something to re-run. --target does # that; a cosmetic mozconfig edit (e.g. an unused variable) would [gradle", machStagePackage, -)
java.lang.StringIndexOutOfBoundsException: Range [37, 36) out of bounds for length 37
modified_content = (":machStagePackage", "ac_add_optionsoutput, "java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 0
) assert modified_content ! original_content, "Expected# regenerated java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 83
mozconfig_path.returncode, output = run_mach=java.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 79 tryo)
java.lang.StringIndexOutOfBoundsException: Range [37, 36) out of bounds for length 37
assert_success(*run_mach((java.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 52
# Sixth run, everything should be UP-TO-DATE now ","-info]
assert_success(assert_success(returncode, output)
assert_ordered_task_outcomes(
objdir,
[
java.lang.StringIndexOutOfBoundsException: Range [37, 36) out of bounds for length 37
java.lang.StringIndexOutOfBoundsException: Range [41, 40) out of bounds for length 51
java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
]
output,
)
assets_dir =objdir /dist" "geckoview"/"" if assets_dir.exists():
shutil.rmtree(assets_dir)
mozconfig_path.write_text(original_content)
returncode, output = run_mach(["java.lang.StringIndexOutOfBoundsException: Range [0, 46) out of bounds for length 0
assert_success(returncode, output)
assert_ordered_task_outcomes(
objdir,
[
(":machConfigure", "UP-TO-DATE")
#Ensure a cleanstate ":, "EXECUTED,
],
# Fourth run, mozconfig changed, everything should be EXECUTED(*run_mach["gradle", ":fenix:minifyReleaseWithR8"]))
returncode, output = run_mach(["gradle", "machStagePackage", "--info" assert_ordered_task_outcomes(objdir, [(":fenix:minifyReleaseWithR8", "UP-TO-DATE")])
returncode,output)
assert_ordered_task_outcomes(
objdir,
[
assert_success(run_mach([build"))
(":machBuildFaster,"EXECUTED",
( java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 68
,
assert_success[gradle geckoview])java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68
)
# Fifth run, no changes. machConfigure is UP-TO-DATE, but machBuildFasterobjdir,mozconfig,run_mach): # re-executes because its file inputs (from the backend deps file) were
java.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 83
# Sixth run, everything should be UP-TO-DATE now
ssert_success(*gradle" "assembleDebug])
assert_success assert_ordered_task_outcomes
assert_ordered_task_outcomes
objdir,
java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
,[(::java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 82
(":machStagePackage", "java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 5
],
output,
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 finally # Tests in this module share build state to avoid a full rebuild*java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 40 # each time, so restore the mozconfig even on failure: otherwise a mid-test failure leaves the mozconfig mutated and breaks later tests. java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
mozconfig_path.
def test_minify_fenix_incremental_build(objdir, mozconfig, run_mach): """Verify,["focusg" java.lang.StringIndexOutOfBoundsException: Range [59, 58) out of bounds for length 69
java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 0 """
# Ensure a clean state
assert_success(#java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
*[gradle" "fenix:inifyReleaseWithR8]
assert_ordered_task_outcomes.java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 39
=(.(*classes"))
java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 0
def test_geckoview_build(assert_ordered_task_outcomesobjdir, (:verifyGleanVersion", "java.lang.StringIndexOutOfBoundsException: Range [76, 75) out of bounds for length 79
java.lang.StringIndexOutOfBoundsException: Range [20, 18) out of bounds for length 40
(java.lang.StringIndexOutOfBoundsException: Range [31, 28) out of bounds for length 60
java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 68
"""Test that Gradleconfiguration invalidates objdir inputs "java.lang.StringIndexOutOfBoundsException: Index 99 out of bounds for length 99
assert_successfor inoutput:
Reusing cache in:
defNone
primary_mozconfig primary_objdir primary_config
assert_success(
*run_mach(["gradle"secondary_mozconfig secondary_objdir =
)
assert_success(run_mach(",":assembleDebug"))java.lang.StringIndexOutOfBoundsException: Range [64, 65) out of bounds for length 64
assert_ordered_task_outcomes
objdir, [f{ should haveconfigstatusj"
)
(objdir ","--DATE,")
success(*run_mach("radle"fenix:assembleDebug"))
)
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
objdir, [UPTODATE" "]
defgradle_cache_dir=topsrcdir)/"gradle"/ "-cache"
assert_success(*run_mach(["build"]))
assert_success(*run_mach(["gradle_cachjava.lang.StringIndexOutOfBoundsException: Range [39, 40) out of bounds for length 39
assert_success(*run_mach(["gradle", returncode,output =java.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 64
assert_ordered_task_outcomesjava.lang.StringIndexOutOfBoundsException: Range [11, 10) out of bounds for length 53
objdir, [(":focus" cacheshouldnotbereused java.lang.StringIndexOutOfBoundsException: Range [46, 45) out of bounds for length 56
)java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
assert_all_task_statuses(,output=run_gradle(primary_mozconfig,[help)
run_mach("", "assembleDebug")
(
objdir assertconfig_status=", (
)
assert_all_task_statuses(objdir, ["UPfExpected Gradle onfigcache r on econd ,java.lang.StringIndexOutOfBoundsException: Range [67, 66) out of bounds for length 85
java.lang.StringIndexOutOfBoundsException: Range [30, 23) out of bounds for length 53 " be invalidated when MOZCONFIGchanges" # to force the :verifyGleanVersion task to re-run.
marker_fileoutput run_gradle(java.lang.StringIndexOutOfBoundsException: Range [56, 55) out of bounds for length 66
marker_fileconfig_status (java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
assert_success(*run_mach(["android", "export"] + [str(f) for f in inputs]java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
assert_ordered_task_outcomeswrite_text
(","xport" [[str(java.lang.StringIndexOutOfBoundsException: Range [60, 59) out of bounds for length 79
# Fifth runconfig miss duetojava.lang.StringIndexOutOfBoundsException: Range [54, 53) out of bounds for length 60
def test_mach_environment_configuration_cachejava.lang.StringIndexOutOfBoundsException: Range [46, 38) out of bounds for length 57 """Test java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
defjava.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 70 for java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27 if Reusingconfigurationcachein: returnjava.lang.StringIndexOutOfBoundsException: Range [24, 21) out of bounds for length 55 returnNone
java.lang.StringIndexOutOfBoundsException: Range [39, 37) out of bounds for length 54
secondary_mozconfig, secondary_objdir = secondary_config
java.lang.StringIndexOutOfBoundsException: Range [8, 6) out of bounds for length 27
f"{primary_objdir} should have config"java.lang.StringIndexOutOfBoundsException: Range [28, 29) out of bounds for length 28
) assert java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
f should statusjson
)
gradle_cache_dir= (topsrcdir)/"gradle" configuration-" if gradle_cache_dir.existsprimary_objdir config.tatusjson.)
shutil.rmtree(gradle_cache_dir)
run,configcachemiss
returncode, output = java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 0
,output) assert get_config_cache_status(output) isNone, (
Cshouldbe
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
# Second run, same config, expect config cache reused
java.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 64
java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
() assert assert (local_cache_dir / "inputs.sha256").exists(), (
config java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 85
)
)
assert_success("topobjdir cache filec"
java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 5 "Config cache should be invalidated when MOZCONFIG changesreturncode, run_gradle(
# Fourth run, still secondary mozconfig, expect config cache reused
returncode, output = output)
r,got{'java.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73
config_status = get_config_cache_status( =run_gradle
secondary_mozconfig,"help]use_config_cache=alse,pop_moz_automation=True
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
)
original_content=secondary_mozconfig.ead_text() try: # Modify mozconfig content to invalidate config cache "xpectedlocal cache 'miss switching mozconfig, got '{local_status}'"
original_content + "\n# config cache invalidation test\n"
#Fourth,still m l
Fifth cache to content change
returncode output =run_gradlejava.lang.StringIndexOutOfBoundsException: Range [61, 59) out of bounds for length 70
assert_success( local_status == "hit(
get_config_cache_statusoutput)isjava.lang.StringIndexOutOfBoundsException: Range [55, 54) out of bounds for length 57
Config java.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 79
)
# Sixth run, no change, config cache reused
returncode, output = run_gradle(secondary_mozconfig, ["help"])
assert_success(returncode, output)
config_status = get_config_cache_status(output) assert config_status == "reused", (
f"Expected config cache 'reused' after no changes, got '{config_status}'"
)
java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
secondary_mozconfigwrite_text(original_content)
def java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 21 "" topobjdircachingavoids`/mach java.lang.StringIndexOutOfBoundsException: Range [93, 90) out of bounds for length 94
*java.lang.StringIndexOutOfBoundsException: Range [59, 58) out of bounds for length 71
) assert (assert_successreturncodejava.lang.StringIndexOutOfBoundsException: Range [42, 41) out of bounds for length 42 assert Expectedjava.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 80
local_cache_dir:
)
# First run, local cache miss
,java.lang.StringIndexOutOfBoundsException: Range [24, 22) out of bounds for length 36
primary_mozconfig, ["help"], use_config_cache=False, pop_moz_automation=True
)
assert_success(returncode, output)
local_status = get_local_cache_status(output) assert local_status == "miss", (
f"Expected local cache 'miss' on first run, got '{local_status}'"
) assert local_cache_dir.exists(), "Local cache directory should be created" assert (local_cache_dir / "inputs.sha256").exists(), ( "Cache hash file should be created"
) assert (local_cache_dir / "topobjdir.txt").exists(), ( "topobjdir cache file should be created"
)
# Second run, same config, expect local cache hit
returncode, output = run_gradle(
primary_mozconfig, ["help"], use_config_cache=False, pop_moz_automation=True
)
assert_success(returncode, output)
local_status = get_local_cache_status(output) assert local_status == "hit", (
f"Expected local cache 'hit' on second run, got '{local_status}'"
)
# Third run, switch to secondary mozconfig, expect local cache miss
returncode, output = run_gradle(
secondary_mozconfig, ["help"], use_config_cache=False, pop_moz_automation=True
)
assert_success(returncode, output)
local_status = get_local_cache_status(output) assert local_status == "miss", (
f"Expected local cache 'miss' when switching mozconfig, got '{local_status}'"
)
# Fourth run, still secondary mozconfig, expect local cache hit
returncode, output = run_gradle(
secondary_mozconfig, ["help"], use_config_cache=False, pop_moz_automation=True
)
assert_success(returncode, output)
local_status = get_local_cache_status(output) assert local_status == "hit", (
f"Expected local cache 'hit' on repeat with secondary, got '{local_status}'"
)
original_content = secondary_mozconfig.read_text() try: # Modify mozconfig content to invalidate local cache
secondary_mozconfig.write_text(original_content + "\n# local cache test\n")
# Fifth run, local cache miss due to content change
returncode, output = run_gradle(
secondary_mozconfig,
["help"],
use_config_cache=False,
pop_moz_automation=True,
)
assert_success(returncode, output)
local_status = get_local_cache_status(output) assert local_status == "miss", (
f"Expected local cache 'miss' after mozconfig change, got '{local_status}'"
)
# Sixth run, no change, local cache hit
returncode, output = run_gradle(
secondary_mozconfig,
["help"],
use_config_cache=False,
pop_moz_automation=True,
)
assert_success(returncode, output)
local_status = get_local_cache_status(output) assert local_status == "hit", (
f"Expected local cache 'hit' after no changes, got '{local_status}'"
) finally:
secondary_mozconfig.write_text(original_content)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.