blob: 659b4304d2438f23cde00870ebbf0e982c98e7b1 [file] [log] [blame]
#include <gtest/gtest.h>
#include "experiments.h"
#include "experiments_c_api_test.h"
#include <linux/limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "utils.h"
using namespace libexperiments_utils; // NOLINT
int FailingExperimentsRegisterFunc(const char *name) {
return false;
}
class ExperimentsTest : public ::testing::Test {
protected:
static void SetUpTestCase() {
ASSERT_TRUE(realpath(".", root_path_));
snprintf(test_folder_path_, sizeof(test_folder_path_), "%s/exps-XXXXXX",
root_path_);
char strerrbuf[1024] = {'\0'};
ASSERT_TRUE(mkdtemp(test_folder_path_)) <<
strerror_r(errno, strerrbuf, sizeof(strerrbuf)) << "(" << errno << ")";
ASSERT_EQ(chdir(test_folder_path_), 0);
}
static void TearDownTestCase() {
// change out of the test directory and remove it
ASSERT_EQ(chdir(root_path_), 0);
std::string cmd = StringPrintf("rm -r %s", test_folder_path_);
ASSERT_EQ(0, system(cmd.c_str()));
}
bool SetRequested(const std::string &exp_name) {
remove((exp_name + ".unrequested").c_str());
return touch_file((exp_name + ".requested").c_str());
}
bool SetUnrequested(const std::string &exp_name) {
remove((exp_name + ".requested").c_str());
return touch_file((exp_name + ".unrequested").c_str());
}
void Remove(const std::string &exp_name) {
remove((exp_name + ".unrequested").c_str());
remove((exp_name + ".requested").c_str());
remove((exp_name + ".active").c_str());
}
static char root_path_[PATH_MAX];
static char test_folder_path_[PATH_MAX];
};
char ExperimentsTest::test_folder_path_[PATH_MAX] = {0};
char ExperimentsTest::root_path_[PATH_MAX] = {0};
TEST_F(ExperimentsTest, InvalidConfigPath) {
Experiments e;
char invalid_path[1024];
snprintf(invalid_path, sizeof(invalid_path), "%s/nope", test_folder_path_);
ASSERT_FALSE(e.Initialize(invalid_path, 0, &DummyExperimentsRegisterFunc,
{"exp1"}));
}
TEST_F(ExperimentsTest, InvalidRegisterFunc) {
Experiments e;
ASSERT_FALSE(e.Initialize(test_folder_path_, 0, NULL, {"exp1"}));
}
TEST_F(ExperimentsTest, RegisterFuncFails) {
Experiments e;
ASSERT_FALSE(e.Initialize(test_folder_path_, 0,
&FailingExperimentsRegisterFunc, {"exp1"}));
}
TEST_F(ExperimentsTest, Register) {
Experiments e;
ASSERT_TRUE(e.Initialize(test_folder_path_, 0, &DummyExperimentsRegisterFunc,
{"exp1"}));
EXPECT_TRUE(e.IsRegistered("exp1"));
EXPECT_EQ(1, e.GetNumOfRegisteredExperiments());
// add one more
EXPECT_FALSE(e.IsRegistered("exp2"));
EXPECT_TRUE(e.Register("exp2"));
EXPECT_TRUE(e.IsRegistered("exp1"));
EXPECT_TRUE(e.IsRegistered("exp2"));
// repeated registration is ignored
EXPECT_TRUE(e.Register("exp2"));
EXPECT_TRUE(e.IsRegistered("exp1"));
EXPECT_TRUE(e.IsRegistered("exp2"));
// register vector
EXPECT_FALSE(e.IsRegistered("exp3"));
EXPECT_FALSE(e.IsRegistered("exp4"));
EXPECT_FALSE(e.IsRegistered("exp5"));
EXPECT_TRUE(e.Register({"exp3", "exp4", "exp5"}));
EXPECT_TRUE(e.IsRegistered("exp1"));
EXPECT_TRUE(e.IsRegistered("exp2"));
EXPECT_TRUE(e.IsRegistered("exp3"));
EXPECT_TRUE(e.IsRegistered("exp4"));
EXPECT_TRUE(e.IsRegistered("exp5"));
}
TEST_F(ExperimentsTest, Single) {
Experiments e;
ASSERT_TRUE(e.Initialize(test_folder_path_, 0, &DummyExperimentsRegisterFunc,
{"exp1"}));
EXPECT_FALSE(e.IsEnabled("exp1"));
EXPECT_EQ(1, e.GetNumOfRegisteredExperiments());
EXPECT_TRUE(SetRequested("exp1"));
EXPECT_TRUE(e.IsEnabled("exp1"));
EXPECT_TRUE(SetUnrequested("exp1"));
EXPECT_FALSE(e.IsEnabled("exp1"));
EXPECT_TRUE(SetRequested("exp1"));
EXPECT_TRUE(e.IsEnabled("exp1"));
EXPECT_TRUE(SetUnrequested("exp1"));
EXPECT_FALSE(e.IsEnabled("exp1"));
// clean up
Remove("exp1");
}
TEST_F(ExperimentsTest, Multiple) {
Experiments e;
ASSERT_TRUE(e.Initialize(test_folder_path_, 0, &DummyExperimentsRegisterFunc,
{"exp1", "exp2", "exp3"}));
EXPECT_EQ(3, e.GetNumOfRegisteredExperiments());
EXPECT_FALSE(e.IsEnabled("exp1"));
EXPECT_FALSE(e.IsEnabled("exp2"));
EXPECT_FALSE(e.IsEnabled("exp3"));
// activate exp1 - AII
EXPECT_TRUE(SetRequested("exp1"));
EXPECT_TRUE(e.IsEnabled("exp1"));
EXPECT_FALSE(e.IsEnabled("exp2"));
EXPECT_FALSE(e.IsEnabled("exp3"));
// activate exp2 - AAI
EXPECT_TRUE(SetRequested("exp2"));
EXPECT_TRUE(e.IsEnabled("exp1"));
EXPECT_TRUE(e.IsEnabled("exp2"));
EXPECT_FALSE(e.IsEnabled("exp3"));
// active exp3 - AAA
EXPECT_TRUE(SetRequested("exp3"));
EXPECT_TRUE(e.IsEnabled("exp1"));
EXPECT_TRUE(e.IsEnabled("exp2"));
EXPECT_TRUE(e.IsEnabled("exp3"));
// inactivate exp2 - AIA
EXPECT_TRUE(SetUnrequested("exp2"));
EXPECT_TRUE(e.IsEnabled("exp1"));
EXPECT_FALSE(e.IsEnabled("exp2"));
EXPECT_TRUE(e.IsEnabled("exp3"));
// inactivate exp1 file - IIA
EXPECT_TRUE(SetUnrequested("exp1"));
EXPECT_FALSE(e.IsEnabled("exp1"));
EXPECT_FALSE(e.IsEnabled("exp2"));
EXPECT_TRUE(e.IsEnabled("exp3"));
// re-activate exp2 - IAA
EXPECT_TRUE(SetRequested("exp2"));
EXPECT_FALSE(e.IsEnabled("exp1"));
EXPECT_TRUE(e.IsEnabled("exp2"));
EXPECT_TRUE(e.IsEnabled("exp3"));
// inactivate exp1 (re-create file) - IAA
EXPECT_TRUE(SetUnrequested("exp1"));
EXPECT_FALSE(e.IsEnabled("exp1"));
EXPECT_TRUE(e.IsEnabled("exp2"));
EXPECT_TRUE(e.IsEnabled("exp3"));
// inactivate all - III
EXPECT_TRUE(SetUnrequested("exp1"));
EXPECT_TRUE(SetUnrequested("exp2"));
EXPECT_TRUE(SetUnrequested("exp3"));
EXPECT_FALSE(e.IsEnabled("exp1"));
EXPECT_FALSE(e.IsEnabled("exp2"));
EXPECT_FALSE(e.IsEnabled("exp3"));
// clean up
Remove("exp1");
Remove("exp2");
Remove("exp3");
}
TEST_F(ExperimentsTest, TimeBetweenRefresh) {
int64_t kMinTimeBetweenRefresh = secs_to_usecs(3);
int64_t kTimeout = secs_to_usecs(5);
uint64_t start_time = us_elapse(0);
Experiments e;
ASSERT_TRUE(e.Initialize(test_folder_path_, kMinTimeBetweenRefresh,
&DummyExperimentsRegisterFunc, {"exp1"}));
EXPECT_EQ(1, e.GetNumOfRegisteredExperiments());
EXPECT_FALSE(e.IsEnabled("exp1"));
EXPECT_TRUE(SetRequested("exp1"));
// measure time until we see "exp1" active
uint64_t duration = us_elapse(start_time);
while (!e.IsEnabled("exp1") && duration < kTimeout) {
us_sleep(100);
duration = us_elapse(start_time);
}
EXPECT_GE(duration, kMinTimeBetweenRefresh) << "time:" << duration;
EXPECT_LT(duration, kTimeout) << "time:" << duration;
// clean up
Remove("exp1");
}
TEST_F(ExperimentsTest, C_API_Test) {
// returns false on all API functions until initialized is called
EXPECT_FALSE(test_experiments_is_initialized());
EXPECT_FALSE(test_experiments_register("exp1"));
EXPECT_FALSE(test_experiments_is_registered("exp1"));
EXPECT_FALSE(test_experiments_is_enabled("exp1"));
EXPECT_TRUE(SetRequested("exp1"));
EXPECT_FALSE(test_experiments_is_enabled("exp1"));
EXPECT_TRUE(SetUnrequested("exp1"));
// initialize
EXPECT_TRUE(test_experiments_initialize(test_folder_path_));
EXPECT_TRUE(test_experiments_is_initialized());
EXPECT_EQ(0, experiments_get_num_of_registered_experiments());
EXPECT_TRUE(test_experiments_register("exp1"));
EXPECT_TRUE(test_experiments_is_registered("exp1"));
EXPECT_EQ(1, experiments_get_num_of_registered_experiments());
EXPECT_FALSE(test_experiments_is_enabled("exp1"));
EXPECT_TRUE(SetRequested("exp1"));
EXPECT_TRUE(test_experiments_is_enabled("exp1"));
EXPECT_FALSE(test_experiments_is_enabled("exp2"));
EXPECT_TRUE(SetUnrequested("exp1"));
EXPECT_FALSE(test_experiments_is_enabled("exp1"));
// clean up
EXPECT_TRUE(SetUnrequested("exp1"));
}