gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/runner/defs.bzl (about)

     1  """Defines a rule for syscall test targets."""
     2  
     3  load("//tools:defs.bzl", "default_platform", "platform_capabilities", "platforms", "save_restore_platforms")
     4  
     5  # Maps platform names to a GVISOR_PLATFORM_SUPPORT environment variable consumed by platform_util.cc
     6  _platform_support_env_vars = {
     7      platform: ",".join(sorted([
     8          ("%s:%s" % (capability, "TRUE" if supported else "FALSE"))
     9          for capability, supported in support.items()
    10      ]))
    11      for platform, support in platform_capabilities.items()
    12  }
    13  
    14  def _runner_test_impl(ctx):
    15      # Generate a runner binary.
    16      runner = ctx.actions.declare_file(ctx.label.name)
    17      runner_content = "\n".join([
    18          "#!/bin/bash",
    19          "set -euf -x -o pipefail",
    20          "if [[ -n \"${TEST_UNDECLARED_OUTPUTS_DIR}\" ]]; then",
    21          "  mkdir -p \"${TEST_UNDECLARED_OUTPUTS_DIR}\"",
    22          "  chmod a+rwx \"${TEST_UNDECLARED_OUTPUTS_DIR}\"",
    23          "fi",
    24          "exec %s %s \"$@\" %s\n" % (
    25              ctx.files.runner[0].short_path,
    26              " ".join(ctx.attr.runner_args),
    27              ctx.files.test[0].short_path,
    28          ),
    29      ])
    30      ctx.actions.write(runner, runner_content, is_executable = True)
    31  
    32      # Return with all transitive files.
    33      runfiles = ctx.runfiles(
    34          transitive_files = depset(transitive = [
    35              target.data_runfiles.files
    36              for target in (ctx.attr.runner, ctx.attr.test)
    37              if hasattr(target, "data_runfiles")
    38          ]),
    39          files = ctx.files.runner + ctx.files.test,
    40          collect_default = True,
    41          collect_data = True,
    42      )
    43      return [DefaultInfo(executable = runner, runfiles = runfiles)]
    44  
    45  _runner_test = rule(
    46      attrs = {
    47          "runner": attr.label(
    48              default = "//test/runner:runner",
    49          ),
    50          "test": attr.label(
    51              mandatory = True,
    52          ),
    53          "runner_args": attr.string_list(),
    54          "data": attr.label_list(
    55              allow_files = True,
    56          ),
    57      },
    58      test = True,
    59      implementation = _runner_test_impl,
    60  )
    61  
    62  def _syscall_test(
    63          test,
    64          platform,
    65          use_tmpfs,
    66          tags,
    67          debug,
    68          network = "none",
    69          file_access = "exclusive",
    70          overlay = False,
    71          add_host_uds = False,
    72          add_host_connector = False,
    73          add_host_fifo = False,
    74          iouring = False,
    75          container = None,
    76          one_sandbox = True,
    77          fusefs = False,
    78          directfs = False,
    79          leak_check = False,
    80          save = False,
    81          save_resume = False,
    82          **kwargs):
    83      # Prepend "runsc" to non-native platform names.
    84      full_platform = platform if platform == "native" else "runsc_" + platform
    85  
    86      # Name the test appropriately.
    87      name = test.split(":")[1] + "_" + full_platform
    88      if file_access == "shared":
    89          name += "_shared"
    90      if overlay:
    91          name += "_overlay"
    92      if network != "none":
    93          name += "_" + network + "net"
    94      if fusefs:
    95          name += "_fuse"
    96      if directfs:
    97          name += "_directfs"
    98      if save:
    99          name += "_save"
   100      if save_resume:
   101          name += "_save_resume"
   102  
   103      # Apply all tags.
   104      if tags == None:
   105          tags = []
   106  
   107      # Add the full_platform and file access in a tag to make it easier to run
   108      # all the tests on a specific flavor. Use --test_tag_filters=runsc_systrap,file_shared.
   109      tags = list(tags)
   110      tags += [full_platform, "file_" + file_access]
   111  
   112      if save or save_resume:
   113          tags.append("allsave")
   114          if platform in save_restore_platforms:
   115              if save:
   116                  tags.append("save_restore")
   117              if save_resume:
   118                  tags.append("save_resume")
   119  
   120      # Hash this target into one of 15 buckets. This can be used to
   121      # randomly split targets between different workflows.
   122      hash15 = hash(native.package_name() + name) % 15
   123      tags.append("hash15:" + str(hash15))
   124      tags.append("hash15")
   125  
   126      # Disable off-host networking.
   127      tags.append("requires-net:loopback")
   128      tags.append("requires-net:ipv4")
   129      tags.append("block-network")
   130  
   131      # gotsan makes sense only if tests are running in gVisor.
   132      if platform == "native":
   133          tags.append("nogotsan")
   134  
   135      if container == None:
   136          # Containerize in the following cases:
   137          #  - "container" is explicitly specified as a tag
   138          #  - Running tests natively
   139          #  - Running tests with host networking
   140          container = "container" in tags or network == "host"
   141  
   142      if platform == "native":
   143          # The "native" platform supports everything.
   144          platform_support = ",".join(sorted([
   145              ("%s:TRUE" % key)
   146              for key in platform_capabilities[default_platform].keys()
   147          ]))
   148      else:
   149          platform_support = _platform_support_env_vars.get(platform, "")
   150  
   151      runner_args = [
   152          # Arguments are passed directly to runner binary.
   153          "--platform=" + platform,
   154          "--platform-support=" + platform_support,
   155          "--network=" + network,
   156          "--use-tmpfs=" + str(use_tmpfs),
   157          "--fusefs=" + str(fusefs),
   158          "--file-access=" + file_access,
   159          "--overlay=" + str(overlay),
   160          "--add-host-uds=" + str(add_host_uds),
   161          "--add-host-connector=" + str(add_host_connector),
   162          "--add-host-fifo=" + str(add_host_fifo),
   163          "--strace=" + str(debug),
   164          "--debug=" + str(debug),
   165          "--container=" + str(container),
   166          "--one-sandbox=" + str(one_sandbox),
   167          "--iouring=" + str(iouring),
   168          "--directfs=" + str(directfs),
   169          "--leak-check=" + str(leak_check),
   170          "--save=" + str(save),
   171          "--save-resume=" + str(save_resume),
   172      ]
   173  
   174      # Trace points are platform agnostic, so enable them for ptrace only.
   175      if platform == "ptrace":
   176          runner_args.append("--trace")
   177  
   178      # Call the rule above.
   179      _runner_test(
   180          name = name,
   181          test = test,
   182          runner_args = runner_args,
   183          tags = tags,
   184          **kwargs
   185      )
   186  
   187  def all_platforms():
   188      """All platforms returns a list of all platforms."""
   189      available = dict(platforms.items())
   190      available[default_platform] = platforms.get(default_platform, [])
   191      return available.items()
   192  
   193  def syscall_test_variants(
   194          test,
   195          use_tmpfs = False,
   196          add_fusefs = False,
   197          add_overlay = False,
   198          add_host_uds = False,
   199          add_host_connector = False,
   200          add_host_fifo = False,
   201          add_hostinet = False,
   202          add_directfs = True,
   203          one_sandbox = True,
   204          iouring = False,
   205          allow_native = True,
   206          leak_check = True,
   207          debug = True,
   208          container = None,
   209          tags = None,
   210          save = False,
   211          save_resume = False,
   212          size = "medium",
   213          timeout = None,
   214          **kwargs):
   215      """Generates syscall tests for all variants.
   216  
   217      Args:
   218        test: the test target.
   219        use_tmpfs: use tmpfs in the defined tests.
   220        add_fusefs: add a fusefs test.
   221        add_overlay: add an overlay test.
   222        add_host_uds: setup bound UDS on the host.
   223        add_host_connector: setup host threads to connect to bound UDS created by sandbox.
   224        add_host_fifo: setup FIFO files on the host.
   225        add_hostinet: add a hostinet test.
   226        add_directfs: add a directfs test.
   227        one_sandbox: runs each unit test in a new sandbox instance.
   228        iouring: enable IO_URING support.
   229        allow_native: generate a native test variant.
   230        debug: enable debug output.
   231        container: Run the test in a container. If None, determined from other information.
   232        tags: starting test tags.
   233        leak_check: enables leak check.
   234        save: save restore test.
   235        size: test size.
   236        timeout: timeout for the test.
   237        save_resume: save resume test.
   238        **kwargs: additional test arguments.
   239      """
   240      for platform, platform_tags in all_platforms():
   241          # Add directfs to the default platform variant.
   242          directfs = add_directfs and platform == default_platform
   243          _syscall_test(
   244              test = test,
   245              platform = platform,
   246              use_tmpfs = use_tmpfs,
   247              add_host_uds = add_host_uds,
   248              add_host_connector = add_host_connector,
   249              add_host_fifo = add_host_fifo,
   250              tags = platform_tags + tags,
   251              iouring = iouring,
   252              directfs = directfs,
   253              debug = debug,
   254              container = container,
   255              one_sandbox = one_sandbox,
   256              leak_check = leak_check,
   257              save = save,
   258              save_resume = save_resume,
   259              size = size,
   260              timeout = timeout,
   261              **kwargs
   262          )
   263  
   264      if add_overlay:
   265          _syscall_test(
   266              test = test,
   267              platform = default_platform,
   268              use_tmpfs = use_tmpfs,
   269              add_host_uds = add_host_uds,
   270              add_host_connector = add_host_connector,
   271              add_host_fifo = add_host_fifo,
   272              tags = platforms.get(default_platform, []) + tags,
   273              debug = debug,
   274              iouring = iouring,
   275              container = container,
   276              one_sandbox = one_sandbox,
   277              overlay = True,
   278              leak_check = leak_check,
   279              save = save,
   280              save_resume = save_resume,
   281              size = size,
   282              timeout = timeout,
   283              **kwargs
   284          )
   285  
   286      # TODO(b/192114729): hostinet is not supported with S/R.
   287      if add_hostinet and not (save or save_resume):
   288          _syscall_test(
   289              test = test,
   290              platform = default_platform,
   291              use_tmpfs = use_tmpfs,
   292              network = "host",
   293              add_host_uds = add_host_uds,
   294              add_host_connector = add_host_connector,
   295              add_host_fifo = add_host_fifo,
   296              tags = platforms.get(default_platform, []) + tags,
   297              debug = debug,
   298              iouring = iouring,
   299              container = container,
   300              one_sandbox = one_sandbox,
   301              leak_check = leak_check,
   302              save = save,
   303              save_resume = save_resume,
   304              size = size,
   305              timeout = timeout,
   306              **kwargs
   307          )
   308      if not use_tmpfs:
   309          # Also test shared gofer access.
   310          _syscall_test(
   311              test = test,
   312              platform = default_platform,
   313              use_tmpfs = use_tmpfs,
   314              add_host_uds = add_host_uds,
   315              add_host_connector = add_host_connector,
   316              add_host_fifo = add_host_fifo,
   317              tags = platforms.get(default_platform, []) + tags,
   318              iouring = iouring,
   319              debug = debug,
   320              container = container,
   321              one_sandbox = one_sandbox,
   322              file_access = "shared",
   323              leak_check = leak_check,
   324              save = save,
   325              save_resume = save_resume,
   326              size = size,
   327              timeout = timeout,
   328              **kwargs
   329          )
   330      if add_fusefs:
   331          _syscall_test(
   332              test = test,
   333              platform = default_platform,
   334              use_tmpfs = True,
   335              fusefs = True,
   336              add_host_uds = add_host_uds,
   337              add_host_connector = add_host_connector,
   338              add_host_fifo = add_host_fifo,
   339              tags = platforms.get(default_platform, []) + tags,
   340              debug = debug,
   341              container = container,
   342              one_sandbox = one_sandbox,
   343              leak_check = leak_check,
   344              save = save,
   345              save_resume = save_resume,
   346              size = size,
   347              timeout = timeout,
   348              **kwargs
   349          )
   350  
   351  def syscall_test(
   352          test,
   353          use_tmpfs = False,
   354          add_fusefs = False,
   355          add_overlay = False,
   356          add_host_uds = False,
   357          add_host_connector = False,
   358          add_host_fifo = False,
   359          add_hostinet = False,
   360          add_directfs = True,
   361          one_sandbox = True,
   362          iouring = False,
   363          allow_native = True,
   364          leak_check = True,
   365          debug = True,
   366          container = None,
   367          tags = None,
   368          save = True,
   369          size = "medium",
   370          **kwargs):
   371      """syscall_test is a macro that will create targets for all platforms.
   372  
   373      Args:
   374        test: the test target.
   375        use_tmpfs: use tmpfs in the defined tests.
   376        add_fusefs: add a fusefs test.
   377        add_overlay: add an overlay test.
   378        add_host_uds: setup bound UDS on the host.
   379        add_host_connector: setup host threads to connect to bound UDS created by sandbox.
   380        add_host_fifo: setup FIFO files on the host.
   381        add_hostinet: add a hostinet test.
   382        add_directfs: add a directfs test.
   383        one_sandbox: runs each unit test in a new sandbox instance.
   384        iouring: enable IO_URING support.
   385        allow_native: generate a native test variant.
   386        debug: enable debug output.
   387        container: Run the test in a container. If None, determined from other information.
   388        tags: starting test tags.
   389        leak_check: enables leak check.
   390        save: enables save/restore and save/resume test variants.
   391        size: test size.
   392        **kwargs: additional test arguments.
   393      """
   394      if not tags:
   395          tags = []
   396  
   397      if allow_native:
   398          _syscall_test(
   399              test = test,
   400              platform = "native",
   401              use_tmpfs = False,
   402              add_host_uds = add_host_uds,
   403              add_host_connector = add_host_connector,
   404              add_host_fifo = add_host_fifo,
   405              tags = tags,
   406              iouring = iouring,
   407              debug = debug,
   408              container = container,
   409              one_sandbox = one_sandbox,
   410              **kwargs
   411          )
   412  
   413      syscall_test_variants(
   414          test,
   415          use_tmpfs,
   416          add_fusefs,
   417          add_overlay,
   418          add_host_uds,
   419          add_host_connector,
   420          add_host_fifo,
   421          add_hostinet,
   422          add_directfs,
   423          one_sandbox,
   424          iouring,
   425          allow_native,
   426          leak_check,
   427          debug,
   428          container,
   429          tags,
   430          False,  # save, generate all tests without save variant.
   431          False,  # save_resume, generate all tests without save_resume variant.
   432          size,
   433          **kwargs
   434      )
   435  
   436      # Add save and save_resume variants to all other variants generated above.
   437      if save:
   438          # Disable go sanitizers for save tests.
   439          tags.append("nogotsan")
   440          syscall_test_variants(
   441              test,
   442              use_tmpfs,
   443              add_fusefs,
   444              add_overlay,
   445              add_host_uds,
   446              add_host_connector,
   447              add_host_fifo,
   448              add_hostinet,
   449              add_directfs,
   450              one_sandbox,
   451              iouring,
   452              allow_native,
   453              leak_check,
   454              debug,
   455              container,
   456              tags,
   457              True,  # save, generate all tests with save variant.
   458              False,  # save_resume, generate all tests without save_resume variant.
   459              "large",  # size, use size as large by default for all S/R tests.
   460              "long",  # timeout, use long timeout for S/R tests.
   461              **kwargs
   462          )
   463  
   464          # Add save resume variant to all other variants generated above.
   465          syscall_test_variants(
   466              test,
   467              use_tmpfs,
   468              add_fusefs,
   469              add_overlay,
   470              add_host_uds,
   471              add_host_connector,
   472              add_host_fifo,
   473              add_hostinet,
   474              add_directfs,
   475              one_sandbox,
   476              iouring,
   477              allow_native,
   478              leak_check,
   479              debug,
   480              container,
   481              tags,
   482              False,  # save, generate all tests without save variant.
   483              True,  # save_resume, generate all tests with save_resume variant.
   484              "large",  # size, use size as large by default for all S/R tests.
   485              "long",  # timeout, use long timeout for S/R tests.
   486              **kwargs
   487          )