1# Copyright (C) 2022 The Android Open Source Project 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 15TRADEFED_TEST_ATTRIBUTES = { 16 "test": attr.label( 17 providers = [[CcInfo]], 18 doc = "Test target to run in tradefed.", 19 ), 20 "test_identifier": attr.string(), 21 "host_driven": attr.bool( 22 default = True, 23 doc = "Is a host driven test", 24 ), 25 "_tradefed_test_sh_template": attr.label( 26 default = ":tradefed.sh.tpl", 27 allow_single_file = True, 28 doc = "Template script to launch tradefed.", 29 ), 30 "_tradefed_dependencies": attr.label_list( 31 default = [ 32 "//prebuilts/runtime:prebuilt-runtime-adb", 33 "//tools/tradefederation/prebuilts/filegroups/tradefed:bp2build_all_srcs", 34 "//tools/tradefederation/prebuilts/filegroups/suite:compatibility-host-util-prebuilt", 35 "//tools/tradefederation/prebuilts/filegroups/suite:compatibility-tradefed-prebuilt", 36 "//tools/asuite/atest:atest-tradefed", 37 "//tools/asuite/atest/bazel/reporter:bazel-result-reporter", 38 ], 39 doc = "Files needed on the PATH to run tradefed", 40 cfg = "exec", 41 ), 42 43 # Test config and if test config generation attributes. 44 "test_config": attr.label( 45 allow_single_file = True, 46 doc = "Test/Tradefed config.", 47 ), 48 "template_test_config": attr.label( 49 allow_single_file = True, 50 doc = "Template to generate test config.", 51 ), 52 "template_configs": attr.string_list( 53 doc = "Extra tradefed config options to extend into generated test config.", 54 ), 55 "template_install_base": attr.string( 56 default = "/data/local/tmp", 57 doc = "Directory to install tests onto the device for generated config", 58 ), 59} 60 61# Get test config if specified or generate test config from template. 62def _get_or_generate_test_config(ctx): 63 # Validate input 64 c = ctx.file.test_config 65 c_template = ctx.file.template_test_config 66 if c and c_template: 67 fail("Both test_config and test_config_template were provided, please use only 1 of them") 68 if not c and not c_template: 69 fail("Either test_config or test_config_template should be provided") 70 71 # Check for existing tradefed config - and add a symlink with test_identifier. 72 out = ctx.actions.declare_file(ctx.attr.test_identifier + ".config") 73 if c: 74 ctx.actions.symlink( 75 output = out, 76 target_file = c, 77 ) 78 return out 79 80 # No test config found, generate config from template. 81 # Join extra configs together and add xml spacing indent. 82 extra_configs = "\n ".join(ctx.attr.template_configs) 83 ctx.actions.expand_template( 84 template = c_template, 85 output = out, 86 substitutions = { 87 "{MODULE}": ctx.attr.test_identifier, 88 "{EXTRA_CONFIGS}": extra_configs, 89 "{TEST_INSTALL_BASE}": ctx.attr.template_install_base, 90 }, 91 ) 92 return out 93 94# Generate tradefed result reporter config. 95def _create_result_reporter_config(ctx): 96 result_reporters_config_file = ctx.actions.declare_file("result-reporters.xml") 97 config_lines = [ 98 "<?xml version=\"1.0\" encoding=\"utf-8\"?>", 99 "<configuration>", 100 ] 101 102 result_reporters = [ 103 "com.android.tradefed.result.BazelExitCodeResultReporter", 104 "com.android.tradefed.result.BazelXmlResultReporter", 105 ] 106 for result_reporter in result_reporters: 107 config_lines.append(" <result_reporter class=\"%s\" />" % result_reporter) 108 config_lines.append("</configuration>") 109 110 ctx.actions.write(result_reporters_config_file, "\n".join(config_lines)) 111 return result_reporters_config_file 112 113# Generate and run tradefed bash script. 114def _tradefed_test_impl(ctx): 115 # Get or generate test config. 116 test_config = _get_or_generate_test_config(ctx) 117 118 # Generate result reporter config file. 119 report_config = _create_result_reporter_config(ctx) 120 121 # Symlink file names if `__test_binary` was appended in a previous rule. 122 targets = [] 123 for f in ctx.attr.test.files.to_list(): 124 if "__test_binary" not in f.basename: 125 targets.append(f) 126 else: 127 file_name = f.basename.replace("__test_binary", "") 128 out = ctx.actions.declare_file(file_name) 129 ctx.actions.symlink( 130 output = out, 131 target_file = f, 132 ) 133 targets.append(out) 134 135 # Symlink tradefed dependencies. 136 for f in ctx.files._tradefed_dependencies: 137 out = ctx.actions.declare_file(f.basename) 138 ctx.actions.symlink( 139 output = out, 140 target_file = f, 141 ) 142 targets.append(out) 143 144 # Gather runfiles. 145 runfiles = ctx.runfiles() 146 runfiles = runfiles.merge_all([ 147 ctx.attr.test.default_runfiles, 148 ctx.runfiles(files = targets + [test_config, report_config]), 149 ]) 150 151 # Generate script to run tradefed. 152 script = ctx.actions.declare_file("tradefed_test_%s.sh" % ctx.label.name) 153 ctx.actions.expand_template( 154 template = ctx.file._tradefed_test_sh_template, 155 output = script, 156 is_executable = True, 157 substitutions = { 158 "{MODULE}": ctx.attr.test_identifier, 159 }, 160 ) 161 162 return [DefaultInfo( 163 executable = script, 164 runfiles = runfiles, 165 )] 166 167# Generate and run tradefed bash script for deviceless (host) tests. 168_tradefed_test = rule( 169 doc = "A rule used to run tests using Tradefed", 170 attrs = TRADEFED_TEST_ATTRIBUTES, 171 test = True, 172 implementation = _tradefed_test_impl, 173) 174 175def tradefed_host_driven_test(**kwargs): 176 _tradefed_test( 177 **kwargs 178 ) 179 180def tradefed_device_test(**kwargs): 181 _tradefed_test( 182 host_driven = False, 183 **kwargs 184 ) 185