[experiments] A unit test for the experiments framework (#33334)

Adds a test for the experiments codegen. It updates the codegen to parse
test_experiments.yaml and test_experiments_rollouts.yaml files and
generate test_experiments.h and test_experiments.cc files along with an
experiments_test.cc file. The experiments test verifies the returned
value of IsExperimentEnabled with the expected value.
This commit is contained in:
Vignesh Babu 2023-06-29 12:21:11 -07:00 committed by GitHub
parent 278978d6f0
commit bf3ffcf600
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 577 additions and 70 deletions

39
CMakeLists.txt generated
View File

@ -968,6 +968,7 @@ if(gRPC_BUILD_TESTS)
endif()
add_dependencies(buildtests_cxx exception_test)
add_dependencies(buildtests_cxx exec_ctx_wakeup_scheduler_test)
add_dependencies(buildtests_cxx experiments_test)
add_dependencies(buildtests_cxx factory_test)
add_dependencies(buildtests_cxx fake_binder_test)
add_dependencies(buildtests_cxx fake_resolver_test)
@ -11403,6 +11404,44 @@ target_link_libraries(exec_ctx_wakeup_scheduler_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(experiments_test
test/core/experiments/experiments_test.cc
test/core/experiments/fixtures/experiments.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_compile_features(experiments_test PUBLIC cxx_std_14)
target_include_directories(experiments_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(experiments_test
${_gRPC_BASELIB_LIBRARIES}
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ZLIB_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)

View File

@ -7409,6 +7409,18 @@ targets:
- gpr
- upb
uses_polling: false
- name: experiments_test
gtest: true
build: test
language: c++
headers:
- test/core/experiments/fixtures/experiments.h
src:
- test/core/experiments/experiments_test.cc
- test/core/experiments/fixtures/experiments.cc
deps:
- grpc_test_util
uses_polling: false
- name: factory_test
gtest: true
build: test

View File

@ -126,6 +126,7 @@ grpc_cc_library(
"absl/strings",
],
language = "c++",
tags = ["nofixdeps"],
deps = [
"no_destruct",
"//:config_vars",

View File

@ -54,6 +54,31 @@ std::atomic<bool> g_loaded(false);
absl::AnyInvocable<bool(struct ExperimentMetadata)>* g_check_constraints_cb =
nullptr;
class TestExperiments {
public:
TestExperiments(const ExperimentMetadata* experiment_metadata,
size_t num_experiments) {
enabled_ = new bool[num_experiments];
for (size_t i = 0; i < num_experiments; i++) {
if (g_check_constraints_cb != nullptr) {
enabled_[i] = (*g_check_constraints_cb)(experiment_metadata[i]);
} else {
enabled_[i] = experiment_metadata[i].default_value;
}
}
}
// Overloading [] operator to access elements in array style
bool operator[](int index) { return enabled_[index]; }
~TestExperiments() { delete enabled_; }
private:
bool* enabled_;
};
TestExperiments* g_test_experiments = nullptr;
GPR_ATTRIBUTE_NOINLINE Experiments LoadExperimentsFromConfigVariable() {
g_loaded.store(true, std::memory_order_relaxed);
// Set defaults from metadata.
@ -111,11 +136,20 @@ void TestOnlyReloadExperimentsFromConfigVariables() {
PrintExperimentsList();
}
void LoadTestOnlyExperimentsFromMetadata(
const ExperimentMetadata* experiment_metadata, size_t num_experiments) {
g_test_experiments =
new TestExperiments(experiment_metadata, num_experiments);
}
bool IsExperimentEnabled(size_t experiment_id) {
// Normal path: just return the value;
return ExperimentsSingleton().enabled[experiment_id];
}
bool IsTestExperimentEnabled(size_t experiment_id) {
return (*g_test_experiments)[experiment_id];
}
void PrintExperimentsList() {
size_t max_experiment_length = 0;
for (size_t i = 0; i < kNumExperiments; i++) {

View File

@ -26,17 +26,37 @@
namespace grpc_core {
struct ExperimentMetadata {
const char* name;
const char* description;
const char* additional_constaints;
bool default_value;
bool allow_in_fuzzing_config;
};
#ifndef GRPC_EXPERIMENTS_ARE_FINAL
// Return true if experiment \a experiment_id is enabled.
// Experiments are numbered by their order in the g_experiment_metadata array
// declared in experiments.h.
bool IsExperimentEnabled(size_t experiment_id);
// Given a test experiment id, returns true if the test experiment is enabled.
// Test experiments can be loaded using the LoadTestOnlyExperimentsFromMetadata
// method.
bool IsTestExperimentEnabled(size_t experiment_id);
// Reload experiment state from config variables.
// Does not change ForceEnableExperiment state.
// Expects the caller to handle global thread safety - so really only
// appropriate for carefully written tests.
void TestOnlyReloadExperimentsFromConfigVariables();
// Reload experiment state from passed metadata.
// Does not change ForceEnableExperiment state.
// Expects the caller to handle global thread safety - so really only
// appropriate for carefully written tests.
void LoadTestOnlyExperimentsFromMetadata(
const ExperimentMetadata* experiment_metadata, size_t num_experiments);
#endif
// Print out a list of all experiments that are built into this binary.
@ -49,14 +69,6 @@ void PrintExperimentsList();
// If this is called twice for the same experiment, both calls must agree.
void ForceEnableExperiment(absl::string_view experiment_name, bool enable);
struct ExperimentMetadata {
const char* name;
const char* description;
const char* additional_constaints;
bool default_value;
bool allow_in_fuzzing_config;
};
// Register a function to be called to validate the value an experiment can
// take subject to additional constraints.
// The function will take the ExperimentMetadata as its argument. It will return

View File

@ -0,0 +1,47 @@
# Copyright 2023 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test")
grpc_cc_library(
name = "experiments_lib",
srcs = [
"fixtures/experiments.cc",
],
hdrs = [
"fixtures/experiments.h",
],
language = "c++",
deps = [
"//:config_vars",
"//:gpr",
"//src/core:experiments",
"//src/core:no_destruct",
],
)
grpc_cc_test(
name = "experiments_test",
srcs = ["experiments_test.cc"],
external_deps = ["gtest"],
language = "C++",
uses_event_engine = False,
uses_polling = False,
deps = [
":experiments_lib",
"//:gpr",
"//src/core:experiments",
"//test/core/util:grpc_test_util",
],
)

View File

@ -0,0 +1,62 @@
// Copyright 2023 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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.
// Auto generated by tools/codegen/core/gen_experiments.py
#include <grpc/support/port_platform.h>
#include "test/core/experiments/fixtures/experiments.h"
#include "gtest/gtest.h"
#include "src/core/lib/experiments/config.h"
#ifndef GRPC_EXPERIMENTS_ARE_FINAL
bool GetExperimentTestExperiment1ExpectedValue() { return false; }
bool GetExperimentTestExperiment2ExpectedValue() { return false; }
bool GetExperimentTestExperiment3ExpectedValue() {
#ifdef NDEBUG
return false;
#else
return true;
#endif
}
bool GetExperimentTestExperiment4ExpectedValue() { return true; }
TEST(ExperimentsTest, CheckExperimentValuesTest) {
ASSERT_EQ(grpc_core::IsTestExperiment1Enabled(),
GetExperimentTestExperiment1ExpectedValue());
ASSERT_EQ(grpc_core::IsTestExperiment2Enabled(),
GetExperimentTestExperiment2ExpectedValue());
ASSERT_EQ(grpc_core::IsTestExperiment3Enabled(),
GetExperimentTestExperiment3ExpectedValue());
ASSERT_EQ(grpc_core::IsTestExperiment4Enabled(),
GetExperimentTestExperiment4ExpectedValue());
}
#endif // GRPC_EXPERIMENTS_ARE_FINAL
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
grpc_core::LoadTestOnlyExperimentsFromMetadata(
grpc_core::g_test_experiment_metadata, grpc_core::kNumTestExperiments);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,52 @@
// Copyright 2023 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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.
// Auto generated by tools/codegen/core/gen_experiments.py
#include <grpc/support/port_platform.h>
#include "test/core/experiments/fixtures/experiments.h"
#ifndef GRPC_EXPERIMENTS_ARE_FINAL
namespace {
const char* const description_test_experiment_1 = "Test Experiment 1";
const char* const additional_constraints_test_experiment_1 = "{}";
const char* const description_test_experiment_2 = "Test Experiment 2";
const char* const additional_constraints_test_experiment_2 = "{}";
const char* const description_test_experiment_3 = "Test Experiment 3";
const char* const additional_constraints_test_experiment_3 = "{}";
const char* const description_test_experiment_4 = "Test Experiment 4";
const char* const additional_constraints_test_experiment_4 = "{}";
#ifdef NDEBUG
const bool kDefaultForDebugOnly = false;
#else
const bool kDefaultForDebugOnly = true;
#endif
} // namespace
namespace grpc_core {
const ExperimentMetadata g_test_experiment_metadata[] = {
{"test_experiment_1", description_test_experiment_1,
additional_constraints_test_experiment_1, false, true},
{"test_experiment_2", description_test_experiment_2,
additional_constraints_test_experiment_2, false, true},
{"test_experiment_3", description_test_experiment_3,
additional_constraints_test_experiment_3, kDefaultForDebugOnly, true},
{"test_experiment_4", description_test_experiment_4,
additional_constraints_test_experiment_4, true, true},
};
} // namespace grpc_core
#endif

View File

@ -0,0 +1,90 @@
// Copyright 2023 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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.
// Auto generated by tools/codegen/core/gen_experiments.py
//
// This file contains the autogenerated parts of the experiments API.
//
// It generates two symbols for each experiment.
//
// For the experiment named new_car_project, it generates:
//
// - a function IsNewCarProjectEnabled() that returns true if the experiment
// should be enabled at runtime.
//
// - a macro GRPC_EXPERIMENT_IS_INCLUDED_NEW_CAR_PROJECT that is defined if the
// experiment *could* be enabled at runtime.
//
// The function is used to determine whether to run the experiment or
// non-experiment code path.
//
// If the experiment brings significant bloat, the macro can be used to avoid
// including the experiment code path in the binary for binaries that are size
// sensitive.
//
// By default that includes our iOS and Android builds.
//
// Finally, a small array is included that contains the metadata for each
// experiment.
//
// A macro, GRPC_EXPERIMENTS_ARE_FINAL, controls whether we fix experiment
// configuration at build time (if it's defined) or allow it to be tuned at
// runtime (if it's disabled).
//
// If you are using the Bazel build system, that macro can be configured with
// --define=grpc_experiments_are_final=true
#ifndef GRPC_TEST_CORE_EXPERIMENTS_FIXTURES_EXPERIMENTS_H
#define GRPC_TEST_CORE_EXPERIMENTS_FIXTURES_EXPERIMENTS_H
#include <grpc/support/port_platform.h>
#include <stddef.h>
#include "src/core/lib/experiments/config.h"
namespace grpc_core {
#ifdef GRPC_EXPERIMENTS_ARE_FINAL
inline bool IsTestExperiment1Enabled() { return false; }
inline bool IsTestExperiment2Enabled() { return false; }
#ifndef NDEBUG
#define GRPC_EXPERIMENT_IS_INCLUDED_TEST_EXPERIMENT_3
#endif
inline bool IsTestExperiment3Enabled() {
#ifdef NDEBUG
return false;
#else
return true;
#endif
}
#define GRPC_EXPERIMENT_IS_INCLUDED_TEST_EXPERIMENT_4
inline bool IsTestExperiment4Enabled() { return true; }
#else
#define GRPC_EXPERIMENT_IS_INCLUDED_TEST_EXPERIMENT_1
inline bool IsTestExperiment1Enabled() { return IsTestExperimentEnabled(0); }
#define GRPC_EXPERIMENT_IS_INCLUDED_TEST_EXPERIMENT_2
inline bool IsTestExperiment2Enabled() { return IsTestExperimentEnabled(1); }
#define GRPC_EXPERIMENT_IS_INCLUDED_TEST_EXPERIMENT_3
inline bool IsTestExperiment3Enabled() { return IsTestExperimentEnabled(2); }
#define GRPC_EXPERIMENT_IS_INCLUDED_TEST_EXPERIMENT_4
inline bool IsTestExperiment4Enabled() { return IsTestExperimentEnabled(3); }
constexpr const size_t kNumTestExperiments = 4;
extern const ExperimentMetadata g_test_experiment_metadata[kNumTestExperiments];
#endif
} // namespace grpc_core
#endif // GRPC_TEST_CORE_EXPERIMENTS_FIXTURES_EXPERIMENTS_H

View File

@ -0,0 +1,30 @@
# Copyright 2023 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
- name: test_experiment_1
description: Test Experiment 1
expiry: 2023/08/01
owner: blah@abc.com
- name: test_experiment_2
description: Test Experiment 2
expiry: 2023/01/01
owner: blah1@abc.com
- name: test_experiment_3
description: Test Experiment 3
expiry: 2024/01/01
owner: blah2@abc.com
- name: test_experiment_4
description: Test Experiment 4
expiry: 2022/01/01
owner: blah3@abc.com

View File

@ -0,0 +1,22 @@
# Copyright 2023 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
- name: test_experiment_1
default: broken
- name: test_experiment_2
default: false
- name: test_experiment_3
default: debug
- name: test_experiment_4
default: true

View File

@ -64,7 +64,48 @@ If you are using the Bazel build system, that macro can be configured with
"""
def ToCStr(s, encoding="ascii"):
def _EXPERIMENTS_TEST_SKELETON(defs, test_body):
return f"""
#include <grpc/support/port_platform.h>
#include "test/core/experiments/fixtures/experiments.h"
#include "gtest/gtest.h"
#include "src/core/lib/experiments/config.h"
#ifndef GRPC_EXPERIMENTS_ARE_FINAL
{defs}
TEST(ExperimentsTest, CheckExperimentValuesTest) {{
{test_body}
}}
#endif // GRPC_EXPERIMENTS_ARE_FINAL
int main(int argc, char** argv) {{
testing::InitGoogleTest(&argc, argv);
grpc_core::LoadTestOnlyExperimentsFromMetadata(
grpc_core::g_test_experiment_metadata, grpc_core::kNumTestExperiments);
return RUN_ALL_TESTS();
}}
"""
def _EXPERIMENTS_EXPECTED_VALUE(name, expected_value):
return f"""
bool GetExperiment{name}ExpectedValue() {{
{expected_value}
}}
"""
def _EXPERIMENT_CHECK_TEXT(name):
return f"""
ASSERT_EQ(grpc_core::Is{name}Enabled(),
GetExperiment{name}ExpectedValue());
"""
def ToCStr(s, encoding='ascii'):
if isinstance(s, str):
s = s.encode(encoding)
result = ""
@ -268,7 +309,7 @@ class ExperimentsCompiler(object):
rollout_attributes["name"]
].AddRolloutSpecification(self._defaults, rollout_attributes)
def GenerateExperimentsHdr(self, output_file):
def GenerateExperimentsHdr(self, output_file, mode):
with open(output_file, "w") as H:
PutCopyright(H, "//")
PutBanner(
@ -278,8 +319,18 @@ class ExperimentsCompiler(object):
"//",
)
print("#ifndef GRPC_SRC_CORE_LIB_EXPERIMENTS_EXPERIMENTS_H", file=H)
print("#define GRPC_SRC_CORE_LIB_EXPERIMENTS_EXPERIMENTS_H", file=H)
if mode != "test":
include_guard = "GRPC_SRC_CORE_LIB_EXPERIMENTS_EXPERIMENTS_H"
else:
file_path_list = output_file.split("/")[0:-1]
file_name = output_file.split("/")[-1].split(".")[0]
include_guard = (
f"GRPC_{'_'.join(path.upper() for path in file_path_list)}_{file_name.upper()}_H"
)
print(f"#ifndef {include_guard}", file=H)
print(f"#define {include_guard}", file=H)
print(file=H)
print("#include <grpc/support/port_platform.h>", file=H)
print(file=H)
@ -313,20 +364,27 @@ class ExperimentsCompiler(object):
)
print(
"inline bool Is%sEnabled() { return"
" IsExperimentEnabled(%d); }"
% (SnakeToPascal(exp.name), i),
" Is%sExperimentEnabled(%d); }"
% (SnakeToPascal(exp.name), "Test" if mode == "test" else "", i),
file=H,
)
print(file=H)
if mode == "test":
num_experiments_var_name = "kNumTestExperiments"
experiments_metadata_var_name = "g_test_experiment_metadata"
else:
num_experiments_var_name = "kNumExperiments"
experiments_metadata_var_name = "g_experiment_metadata"
print(
"constexpr const size_t kNumExperiments = %d;"
% len(self._experiment_definitions.keys()),
f"constexpr const size_t {num_experiments_var_name} = "
f"{len(self._experiment_definitions.keys())};",
file=H,
)
print(
(
"extern const ExperimentMetadata"
" g_experiment_metadata[kNumExperiments];"
f" {experiments_metadata_var_name}[{num_experiments_var_name}];"
),
file=H,
)
@ -334,11 +392,9 @@ class ExperimentsCompiler(object):
print("#endif", file=H)
print("} // namespace grpc_core", file=H)
print(file=H)
print(
"#endif // GRPC_SRC_CORE_LIB_EXPERIMENTS_EXPERIMENTS_H", file=H
)
print(f"#endif // {include_guard}", file=H)
def GenerateExperimentsSrc(self, output_file):
def GenerateExperimentsSrc(self, output_file, header_file_path, mode):
with open(output_file, "w") as C:
PutCopyright(C, "//")
PutBanner(
@ -348,7 +404,7 @@ class ExperimentsCompiler(object):
)
print("#include <grpc/support/port_platform.h>", file=C)
print('#include "src/core/lib/experiments/experiments.h"', file=C)
print(f"#include \"{header_file_path}\"", file=C)
print(file=C)
print("#ifndef GRPC_EXPERIMENTS_ARE_FINAL", file=C)
print("namespace {", file=C)
@ -380,8 +436,12 @@ class ExperimentsCompiler(object):
print(file=C)
print("namespace grpc_core {", file=C)
print(file=C)
if mode == "test":
experiments_metadata_var_name = "g_test_experiment_metadata"
else:
experiments_metadata_var_name = "g_experiment_metadata"
print(
"const ExperimentMetadata g_experiment_metadata[] = {", file=C
f"const ExperimentMetadata {experiments_metadata_var_name}[] = {{", file=C
)
for _, exp in self._experiment_definitions.items():
print(
@ -400,6 +460,21 @@ class ExperimentsCompiler(object):
print("} // namespace grpc_core", file=C)
print("#endif", file=C)
def GenTest(self, output_file):
with open(output_file, 'w') as C:
PutCopyright(C, "//")
PutBanner(
[C],
["Auto generated by tools/codegen/core/gen_experiments.py"],
"//")
defs = ""
test_body = ""
for _, exp in self._experiment_definitions.items():
defs += _EXPERIMENTS_EXPECTED_VALUE(
SnakeToPascal(exp.name), self._final_return[exp.default])
test_body += _EXPERIMENT_CHECK_TEXT(SnakeToPascal(exp.name))
print(_EXPERIMENTS_TEST_SKELETON(defs, test_body), file=C)
def GenExperimentsBzl(self, output_file):
if self._bzl_list_for_defaults is None:
return

View File

@ -74,63 +74,69 @@ def ParseCommandLineArguments(args):
action="store_false",
help="If specified, disables checking experiment expiry dates",
)
flag_parser.add_argument(
"--disable_gen_hdrs",
action="store_true",
help="If specified, disables generation of experiments hdr files",
)
flag_parser.add_argument(
"--disable_gen_srcs",
action="store_true",
help="If specified, disables generation of experiments source files",
)
flag_parser.add_argument(
"--disable_gen_bzl",
action="store_true",
help="If specified, disables generation of experiments.bzl file",
)
return flag_parser.parse_args(args)
args = ParseCommandLineArguments(sys.argv[1:])
with open("src/core/lib/experiments/experiments.yaml") as f:
attrs = yaml.safe_load(f.read())
with open("src/core/lib/experiments/rollouts.yaml") as f:
rollouts = yaml.safe_load(f.read())
def _GenerateExperimentFiles(args, mode):
if mode == "test":
_EXPERIMENTS_DEFS = "test/core/experiments/fixtures/test_experiments.yaml"
_EXPERIMENTS_ROLLOUTS = (
"test/core/experiments/fixtures/test_experiments_rollout.yaml"
)
_EXPERIMENTS_HDR_FILE = "test/core/experiments/fixtures/experiments.h"
_EXPERIMENTS_SRC_FILE = "test/core/experiments/fixtures/experiments.cc"
else:
_EXPERIMENTS_DEFS = "src/core/lib/experiments/experiments.yaml"
_EXPERIMENTS_ROLLOUTS = "src/core/lib/experiments/rollouts.yaml"
_EXPERIMENTS_HDR_FILE = "src/core/lib/experiments/experiments.h"
_EXPERIMENTS_SRC_FILE = "src/core/lib/experiments/experiments.cc"
compiler = exp.ExperimentsCompiler(
DEFAULTS, FINAL_RETURN, FINAL_DEFINE, BZL_LIST_FOR_DEFAULTS
)
with open(_EXPERIMENTS_DEFS) as f:
attrs = yaml.safe_load(f.read())
experiment_annotation = "gRPC Experiments: "
for attr in attrs:
exp_definition = exp.ExperimentDefinition(attr)
if not exp_definition.IsValid(args.check):
sys.exit(1)
experiment_annotation += exp_definition.name + ":0,"
if not compiler.AddExperimentDefinition(exp_definition):
print("Experiment = %s ERROR adding" % exp_definition.name)
with open(_EXPERIMENTS_ROLLOUTS) as f:
rollouts = yaml.safe_load(f.read())
compiler = exp.ExperimentsCompiler(
DEFAULTS, FINAL_RETURN, FINAL_DEFINE, BZL_LIST_FOR_DEFAULTS
)
experiment_annotation = "gRPC Experiments: "
for attr in attrs:
exp_definition = exp.ExperimentDefinition(attr)
if not exp_definition.IsValid(args.check):
sys.exit(1)
experiment_annotation += exp_definition.name + ":0,"
if not compiler.AddExperimentDefinition(exp_definition):
print("Experiment = %s ERROR adding" % exp_definition.name)
sys.exit(1)
if len(experiment_annotation) > 2000:
print("comma-delimited string of experiments is too long")
sys.exit(1)
if len(experiment_annotation) > 2000:
print("comma-delimited string of experiments is too long")
sys.exit(1)
for rollout_attr in rollouts:
if not compiler.AddRolloutSpecification(rollout_attr):
print("ERROR adding rollout spec")
sys.exit(1)
for rollout_attr in rollouts:
if not compiler.AddRolloutSpecification(rollout_attr):
print("ERROR adding rollout spec")
sys.exit(1)
print(f"Mode = {mode} Generating experiments headers")
compiler.GenerateExperimentsHdr(_EXPERIMENTS_HDR_FILE, mode)
print(f"Mode = {mode} Generating experiments srcs")
compiler.GenerateExperimentsSrc(
_EXPERIMENTS_SRC_FILE, _EXPERIMENTS_HDR_FILE, mode)
if not args.disable_gen_hdrs:
print("Generating experiments headers")
compiler.GenerateExperimentsHdr("src/core/lib/experiments/experiments.h")
if mode == "test":
print("Generating experiments tests")
compiler.GenTest('test/core/experiments/experiments_test.cc')
else:
print("Generating experiments.bzl")
compiler.GenExperimentsBzl("bazel/experiments.bzl")
if not args.disable_gen_srcs:
print("Generating experiments srcs")
compiler.GenerateExperimentsSrc("src/core/lib/experiments/experiments.cc")
if not args.disable_gen_bzl:
print("Generating experiments.bzl")
compiler.GenExperimentsBzl("bazel/experiments.bzl")
_GenerateExperimentFiles(args, "production")
_GenerateExperimentFiles(args, "test")

View File

@ -160,6 +160,7 @@ INTERNAL_DEPS = {
"//test/core/event_engine/fuzzing_event_engine"
),
"test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h": "//test/core/event_engine/fuzzing_event_engine:fuzzing_event_engine_proto",
"test/core/experiments/test_experiments.h": "//test/core/experiments:test_experiments_lib",
"google/api/expr/v1alpha1/syntax.upb.h": "google_type_expr_upb",
"google/rpc/status.upb.h": "google_rpc_status_upb",
"google/protobuf/any.upb.h": "protobuf_any_upb",

View File

@ -3179,6 +3179,30 @@
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "experiments_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,