import os
from copy import deepcopy
from textwrap import dedent
import mozunit
import pytest
from mach.util import get_state_dir
from taskgraph.taskgraph import TaskGraph
from tryselect.tasks import add_chunk_patterns
@pytest.fixture(scope="module" )
def monkeymodule():
with pytest.MonkeyPatch.context() as mp:
yield mp
@pytest.fixture(scope="module" , autouse=True )
def setup_state_dir(monkeymodule, tmp_path_factory, run_mach):
state_dir = tmp_path_factory.mktemp("mozbuild" )
machrc = state_dir / "machrc"
machrc.write_text(
dedent(
"" "
[try ]
default=syntax
"" "
).lstrip()
)
monkeymodule.setenv("EDITOR" , "cat" )
monkeymodule.setenv("MOZBUILD_STATE_PATH" , str(state_dir))
monkeymodule.setenv("MACH_TRY_PRESET_PATHS" , str(state_dir / "try_presets.yml" ))
monkeymodule.setenv("MACHRC" , machrc)
get_state_dir(specific_to_topsrcdir=True )
try :
run_mach(["try" , "--help" ]) # create the virtualenv
except SystemExit:
pass
@pytest.fixture
def target_task_set():
return {
"test/foo-opt" : {
"kind" : "test" ,
"label" : "test/foo-opt" ,
"attributes" : {},
"task" : {},
"optimization" : {},
"dependencies" : {},
},
"test/foo-debug" : {
"kind" : "test" ,
"label" : "test/foo-debug" ,
"attributes" : {},
"task" : {},
"optimization" : {},
"dependencies" : {},
},
"build-baz" : {
"kind" : "build" ,
"label" : "build-baz" ,
"attributes" : {},
"task" : {},
"optimization" : {},
"dependencies" : {},
},
}
@pytest.fixture
def full_task_set(target_task_set):
full_task_set = deepcopy(target_task_set)
full_task_set.update(
{
"test/bar-opt" : {
"kind" : "test" ,
"label" : "test/bar-opt" ,
"attributes" : {},
"task" : {},
"optimization" : {},
"dependencies" : {},
},
"test/bar-debug" : {
"kind" : "test" ,
"label" : "test/bar-debug" ,
"attributes" : {},
"task" : {},
"optimization" : {},
"dependencies" : {},
},
}
)
return full_task_set
@pytest.mark.skipif(os.name == "nt" , reason="site validation fails in CI" )
@pytest.mark.parametrize(
"selector,commands,expected" ,
(
pytest.param(
"fuzzy" ,
["try" , "fuzzy" , "-q" , "'foo" ],
dedent(
"" "
Commit message:
Fuzzy query='foo
mach try command: `./mach try fuzzy -q 'foo`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"tasks" : [
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="fuzzy" ,
),
pytest.param(
"fuzzy" ,
["try" , "fuzzy" , "-q" , "'bar" ],
"no tasks selected\n" ,
id="fuzzy" ,
),
pytest.param(
"fuzzy" ,
["try" , "fuzzy" , "--full" , "-q" , "'bar" ],
dedent(
"" "
Commit message:
Fuzzy query='bar
mach try command: `./mach try fuzzy --full -q 'bar`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"tasks" : [
"test/bar-debug" ,
"test/bar-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="fuzzy" ,
),
pytest.param(
"fuzzy" ,
["try" , "fuzzy" , "--full" , "-q" , "'foo" , "-q" , "'bar" ],
dedent(
"" "
Commit message:
Fuzzy query='foo&query=' bar
mach try command: `./mach try fuzzy --full -q 'foo -q ' bar`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"tasks" : [
"test/bar-debug" ,
"test/bar-opt" ,
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="fuzzy multiple selectors" ,
),
pytest.param(
"fuzzy" ,
["try" , "fuzzy" , "--and" , "-q" , "'foo" , "-q" , "'opt" ],
dedent(
"" "
Commit message:
Fuzzy query='foo&query=' opt
mach try command: `./mach try fuzzy --and -q 'foo -q ' opt`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"tasks" : [
"test/foo-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="fuzzy query intersection" ,
),
pytest.param(
"fuzzy" ,
[
["try" , "fuzzy" , "--save" , "foo" , "-q" , "'test" , "-q" , "'opt" ],
["try" , "fuzzy" , "--preset" , "foo" , "-xq" , "'test" ],
],
dedent(
"" "
preset saved, run with : --preset=foo
Commit message:
Fuzzy query='test&query=' opt&query='test
mach try command: `./mach try fuzzy --preset foo -xq 'test`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"tasks" : [
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="fuzzy intersection with preset containing multiple queries" ,
),
pytest.param(
"fuzzy" ,
["try" , "fuzzy" , "--full" , "-q" , "testfoo | 'testbar" ],
dedent(
"" "
Commit message:
Fuzzy query=testfoo | 'testbar
mach try command: `./mach try fuzzy --full -q testfoo | 'testbar`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"tasks" : [
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="fuzzy exact match" ,
),
pytest.param(
"fuzzy" ,
["try" , "fuzzy" , "--full" , "--exact" , "-q" , "testfoo | 'testbar" ],
dedent(
"" "
Commit message:
Fuzzy query=testfoo | 'testbar
mach try command: `./mach try fuzzy --full --exact -q testfoo | 'testbar`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"tasks" : [
"test/bar-debug" ,
"test/bar-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="fuzzy exact match" ,
),
pytest.param(
"fuzzy" ,
["try" , "fuzzy" , "--env" , "FOO=1" , "--env" , "BAR=baz" , "-q" , "'foo" ],
dedent(
"" "
Commit message:
Fuzzy query='foo
mach try command: `./mach try fuzzy --env FOO=1 --env BAR=baz -q 'foo`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"BAR" : "baz" ,
"FOO" : "1" ,
"TRY_SELECTOR" : "fuzzy"
},
"tasks" : [
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="fuzzy task config" ,
),
pytest.param(
"auto" ,
["try" , "auto" ],
dedent(
"" "
Commit message:
Tasks automatically selected.
mach try command: `./mach try auto`
Pushed via `mach try auto`
Calculated try_task_config.json:
{
"parameters" : {
"filters" : [
"try_auto"
],
"optimize_strategies" : "gecko_taskgraph.optimize:tryselect.bugbug_reduced_manifests_config_selection_medium" ,
"optimize_target_tasks" : true ,
"test_manifest_loader" : "bugbug" ,
"try_mode" : "try_auto" ,
"try_task_config" : {}
},
"version" : 2
}
"" "
).lstrip(),
id="auto selector" ,
),
pytest.param(
"auto" ,
["try" , "auto" , "--closed-tree" ],
dedent(
"" "
Commit message:
Tasks automatically selected. ON A CLOSED TREE
mach try command: `./mach try auto --closed-tree`
Pushed via `mach try auto`
Calculated try_task_config.json:
{
"parameters" : {
"filters" : [
"try_auto"
],
"optimize_strategies" : "gecko_taskgraph.optimize:tryselect.bugbug_reduced_manifests_config_selection_medium" ,
"optimize_target_tasks" : true ,
"test_manifest_loader" : "bugbug" ,
"try_mode" : "try_auto" ,
"try_task_config" : {}
},
"version" : 2
}
"" "
).lstrip(),
id="auto" ,
),
pytest.param(
"auto" ,
["try" , "auto" , "--closed-tree" , "-m" , "foo {msg} bar" ],
dedent(
"" "
Commit message:
foo Tasks automatically selected. bar ON A CLOSED TREE
mach try command: `./mach try auto --closed-tree -m foo {msg} bar`
Pushed via `mach try auto`
Calculated try_task_config.json:
{
"parameters" : {
"filters" : [
"try_auto"
],
"optimize_strategies" : "gecko_taskgraph.optimize:tryselect.bugbug_reduced_manifests_config_selection_medium" ,
"optimize_target_tasks" : true ,
"test_manifest_loader" : "bugbug" ,
"try_mode" : "try_auto" ,
"try_task_config" : {}
},
"version" : 2
}
"" "
).lstrip(),
id="auto" ,
),
pytest.param(
"empty" ,
["try" , "empty" ],
dedent(
"" "
Commit message:
No try selector specified, use "Add New Jobs" to select tasks.
mach try command: `./mach try empty`
Pushed via `mach try empty`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "empty"
},
"tasks" : []
}
},
"version" : 2
}
"" "
).lstrip(),
id="empty" ,
),
pytest.param(
"empty" ,
["try" , "empty" , "--closed-tree" ],
dedent(
"" "
Commit message:
No try selector specified, use "Add New Jobs" to select tasks. ON A CLOSED TREE
mach try command: `./mach try empty --closed-tree`
Pushed via `mach try empty`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "empty"
},
"tasks" : []
}
},
"version" : 2
}
"" "
).lstrip(),
id="empty" ,
),
pytest.param(
"empty" ,
["try" , "empty" , "--closed-tree" , "-m" , "foo {msg} bar" ],
dedent(
"" "
Commit message:
foo No try selector specified, use "Add New Jobs" to select tasks. bar ON A CLOSED TREE
mach try command: `./mach try empty --closed-tree -m foo {msg} bar`
Pushed via `mach try empty`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "empty"
},
"tasks" : []
}
},
"version" : 2
}
"" "
).lstrip(),
id="empty" ,
),
pytest.param(
"fuzzy" ,
["try" , "fuzzy" , "-q" , "foo" , "--message" , "Foobar" ],
dedent(
"" "
Commit message:
Foobar
Fuzzy query=foo
mach try command: `./mach try fuzzy -q foo --message Foobar`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"tasks" : [
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="message fuzzy" ,
),
pytest.param(
"fuzzy" ,
["try" , "fuzzy" , "-q" , "foo" , "-m" , "Foobar: {msg}" ],
dedent(
"" "
Commit message:
Foobar: Fuzzy query=foo
mach try command: `./mach try fuzzy -q foo -m Foobar: {msg}`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"tasks" : [
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="message fuzzy" ,
),
pytest.param(
"syntax" ,
["try" , "syntax" , "-p" , "linux" , "-u" , "mochitests" , "--message" , "Foobar" ],
dedent(
"" "
Commit message:
Foobar
try : -b do -p linux -u mochitests
mach try command: `./mach try syntax -p linux -u mochitests --message Foobar`
Pushed via `mach try syntax`
"" "
).lstrip(),
id="message syntax" ,
),
pytest.param(
"syntax" ,
["try" , "syntax" , "-p" , "linux" , "-u" , "mochitests" , "-m" , "Foobar: {msg}" ],
dedent(
"" "
Commit message:
Foobar: try : -b do -p linux -u mochitests
mach try command: `./mach try syntax -p linux -u mochitests -m Foobar: {msg}`
Pushed via `mach try syntax`
"" "
).lstrip(),
id="message syntax" ,
),
pytest.param(
"syntax" ,
[
[
"try" ,
"--save" ,
"foo" ,
"-b" ,
"do" ,
"-p" ,
"linux" ,
"-u" ,
"mochitests" ,
"-t" ,
"none" ,
"--tag" ,
"foo" ,
],
["try" , "--preset" , "foo" ],
["try" , "syntax" , "--preset" , "foo" ],
["try" , "--edit-presets" ],
],
dedent(
"" "
preset saved, run with : --preset=foo
Commit message:
try : -b do -p linux -u mochitests -t none --tag foo
mach try command: `./mach try --preset foo`
Pushed via `mach try syntax`
Commit message:
try : -b do -p linux -u mochitests -t none --tag foo
mach try command: `./mach try syntax --preset foo`
Pushed via `mach try syntax`
foo:
dry_run: true
platforms:
- linux
selector: syntax
tags:
- foo
talos:
- none
tests:
- mochitests
"" "
).lstrip(),
id="preset with no subcommand" ,
),
pytest.param(
"syntax" ,
[
[
"try" ,
"syntax" ,
"--save" ,
"foo" ,
"-b" ,
"do" ,
"-p" ,
"linux" ,
"-u" ,
"mochitests" ,
"-t" ,
"none" ,
"--tag" ,
"foo" ,
],
["try" , "--preset" , "foo" ],
["try" , "syntax" , "--preset" , "foo" ],
["try" , "--edit-presets" ],
],
dedent(
"" "
preset saved, run with : --preset=foo
Commit message:
try : -b do -p linux -u mochitests -t none --tag foo
mach try command: `./mach try --preset foo`
Pushed via `mach try syntax`
Commit message:
try : -b do -p linux -u mochitests -t none --tag foo
mach try command: `./mach try syntax --preset foo`
Pushed via `mach try syntax`
foo:
dry_run: true
no_artifact: true
platforms:
- linux
selector: syntax
tags:
- foo
talos:
- none
tests:
- mochitests
"" "
).lstrip(),
id="preset with syntax subcommand" ,
),
pytest.param(
"fuzzy" ,
[
["try" , "fuzzy" , "--save" , "foo" , "-q" , "'foo" , "--rebuild" , "5" ],
["try" , "fuzzy" , "--preset" , "foo" ],
["try" , "--preset" , "foo" ],
["try" , "--edit-presets" ],
],
dedent(
"" "
preset saved, run with : --preset=foo
Commit message:
Fuzzy query='foo
mach try command: `./mach try fuzzy --preset foo`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"rebuild" : 5,
"tasks" : [
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
Commit message:
Fuzzy query='foo
mach try command: `./mach try --preset foo`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"rebuild" : 5,
"tasks" : [
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
foo:
dry_run: true
no_artifact: true
query:
- "'foo"
rebuild: 5
selector: fuzzy
"" "
).lstrip(),
id="preset with fuzzy subcommand" ,
),
pytest.param(
"fuzzy" ,
[
["try" , "fuzzy" , "--save" , "foo" , "-q" , "'foo" , "--rebuild" , "5" ],
["try" , "fuzzy" , "--preset" , "foo" , "-q" "'build" ],
["try" , "fuzzy" , "--preset" , "foo" , "-xq" "'opt" ],
],
dedent(
"" "
preset saved, run with : --preset=foo
Commit message:
Fuzzy query='foo&query=' build
mach try command: `./mach try fuzzy --preset foo -q'build`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"rebuild" : 5,
"tasks" : [
"build-baz" ,
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
Commit message:
Fuzzy query='foo&query=' opt
mach try command: `./mach try fuzzy --preset foo -xq'opt`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"rebuild" : 5,
"tasks" : [
"test/foo-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="preset queries can be appended" ,
),
pytest.param(
"fuzzy" ,
[
["try" , "fuzzy" , "--save" , "foo" , "-q" , "'foo" , "--rebuild" , "5" ],
[
"try" ,
"fuzzy" ,
"--preset" ,
"foo" ,
"--gecko-profile-features=nostacksampling,cpu" ,
],
],
dedent(
"" "
preset saved, run with : --preset=foo
Commit message:
Fuzzy query='foo
mach try command: `./mach try fuzzy --preset foo --gecko-profile-features=nostacksampling,cpu`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"gecko-profile" : true ,
"gecko-profile-features" : "nostacksampling,cpu" ,
"rebuild" : 5,
"tasks" : [
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
"" "
).lstrip(),
id="gecko-profile handling" ,
),
pytest.param(
"fuzzy" ,
[
[
"try" ,
"fuzzy" ,
"--save" ,
"foo" ,
"-q" ,
"'foo" ,
"--rebuild" ,
"5" ,
"--gecko-profile-features=nostacksampling,cpu" ,
],
["try" , "fuzzy" , "--preset" , "foo" ],
["try" , "fuzzy" , "--edit-presets" , "foo" ],
],
dedent(
"" "
preset saved, run with : --preset=foo
Commit message:
Fuzzy query='foo
mach try command: `./mach try fuzzy --preset foo`
Pushed via `mach try fuzzy`
Calculated try_task_config.json:
{
"parameters" : {
"optimize_target_tasks" : false ,
"try_task_config" : {
"env" : {
"TRY_SELECTOR" : "fuzzy"
},
"gecko-profile" : true ,
"gecko-profile-features" : "nostacksampling,cpu" ,
"rebuild" : 5,
"tasks" : [
"test/foo-debug" ,
"test/foo-opt"
]
}
},
"version" : 2
}
foo:
dry_run: true
gecko_profile_features: nostacksampling,cpu
no_artifact: true
query:
- "'foo"
rebuild: 5
selector: fuzzy
"" "
).lstrip(),
id="gecko-profile handling" ,
),
),
)
def test_run_mach(
capfd,
mocker,
run_mach,
target_task_set,
full_task_set,
selector,
commands,
expected,
):
"" "These tests were initially converted from the `cramtest` framework. It's
likely there is duplication of test coverage between here and the specific
selector tests."" "
mocker.patch("tryselect.push.display_push_estimates" )
capfd.readouterr()
if isinstance(commands[0], str):
commands = [commands]
for cmd in commands:
m = mocker.patch("tryselect.push.get_sys_argv" )
m.return_value = f"./mach {' '.join(cmd)}"
cmd.append("--no-push" )
if selector in cmd:
cmd.append("--no-artifact" )
if selector == "fuzzy" :
def fake_generate_tasks(*args, **kwargs):
task_set = target_task_set
if "--full" in cmd:
task_set = full_task_set
return add_chunk_patterns(TaskGraph.from_json(task_set)[1])
m = mocker.patch(f"tryselect.selectors.{selector}.generate_tasks" )
m.side_effect = fake_generate_tasks
try :
cmd.insert(0, f"--settings={os.environ['MACHRC']}" )
run_mach(cmd)
except SystemExit:
pass
out, _ = capfd.readouterr()
assert out == expected
if __name__ == "__main__" :
mozunit.main()
quality 99%
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland