1# Copyright 2024 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""Tests for construction of Python version matching config settings.""" 15 16load("@//python:versions.bzl", "MINOR_MAPPING") 17load("@rules_testing//lib:analysis_test.bzl", "analysis_test") 18load("@rules_testing//lib:test_suite.bzl", "test_suite") 19load("@rules_testing//lib:truth.bzl", "subjects") 20load("@rules_testing//lib:util.bzl", rt_util = "util") 21 22_tests = [] 23 24def _subject_impl(ctx): 25 _ = ctx # @unused 26 return [DefaultInfo()] 27 28_subject = rule( 29 implementation = _subject_impl, 30 attrs = { 31 "match_cpu": attr.string(), 32 "match_micro": attr.string(), 33 "match_minor": attr.string(), 34 "match_os": attr.string(), 35 "match_os_cpu": attr.string(), 36 "no_match": attr.string(), 37 "no_match_micro": attr.string(), 38 }, 39) 40 41def _test_minor_version_matching(name): 42 minor_matches = { 43 # Having it here ensures that we can mix and match config settings defined in 44 # the repo and elsewhere 45 str(Label("//python/config_settings:is_python_3.11")): "matched-3.11", 46 "//conditions:default": "matched-default", 47 } 48 minor_cpu_matches = { 49 str(Label(":is_python_3.11_aarch64")): "matched-3.11-aarch64", 50 str(Label(":is_python_3.11_ppc")): "matched-3.11-ppc", 51 str(Label(":is_python_3.11_s390x")): "matched-3.11-s390x", 52 str(Label(":is_python_3.11_x86_64")): "matched-3.11-x86_64", 53 } 54 minor_os_matches = { 55 str(Label(":is_python_3.11_linux")): "matched-3.11-linux", 56 str(Label(":is_python_3.11_osx")): "matched-3.11-osx", 57 str(Label(":is_python_3.11_windows")): "matched-3.11-windows", 58 } 59 minor_os_cpu_matches = { 60 str(Label(":is_python_3.11_linux_aarch64")): "matched-3.11-linux-aarch64", 61 str(Label(":is_python_3.11_linux_ppc")): "matched-3.11-linux-ppc", 62 str(Label(":is_python_3.11_linux_s390x")): "matched-3.11-linux-s390x", 63 str(Label(":is_python_3.11_linux_x86_64")): "matched-3.11-linux-x86_64", 64 str(Label(":is_python_3.11_osx_aarch64")): "matched-3.11-osx-aarch64", 65 str(Label(":is_python_3.11_osx_x86_64")): "matched-3.11-osx-x86_64", 66 str(Label(":is_python_3.11_windows_x86_64")): "matched-3.11-windows-x86_64", 67 } 68 69 rt_util.helper_target( 70 _subject, 71 name = name + "_subject", 72 match_minor = select(minor_matches), 73 match_cpu = select(minor_matches | minor_cpu_matches), 74 match_os = select(minor_matches | minor_os_matches), 75 match_os_cpu = select(minor_matches | minor_cpu_matches | minor_os_matches | minor_os_cpu_matches), 76 no_match = select({ 77 "//python/config_settings:is_python_3.12": "matched-3.12", 78 "//conditions:default": "matched-default", 79 }), 80 ) 81 82 analysis_test( 83 name = name, 84 target = name + "_subject", 85 impl = _test_minor_version_matching_impl, 86 config_settings = { 87 str(Label("//python/config_settings:python_version")): "3.11.1", 88 "//command_line_option:platforms": str(Label("//tests/config_settings:linux_aarch64")), 89 }, 90 ) 91 92def _test_minor_version_matching_impl(env, target): 93 target = env.expect.that_target(target) 94 target.attr("match_cpu", factory = subjects.str).equals( 95 "matched-3.11-aarch64", 96 ) 97 target.attr("match_minor", factory = subjects.str).equals( 98 "matched-3.11", 99 ) 100 target.attr("match_os", factory = subjects.str).equals( 101 "matched-3.11-linux", 102 ) 103 target.attr("match_os_cpu", factory = subjects.str).equals( 104 "matched-3.11-linux-aarch64", 105 ) 106 target.attr("no_match", factory = subjects.str).equals( 107 "matched-default", 108 ) 109 110_tests.append(_test_minor_version_matching) 111 112def _test_latest_micro_version_matching(name): 113 rt_util.helper_target( 114 _subject, 115 name = name + "_subject", 116 match_minor = select({ 117 "//python/config_settings:is_python_3.12": "matched-3.12", 118 "//conditions:default": "matched-default", 119 }), 120 match_micro = select({ 121 "//python/config_settings:is_python_" + MINOR_MAPPING["3.12"]: "matched-3.12", 122 "//conditions:default": "matched-default", 123 }), 124 no_match_micro = select({ 125 "//python/config_settings:is_python_3.12.0": "matched-3.12", 126 "//conditions:default": "matched-default", 127 }), 128 no_match = select({ 129 "//python/config_settings:is_python_" + MINOR_MAPPING["3.11"]: "matched-3.11", 130 "//conditions:default": "matched-default", 131 }), 132 ) 133 134 analysis_test( 135 name = name, 136 target = name + "_subject", 137 impl = _test_latest_micro_version_matching_impl, 138 config_settings = { 139 str(Label("//python/config_settings:python_version")): "3.12", 140 }, 141 ) 142 143def _test_latest_micro_version_matching_impl(env, target): 144 target = env.expect.that_target(target) 145 target.attr("match_minor", factory = subjects.str).equals( 146 "matched-3.12", 147 ) 148 target.attr("match_micro", factory = subjects.str).equals( 149 "matched-3.12", 150 ) 151 target.attr("no_match_micro", factory = subjects.str).equals( 152 "matched-default", 153 ) 154 target.attr("no_match", factory = subjects.str).equals( 155 "matched-default", 156 ) 157 158_tests.append(_test_latest_micro_version_matching) 159 160def construct_config_settings_test_suite(name): # buildifier: disable=function-docstring 161 # We have CI runners running on a great deal of the platforms from the list below, 162 # hence use all of them within tests. 163 for os in ["linux", "osx", "windows"]: 164 native.config_setting( 165 name = "is_python_3.11_" + os, 166 constraint_values = [ 167 "@platforms//os:" + os, 168 ], 169 flag_values = { 170 "//python/config_settings:_python_version_major_minor": "3.11", 171 }, 172 ) 173 174 for cpu in ["s390x", "ppc", "x86_64", "aarch64"]: 175 native.config_setting( 176 name = "is_python_3.11_" + cpu, 177 constraint_values = [ 178 "@platforms//cpu:" + cpu, 179 ], 180 flag_values = { 181 "//python/config_settings:_python_version_major_minor": "3.11", 182 }, 183 ) 184 185 for (os, cpu) in [ 186 ("linux", "aarch64"), 187 ("linux", "ppc"), 188 ("linux", "s390x"), 189 ("linux", "x86_64"), 190 ("osx", "aarch64"), 191 ("osx", "x86_64"), 192 ("windows", "x86_64"), 193 ]: 194 native.config_setting( 195 name = "is_python_3.11_{}_{}".format(os, cpu), 196 constraint_values = [ 197 "@platforms//cpu:" + cpu, 198 "@platforms//os:" + os, 199 ], 200 flag_values = { 201 "//python/config_settings:_python_version_major_minor": "3.11", 202 }, 203 ) 204 205 test_suite( 206 name = name, 207 tests = _tests, 208 ) 209 210 native.platform( 211 name = "linux_aarch64", 212 constraint_values = [ 213 "@platforms//os:linux", 214 "@platforms//cpu:aarch64", 215 ], 216 ) 217