blob: 32ccd1ca3a5520c63c581ed5d336992ad08d7fa9 [file] [log] [blame] [edit]
#!/usr/bin/env fuchsia-vendored-python
# Copyright 2025 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import sys
import typing as T
import unittest
sys.path.insert(0, os.path.dirname(__file__))
from gn_targets_utils import (
BazelBuildActionQuery,
BazelBuildActionsMap,
find_gn_bazel_action_infos_for,
)
class BazelBuildActionsMapTest(unittest.TestCase):
_JSON_INPUT = [
{
"bazel_targets": [
"//bazel/target:1",
"//bazel/target:2",
],
"gn_target": "//some/gn:target_1",
"gn_targets_dir": "obj/some/gn/target_1.gn_targets",
"gn_targets_manifest": "gen/some/gn/target_1.gn_targets.json",
"no_sdk": False,
"bazel_command_file": "obj/some/gn/target_1.bazel_command.sh",
"build_events_log_json": "obj/some/gn/target_1.events_log.json",
"path_mapping": "obj/some/gn/target_1.path_mapping",
},
{
"bazel_targets": [
"//another/target:3",
"//another/target:4",
],
"gn_target": "//some/gn:target_2",
"gn_targets_dir": "obj/some/gn/target_2.gn_targets",
"gn_targets_manifest": "gen/some/gn/target_2.gn_targets.json",
"no_sdk": False,
"bazel_command_file": "obj/some/gn/target_2.bazel_command.sh",
"build_events_log_json": "obj/some/gn/target_2.events_log.json",
"path_mapping": "obj/some/gn/target_2.path_mapping",
},
]
def test_actions_map(self) -> None:
actions_map = BazelBuildActionsMap(self._JSON_INPUT)
self.assertListEqual(
actions_map.bazel_targets,
[
"//another/target:3",
"//another/target:4",
"//bazel/target:1",
"//bazel/target:2",
],
)
self.assertEqual(
actions_map.find_gn_target_for("//bazel/target:1"),
"//some/gn:target_1",
)
self.assertEqual(
actions_map.find_gn_target_for("//bazel/target:2"),
"//some/gn:target_1",
)
self.assertEqual(
actions_map.find_gn_target_for("//another/target:3"),
"//some/gn:target_2",
)
self.assertEqual(
actions_map.find_gn_target_for("//another/target:4"),
"//some/gn:target_2",
)
self.assertEqual(actions_map.find_gn_target_for("//does/not:exist"), "")
info = actions_map.get_info("//some/gn:target_1")
self.assertEqual(info.gn_target, "//some/gn:target_1")
self.assertListEqual(
info.bazel_targets,
[
"//bazel/target:1",
"//bazel/target:2",
],
)
self.assertFalse(info.no_sdk)
self.assertEqual(
info.gn_targets_dir,
"obj/some/gn/target_1.gn_targets",
)
self.assertEqual(
info.gn_targets_manifest, "gen/some/gn/target_1.gn_targets.json"
)
self.assertEqual(actions_map.get_info("//does/not:exist"), None)
def test_query(self) -> None:
actions_map = BazelBuildActionsMap(self._JSON_INPUT)
self.maxDiff = None
action_query = BazelBuildActionQuery("//some:target", actions_map)
self.assertListEqual(
action_query.make_query_command(["bazel"]),
[
"bazel",
"query",
"--config=no_gn_targets",
"--config=quiet",
"--keep_going",
r"""allpaths(set(//another/target:3 //another/target:4 //bazel/target:1 //bazel/target:2), //some:target)""",
],
)
self.assertListEqual(action_query.process_query_output(""), [])
query_output = r"""//another/target:3
//intermediate/target:path
//other:thingy
//some:target
"""
self.assertListEqual(
action_query.process_query_output(query_output),
["//some/gn:target_2"],
)
self.assertEqual(action_query.filter_query_errors(""), "")
self.assertEqual(
action_query.filter_query_errors(
r"""ERROR: /work/space/foo/BUILD.bazel: no such package '@@gn_targets//src/foo:gn_artifact
ERROR: Evaluation of query "allpaths(set(//src/foo:bazel_target_1 //src/foo:bazel_target_2), //src/foo/lib:target)" failed.
"""
),
"",
)
self.assertEqual(
action_query.filter_query_errors(
r"""ERROR: /work/space/foo/BUILD.bazel: no such package '@@gn_targets//src/foo:gn_artifact
ERROR: This is an unrelated error message
ERROR: And this is another one
ERROR: Evaluation of query "allpaths(set(//src/foo:bazel_target_1 //src/foo:bazel_target_2), //src/foo/lib:target)" failed.
"""
),
"ERROR: This is an unrelated error message\nERROR: And this is another one",
)
class FindGnBazelActioInfosForTest(unittest.TestCase):
_JSON_INPUT = [
{
"bazel_targets": [
"//bazel/target:1",
"//bazel/target:2",
],
"gn_target": "//some/gn:target_1",
"gn_targets_dir": "obj/some/gn/target_1.gn_targets",
"gn_targets_manifest": "gen/some/gn/target_1.gn_targets.json",
"no_sdk": False,
"bazel_command_file": "obj/some/gn/target_1.bazel_command.sh",
"build_events_log_json": "obj/some/gn/target_1.events_log.json",
"path_mapping": "obj/some/gn/target_1.path_mapping",
},
{
"bazel_targets": [
"//another/target:3",
"//another/target:4",
],
"gn_target": "//some/gn:target_2",
"gn_targets_dir": "obj/some/gn/target_2.gn_targets",
"gn_targets_manifest": "gen/some/gn/target_2.gn_targets.json",
"no_sdk": False,
"bazel_command_file": "obj/some/gn/target_2.bazel_command.sh",
"build_events_log_json": "obj/some/gn/target_2.events_log.json",
"path_mapping": "obj/some/gn/target_2.path_mapping",
},
]
def setUp(self) -> None:
self.actions_map = BazelBuildActionsMap(self._JSON_INPUT)
self.errors: list[str] = []
def tearDown(self) -> None:
pass
@property
def log_err(self) -> T.Callable[[str], None]:
def _log_err(msg: str) -> None:
self.errors.append(msg)
return _log_err
def test_malformed_bazel_targets(self) -> None:
self.errors = []
result = find_gn_bazel_action_infos_for(
"no_leading_slashes:target",
self.actions_map,
["bazel"],
log_err=self.log_err,
)
self.assertListEqual(result, [])
self.assertListEqual(
self.errors,
["Target label must start with // or @: no_leading_slashes:target"],
)
self.errors = []
result = find_gn_bazel_action_infos_for(
"//gn/label(//with:toolchain)",
self.actions_map,
["bazel"],
log_err=self.log_err,
)
self.assertListEqual(result, [])
self.assertListEqual(
self.errors,
[
"Target label cannot include GN toolchain suffix: //gn/label(//with:toolchain)"
],
)
def test_direct_mapping(self) -> None:
def command_runner(args: list[str]) -> tuple[int, str, str]:
return 1, "", "An unexpected error\nAnd another one\n"
result = find_gn_bazel_action_infos_for(
"//bazel/target:1",
self.actions_map,
["bazel"],
log_err=self.log_err,
command_runner=command_runner,
)
self.assertListEqual(
result, [self.actions_map.get_info("//some/gn:target_1")]
)
self.assertListEqual(self.errors, [])
def test_single_dependency(self) -> None:
def command_runner(args: list[str]) -> tuple[int, str, str]:
return (
1,
r"""//bazel/target/dependency:5
//bazel/some/other:dependency
//bazel/target:1
""",
r"""Starting local Bazel server and connecting to it...
WARNING: --keep_going specified, ignoring errors.
ERROR: /tmp/work: no such package '@@gn_targets//src/foo:bar' ...
ERROR: Evaluation of query "allpaths(set(...), //bazel/target/dependency:5) failed.
""",
)
result = find_gn_bazel_action_infos_for(
"//bazel/target/dependency:5",
self.actions_map,
["bazel"],
log_err=self.log_err,
command_runner=command_runner,
)
self.assertListEqual(self.errors, [])
self.assertListEqual(
result, [self.actions_map.get_info("//some/gn:target_1")]
)
def test_multiple_dependencies_same_gn_action(self) -> None:
def command_runner(args: list[str]) -> tuple[int, str, str]:
return (
1,
r"""//bazel/target/dependency:5
//bazel/some/other:dependency
//bazel/target:1
//bazel/target:2
""",
r"""Starting local Bazel server and connecting to it...
WARNING: --keep_going specified, ignoring errors.
ERROR: /tmp/work: no such package '@@gn_targets//src/foo:bar' ...
ERROR: Evaluation of query "allpaths(set(...), //bazel/target/dependency:5) failed.
""",
)
result = find_gn_bazel_action_infos_for(
"//bazel/target/dependency:5",
self.actions_map,
["bazel"],
log_err=self.log_err,
command_runner=command_runner,
)
self.assertListEqual(self.errors, [])
self.assertListEqual(
result, [self.actions_map.get_info("//some/gn:target_1")]
)
def test_multiple_dependencies(self) -> None:
def command_runner(args: list[str]) -> tuple[int, str, str]:
return (
1,
r"""//bazel/target/dependency:5
//bazel/some/other:dependency
//bazel/target:1
//bazel/extra:dependency
//another/target:4
""",
r"""Starting local Bazel server and connecting to it...
WARNING: --keep_going specified, ignoring errors.
ERROR: /tmp/work: no such package '@@gn_targets//src/foo:bar' ...
ERROR: Evaluation of query "allpaths(set(...), //bazel/target/dependency:5) failed.
""",
)
result = find_gn_bazel_action_infos_for(
"//bazel/target/dependency:5",
self.actions_map,
["bazel"],
log_err=self.log_err,
command_runner=command_runner,
)
self.assertListEqual(self.errors, [])
self.assertListEqual(
result,
[
self.actions_map.get_info("//some/gn:target_1"),
self.actions_map.get_info("//some/gn:target_2"),
],
)
def test_unknown_dependency(self) -> None:
def command_runner(args: list[str]) -> tuple[int, str, str]:
return 0, "", ""
result = find_gn_bazel_action_infos_for(
"//bazel/dependency:unknown",
self.actions_map,
["bazel"],
log_err=self.log_err,
command_runner=command_runner,
)
self.assertListEqual(result, [])
self.assertListEqual(self.errors, [])
def test_unexpected_query_errors(self) -> None:
def command_runner(args: list[str]) -> tuple[int, str, str]:
return 1, "", "An unexpected error\nAnd another one\n"
result = find_gn_bazel_action_infos_for(
"//bazel/target/dependency:5",
self.actions_map,
["bazel"],
log_err=self.log_err,
command_runner=command_runner,
)
self.assertListEqual(result, [])
self.assertListEqual(
self.errors,
[
r"""Bazel query returned unexpected errors:
An unexpected error
And another one
"""
],
)
if __name__ == "__main__":
unittest.main()