xref: /aosp_15_r20/external/pigweed/pw_build/python_action_test.gni (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2023 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://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, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
15import("//build_overrides/pigweed.gni")
16
17import("$dir_pw_build/python.gni")
18import("$dir_pw_build/test_info.gni")
19
20# Creates a Python action to use as a test and associated metadata.
21#
22# This template derives several additional targets:
23#   - <target_name>.metadata produces the test metadata when included in a
24#     `pw_test_group`. This metadata includes the Ninja target that runs the
25#     test.
26#   - <target_name>.script creates a `pw_python_action` to run the test and
27#     wraps it as a standalone `pw_python_package`.
28#   - <target_name>.group creates a `pw_python_group` in order to apply tools,
29#     e.g. linters, to the standalone package.
30#   - <target_name>.lib is an empty group for compatibility with
31#     `pw_test_group`.
32#   - <target_name>.run invokes the test.
33#
34# Targets defined using this template will produce test metadata with a
35# `test_type` of "action_test" and a `ninja_target` value that will invoke the
36# test when passed to Ninja, i.e. `ninja -C out <ninja_target>`.
37#
38# Args:
39#   - The following args have the same meaning as for `pw_test`:
40#         enable_if
41#         envvars (may also use `environment`)
42#         tags
43#         extra_metadata
44#         source_gen_deps
45#
46#   - The following args have the same meaning as for `pw_python_action`:
47#         script (may be omitted if `sources` has length=1)
48#         args
49#         deps
50#         environment (may also use `envvars`)
51#         working_directory
52#         command_launcher
53#         venv
54#
55#   - The following args have the same meaning as for `pw_python_package`:
56#         sources
57#         python_deps
58#         other_deps
59#         inputs
60#         static_analysis
61#         pylintrc
62#         mypy_ini
63#         ruff_toml
64#
65#   - action: Optional string or scope. If a string, this should be a label to
66#         a `pw_python_action` target that performs the test. If a scope, this
67#         has the same meaning as for `pw_python_script`.
68template("pw_python_action_test") {
69  _test_target_name = target_name
70  _deps = []
71  _run_deps = []
72  _metadata = {
73  }
74
75  _test_is_enabled = !defined(invoker.enable_if) || invoker.enable_if
76  if (_test_is_enabled) {
77    # Metadata for this test when used as part of a pw_test_group target.
78    _test_metadata = "${target_name}.metadata"
79    _ninja_target = "$target_out_dir/$target_name.run.stamp"
80    _extra_metadata = {
81      forward_variables_from(invoker, [ "extra_metadata" ])
82      ninja_target = rebase_path(_ninja_target, root_build_dir)
83    }
84    pw_test_info(_test_metadata) {
85      test_type = "action_test"
86      test_name = _test_target_name
87      forward_variables_from(invoker, [ "tags" ])
88      extra_metadata = _extra_metadata
89    }
90    _deps += [ ":$_test_metadata" ]
91    _metadata = {
92      test_barrier = [ ":$_test_metadata" ]
93    }
94
95    if (defined(invoker.action) && invoker.action == "${invoker.action}") {
96      # `action` is a label to an existing Python action.
97      _run_deps = [ invoker.action ]
98      if (defined(invoker.deps)) {
99        _deps += invoker.deps
100      }
101    } else {
102      # Wrap the action in a Python script target for additional flexibility.
103      _test_script_name = _test_target_name + ".script"
104
105      _sources = []
106      if (defined(invoker.script)) {
107        _sources += [ invoker.script ]
108      }
109      if (defined(invoker.sources)) {
110        _sources += invoker.sources
111      }
112
113      pw_python_script(_test_script_name) {
114        other_deps = []
115        forward_variables_from(invoker,
116                               [
117                                 "action",
118                                 "python_deps",
119                                 "other_deps",
120                                 "inputs",
121                                 "static_analysis",
122                                 "testonly",
123                                 "pylintrc",
124                                 "mypy_ini",
125                                 "ruff_toml",
126                               ])
127        sources = _sources
128        if (defined(invoker.source_gen_deps)) {
129          other_deps += invoker.source_gen_deps
130        }
131        if (!defined(pylintrc)) {
132          pylintrc = "$dir_pigweed/.pylintrc"
133        }
134        if (!defined(mypy_ini)) {
135          mypy_ini = "$dir_pigweed/.mypy.ini"
136        }
137        if (!defined(ruff_toml)) {
138          ruff_toml = "$dir_pigweed/.ruff.toml"
139        }
140        if (!defined(action)) {
141          action = {
142            environment = []
143            forward_variables_from(invoker,
144                                   [
145                                     "script",
146                                     "args",
147                                     "deps",
148                                     "environment",
149                                     "working_directory",
150                                     "command_launcher",
151                                     "venv",
152                                   ])
153            if (defined(invoker.envvars)) {
154              environment += invoker.envvars
155            }
156            stamp = true
157          }
158        }
159      }
160      _deps += [ ":$_test_script_name" ]
161      _run_deps = [ ":$_test_script_name.action" ]
162
163      # Create a Python group in order to ensure the package is linted.
164      _test_python_group = _test_target_name + ".group"
165      pw_python_group(_test_python_group) {
166        python_deps = [ ":$_test_script_name" ]
167      }
168      _deps += [ ":$_test_python_group" ]
169    }
170  } else {
171    if (defined(invoker.source_gen_deps)) {
172      _deps += invoker.source_gen_deps
173    }
174  }
175
176  # For compatibility with `pw_test_group`.
177  group(_test_target_name + ".lib") {
178    forward_variables_from(invoker, [ "testonly" ])
179  }
180
181  # For compatibility with `pw_test_group`.
182  group(_test_target_name + ".run") {
183    forward_variables_from(invoker, [ "testonly" ])
184    deps = _run_deps
185  }
186
187  group(_test_target_name) {
188    forward_variables_from(invoker, [ "testonly" ])
189    deps = _deps
190    metadata = _metadata
191  }
192}
193