• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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