From f4a08988a1b1eb57d18f9b522682193d789277d8 Mon Sep 17 00:00:00 2001 From: Laith Sakka Date: Mon, 20 Nov 2023 11:48:32 -0800 Subject: [PATCH] Create ExpressionFuzzerVerifier::Options and move all flags to FuzzerRunner (#7634) Summary: Fuzzer runner is the component that wraps ExpressionFuzzerVerifier into a unit test. Instead of ExpressionFuzzerVerifier reading the options from global flags this diff add ExpressionFuzzerVerifier::Options. Fuzzer runner will read all configs and pass it to ExpressionFuzzerVerifier. With this change there is no more global configs controlling ExpressionFuzzerVerifier or ExpressionFuzzer. All config reading happens in FuzzerRunner.cpp only. Differential Revision: D51417731 --- .../expression/tests/ExpressionFuzzerTest.cpp | 2 + .../tests/ExpressionFuzzerVerifier.cpp | 229 +++--------------- .../tests/ExpressionFuzzerVerifier.h | 59 ++++- velox/expression/tests/FuzzerRunner.cpp | 187 +++++++++++++- velox/expression/tests/FuzzerRunner.h | 5 +- .../tests/SparkExpressionFuzzerTest.cpp | 2 + 6 files changed, 285 insertions(+), 199 deletions(-) diff --git a/velox/expression/tests/ExpressionFuzzerTest.cpp b/velox/expression/tests/ExpressionFuzzerTest.cpp index c6e0e15d981f9..5d25c16442332 100644 --- a/velox/expression/tests/ExpressionFuzzerTest.cpp +++ b/velox/expression/tests/ExpressionFuzzerTest.cpp @@ -27,6 +27,8 @@ DEFINE_int64( "Initial seed for random number generator used to reproduce previous " "results (0 means start with random seed)."); +using facebook::velox::test::FuzzerRunner; + int main(int argc, char** argv) { facebook::velox::functions::prestosql::registerAllScalarFunctions(); diff --git a/velox/expression/tests/ExpressionFuzzerVerifier.cpp b/velox/expression/tests/ExpressionFuzzerVerifier.cpp index 084471d3a2555..fd102e96586e5 100644 --- a/velox/expression/tests/ExpressionFuzzerVerifier.cpp +++ b/velox/expression/tests/ExpressionFuzzerVerifier.cpp @@ -31,190 +31,12 @@ #include "velox/expression/tests/ExpressionFuzzer.h" #include "velox/expression/tests/utils/ArgumentTypeFuzzer.h" -DEFINE_int32(steps, 10, "Number of expressions to generate and execute."); - -DEFINE_int32( - duration_sec, - 0, - "For how long it should run (in seconds). If zero, " - "it executes exactly --steps iterations and exits."); - -DEFINE_int32( - batch_size, - 100, - "The number of elements on each generated vector."); - -DEFINE_bool( - retry_with_try, - false, - "Retry failed expressions by wrapping it using a try() statement."); - -DEFINE_bool( - find_minimal_subexpression, - false, - "Automatically seeks minimum failed subexpression on result mismatch"); - -DEFINE_bool( - disable_constant_folding, - false, - "Disable constant-folding in the common evaluation path."); - -DEFINE_string( - repro_persist_path, - "", - "Directory path for persistence of data and SQL when fuzzer fails for " - "future reproduction. Empty string disables this feature."); - -DEFINE_bool( - persist_and_run_once, - false, - "Persist repro info before evaluation and only run one iteration. " - "This is to rerun with the seed number and persist repro info upon a " - "crash failure. Only effective if repro_persist_path is set."); - -DEFINE_double( - lazy_vector_generation_ratio, - 0.0, - "Specifies the probability with which columns in the input row " - "vector will be selected to be wrapped in lazy encoding " - "(expressed as double from 0 to 1)."); - -DEFINE_int32( - max_expression_trees_per_step, - 1, - "This sets an upper limit on the number of expression trees to generate " - "per step. These trees would be executed in the same ExprSet and can " - "re-use already generated columns and subexpressions (if re-use is " - "enabled)."); - -// The flags bellow are used to initialize ExpressionFuzzer::options. -DEFINE_string( - only, - "", - "If specified, Fuzzer will only choose functions from " - "this comma separated list of function names " - "(e.g: --only \"split\" or --only \"substr,ltrim\")."); - -DEFINE_string( - special_forms, - "and,or,cast,coalesce,if,switch", - "Comma-separated list of special forms to use in generated expression. " - "Supported special forms: and, or, coalesce, if, switch, cast."); - -DEFINE_int32( - velox_fuzzer_max_level_of_nesting, - 10, - "Max levels of expression nesting. The default value is 10 and minimum is 1."); - -DEFINE_int32( - max_num_varargs, - 5, - "The maximum number of variadic arguments fuzzer will generate for " - "functions that accept variadic arguments. Fuzzer will generate up to " - "max_num_varargs arguments for the variadic list in addition to the " - "required arguments by the function."); - -DEFINE_double( - null_ratio, - 0.1, - "Chance of adding a null constant to the plan, or null value in a vector " - "(expressed as double from 0 to 1)."); - -DEFINE_bool( - enable_variadic_signatures, - false, - "Enable testing of function signatures with variadic arguments."); - -DEFINE_bool( - enable_dereference, - false, - "Allow fuzzer to generate random expressions with dereference and row_constructor functions."); - -DEFINE_bool( - velox_fuzzer_enable_complex_types, - false, - "Enable testing of function signatures with complex argument or return types."); - -DEFINE_bool( - velox_fuzzer_enable_column_reuse, - false, - "Enable generation of expressions where one input column can be " - "used by multiple subexpressions"); - -DEFINE_bool( - velox_fuzzer_enable_expression_reuse, - false, - "Enable generation of expressions that re-uses already generated " - "subexpressions."); - -DEFINE_string( - assign_function_tickets, - "", - "Comma separated list of function names and their tickets in the format " - "=. Every ticket represents an opportunity for " - "a function to be chosen from a pool of candidates. By default, " - "every function has one ticket, and the likelihood of a function " - "being picked can be increased by allotting it more tickets. Note " - "that in practice, increasing the number of tickets does not " - "proportionally increase the likelihood of selection, as the selection " - "process involves filtering the pool of candidates by a required " - "return type so not all functions may compete against the same number " - "of functions at every instance. Number of tickets must be a positive " - "integer. Example: eq=3,floor=5"); - namespace facebook::velox::test { namespace { using exec::SignatureBinder; -VectorFuzzer::Options getVectorFuzzerOptions() { - VectorFuzzer::Options opts; - opts.vectorSize = FLAGS_batch_size; - opts.stringVariableLength = true; - opts.stringLength = 100; - opts.nullRatio = FLAGS_null_ratio; - return opts; -} - -ExpressionFuzzer::Options getExpressionFuzzerOptions( - const std::unordered_set& skipFunctions) { - ExpressionFuzzer::Options opts; - opts.maxLevelOfNesting = FLAGS_velox_fuzzer_max_level_of_nesting; - opts.maxNumVarArgs = FLAGS_max_num_varargs; - opts.enableVariadicSignatures = FLAGS_enable_variadic_signatures; - opts.enableDereference = FLAGS_enable_dereference; - opts.enableComplexTypes = FLAGS_velox_fuzzer_enable_complex_types; - opts.enableColumnReuse = FLAGS_velox_fuzzer_enable_column_reuse; - opts.enableExpressionReuse = FLAGS_velox_fuzzer_enable_expression_reuse; - opts.functionTickets = FLAGS_assign_function_tickets; - opts.nullRatio = FLAGS_null_ratio; - opts.specialForms = FLAGS_special_forms; - opts.useOnlyFunctions = FLAGS_only; - opts.skipFunctions = skipFunctions; - return opts; -} - -// Randomly pick columns from the input row vector to wrap in lazy. -// Negative column indices represent lazy vectors that have been preloaded -// before feeding them to the evaluator. This list is sorted on the absolute -// value of the entries. -std::vector generateLazyColumnIds( - const RowVectorPtr& rowVector, - VectorFuzzer& vectorFuzzer) { - std::vector columnsToWrapInLazy; - if (FLAGS_lazy_vector_generation_ratio > 0) { - for (int idx = 0; idx < rowVector->childrenSize(); idx++) { - VELOX_CHECK_NOT_NULL(rowVector->childAt(idx)); - if (vectorFuzzer.coinToss(FLAGS_lazy_vector_generation_ratio)) { - columnsToWrapInLazy.push_back( - vectorFuzzer.coinToss(0.8) ? idx : -1 * idx); - } - } - } - return columnsToWrapInLazy; -} - /// Returns row numbers for non-null rows among all children in'data' or null /// if all rows are null. BufferPtr extractNonNullIndices(const RowVectorPtr& data) { @@ -291,20 +113,21 @@ uint32_t levelOfNesting(const TypePtr& type) { ExpressionFuzzerVerifier::ExpressionFuzzerVerifier( const FunctionSignatureMap& signatureMap, size_t initialSeed, - const std::unordered_set& skipFunctions) - : verifier_( + const ExpressionFuzzerVerifier::Options& options) + : options_(options), + verifier_( &execCtx_, - {FLAGS_disable_constant_folding, - FLAGS_repro_persist_path, - FLAGS_persist_and_run_once}), + {options_.disableConstantFolding, + options_.reproPersistPath, + options_.persistAndRunOnce}), vectorFuzzer_(std::make_shared( - getVectorFuzzerOptions(), + options_.vectorFuzzerOptions, execCtx_.pool())), expressionFuzzer_( signatureMap, initialSeed, vectorFuzzer_, - getExpressionFuzzerOptions(skipFunctions)) { + options.expressionFuzzerOptions) { seed(initialSeed); size_t totalFunctions = 0; @@ -328,6 +151,22 @@ ExpressionFuzzerVerifier::ExpressionFuzzerVerifier( } } +std::vector ExpressionFuzzerVerifier::generateLazyColumnIds( + const RowVectorPtr& rowVector, + VectorFuzzer& vectorFuzzer) { + std::vector columnsToWrapInLazy; + if (options_.lazyVectorGenerationRatio > 0) { + for (int idx = 0; idx < rowVector->childrenSize(); idx++) { + VELOX_CHECK_NOT_NULL(rowVector->childAt(idx)); + if (vectorFuzzer.coinToss(options_.lazyVectorGenerationRatio)) { + columnsToWrapInLazy.push_back( + vectorFuzzer.coinToss(0.8) ? idx : -1 * idx); + } + } + } + return columnsToWrapInLazy; +} + void ExpressionFuzzerVerifier::reSeed() { seed(rng_()); } @@ -341,12 +180,12 @@ void ExpressionFuzzerVerifier::seed(size_t seed) { template bool ExpressionFuzzerVerifier::isDone(size_t i, T startTime) const { - if (FLAGS_duration_sec > 0) { + if (options_.durationSeconds > 0) { std::chrono::duration elapsed = std::chrono::system_clock::now() - startTime; - return elapsed.count() >= FLAGS_duration_sec; + return elapsed.count() >= options_.durationSeconds; } - return i >= FLAGS_steps; + return i >= options_.steps; } void ExpressionFuzzerVerifier::logStats() { @@ -452,7 +291,7 @@ void ExpressionFuzzerVerifier::retryWithTry( columnsToWrapInLazy) .result; } catch (const std::exception& e) { - if (FLAGS_find_minimal_subexpression) { + if (options_.findMinimalSubexpression) { computeMinimumSubExpression( {&execCtx_, {false, ""}}, *vectorFuzzer_, @@ -483,7 +322,7 @@ void ExpressionFuzzerVerifier::retryWithTry( false, // canThrow columnsToWrapInLazy); } catch (const std::exception& e) { - if (FLAGS_find_minimal_subexpression) { + if (options_.findMinimalSubexpression) { computeMinimumSubExpression( {&execCtx_, {false, ""}}, *vectorFuzzer_, @@ -498,10 +337,10 @@ void ExpressionFuzzerVerifier::retryWithTry( void ExpressionFuzzerVerifier::go() { VELOX_CHECK( - FLAGS_steps > 0 || FLAGS_duration_sec > 0, + options_.steps > 0 || options_.durationSeconds > 0, "Either --steps or --duration_sec needs to be greater than zero.") VELOX_CHECK_GT( - FLAGS_max_expression_trees_per_step, + options_.maxExpressionTreesPerStep, 0, "--max_expression_trees_per_step needs to be greater than zero.") @@ -515,7 +354,7 @@ void ExpressionFuzzerVerifier::go() { // Generate multiple expression trees and input data vectors. They can // re-use columns and share sub-expressions if the appropriate flag is set. int numExpressionTrees = boost::random::uniform_int_distribution( - 1, FLAGS_max_expression_trees_per_step)(rng_); + 1, options_.maxExpressionTreesPerStep)(rng_); auto [expressions, inputType, selectionStats] = expressionFuzzer_.fuzzExpressions(numExpressionTrees); @@ -540,7 +379,7 @@ void ExpressionFuzzerVerifier::go() { true, // canThrow columnsToWrapInLazy); } catch (const std::exception& e) { - if (FLAGS_find_minimal_subexpression) { + if (options_.findMinimalSubexpression) { computeMinimumSubExpression( {&execCtx_, {false, ""}}, *vectorFuzzer_, @@ -554,7 +393,7 @@ void ExpressionFuzzerVerifier::go() { // If both paths threw compatible exceptions, we add a try() function to // the expression's root and execute it again. This time the expression // cannot throw. - if (result.exceptionPtr && FLAGS_retry_with_try) { + if (result.exceptionPtr && options_.retryWithTry) { LOG(INFO) << "Both paths failed with compatible exceptions. Retrying expression using try()."; retryWithTry(plans, rowVector, resultVectors, columnsToWrapInLazy); diff --git a/velox/expression/tests/ExpressionFuzzerVerifier.h b/velox/expression/tests/ExpressionFuzzerVerifier.h index 3526a430eebeb..1584030b88f6f 100644 --- a/velox/expression/tests/ExpressionFuzzerVerifier.h +++ b/velox/expression/tests/ExpressionFuzzerVerifier.h @@ -48,16 +48,63 @@ namespace facebook::velox::test { class ExpressionFuzzerVerifier { public: + struct Options; + ExpressionFuzzerVerifier( const FunctionSignatureMap& signatureMap, size_t initialSeed, - const std::unordered_set& skipFunctions = {}); + const Options& options); // This function starts the test that is performed by the // ExpressionFuzzerVerifier which is generating random expressions and // verifying them. void go(); + struct Options { + // Number of expressions to generate and execute. + int32_t steps = 10; + + // For how long it should run (in seconds). If zero it executes exactly + // --steps iterations and exits. + int32_t durationSeconds = 0; + + // The number of elements on each generated vector. + int32_t batchSize = 100; + + // Retry failed expressions by wrapping it using a try() statement. + bool retryWithTry = false; + + // Automatically seeks minimum failed subexpression on result mismatch + bool findMinimalSubexpression = false; + + // Disable constant folding in the common evaluation path. + bool disableConstantFolding = false; + + // Directory path for persistence of data and SQL when fuzzer fails for + // future reproduction. Empty string disables this feature. + std::string reproPersistPath = ""; + + // Persist repro info before evaluation and only run one iteration. + // This is to rerun with the seed number and persist repro info upon a + // crash failure. Only effective if repro_persist_path is set. + bool persistAndRunOnce = false; + + // Specifies the probability with which columns in the input row vector will + // be selected to be wrapped in lazy encoding (expressed as double from 0 to + // 1). + double lazyVectorGenerationRatio = 0.0; + + // This sets an upper limit on the number of expression trees to generate + // per step. These trees would be executed in the same ExprSet and can + // re-use already generated columns and subexpressions (if re-use is + // enabled). + int32_t maxExpressionTreesPerStep = 1; + + VectorFuzzer::Options vectorFuzzerOptions; + + ExpressionFuzzer::Options expressionFuzzerOptions; + }; + private: struct ExprUsageStats { // Num of times the expression was randomly selected. @@ -132,6 +179,16 @@ class ExpressionFuzzerVerifier { /// proportionOfTimesSelected numProcessedRows. void logStats(); + // Randomly pick columns from the input row vector to wrap in lazy. + // Negative column indices represent lazy vectors that have been preloaded + // before feeding them to the evaluator. This list is sorted on the absolute + // value of the entries. + std::vector generateLazyColumnIds( + const RowVectorPtr& rowVector, + VectorFuzzer& vectorFuzzer); + + const Options options_; + FuzzerGenerator rng_; size_t currentSeed_{0}; diff --git a/velox/expression/tests/FuzzerRunner.cpp b/velox/expression/tests/FuzzerRunner.cpp index 9727e0d7d52f8..aef6b786f8dae 100644 --- a/velox/expression/tests/FuzzerRunner.cpp +++ b/velox/expression/tests/FuzzerRunner.cpp @@ -15,6 +15,188 @@ */ #include "velox/expression/tests/FuzzerRunner.h" +#include "velox/expression/tests/ExpressionFuzzer.h" + +DEFINE_int32(steps, 10, "Number of expressions to generate and execute."); + +DEFINE_int32( + duration_sec, + 0, + "For how long it should run (in seconds). If zero, " + "it executes exactly --steps iterations and exits."); + +DEFINE_int32( + batch_size, + 100, + "The number of elements on each generated vector."); + +DEFINE_bool( + retry_with_try, + false, + "Retry failed expressions by wrapping it using a try() statement."); + +DEFINE_bool( + find_minimal_subexpression, + false, + "Automatically seeks minimum failed subexpression on result mismatch"); + +DEFINE_bool( + disable_constant_folding, + false, + "Disable constant-folding in the common evaluation path."); + +DEFINE_string( + repro_persist_path, + "", + "Directory path for persistence of data and SQL when fuzzer fails for " + "future reproduction. Empty string disables this feature."); + +DEFINE_bool( + persist_and_run_once, + false, + "Persist repro info before evaluation and only run one iteration. " + "This is to rerun with the seed number and persist repro info upon a " + "crash failure. Only effective if repro_persist_path is set."); + +DEFINE_double( + lazy_vector_generation_ratio, + 0.0, + "Specifies the probability with which columns in the input row " + "vector will be selected to be wrapped in lazy encoding " + "(expressed as double from 0 to 1)."); + +DEFINE_int32( + max_expression_trees_per_step, + 1, + "This sets an upper limit on the number of expression trees to generate " + "per step. These trees would be executed in the same ExprSet and can " + "re-use already generated columns and subexpressions (if re-use is " + "enabled)."); + +// The flags bellow are used to initialize ExpressionFuzzer::options. +DEFINE_string( + only, + "", + "If specified, Fuzzer will only choose functions from " + "this comma separated list of function names " + "(e.g: --only \"split\" or --only \"substr,ltrim\")."); + +DEFINE_string( + special_forms, + "and,or,cast,coalesce,if,switch", + "Comma-separated list of special forms to use in generated expression. " + "Supported special forms: and, or, coalesce, if, switch, cast."); + +DEFINE_int32( + velox_fuzzer_max_level_of_nesting, + 10, + "Max levels of expression nesting. The default value is 10 and minimum is 1."); + +DEFINE_int32( + max_num_varargs, + 5, + "The maximum number of variadic arguments fuzzer will generate for " + "functions that accept variadic arguments. Fuzzer will generate up to " + "max_num_varargs arguments for the variadic list in addition to the " + "required arguments by the function."); + +DEFINE_double( + null_ratio, + 0.1, + "Chance of adding a null constant to the plan, or null value in a vector " + "(expressed as double from 0 to 1)."); + +DEFINE_bool( + enable_variadic_signatures, + false, + "Enable testing of function signatures with variadic arguments."); + +DEFINE_bool( + enable_dereference, + false, + "Allow fuzzer to generate random expressions with dereference and row_constructor functions."); + +DEFINE_bool( + velox_fuzzer_enable_complex_types, + false, + "Enable testing of function signatures with complex argument or return types."); + +DEFINE_bool( + velox_fuzzer_enable_column_reuse, + false, + "Enable generation of expressions where one input column can be " + "used by multiple subexpressions"); + +DEFINE_bool( + velox_fuzzer_enable_expression_reuse, + false, + "Enable generation of expressions that re-uses already generated " + "subexpressions."); + +DEFINE_string( + assign_function_tickets, + "", + "Comma separated list of function names and their tickets in the format " + "=. Every ticket represents an opportunity for " + "a function to be chosen from a pool of candidates. By default, " + "every function has one ticket, and the likelihood of a function " + "being picked can be increased by allotting it more tickets. Note " + "that in practice, increasing the number of tickets does not " + "proportionally increase the likelihood of selection, as the selection " + "process involves filtering the pool of candidates by a required " + "return type so not all functions may compete against the same number " + "of functions at every instance. Number of tickets must be a positive " + "integer. Example: eq=3,floor=5"); + +namespace facebook::velox::test { + +namespace { +VectorFuzzer::Options getVectorFuzzerOptions() { + VectorFuzzer::Options opts; + opts.vectorSize = FLAGS_batch_size; + opts.stringVariableLength = true; + opts.stringLength = 100; + opts.nullRatio = FLAGS_null_ratio; + return opts; +} + +ExpressionFuzzer::Options getExpressionFuzzerOptions( + const std::unordered_set& skipFunctions) { + ExpressionFuzzer::Options opts; + opts.maxLevelOfNesting = FLAGS_velox_fuzzer_max_level_of_nesting; + opts.maxNumVarArgs = FLAGS_max_num_varargs; + opts.enableVariadicSignatures = FLAGS_enable_variadic_signatures; + opts.enableDereference = FLAGS_enable_dereference; + opts.enableComplexTypes = FLAGS_velox_fuzzer_enable_complex_types; + opts.enableColumnReuse = FLAGS_velox_fuzzer_enable_column_reuse; + opts.enableExpressionReuse = FLAGS_velox_fuzzer_enable_expression_reuse; + opts.functionTickets = FLAGS_assign_function_tickets; + opts.nullRatio = FLAGS_null_ratio; + opts.specialForms = FLAGS_special_forms; + opts.useOnlyFunctions = FLAGS_only; + opts.skipFunctions = skipFunctions; + return opts; +} + +ExpressionFuzzerVerifier::Options getExpressionFuzzerVerifierOptions( + const std::unordered_set& skipFunctions) { + ExpressionFuzzerVerifier::Options opts; + opts.steps = FLAGS_steps; + opts.durationSeconds = FLAGS_duration_sec; + opts.batchSize = FLAGS_batch_size; + opts.retryWithTry = FLAGS_retry_with_try; + opts.findMinimalSubexpression = FLAGS_find_minimal_subexpression; + opts.disableConstantFolding = FLAGS_disable_constant_folding; + opts.reproPersistPath = FLAGS_repro_persist_path; + opts.persistAndRunOnce = FLAGS_persist_and_run_once; + opts.lazyVectorGenerationRatio = FLAGS_lazy_vector_generation_ratio; + opts.maxExpressionTreesPerStep = FLAGS_max_expression_trees_per_step; + opts.vectorFuzzerOptions = getVectorFuzzerOptions(); + opts.expressionFuzzerOptions = getExpressionFuzzerOptions(skipFunctions); + return opts; +} + +} // namespace // static int FuzzerRunner::run( @@ -29,7 +211,8 @@ void FuzzerRunner::runFromGtest( size_t seed, const std::unordered_set& skipFunctions) { auto signatures = facebook::velox::getFunctionSignatures(); - facebook::velox::test::ExpressionFuzzerVerifier( - signatures, seed, skipFunctions) + ExpressionFuzzerVerifier( + signatures, seed, getExpressionFuzzerVerifierOptions(skipFunctions)) .go(); } +} // namespace facebook::velox::test diff --git a/velox/expression/tests/FuzzerRunner.h b/velox/expression/tests/FuzzerRunner.h index 6f2936e5d23ca..3341359da30c3 100644 --- a/velox/expression/tests/FuzzerRunner.h +++ b/velox/expression/tests/FuzzerRunner.h @@ -24,8 +24,9 @@ #include "velox/expression/tests/ExpressionFuzzerVerifier.h" #include "velox/functions/FunctionRegistry.h" -/// FuzzerRunner leverages ExpressionFuzzerVerifier to create a unit test. +namespace facebook::velox::test { +/// FuzzerRunner leverages ExpressionFuzzerVerifier to create a gtest unit test. class FuzzerRunner { public: static int run( @@ -36,3 +37,5 @@ class FuzzerRunner { size_t seed, const std::unordered_set& skipFunctions); }; + +} // namespace facebook::velox::test diff --git a/velox/expression/tests/SparkExpressionFuzzerTest.cpp b/velox/expression/tests/SparkExpressionFuzzerTest.cpp index e47cf3b19eb97..fa373ef9eecaf 100644 --- a/velox/expression/tests/SparkExpressionFuzzerTest.cpp +++ b/velox/expression/tests/SparkExpressionFuzzerTest.cpp @@ -30,6 +30,8 @@ DEFINE_int64( "Initial seed for random number generator " "(use it to reproduce previous results)."); +using facebook::velox::test::FuzzerRunner; + int main(int argc, char** argv) { facebook::velox::functions::sparksql::registerFunctions("");