Supports regression test in fuzzing_launcher (#56)

Supports regression test in fuzzing_launcher

Adds string_flag engine to decide the fuzzing_launcher behavior.

Adds engine to launcher and adds is_regression to fuzzing_launcher

Constructs all launcher args in a list

Signed-off-by: tengpeng <tengpeng.li2020@gmail.com>

	modified:   .bazelrc
	modified:   WORKSPACE
	modified:   fuzzing/BUILD
	modified:   fuzzing/common.bzl
	modified:   fuzzing/repositories.bzl
	modified:   fuzzing/tools/launcher.py
diff --git a/.bazelrc b/.bazelrc
index 04e7893..f7e8121 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -21,11 +21,13 @@
 build:asan-libfuzzer --config=clang
 build:asan-libfuzzer --linkopt=-fsanitize=fuzzer,address
 build:asan-libfuzzer --copt=-fsanitize=fuzzer,address
+build:asan-libfuzzer --//fuzzing:engine=libfuzzer
 
 # Flags for Clang with MSAN and libfuzzer
 build:msan-libfuzzer --config=clang
 build:msan-libfuzzer --linkopt=-fsanitize=memory,fuzzer
 build:msan-libfuzzer --copt=-fsanitize=memory,fuzzer
+build:msan-libfuzzer --//fuzzing:engine=libfuzzer
 
 # Flags for Clang with MSAN and libfuzzer, outputting detailed report
 build:msan-libfuzzer-repro --config=msan-libfuzzer
diff --git a/WORKSPACE b/WORKSPACE
index e9acaea..d12000d 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -18,6 +18,9 @@
 load("//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
 rules_fuzzing_dependencies()
 
+load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+bazel_skylib_workspace()
+
 load("@rules_python//python:repositories.bzl", "py_repositories")
 py_repositories()
 
diff --git a/fuzzing/BUILD b/fuzzing/BUILD
index 12ffde7..4aea218 100644
--- a/fuzzing/BUILD
+++ b/fuzzing/BUILD
@@ -12,3 +12,15 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
+load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
+
+string_flag(
+    name = "engine",
+    build_setting_default = "default",
+    values = [
+        "default",
+        "libfuzzer",
+    ],
+    visibility = ["//visibility:public"],
+)
diff --git a/fuzzing/cc_deps.bzl b/fuzzing/cc_deps.bzl
index 5c5b930..59f556a 100644
--- a/fuzzing/cc_deps.bzl
+++ b/fuzzing/cc_deps.bzl
@@ -52,6 +52,7 @@
         name = name + "_run",
         target = name,
         corpus = name + "_corpus" if corpus else None,
+        is_regression = False,
         # Since the script depends on the _fuzz_test above, which is a cc_test,
         # this attribute must be set.
         testonly = True,
diff --git a/fuzzing/common.bzl b/fuzzing/common.bzl
index c7db93d..c1604a9 100644
--- a/fuzzing/common.bzl
+++ b/fuzzing/common.bzl
@@ -15,18 +15,26 @@
 
 """This file contains common rules for fuzzing test."""
 
+load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
+
 def _fuzzing_launcher_impl(ctx):
     # Generate a script to launcher the fuzzing test.
     script = ctx.actions.declare_file("%s" % ctx.label.name)
+    args = [
+        ctx.executable._launcher.short_path,
+        ctx.executable.target.short_path,
+        "--corpus_dir=" + ctx.file.corpus.short_path if ctx.attr.corpus else "",
+        "--engine=" + ctx.attr._engine[BuildSettingInfo].value,
+    ]
+
+    if ctx.attr.is_regression:
+        args.append("--regression=True")
 
     script_template = """#!/bin/sh
-exec {launcher_path} {target_binary_path} --corpus_dir={corpus_dir} "$@"
-"""
+exec {launcher_args} "$@" """
 
     script_content = script_template.format(
-        launcher_path = ctx.executable._launcher.short_path,
-        target_binary_path = ctx.executable.target.short_path,
-        corpus_dir = ctx.file.corpus.short_path if ctx.attr.corpus else "",
+        launcher_args = " ".join(args),
     )
     ctx.actions.write(script, script_content, is_executable = True)
 
@@ -50,6 +58,11 @@
             executable = True,
             cfg = "host",
         ),
+        "_engine": attr.label(
+            default = ":engine",
+            doc = "The engine type.",
+            providers = [BuildSettingInfo],
+        ),
         "target": attr.label(
             executable = True,
             doc = "The fuzzing test to run.",
@@ -60,6 +73,10 @@
             doc = "The target to create a directory containing corpus files.",
             allow_single_file = True,
         ),
+        "is_regression": attr.bool(
+            doc = "If set true the target is for a regression test.",
+            default = True,
+        ),
     },
     executable = True,
 )
diff --git a/fuzzing/repositories.bzl b/fuzzing/repositories.bzl
index b01336e..18d24ec 100644
--- a/fuzzing/repositories.bzl
+++ b/fuzzing/repositories.bzl
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Contains the external dependencies
+"""Contains the external dependencies."""
 
 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
 
@@ -30,3 +30,12 @@
         url = "https://github.com/bazelbuild/rules_pkg/releases/download/0.2.5/rules_pkg-0.2.5.tar.gz",
         sha256 = "352c090cc3d3f9a6b4e676cf42a6047c16824959b438895a76c2989c6d7c246a",
     )
+
+    http_archive(
+        name = "bazel_skylib",
+        urls = [
+            "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz",
+            "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz",
+        ],
+        sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44",
+    )
diff --git a/fuzzing/tools/launcher.py b/fuzzing/tools/launcher.py
index adc2ed3..21e47de 100644
--- a/fuzzing/tools/launcher.py
+++ b/fuzzing/tools/launcher.py
@@ -36,6 +36,14 @@
     "If non-empty, a directory that will be used as a seed corpus for the fuzzer run."
 )
 
+flags.DEFINE_enum(
+    "engine", "default", ["default", "libfuzzer"],
+    "The type of the engine, the default is to run a gUnit test.")
+
+flags.DEFINE_bool(
+    "regression", False,
+    "If set True, the script will trigger the target as a regression test.")
+
 
 def main(argv):
     if len(argv) != 2:
@@ -44,8 +52,11 @@
             "\n\tpython " + __file__ + " EXECUTABLE")
 
     command_args = [argv[1]]
-    command_args.append("-max_total_time=" + str(FLAGS.timeout_secs))
-    command_args.append("-timeout=" + str(FLAGS.timeout_secs))
+    if FLAGS.engine == "libfuzzer":
+        command_args.append("-max_total_time=" + str(FLAGS.timeout_secs))
+        command_args.append("-timeout=" + str(FLAGS.timeout_secs))
+        if FLAGS.regression:
+            command_args.append("-runs=0")
     if FLAGS.corpus_dir:
         command_args.append(FLAGS.corpus_dir)
     os.execv(argv[1], command_args)