blob: 09047a83ea94db9c373ba2f8bd0a54234b42f692 [file]
# Copyright 2025 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Tests for the bazel_driver."""
import unittest
from pw_build.workflows.bazel_driver import BazelBuildDriver
from pw_build.proto import build_driver_pb2
_BAZEL_BUILD_JOB_REQUEST = """
{
"jobs": [
{
"build": {
"build_config": {
"build_type": "bazel",
"args": ["--config=rp2040"],
"env": {
"FOO": "bar"
}
},
"targets": [
"//..."
]
}
}
]
}
"""
_BAZEL_BUILD_NO_TEST_JOB_REQUEST = """
{
"jobs": [
{
"build": {
"build_config": {
"build_type": "bazel",
"args": ["--config=rp2040"],
"driver_options": {
"@type": "pw.build.proto.BazelDriverOptions",
"no_test": true
}
},
"targets": [
"//..."
]
}
}
]
}
"""
_BAZEL_BUILD_CUSTOM_SUBDIR_JOB_REQUEST = """
{
"jobs": [
{
"build": {
"build_config": {
"build_type": "bazel",
"args": ["--config=rp2040"],
"driver_options": {
"@type": "pw.build.proto.BazelDriverOptions",
"project_working_subdir": "examples/build"
}
},
"targets": [
"//..."
]
}
}
]
}
"""
_BAZEL_TOOL_JOB_REQUEST = """
{
"jobs": [
{
"tool": {
"build_config": {
"build_type": "bazel",
"args": ["--subcommands"],
"env": {
"BAZ": "qux"
}
},
"target": "@pigweed//:format"
}
}
]
}
"""
_BAZEL_TOOL_CUSTOM_SUBDIR_JOB_REQUEST = """
{
"jobs": [
{
"tool": {
"build_config": {
"build_type": "bazel",
"args": ["--subcommands"],
"env": {
"BAZ": "qux"
},
"driver_options": {
"@type": "pw.build.proto.BazelDriverOptions",
"project_working_subdir": "examples/tool"
}
},
"target": "@pigweed//:format"
}
}
]
}
"""
_BAZEL_BUILD_JOB_WITH_STARTUP_ARGS_REQUEST = """
{
"jobs": [
{
"build": {
"build_config": {
"build_type": "bazel",
"args": [
"--config=rp2040",
"--output_base=/tmp/bazel",
"--batch",
"--nobatch_cpu_scheduling",
"--max_idle_secs",
"60",
"--verbose_failures"
],
"env": {
"FOO": "bar"
}
},
"targets": [
"//..."
]
}
}
]
}
"""
_BAZEL_TOOL_JOB_WITH_STARTUP_ARGS_REQUEST = """
{
"jobs": [
{
"tool": {
"build_config": {
"build_type": "bazel",
"args": [
"--subcommands",
"--output_base=/tmp/bazel",
"--batch"
],
"env": {
"BAZ": "qux"
}
},
"target": "@pigweed//:format"
}
}
]
}
"""
class TestBazelBuildDriver(unittest.TestCase):
"""Tests for the bazel_driver."""
def test_bazel_build_driver_for_build(self):
"""Checks that all properties are handled during a build sequence."""
driver = BazelBuildDriver()
response = driver.generate_jobs_from_json(_BAZEL_BUILD_JOB_REQUEST)
self.assertEqual(len(response.jobs), 1)
# Verify the build job
build_job = response.jobs[0]
self.assertEqual(len(build_job.actions), 3)
# Check canonicalize-flags action for build
self.assertEqual(build_job.actions[0].executable, 'bazelisk')
self.assertEqual(
list(build_job.actions[0].args),
['canonicalize-flags', '--', '--config=rp2040'],
)
self.assertEqual(build_job.actions[0].env['FOO'], 'bar')
# Check build action
self.assertEqual(build_job.actions[1].executable, 'bazelisk')
self.assertEqual(
list(build_job.actions[1].args),
[
'build',
'--symlink_prefix=${BUILD_ROOT}/bazel-',
'--config=rp2040',
'--',
'//...',
],
)
self.assertEqual(build_job.actions[1].env['FOO'], 'bar')
# Check test action
self.assertEqual(build_job.actions[2].executable, 'bazelisk')
self.assertEqual(
list(build_job.actions[2].args),
[
'test',
'--symlink_prefix=${BUILD_ROOT}/bazel-',
'--config=rp2040',
'--',
'//...',
],
)
self.assertEqual(build_job.actions[2].env['FOO'], 'bar')
# Ensure all Bazel commands are run from the invoker's CWD.
for action in build_job.actions:
self.assertEqual(
action.run_from,
build_driver_pb2.Action.InvocationLocation.INVOKER_CWD,
)
def test_bazel_build_driver_for_build_with_no_test(self):
"""Checks that all properties are handled during a build sequence."""
driver = BazelBuildDriver()
response = driver.generate_jobs_from_json(
_BAZEL_BUILD_NO_TEST_JOB_REQUEST
)
self.assertEqual(len(response.jobs), 1)
# Verify the build job
build_job = response.jobs[0]
self.assertEqual(len(build_job.actions), 2)
# Check canonicalize-flags action for build
self.assertEqual(build_job.actions[0].executable, 'bazelisk')
self.assertEqual(
list(build_job.actions[0].args),
['canonicalize-flags', '--', '--config=rp2040'],
)
# Check build action
self.assertEqual(build_job.actions[1].executable, 'bazelisk')
self.assertEqual(
list(build_job.actions[1].args),
[
'build',
'--symlink_prefix=${BUILD_ROOT}/bazel-',
'--config=rp2040',
'--',
'//...',
],
)
# Ensure all Bazel commands are run from the invoker's CWD.
for action in build_job.actions:
self.assertEqual(
action.run_from,
build_driver_pb2.Action.InvocationLocation.INVOKER_CWD,
)
def test_bazel_build_driver_for_build_with_custom_subdir(self):
"""Checks that a working subdirectory is included in actions."""
driver = BazelBuildDriver()
response = driver.generate_jobs_from_json(
_BAZEL_BUILD_CUSTOM_SUBDIR_JOB_REQUEST
)
self.assertEqual(len(response.jobs), 1)
# Verify the build job
build_job = response.jobs[0]
self.assertEqual(
list(action.args[0] for action in build_job.actions),
["canonicalize-flags", "build", "test"],
)
# Check canonicalize-flags action for build
self.assertEqual(build_job.actions[0].executable, 'bazelisk')
self.assertEqual(
list(build_job.actions[0].args),
['canonicalize-flags', '--', '--config=rp2040'],
)
# Check build action
self.assertEqual(build_job.actions[1].executable, 'bazelisk')
self.assertEqual(
list(build_job.actions[1].args),
[
'build',
'--symlink_prefix=${BUILD_ROOT}/bazel-',
'--config=rp2040',
'--',
'//...',
],
)
# Ensure all Bazel commands are run from the custom project subdir.
for action in build_job.actions:
self.assertEqual(
action.run_from,
build_driver_pb2.Action.InvocationLocation.PROJECT_SUBDIR,
)
self.assertEqual(
action.project_working_subdir,
'examples/build',
)
def test_bazel_build_driver_for_tool(self):
"""Checks that all properties are handled during a tool sequence."""
driver = BazelBuildDriver()
response = driver.generate_jobs_from_json(_BAZEL_TOOL_JOB_REQUEST)
self.assertEqual(len(response.jobs), 1)
# Verify the tool job
tool_job = response.jobs[0]
self.assertEqual(len(tool_job.actions), 2)
# Check canonicalize-flags action for tool
self.assertEqual(tool_job.actions[0].executable, 'bazelisk')
self.assertEqual(
list(tool_job.actions[0].args),
['canonicalize-flags', '--', '--subcommands'],
)
self.assertEqual(tool_job.actions[0].env['BAZ'], 'qux')
# Check run action
self.assertEqual(tool_job.actions[1].executable, 'bazelisk')
self.assertEqual(
list(tool_job.actions[1].args),
[
'run',
'--ui_event_filters=FATAL,ERROR,PROGRESS',
'--experimental_convenience_symlinks=ignore',
'--subcommands',
'@pigweed//:format',
'--',
'${FORWARDED_LAUNCH_ARGS}',
],
)
self.assertEqual(tool_job.actions[1].env['BAZ'], 'qux')
# Ensure all Bazel commands are run from the invoker's CWD.
for action in tool_job.actions:
self.assertEqual(
action.run_from,
build_driver_pb2.Action.InvocationLocation.INVOKER_CWD,
)
def test_bazel_build_driver_with_startup_args(self):
"""Checks that startup args are handled during a build sequence."""
driver = BazelBuildDriver()
response = driver.generate_jobs_from_json(
_BAZEL_BUILD_JOB_WITH_STARTUP_ARGS_REQUEST
)
self.assertEqual(len(response.jobs), 1)
# Verify the build job
build_job = response.jobs[0]
self.assertEqual(len(build_job.actions), 3)
# Check canonicalize-flags action for build
self.assertEqual(build_job.actions[0].executable, 'bazelisk')
self.assertEqual(
list(build_job.actions[0].args),
[
'--output_base=/tmp/bazel',
'--batch',
'--nobatch_cpu_scheduling',
'--max_idle_secs',
'60',
'canonicalize-flags',
'--',
'--config=rp2040',
'--verbose_failures',
],
)
self.assertEqual(build_job.actions[0].env['FOO'], 'bar')
# Check build action
self.assertEqual(build_job.actions[1].executable, 'bazelisk')
self.assertEqual(
list(build_job.actions[1].args),
[
'--output_base=/tmp/bazel',
'--batch',
'--nobatch_cpu_scheduling',
'--max_idle_secs',
'60',
'build',
'--symlink_prefix=${BUILD_ROOT}/bazel-',
'--config=rp2040',
'--verbose_failures',
'--',
'//...',
],
)
self.assertEqual(build_job.actions[1].env['FOO'], 'bar')
# Check test action
self.assertEqual(build_job.actions[2].executable, 'bazelisk')
self.assertEqual(
list(build_job.actions[2].args),
[
'--output_base=/tmp/bazel',
'--batch',
'--nobatch_cpu_scheduling',
'--max_idle_secs',
'60',
'test',
'--symlink_prefix=${BUILD_ROOT}/bazel-',
'--config=rp2040',
'--verbose_failures',
'--',
'//...',
],
)
self.assertEqual(build_job.actions[2].env['FOO'], 'bar')
def test_bazel_tool_driver_with_startup_args(self):
"""Checks that startup args are handled during a tool sequence."""
driver = BazelBuildDriver()
response = driver.generate_jobs_from_json(
_BAZEL_TOOL_JOB_WITH_STARTUP_ARGS_REQUEST
)
self.assertEqual(len(response.jobs), 1)
# Verify the tool job
tool_job = response.jobs[0]
self.assertEqual(len(tool_job.actions), 2)
# Check canonicalize-flags action for tool
self.assertEqual(tool_job.actions[0].executable, 'bazelisk')
self.assertEqual(
list(tool_job.actions[0].args),
[
'--output_base=/tmp/bazel',
'--batch',
'canonicalize-flags',
'--',
'--subcommands',
],
)
self.assertEqual(tool_job.actions[0].env['BAZ'], 'qux')
# Check run action
self.assertEqual(tool_job.actions[1].executable, 'bazelisk')
self.assertEqual(
list(tool_job.actions[1].args),
[
'--output_base=/tmp/bazel',
'--batch',
'run',
'--ui_event_filters=FATAL,ERROR,PROGRESS',
'--experimental_convenience_symlinks=ignore',
'--subcommands',
'@pigweed//:format',
'--',
'${FORWARDED_LAUNCH_ARGS}',
],
)
self.assertEqual(tool_job.actions[1].env['BAZ'], 'qux')
def test_bazel_tool_driver_with_custom_subdir(self):
"""Checks that project subdirs are handled during a tool sequence."""
driver = BazelBuildDriver()
response = driver.generate_jobs_from_json(
_BAZEL_TOOL_CUSTOM_SUBDIR_JOB_REQUEST
)
self.assertEqual(len(response.jobs), 1)
# Verify the tool job
tool_job = response.jobs[0]
self.assertEqual(len(tool_job.actions), 2)
# Check canonicalize-flags action for tool
self.assertEqual(tool_job.actions[0].executable, 'bazelisk')
self.assertEqual(tool_job.actions[0].env['BAZ'], 'qux')
# Check run action
self.assertEqual(tool_job.actions[1].executable, 'bazelisk')
self.assertEqual(tool_job.actions[1].env['BAZ'], 'qux')
# Ensure all Bazel commands are run from the custom project subdir.
for action in tool_job.actions:
self.assertEqual(
action.run_from,
build_driver_pb2.Action.InvocationLocation.PROJECT_SUBDIR,
)
self.assertEqual(
action.project_working_subdir,
'examples/tool',
)
def test_nop(self):
driver = BazelBuildDriver()
response = driver.generate_jobs_from_json('{}')
self.assertEqual(len(response.jobs), 0)
def test_empty_job(self):
driver = BazelBuildDriver()
response = driver.generate_jobs_from_json('{"jobs":[{}]}')
self.assertEqual(len(response.jobs), 1)
job = response.jobs[0]
self.assertEqual(len(job.actions), 0)
if __name__ == '__main__':
unittest.main()