1#!/usr/bin/env python3 2# Copyright 2016 gRPC authors. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15"""Definition of targets run distribution package tests.""" 16 17import os.path 18import sys 19 20sys.path.insert(0, os.path.abspath("..")) 21import python_utils.jobset as jobset 22 23 24def create_docker_jobspec( 25 name, 26 dockerfile_dir, 27 shell_command, 28 environ={}, 29 flake_retries=0, 30 timeout_retries=0, 31 copy_rel_path=None, 32 timeout_seconds=30 * 60, 33): 34 """Creates jobspec for a task running under docker.""" 35 environ = environ.copy() 36 # the entire repo will be cloned if copy_rel_path is not set. 37 if copy_rel_path: 38 environ["RELATIVE_COPY_PATH"] = copy_rel_path 39 40 docker_args = [] 41 for k, v in list(environ.items()): 42 docker_args += ["-e", "%s=%s" % (k, v)] 43 docker_env = { 44 "DOCKERFILE_DIR": dockerfile_dir, 45 "DOCKER_RUN_SCRIPT": "tools/run_tests/dockerize/docker_run.sh", 46 "DOCKER_RUN_SCRIPT_COMMAND": shell_command, 47 } 48 jobspec = jobset.JobSpec( 49 cmdline=["tools/run_tests/dockerize/build_and_run_docker.sh"] 50 + docker_args, 51 environ=docker_env, 52 shortname="distribtest.%s" % (name), 53 timeout_seconds=timeout_seconds, 54 flake_retries=flake_retries, 55 timeout_retries=timeout_retries, 56 ) 57 return jobspec 58 59 60def create_jobspec( 61 name, 62 cmdline, 63 environ=None, 64 shell=False, 65 flake_retries=0, 66 timeout_retries=0, 67 use_workspace=False, 68 timeout_seconds=10 * 60, 69): 70 """Creates jobspec.""" 71 environ = environ.copy() 72 if use_workspace: 73 environ["WORKSPACE_NAME"] = "workspace_%s" % name 74 cmdline = [ 75 "bash", 76 "tools/run_tests/artifacts/run_in_workspace.sh", 77 ] + cmdline 78 jobspec = jobset.JobSpec( 79 cmdline=cmdline, 80 environ=environ, 81 shortname="distribtest.%s" % (name), 82 timeout_seconds=timeout_seconds, 83 flake_retries=flake_retries, 84 timeout_retries=timeout_retries, 85 shell=shell, 86 ) 87 return jobspec 88 89 90class CSharpDistribTest(object): 91 """Tests C# NuGet package""" 92 93 def __init__( 94 self, 95 platform, 96 arch, 97 docker_suffix=None, 98 use_dotnet_cli=False, 99 presubmit=False, 100 ): 101 self.name = "csharp_%s_%s" % (platform, arch) 102 self.platform = platform 103 self.arch = arch 104 self.docker_suffix = docker_suffix 105 self.labels = ["distribtest", "csharp", platform, arch] 106 if presubmit: 107 self.labels.append("presubmit") 108 self.script_suffix = "" 109 if docker_suffix: 110 self.name += "_%s" % docker_suffix 111 self.labels.append(docker_suffix) 112 if use_dotnet_cli: 113 self.name += "_dotnetcli" 114 self.script_suffix = "_dotnetcli" 115 self.labels.append("dotnetcli") 116 else: 117 self.labels.append("olddotnet") 118 119 def pre_build_jobspecs(self): 120 return [] 121 122 def build_jobspec(self, inner_jobs=None): 123 del inner_jobs # arg unused as there is little opportunity for parallelizing whats inside the distribtests 124 if self.platform == "linux": 125 return create_docker_jobspec( 126 self.name, 127 "tools/dockerfile/distribtest/csharp_%s_%s" 128 % (self.docker_suffix, self.arch), 129 "test/distrib/csharp/run_distrib_test%s.sh" 130 % self.script_suffix, 131 copy_rel_path="test/distrib", 132 ) 133 elif self.platform == "macos": 134 return create_jobspec( 135 self.name, 136 [ 137 "test/distrib/csharp/run_distrib_test%s.sh" 138 % self.script_suffix 139 ], 140 environ={ 141 "EXTERNAL_GIT_ROOT": "../../../..", 142 "SKIP_NETCOREAPP21_DISTRIBTEST": "1", 143 "SKIP_NET50_DISTRIBTEST": "1", 144 }, 145 use_workspace=True, 146 ) 147 elif self.platform == "windows": 148 # TODO(jtattermusch): re-enable windows distribtest 149 return create_jobspec( 150 self.name, 151 ["bash", "tools/run_tests/artifacts/run_distribtest_csharp.sh"], 152 environ={}, 153 use_workspace=True, 154 ) 155 else: 156 raise Exception("Not supported yet.") 157 158 def __str__(self): 159 return self.name 160 161 162class PythonDistribTest(object): 163 """Tests Python package""" 164 165 def __init__( 166 self, platform, arch, docker_suffix, source=False, presubmit=False 167 ): 168 self.source = source 169 if source: 170 self.name = "python_dev_%s_%s_%s" % (platform, arch, docker_suffix) 171 else: 172 self.name = "python_%s_%s_%s" % (platform, arch, docker_suffix) 173 self.platform = platform 174 self.arch = arch 175 self.docker_suffix = docker_suffix 176 self.labels = ["distribtest", "python", platform, arch, docker_suffix] 177 if presubmit: 178 self.labels.append("presubmit") 179 180 def pre_build_jobspecs(self): 181 return [] 182 183 def build_jobspec(self, inner_jobs=None): 184 # TODO(jtattermusch): honor inner_jobs arg for this task. 185 del inner_jobs 186 if not self.platform == "linux": 187 raise Exception("Not supported yet.") 188 189 if self.source: 190 return create_docker_jobspec( 191 self.name, 192 "tools/dockerfile/distribtest/python_dev_%s_%s" 193 % (self.docker_suffix, self.arch), 194 "test/distrib/python/run_source_distrib_test.sh", 195 copy_rel_path="test/distrib", 196 timeout_seconds=45 * 60, 197 ) 198 else: 199 return create_docker_jobspec( 200 self.name, 201 "tools/dockerfile/distribtest/python_%s_%s" 202 % (self.docker_suffix, self.arch), 203 "test/distrib/python/run_binary_distrib_test.sh", 204 copy_rel_path="test/distrib", 205 timeout_seconds=45 * 60, 206 ) 207 208 def __str__(self): 209 return self.name 210 211 212class RubyDistribTest(object): 213 """Tests Ruby package""" 214 215 def __init__( 216 self, 217 platform, 218 arch, 219 docker_suffix, 220 ruby_version=None, 221 source=False, 222 presubmit=False, 223 protobuf_version="", 224 ): 225 self.package_type = "binary" 226 if source: 227 self.package_type = "source" 228 self.name = "ruby_%s_%s_%s_version_%s_package_type_%s" % ( 229 platform, 230 arch, 231 docker_suffix, 232 ruby_version or "unspecified", 233 self.package_type, 234 ) 235 if not protobuf_version == "": 236 self.name += "_protobuf_%s" % protobuf_version 237 self.platform = platform 238 self.arch = arch 239 self.docker_suffix = docker_suffix 240 self.ruby_version = ruby_version 241 self.protobuf_version = protobuf_version 242 self.labels = ["distribtest", "ruby", platform, arch, docker_suffix] 243 if presubmit: 244 self.labels.append("presubmit") 245 246 def pre_build_jobspecs(self): 247 return [] 248 249 def build_jobspec(self, inner_jobs=None): 250 # TODO(jtattermusch): honor inner_jobs arg for this task. 251 del inner_jobs 252 arch_to_gem_arch = { 253 "x64": "x86_64", 254 "x86": "x86", 255 } 256 if not self.platform == "linux": 257 raise Exception("Not supported yet.") 258 259 dockerfile_name = "tools/dockerfile/distribtest/ruby_%s_%s" % ( 260 self.docker_suffix, 261 self.arch, 262 ) 263 if self.ruby_version is not None: 264 dockerfile_name += "_%s" % self.ruby_version 265 return create_docker_jobspec( 266 self.name, 267 dockerfile_name, 268 "test/distrib/ruby/run_distrib_test.sh %s %s %s %s" 269 % ( 270 arch_to_gem_arch[self.arch], 271 self.platform, 272 self.package_type, 273 self.protobuf_version, 274 ), 275 copy_rel_path="test/distrib", 276 ) 277 278 def __str__(self): 279 return self.name 280 281 282class PHP8DistribTest(object): 283 """Tests PHP8 package""" 284 285 def __init__(self, platform, arch, docker_suffix=None, presubmit=False): 286 self.name = "php8_%s_%s_%s" % (platform, arch, docker_suffix) 287 self.platform = platform 288 self.arch = arch 289 self.docker_suffix = docker_suffix 290 self.labels = ["distribtest", "php", "php8", platform, arch] 291 if presubmit: 292 self.labels.append("presubmit") 293 if docker_suffix: 294 self.labels.append(docker_suffix) 295 296 def pre_build_jobspecs(self): 297 return [] 298 299 def build_jobspec(self, inner_jobs=None): 300 # TODO(jtattermusch): honor inner_jobs arg for this task. 301 del inner_jobs 302 if self.platform == "linux": 303 return create_docker_jobspec( 304 self.name, 305 "tools/dockerfile/distribtest/php8_%s_%s" 306 % (self.docker_suffix, self.arch), 307 "test/distrib/php/run_distrib_test.sh", 308 copy_rel_path="test/distrib", 309 ) 310 elif self.platform == "macos": 311 return create_jobspec( 312 self.name, 313 ["test/distrib/php/run_distrib_test_macos.sh"], 314 environ={"EXTERNAL_GIT_ROOT": "../../../.."}, 315 timeout_seconds=30 * 60, 316 use_workspace=True, 317 ) 318 else: 319 raise Exception("Not supported yet.") 320 321 def __str__(self): 322 return self.name 323 324 325class CppDistribTest(object): 326 """Tests Cpp make install by building examples.""" 327 328 def __init__( 329 self, platform, arch, docker_suffix=None, testcase=None, presubmit=False 330 ): 331 if platform == "linux": 332 self.name = "cpp_%s_%s_%s_%s" % ( 333 platform, 334 arch, 335 docker_suffix, 336 testcase, 337 ) 338 else: 339 self.name = "cpp_%s_%s_%s" % (platform, arch, testcase) 340 self.platform = platform 341 self.arch = arch 342 self.docker_suffix = docker_suffix 343 self.testcase = testcase 344 self.labels = [ 345 "distribtest", 346 "cpp", 347 platform, 348 arch, 349 testcase, 350 ] 351 if presubmit: 352 self.labels.append("presubmit") 353 if docker_suffix: 354 self.labels.append(docker_suffix) 355 356 def pre_build_jobspecs(self): 357 return [] 358 359 def build_jobspec(self, inner_jobs=None): 360 environ = {} 361 if inner_jobs is not None: 362 # set number of parallel jobs for the C++ build 363 environ["GRPC_CPP_DISTRIBTEST_BUILD_COMPILER_JOBS"] = str( 364 inner_jobs 365 ) 366 367 if self.platform == "linux": 368 return create_docker_jobspec( 369 self.name, 370 "tools/dockerfile/distribtest/cpp_%s_%s" 371 % (self.docker_suffix, self.arch), 372 "test/distrib/cpp/run_distrib_test_%s.sh" % self.testcase, 373 timeout_seconds=60 * 60, 374 ) 375 elif self.platform == "windows": 376 return create_jobspec( 377 self.name, 378 ["test\\distrib\\cpp\\run_distrib_test_%s.bat" % self.testcase], 379 environ={}, 380 timeout_seconds=60 * 60, 381 use_workspace=True, 382 ) 383 else: 384 raise Exception("Not supported yet.") 385 386 def __str__(self): 387 return self.name 388 389 390def targets(): 391 """Gets list of supported targets""" 392 return [ 393 # C++ 394 # The "dummy" C++ distribtest so that the set of tasks to run isn't empty 395 # when grpc_distribtest_standalone runs on PRs. 396 CppDistribTest("linux", "x64", "debian11", "dummy", presubmit=True), 397 CppDistribTest("linux", "x64", "debian11", "cmake", presubmit=False), 398 CppDistribTest( 399 "linux", "x64", "debian11", "cmake_as_submodule", presubmit=False 400 ), 401 CppDistribTest( 402 "linux", 403 "x64", 404 "debian11", 405 "cmake_as_externalproject", 406 presubmit=False, 407 ), 408 CppDistribTest( 409 "linux", "x64", "debian11", "cmake_fetchcontent", presubmit=False 410 ), 411 CppDistribTest( 412 "linux", "x64", "debian11", "cmake_module_install", presubmit=False 413 ), 414 CppDistribTest( 415 "linux", "x64", "debian11", "cmake_pkgconfig", presubmit=False 416 ), 417 CppDistribTest( 418 "linux", 419 "x64", 420 "debian11_aarch64_cross", 421 "cmake_aarch64_cross", 422 presubmit=False, 423 ), 424 CppDistribTest("windows", "x86", testcase="cmake", presubmit=True), 425 CppDistribTest( 426 "windows", 427 "x86", 428 testcase="cmake_as_externalproject", 429 presubmit=True, 430 ), 431 CppDistribTest( 432 "windows", 433 "x86", 434 testcase="cmake_for_dll", 435 presubmit=True, 436 ), 437 # C# 438 CSharpDistribTest( 439 "linux", "x64", "debian11", use_dotnet_cli=True, presubmit=True 440 ), 441 CSharpDistribTest("linux", "x64", "ubuntu2204", use_dotnet_cli=True), 442 CSharpDistribTest( 443 "linux", "x64", "alpine", use_dotnet_cli=True, presubmit=True 444 ), 445 CSharpDistribTest( 446 "linux", "x64", "dotnet31", use_dotnet_cli=True, presubmit=True 447 ), 448 CSharpDistribTest( 449 "linux", "x64", "dotnet5", use_dotnet_cli=True, presubmit=True 450 ), 451 CSharpDistribTest("macos", "x64", use_dotnet_cli=True, presubmit=True), 452 CSharpDistribTest("windows", "x86", presubmit=True), 453 CSharpDistribTest("windows", "x64", presubmit=True), 454 # Python 455 PythonDistribTest("linux", "x64", "bullseye", presubmit=True), 456 PythonDistribTest("linux", "x86", "bullseye", presubmit=True), 457 PythonDistribTest("linux", "x64", "fedora39"), 458 PythonDistribTest("linux", "x64", "arch"), 459 PythonDistribTest("linux", "x64", "alpine"), 460 PythonDistribTest("linux", "x64", "ubuntu2204"), 461 PythonDistribTest( 462 "linux", "aarch64", "python38_buster", presubmit=True 463 ), 464 PythonDistribTest( 465 "linux", "x64", "alpine3.7", source=True, presubmit=True 466 ), 467 PythonDistribTest( 468 "linux", "x64", "bullseye", source=True, presubmit=True 469 ), 470 PythonDistribTest( 471 "linux", "x86", "bullseye", source=True, presubmit=True 472 ), 473 PythonDistribTest("linux", "x64", "fedora39", source=True), 474 PythonDistribTest("linux", "x64", "arch", source=True), 475 PythonDistribTest("linux", "x64", "ubuntu2204", source=True), 476 # Ruby 477 RubyDistribTest( 478 "linux", 479 "x64", 480 "debian11", 481 ruby_version="ruby_3_2", 482 source=True, 483 presubmit=True, 484 ), 485 RubyDistribTest( 486 "linux", "x64", "debian11", ruby_version="ruby_3_0", presubmit=True 487 ), 488 RubyDistribTest( 489 "linux", "x64", "debian11", ruby_version="ruby_3_1", presubmit=True 490 ), 491 RubyDistribTest( 492 "linux", "x64", "debian11", ruby_version="ruby_3_2", presubmit=True 493 ), 494 RubyDistribTest( 495 "linux", "x64", "debian11", ruby_version="ruby_3_3", presubmit=True 496 ), 497 RubyDistribTest( 498 "linux", 499 "x64", 500 "debian11", 501 ruby_version="ruby_3_3", 502 protobuf_version="3.25", 503 presubmit=True, 504 ), 505 RubyDistribTest( 506 "linux", "x64", "debian11", ruby_version="ruby_3_4", presubmit=True 507 ), 508 RubyDistribTest("linux", "x64", "ubuntu2004"), 509 RubyDistribTest("linux", "x64", "ubuntu2204", presubmit=True), 510 # PHP8 511 PHP8DistribTest("linux", "x64", "debian12", presubmit=True), 512 PHP8DistribTest("macos", "x64", presubmit=True), 513 ] 514