blob: a38d6579623d350b500fd53aac4324f90f850d3e [file] [log] [blame]
# Copyright 2023 The Bazel Authors. All rights reserved.
#
# 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
#
# http://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.
"""render_pkg_aliases tests"""
load("@rules_testing//lib:test_suite.bzl", "test_suite")
load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility
load("//python/private:render_pkg_aliases.bzl", "render_pkg_aliases", "whl_alias") # buildifier: disable=bzl-visibility
def _normalize_label_strings(want):
"""normalize expected strings.
This function ensures that the desired `render_pkg_aliases` outputs are
normalized from `bzlmod` to `WORKSPACE` values so that we don't have to
have to sets of expected strings. The main difference is that under
`bzlmod` the `str(Label("//my_label"))` results in `"@@//my_label"` whereas
under `non-bzlmod` we have `"@//my_label"`. This function does
`string.replace("@@", "@")` to normalize the strings.
NOTE, in tests, we should only use keep `@@` usage in expectation values
for the test cases where the whl_alias has the `config_setting` constructed
from a `Label` instance.
"""
if "@@" not in want:
fail("The expected string does not have '@@' labels, consider not using the function")
if BZLMOD_ENABLED:
# our expectations are already with double @
return want
return want.replace("@@", "@")
_tests = []
def _test_empty(env):
actual = render_pkg_aliases(
aliases = None,
)
want = {}
env.expect.that_dict(actual).contains_exactly(want)
_tests.append(_test_empty)
def _test_legacy_aliases(env):
actual = render_pkg_aliases(
aliases = {
"foo": [
whl_alias(repo = "pypi_foo"),
],
},
)
want_key = "foo/BUILD.bazel"
want_content = """\
load("@bazel_skylib//lib:selects.bzl", "selects")
package(default_visibility = ["//visibility:public"])
alias(
name = "foo",
actual = ":pkg",
)
alias(
name = "pkg",
actual = "@pypi_foo//:pkg",
)
alias(
name = "whl",
actual = "@pypi_foo//:whl",
)
alias(
name = "data",
actual = "@pypi_foo//:data",
)
alias(
name = "dist_info",
actual = "@pypi_foo//:dist_info",
)"""
env.expect.that_dict(actual).contains_exactly({want_key: want_content})
_tests.append(_test_legacy_aliases)
def _test_bzlmod_aliases(env):
actual = render_pkg_aliases(
default_version = "3.2",
aliases = {
"bar-baz": [
whl_alias(version = "3.2", repo = "pypi_32_bar_baz", config_setting = "//:my_config_setting"),
],
},
)
want_key = "bar_baz/BUILD.bazel"
want_content = """\
load("@bazel_skylib//lib:selects.bzl", "selects")
package(default_visibility = ["//visibility:public"])
alias(
name = "bar_baz",
actual = ":pkg",
)
alias(
name = "pkg",
actual = selects.with_or(
{
(
"//:my_config_setting",
"//conditions:default",
): "@pypi_32_bar_baz//:pkg",
},
),
)
alias(
name = "whl",
actual = selects.with_or(
{
(
"//:my_config_setting",
"//conditions:default",
): "@pypi_32_bar_baz//:whl",
},
),
)
alias(
name = "data",
actual = selects.with_or(
{
(
"//:my_config_setting",
"//conditions:default",
): "@pypi_32_bar_baz//:data",
},
),
)
alias(
name = "dist_info",
actual = selects.with_or(
{
(
"//:my_config_setting",
"//conditions:default",
): "@pypi_32_bar_baz//:dist_info",
},
),
)"""
env.expect.that_collection(actual.keys()).contains_exactly([want_key])
env.expect.that_str(actual[want_key]).equals(want_content)
_tests.append(_test_bzlmod_aliases)
def _test_bzlmod_aliases_with_no_default_version(env):
actual = render_pkg_aliases(
default_version = None,
aliases = {
"bar-baz": [
whl_alias(
version = "3.2",
repo = "pypi_32_bar_baz",
# pass the label to ensure that it gets converted to string
config_setting = Label("//python/config_settings:is_python_3.2"),
),
whl_alias(version = "3.1", repo = "pypi_31_bar_baz"),
],
},
)
want_key = "bar_baz/BUILD.bazel"
want_content = """\
load("@bazel_skylib//lib:selects.bzl", "selects")
package(default_visibility = ["//visibility:public"])
_NO_MATCH_ERROR = \"\"\"\\
No matching wheel for current configuration's Python version.
The current build configuration's Python version doesn't match any of the Python
versions available for this wheel. This wheel supports the following Python versions:
3.1, 3.2
As matched by the `@rules_python//python/config_settings:is_python_<version>`
configuration settings.
To determine the current configuration's Python version, run:
`bazel config <config id>` (shown further below)
and look for
rules_python//python/config_settings:python_version
If the value is missing, then the "default" Python version is being used,
which has a "null" version value and will not match version constraints.
\"\"\"
alias(
name = "bar_baz",
actual = ":pkg",
)
alias(
name = "pkg",
actual = selects.with_or(
{
"@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:pkg",
"@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg",
},
no_match_error = _NO_MATCH_ERROR,
),
)
alias(
name = "whl",
actual = selects.with_or(
{
"@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:whl",
"@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl",
},
no_match_error = _NO_MATCH_ERROR,
),
)
alias(
name = "data",
actual = selects.with_or(
{
"@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:data",
"@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data",
},
no_match_error = _NO_MATCH_ERROR,
),
)
alias(
name = "dist_info",
actual = selects.with_or(
{
"@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:dist_info",
"@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info",
},
no_match_error = _NO_MATCH_ERROR,
),
)"""
env.expect.that_collection(actual.keys()).contains_exactly([want_key])
env.expect.that_str(actual[want_key]).equals(_normalize_label_strings(want_content))
_tests.append(_test_bzlmod_aliases_with_no_default_version)
def _test_bzlmod_aliases_for_non_root_modules(env):
actual = render_pkg_aliases(
# NOTE @aignas 2024-01-17: if the default X.Y version coincides with the
# versions that are used in the root module, then this would be the same as
# as _test_bzlmod_aliases.
#
# However, if the root module uses a different default version than the
# non-root module, then we will have a no-match-error because the default_version
# is not in the list of the versions in the whl_map.
default_version = "3.3",
aliases = {
"bar-baz": [
whl_alias(version = "3.2", repo = "pypi_32_bar_baz"),
whl_alias(version = "3.1", repo = "pypi_31_bar_baz"),
],
},
)
want_key = "bar_baz/BUILD.bazel"
want_content = """\
load("@bazel_skylib//lib:selects.bzl", "selects")
package(default_visibility = ["//visibility:public"])
_NO_MATCH_ERROR = \"\"\"\\
No matching wheel for current configuration's Python version.
The current build configuration's Python version doesn't match any of the Python
versions available for this wheel. This wheel supports the following Python versions:
3.1, 3.2
As matched by the `@rules_python//python/config_settings:is_python_<version>`
configuration settings.
To determine the current configuration's Python version, run:
`bazel config <config id>` (shown further below)
and look for
rules_python//python/config_settings:python_version
If the value is missing, then the "default" Python version is being used,
which has a "null" version value and will not match version constraints.
\"\"\"
alias(
name = "bar_baz",
actual = ":pkg",
)
alias(
name = "pkg",
actual = selects.with_or(
{
"@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:pkg",
"@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg",
},
no_match_error = _NO_MATCH_ERROR,
),
)
alias(
name = "whl",
actual = selects.with_or(
{
"@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:whl",
"@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl",
},
no_match_error = _NO_MATCH_ERROR,
),
)
alias(
name = "data",
actual = selects.with_or(
{
"@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:data",
"@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data",
},
no_match_error = _NO_MATCH_ERROR,
),
)
alias(
name = "dist_info",
actual = selects.with_or(
{
"@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:dist_info",
"@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info",
},
no_match_error = _NO_MATCH_ERROR,
),
)"""
env.expect.that_collection(actual.keys()).contains_exactly([want_key])
env.expect.that_str(actual[want_key]).equals(_normalize_label_strings(want_content))
_tests.append(_test_bzlmod_aliases_for_non_root_modules)
def _test_aliases_are_created_for_all_wheels(env):
actual = render_pkg_aliases(
default_version = "3.2",
aliases = {
"bar": [
whl_alias(version = "3.1", repo = "pypi_31_bar"),
whl_alias(version = "3.2", repo = "pypi_32_bar"),
],
"foo": [
whl_alias(version = "3.1", repo = "pypi_32_foo"),
whl_alias(version = "3.2", repo = "pypi_31_foo"),
],
},
)
want_files = [
"bar/BUILD.bazel",
"foo/BUILD.bazel",
]
env.expect.that_dict(actual).keys().contains_exactly(want_files)
_tests.append(_test_aliases_are_created_for_all_wheels)
def _test_aliases_with_groups(env):
actual = render_pkg_aliases(
default_version = "3.2",
aliases = {
"bar": [
whl_alias(version = "3.1", repo = "pypi_31_bar"),
whl_alias(version = "3.2", repo = "pypi_32_bar"),
],
"baz": [
whl_alias(version = "3.1", repo = "pypi_31_baz"),
whl_alias(version = "3.2", repo = "pypi_32_baz"),
],
"foo": [
whl_alias(version = "3.1", repo = "pypi_32_foo"),
whl_alias(version = "3.2", repo = "pypi_31_foo"),
],
},
requirement_cycles = {
"group": ["bar", "baz"],
},
)
want_files = [
"bar/BUILD.bazel",
"foo/BUILD.bazel",
"baz/BUILD.bazel",
"_groups/BUILD.bazel",
]
env.expect.that_dict(actual).keys().contains_exactly(want_files)
want_key = "_groups/BUILD.bazel"
# Just check that it contains a private whl
env.expect.that_str(actual[want_key]).contains("//bar:_whl")
want_key = "bar/BUILD.bazel"
# Just check that it contains a private whl
env.expect.that_str(actual[want_key]).contains("name = \"_whl\"")
env.expect.that_str(actual[want_key]).contains("name = \"whl\"")
env.expect.that_str(actual[want_key]).contains("\"//_groups:group_whl\"")
_tests.append(_test_aliases_with_groups)
def render_pkg_aliases_test_suite(name):
"""Create the test suite.
Args:
name: the name of the test suite
"""
test_suite(name = name, basic_tests = _tests)