TEST(FsTest, DISABLED_MountInfoTableRead) { // Examine the calling process's mountinfo table. Try<fs::MountInfoTable> table = fs::MountInfoTable::read(); ASSERT_SOME(table); // Every system should have at least a rootfs mounted. Option<MountInfoTable::Entry> root = None(); foreach (const MountInfoTable::Entry& entry, table.get().entries) { if (entry.target == "/") { root = entry; } } EXPECT_SOME(root); // Repeat for pid 1. table = fs::MountInfoTable::read(1); ASSERT_SOME(table); // Every system should have at least a rootfs mounted. root = None(); foreach (const MountInfoTable::Entry& entry, table.get().entries) { if (entry.target == "/") { root = entry; } } EXPECT_SOME(root); }
TEST_F(ZooKeeperTest, LeaderDetectorCancellationHandling) { Duration timeout = Seconds(10); Group group(server->connectString(), timeout, "/test/"); LeaderDetector detector(&group); AWAIT_READY(group.join("member 1")); Future<Option<Group::Membership> > leader = detector.detect(); AWAIT_READY(leader); EXPECT_SOME(leader.get()); // Cancel the member and join another. Future<bool> cancelled = group.cancel(leader.get().get()); AWAIT_READY(cancelled); EXPECT_TRUE(cancelled.get()); leader = detector.detect(leader.get()); AWAIT_READY(leader); EXPECT_NONE(leader.get()); AWAIT_READY(group.join("member 2")); // Detect a new leader. leader = detector.detect(leader.get()); AWAIT_READY(leader); EXPECT_SOME(leader.get()); }
TEST(AgentCallValidationTest, RemoveNestedContainer) { // Missing `remove_nested_container`. agent::Call call; call.set_type(agent::Call::REMOVE_NESTED_CONTAINER); Option<Error> error = validation::agent::call::validate(call); EXPECT_SOME(error); // Expecting a `container_id.parent`. ContainerID containerId; containerId.set_value(UUID::random().toString()); agent::Call::RemoveNestedContainer* removeNestedContainer = call.mutable_remove_nested_container(); removeNestedContainer->mutable_container_id()->CopyFrom(containerId); error = validation::agent::call::validate(call); EXPECT_SOME(error); // Test the valid case. ContainerID parentContainerId; parentContainerId.set_value(UUID::random().toString()); removeNestedContainer->mutable_container_id()->mutable_parent()->CopyFrom( containerId); error = validation::agent::call::validate(call); EXPECT_NONE(error); }
TEST(Stout, Some) { Option<int> o1 = Some(42); EXPECT_SOME(o1); EXPECT_EQ(42, o1.get()); Result<int> r1 = Some(42); EXPECT_SOME(r1); EXPECT_EQ(42, r1.get()); Try<Option<int> > t1 = Some(42); ASSERT_SOME(t1); EXPECT_SOME(t1.get()); EXPECT_EQ(42, t1.get().get()); t1 = None(); ASSERT_SOME(t1); EXPECT_NONE(t1.get()); Try<Result<int> > t2 = Some(42); ASSERT_SOME(t2); EXPECT_SOME(t2.get()); EXPECT_EQ(42, t2.get().get()); Option<Result<int> > o2 = Some(42); ASSERT_SOME(o2); EXPECT_SOME(o2.get()); EXPECT_EQ(42, o2.get().get()); Option<Result<int> > o3 = Some(Some(42)); ASSERT_SOME(o3); EXPECT_SOME(o3.get()); EXPECT_EQ(42, o3.get().get()); Result<Option<int> > r2 = Some(42); ASSERT_SOME(r2); EXPECT_SOME(r2.get()); EXPECT_EQ(42, r2.get().get()); Result<Option<int> > r3 = Some(Some(42)); ASSERT_SOME(r3); EXPECT_SOME(r3.get()); EXPECT_EQ(42, r3.get().get()); Option<std::string> o4 = Some("hello"); EXPECT_SOME(o4); EXPECT_EQ("hello", o4.get()); Result<std::string> r4 = Some("world"); EXPECT_SOME(r4); EXPECT_EQ("world", r4.get()); std::map<std::string, Option<std::string> > values; values["no-debug"] = None(); values["debug"] = None(); values["debug"] = Some("true"); values["debug"] = Some("false"); values["name"] = Some("frank"); }
// Tests that the common validation code for the // `Secret` message works as expected. TEST(AgentValidationTest, Secret) { // Test a secret of VALUE type. { Secret secret; secret.set_type(Secret::VALUE); Option<Error> error = validateSecret(secret); EXPECT_SOME(error); EXPECT_EQ( "Secret of type VALUE must have the 'value' field set", error->message); secret.mutable_value()->set_data("SECRET_VALUE"); secret.mutable_reference()->set_name("SECRET_NAME"); error = validateSecret(secret); EXPECT_SOME(error); EXPECT_EQ( "Secret of type VALUE must not have the 'reference' field set", error->message); // Test the valid case. secret.clear_reference(); error = validateSecret(secret); EXPECT_NONE(error); } // Test a secret of REFERENCE type. { Secret secret; secret.set_type(Secret::REFERENCE); Option<Error> error = validateSecret(secret); EXPECT_SOME(error); EXPECT_EQ( "Secret of type REFERENCE must have the 'reference' field set", error->message); secret.mutable_reference()->set_name("SECRET_NAME"); secret.mutable_value()->set_data("SECRET_VALUE"); error = validateSecret(secret); EXPECT_SOME(error); EXPECT_EQ( "Secret 'SECRET_NAME' of type REFERENCE " "must not have the 'value' field set", error->message); // Test the valid case. secret.clear_value(); error = validateSecret(secret); EXPECT_NONE(error); } }
TEST(QoSPipelineTest, NoCorrections) { uint64_t WINDOWS_SIZE = 10; uint64_t CONTENTION_COOLDOWN = 10; double_t RELATIVE_THRESHOLD = 0.5; MockSlaveUsage mockSlaveUsage(QOS_PIPELINE_FIXTURE1); QoSControllerPipeline* pipeline = new CpuQoSPipeline<RollingChangePointDetector>( QoSPipelineConf( ChangePointDetectionState::createForRollingDetector( WINDOWS_SIZE, CONTENTION_COOLDOWN, RELATIVE_THRESHOLD), ema::DEFAULT_ALPHA, false, true)); // First iteration. Result<QoSCorrections> corrections = pipeline->run(mockSlaveUsage.usage().get()); EXPECT_NONE(corrections); // Second iteration. corrections = pipeline->run(mockSlaveUsage.usage().get()); EXPECT_SOME(corrections); EXPECT_TRUE(corrections.get().empty()); delete pipeline; }
TEST_F(ZooKeeperTest, LeaderDetectorTimeoutHandling) { Duration timeout = Seconds(10); Group group(server->connectString(), timeout, "/test/"); LeaderDetector detector(&group); AWAIT_READY(group.join("member 1")); Future<Option<Group::Membership> > leader = detector.detect(); AWAIT_READY(leader); EXPECT_SOME(leader.get()); leader = detector.detect(leader.get()); Future<Nothing> reconnecting = FUTURE_DISPATCH( group.process->self(), &GroupProcess::reconnecting); server->shutdownNetwork(); AWAIT_READY(reconnecting); Clock::pause(); // Settle to make sure 'reconnecting' schedules the timeout before // we advance. Clock::settle(); Clock::advance(timeout); // The detect operation times out. AWAIT_READY(leader); EXPECT_NONE(leader.get()); }
TEST(SchedTest, ROOT_PolicySelf) { Try<Policy> original = sched::policy::get(); ASSERT_SOME(original); Policy different = (original.get() == Policy::OTHER ? Policy::IDLE : Policy::OTHER); // Change our own scheduling policy. EXPECT_SOME(sched::policy::set(different)); EXPECT_SOME_EQ(different, sched::policy::get()); // Change it back. EXPECT_SOME(sched::policy::set(original.get())); EXPECT_SOME_EQ(original.get(), sched::policy::get()); }
TEST(QoSPipelineTest, NoCorrections) { uint64_t WINDOWS_SIZE = 10; uint64_t CONTENTION_COOLDOWN = 10; double_t FRATIONAL_THRESHOLD = 0.5; MockSlaveUsage mockSlaveUsage(QOS_PIPELINE_FIXTURE1); SerenityConfig conf; conf["Detector"] = createAssuranceDetectorCfg( WINDOWS_SIZE, CONTENTION_COOLDOWN, FRATIONAL_THRESHOLD); conf.set(ENABLED_VISUALISATION, false); conf.set(VALVE_OPENED, true); QoSControllerPipeline* pipeline = new CpuQoSPipeline(conf); // First iteration. Result<QoSCorrections> corrections = pipeline->run(mockSlaveUsage.usage().get()); EXPECT_NONE(corrections); // Second iteration. corrections = pipeline->run(mockSlaveUsage.usage().get()); EXPECT_SOME(corrections); EXPECT_TRUE(corrections.get().empty()); delete pipeline; }
TEST(AgentValidationTest, ContainerID) { ContainerID containerId; Option<Error> error; // No empty IDs. containerId.set_value(""); error = validation::container::validateContainerId(containerId); EXPECT_SOME(error); // No slashes. containerId.set_value("/"); error = validation::container::validateContainerId(containerId); EXPECT_SOME(error); containerId.set_value("\\"); error = validation::container::validateContainerId(containerId); EXPECT_SOME(error); // No spaces. containerId.set_value("redis backup"); error = validation::container::validateContainerId(containerId); EXPECT_SOME(error); // No periods. containerId.set_value("redis.backup"); error = validation::container::validateContainerId(containerId); EXPECT_SOME(error); // Cannot be '.'. containerId.set_value("."); error = validation::container::validateContainerId(containerId); EXPECT_SOME(error); // Cannot be '..'. containerId.set_value(".."); error = validation::container::validateContainerId(containerId); EXPECT_SOME(error); // Valid. containerId.set_value("redis"); error = validation::container::validateContainerId(containerId); EXPECT_NONE(error); // Valid with invalid parent (empty `ContainerID.value`). containerId.set_value("backup"); containerId.mutable_parent(); error = validation::container::validateContainerId(containerId); EXPECT_SOME(error); // Valid with valid parent. containerId.set_value("backup"); containerId.mutable_parent()->set_value("redis"); error = validation::container::validateContainerId(containerId); EXPECT_NONE(error); }
// Test varioud hook install/uninstall mechanisms. TEST_F(HookTest, HookLoading) { // Installing unknown hooks should fail. EXPECT_ERROR(HookManager::initialize("Unknown Hook")); // Uninstalling an unknown hook should fail. EXPECT_ERROR(HookManager::unload("Unknown Hook")); // Installing an already installed hook should fail. EXPECT_ERROR(HookManager::initialize(HOOK_MODULE_NAME)); // Uninstalling a hook should succeed. EXPECT_SOME(HookManager::unload(HOOK_MODULE_NAME)); // Uninstalling an already uninstalled hook should fail. EXPECT_ERROR(HookManager::unload(HOOK_MODULE_NAME)); // This is needed to allow the tear-down to succeed. EXPECT_SOME(HookManager::initialize(HOOK_MODULE_NAME)); }
// This test verifies that the pending future returned by // 'Authenticator::authenticate()' is properly failed when the // Authenticator Session is destroyed in the middle of authentication. TYPED_TEST(CRAMMD5Authentication, AuthenticatorDestructionRace) { // Launch a dummy process (somebody to send the AuthenticateMessage). UPID pid = spawn(new ProcessBase(), true); Credential credential1; credential1.set_principal("benh"); credential1.set_secret("secret"); Credentials credentials; Credential* credential2 = credentials.add_credentials(); credential2->set_principal(credential1.principal()); credential2->set_secret(credential1.secret()); Future<Message> message = FUTURE_MESSAGE(Eq(AuthenticateMessage().GetTypeName()), _, _); Try<Authenticatee*> authenticatee = TypeParam::TypeAuthenticatee::create(); CHECK_SOME(authenticatee); Future<bool> client = authenticatee.get()->authenticate(pid, UPID(), credential1); AWAIT_READY(message); Try<Authenticator*> authenticator = TypeParam::TypeAuthenticator::create(); CHECK_SOME(authenticator); EXPECT_SOME(authenticator.get()->initialize(credentials)); // Drop the AuthenticationStepMessage from authenticator session to // keep the authentication from getting completed. Future<AuthenticationStepMessage> authenticationStepMessage = DROP_PROTOBUF(AuthenticationStepMessage(), _, _); Future<Option<string>> principal = authenticator.get()->authenticate(message.get().from); AWAIT_READY(authenticationStepMessage); // At this point 'AuthenticatorProcess::authenticate()' has been // executed. // Authentication should be pending. ASSERT_TRUE(principal.isPending()); // Now delete the authenticator. delete authenticator.get(); // The future should be failed at this point. AWAIT_FAILED(principal); terminate(pid); delete authenticatee.get(); }
TEST(ZooKeeper, URL) { Try<zookeeper::URL> url = zookeeper::URL::parse("zk://*****:*****@host1:port1"); EXPECT_SOME(url); EXPECT_FALSE(url.get().authentication.isNone()); EXPECT_EQ("digest", url.get().authentication.get().scheme); EXPECT_EQ("jake:1", url.get().authentication.get().credentials); EXPECT_EQ("host1:port1", url.get().servers); EXPECT_EQ("/", url.get().path); url = zookeeper::URL::parse("zk://*****:*****@host1:port1/"); EXPECT_SOME(url); EXPECT_FALSE(url.get().authentication.isNone()); EXPECT_EQ("digest", url.get().authentication.get().scheme); EXPECT_EQ("jake:1", url.get().authentication.get().credentials); EXPECT_EQ("host1:port1", url.get().servers); EXPECT_EQ("/", url.get().path); url = zookeeper::URL::parse("zk://*****:*****@host1:port1,host2:port2"); EXPECT_SOME(url); EXPECT_FALSE(url.get().authentication.isNone()); EXPECT_EQ("digest", url.get().authentication.get().scheme); EXPECT_EQ("jake:1", url.get().authentication.get().credentials); EXPECT_EQ("host1:port1,host2:port2", url.get().servers); EXPECT_EQ("/", url.get().path); url = zookeeper::URL::parse("zk://*****:*****@host1:port1,host2:port2/"); EXPECT_SOME(url); EXPECT_FALSE(url.get().authentication.isNone()); EXPECT_EQ("digest", url.get().authentication.get().scheme); EXPECT_EQ("jake:1", url.get().authentication.get().credentials); EXPECT_EQ("host1:port1,host2:port2", url.get().servers); EXPECT_EQ("/", url.get().path); url = zookeeper::URL::parse("zk://*****:*****@host1:port1,host2:port2/path/to/znode"); EXPECT_SOME(url); EXPECT_FALSE(url.get().authentication.isNone()); EXPECT_EQ("digest", url.get().authentication.get().scheme); EXPECT_EQ("jake:1", url.get().authentication.get().credentials); EXPECT_EQ("host1:port1,host2:port2", url.get().servers); EXPECT_EQ("/path/to/znode", url.get().path); }
TYPED_TEST(CRAMMD5Authentication, Success) { // Launch a dummy process (somebody to send the AuthenticateMessage). UPID pid = spawn(new ProcessBase(), true); Credential credential1; credential1.set_principal("benh"); credential1.set_secret("secret"); Credentials credentials; Credential* credential2 = credentials.add_credentials(); credential2->set_principal(credential1.principal()); credential2->set_secret(credential1.secret()); Future<Message> message = FUTURE_MESSAGE(Eq(AuthenticateMessage().GetTypeName()), _, _); Try<Authenticatee*> authenticatee = TypeParam::TypeAuthenticatee::create(); CHECK_SOME(authenticatee); Future<bool> client = authenticatee.get()->authenticate(pid, UPID(), credential1); AWAIT_READY(message); Try<Authenticator*> authenticator = TypeParam::TypeAuthenticator::create(); CHECK_SOME(authenticator); EXPECT_SOME(authenticator.get()->initialize(credentials)); Future<Option<string>> principal = authenticator.get()->authenticate(message.get().from); AWAIT_EQ(true, client); AWAIT_READY(principal); EXPECT_SOME_EQ("benh", principal.get()); terminate(pid); delete authenticator.get(); delete authenticatee.get(); }
TEST_F(AppcSpecTest, ValidateImageManifest) { JSON::Value manifest = JSON::parse( "{" " \"acKind\": \"ImageManifest\"," " \"acVersion\": \"0.6.1\"," " \"name\": \"foo.com/bar\"," " \"labels\": [" " {" " \"name\": \"version\"," " \"value\": \"1.0.0\"" " }," " {" " \"name\": \"arch\"," " \"value\": \"amd64\"" " }," " {" " \"name\": \"os\"," " \"value\": \"linux\"" " }" " ]," " \"annotations\": [" " {" " \"name\": \"created\"," " \"value\": \"1438983392\"" " }" " ]" "}").get(); EXPECT_SOME(spec::parse(stringify(manifest))); // Incorrect acKind for image manifest. manifest = JSON::parse( "{" " \"acKind\": \"PodManifest\"," " \"acVersion\": \"0.6.1\"," " \"name\": \"foo.com/bar\"" "}").get(); EXPECT_ERROR(spec::parse(stringify(manifest))); }
TEST_F(AppcSpecTest, ValidateLayout) { string image = os::getcwd(); JSON::Value manifest = JSON::parse( "{" " \"acKind\": \"ImageManifest\"," " \"acVersion\": \"0.6.1\"," " \"name\": \"foo.com/bar\"" "}").get(); ASSERT_SOME(os::write(path::join(image, "manifest"), stringify(manifest))); // Missing rootfs. EXPECT_SOME(spec::validateLayout(image)); ASSERT_SOME(os::mkdir(path::join(image, "rootfs", "tmp"))); ASSERT_SOME(os::write(path::join(image, "rootfs", "tmp", "test"), "test")); EXPECT_NONE(spec::validateLayout(image)); }
// Change the scheduling policy of a different process (our child). TEST(SchedTest, ROOT_PolicyChild) { Try<Policy> original = sched::policy::get(); ASSERT_SOME(original); Policy different = (original.get() == Policy::OTHER ? Policy::IDLE : Policy::OTHER); pid_t pid = ::fork(); ASSERT_NE(-1, pid); if (pid == 0) { // Child. sleep(10); ABORT("Child process should not reach here"); } // Continue in parent. // Check the child has inherited our policy. EXPECT_SOME_EQ(original.get(), sched::policy::get(pid)); // Check we can change the child's policy. EXPECT_SOME(sched::policy::set(different, pid)); EXPECT_SOME_EQ(different, sched::policy::get(pid)); process::Future<Option<int>> status = process::reap(pid); // Kill the child process. ASSERT_NE(-1, ::kill(pid, SIGKILL)); // Wait for the child process. AWAIT_READY(status); ASSERT_SOME(status.get()); EXPECT_TRUE(WIFSIGNALED(status.get().get())); EXPECT_EQ(SIGKILL, WTERMSIG(status.get().get())); }
// Verify version parser. TEST(VersionTest, Parse) { Try<Version> version1 = Version::parse("1.20.3"); Try<Version> version2 = Version::parse("1.20"); Try<Version> version3 = Version::parse("1"); EXPECT_GT(version1.get(), version2.get()); EXPECT_GT(version2.get(), version3.get()); EXPECT_EQ(stringify(version2.get()), "1.20.0"); EXPECT_EQ(stringify(version3.get()), "1.0.0"); // Verify that tagged/labeled versions work. Try<Version> version4 = Version::parse("1.20.3-rc1"); EXPECT_SOME(version4); EXPECT_EQ(version4.get(), version1.get()); EXPECT_EQ(stringify(version4.get()), "1.20.3"); EXPECT_ERROR(Version::parse("0.a.b")); EXPECT_ERROR(Version::parse("")); EXPECT_ERROR(Version::parse("a")); EXPECT_ERROR(Version::parse("1.")); EXPECT_ERROR(Version::parse(".1.2")); EXPECT_ERROR(Version::parse("0.1.2.3")); }
TEST(AgentCallValidationTest, LaunchNestedContainerSession) { // Missing `launch_nested_container_session`. agent::Call call; call.set_type(agent::Call::LAUNCH_NESTED_CONTAINER_SESSION); Option<Error> error = validation::agent::call::validate(call); EXPECT_SOME(error); // `container_id` is not valid. ContainerID badContainerId; badContainerId.set_value("no spaces allowed"); agent::Call::LaunchNestedContainerSession* launch = call.mutable_launch_nested_container_session(); launch->mutable_container_id()->CopyFrom(badContainerId); error = validation::agent::call::validate(call); EXPECT_SOME(error); // Valid `container_id` but missing `container_id.parent`. ContainerID containerId; containerId.set_value(UUID::random().toString()); launch->mutable_container_id()->CopyFrom(containerId); error = validation::agent::call::validate(call); EXPECT_SOME(error); // Valid `container_id.parent` but invalid `command.environment`. Set // an invalid environment variable to check that the common validation // code for the command's environment is being executed. ContainerID parentContainerId; parentContainerId.set_value(UUID::random().toString()); launch->mutable_container_id()->mutable_parent()->CopyFrom(parentContainerId); launch->mutable_command()->CopyFrom(createCommandInfo("exit 0")); Environment::Variable* variable = launch ->mutable_command() ->mutable_environment() ->mutable_variables() ->Add(); variable->set_name("ENV_VAR_KEY"); variable->set_type(mesos::Environment::Variable::VALUE); error = validation::agent::call::validate(call); EXPECT_SOME(error); EXPECT_EQ( "'launch_nested_container_session.command' is invalid: Environment " "variable 'ENV_VAR_KEY' of type 'VALUE' must have a value set", error->message); // Test the valid case. variable->set_value("env_var_value"); error = validation::agent::call::validate(call); EXPECT_NONE(error); // Any number of parents is valid. ContainerID grandparentContainerId; grandparentContainerId.set_value(UUID::random().toString()); launch->mutable_container_id()->mutable_parent()->mutable_parent()->CopyFrom( grandparentContainerId); error = validation::agent::call::validate(call); EXPECT_NONE(error); }
~HookTest() { // Unload the hooks so a subsequent install may succeed. EXPECT_SOME(HookManager::unload(HOOK_MODULE_NAME)); }
TEST(QoSIpcPipelineTest, AssuranceDetectorTwoDropCorrectionsWithEma) { uint64_t WINDOWS_SIZE = 10; uint64_t CONTENTION_COOLDOWN = 4; double_t FRATIONAL_THRESHOLD = 0.3; double_t SEVERITY_LEVEL = 1; double_t NEAR_LEVEL = 0.1; MockSlaveUsage mockSlaveUsage(QOS_PIPELINE_FIXTURE2); SerenityConfig conf; conf["Detector"] = createAssuranceDetectorCfg( WINDOWS_SIZE, CONTENTION_COOLDOWN, FRATIONAL_THRESHOLD, SEVERITY_LEVEL, NEAR_LEVEL); conf.set(ema::ALPHA, 0.9); conf.set(ENABLED_VISUALISATION, false); conf.set(VALVE_OPENED, true); QoSControllerPipeline* pipeline = new CpuQoSPipeline(conf); // First iteration. Result<QoSCorrections> corrections = pipeline->run(mockSlaveUsage.usage().get()); EXPECT_NONE(corrections); ResourceUsage usage = mockSlaveUsage.usage().get(); const int32_t LOAD_ITERATIONS = 17; LoadGenerator loadGen( [](double_t iter) { return 1; }, new ZeroNoise(), LOAD_ITERATIONS); for (; loadGen.end(); loadGen++) { // Test scenario: After 10 iterations create drop in IPC // for executor num 3. double_t ipcFor3Executor = (*loadGen)(); if (loadGen.iteration >= 11) { ipcFor3Executor /= 2.0; } usage.mutable_executors(PR_4CPUS)->CopyFrom( generateIPC(usage.executors(PR_4CPUS), ipcFor3Executor, (*loadGen).timestamp)); usage.mutable_executors(PR_2CPUS)->CopyFrom( generateIPC(usage.executors(PR_2CPUS), (*loadGen)(), (*loadGen).timestamp)); // Third iteration (repeated). corrections = pipeline->run(usage); // Assurance Detector will wait for signal to be returned to the // established state. if (loadGen.iteration == 11 || loadGen.iteration == 16) { EXPECT_SOME(corrections); ASSERT_EQ(slave::QoSCorrection_Type_KILL, corrections.get().front().type()); // Make sure that we do not kill PR tasks! EXPECT_NE("serenityPR", corrections.get().front().kill().executor_id().value()); EXPECT_NE("serenityPR2", corrections.get().front().kill().executor_id().value()); } else { EXPECT_SOME(corrections); EXPECT_TRUE(corrections.get().empty()); } } delete pipeline; }
// This test verifies that the environment secrets are resolved when launching a // task. TEST_F(EnvironmentSecretIsolatorTest, ResolveSecret) { Try<Owned<cluster::Master>> master = StartMaster(); ASSERT_SOME(master); mesos::internal::slave::Flags flags = CreateSlaveFlags(); Fetcher fetcher(flags); Try<SecretResolver*> secretResolver = SecretResolver::create(); EXPECT_SOME(secretResolver); Try<MesosContainerizer*> containerizer = MesosContainerizer::create(flags, false, &fetcher, secretResolver.get()); EXPECT_SOME(containerizer); Owned<MasterDetector> detector = master.get()->createDetector(); Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), containerizer.get()); ASSERT_SOME(slave); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL); EXPECT_CALL(sched, registered(&driver, _, _)); Future<std::vector<Offer>> offers; EXPECT_CALL(sched, resourceOffers(&driver, _)) .WillOnce(FutureArg<1>(&offers)) .WillRepeatedly(Return()); // Ignore subsequent offers. driver.start(); AWAIT_READY(offers); EXPECT_FALSE(offers->empty()); const string commandString = strings::format( "env; test \"$%s\" = \"%s\"", SECRET_ENV_NAME, SECRET_VALUE).get(); CommandInfo command; command.set_value(commandString); // Request a secret. // TODO(kapil): Update createEnvironment() to support secrets. mesos::Environment::Variable *env = command.mutable_environment()->add_variables(); env->set_name(SECRET_ENV_NAME); env->set_type(mesos::Environment::Variable::SECRET); mesos::Secret* secret = env->mutable_secret(); secret->set_type(Secret::VALUE); secret->mutable_value()->set_data(SECRET_VALUE); TaskInfo task = createTask( offers.get()[0].slave_id(), Resources::parse("cpus:0.1;mem:32").get(), command); // NOTE: Successful tasks will output two status updates. Future<TaskStatus> statusRunning; Future<TaskStatus> statusFinished; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&statusRunning)) .WillOnce(FutureArg<1>(&statusFinished)); driver.launchTasks(offers.get()[0].id(), {task}); AWAIT_READY(statusRunning); EXPECT_EQ(TASK_RUNNING, statusRunning.get().state()); AWAIT_READY(statusFinished); EXPECT_EQ(TASK_FINISHED, statusFinished.get().state()); driver.stop(); driver.join(); }
TEST(QoSIpsPipelineTest, RollingFractionalDetectorOneDropCorrectionsWithEma) { QoSPipelineConf conf; ChangePointDetectionState cpdState; // Detector configuration: // How far we look back in samples. cpdState.windowSize = 10; // How many iterations detector will wait with creating another // contention. cpdState.contentionCooldown = 10; // Defines how much (relatively to base point) value must drop to trigger // contention. // Most detectors will use that. cpdState.fractionalThreshold = 0.5; // Defines how many instructions can be done per one CPU in one second. // This option helps RollingFractionalDetector to estimate severity of // drop. cpdState.severityLevel = 1000000000; // 1 Billion. conf.cpdState = cpdState; conf.emaAlpha = 0.4; conf.visualisation = false; // Let's start with QoS pipeline disabled. conf.valveOpened = true; MockSlaveUsage mockSlaveUsage(QOS_PIPELINE_FIXTURE3); QoSControllerPipeline* pipeline = new IpsQoSPipeline<RollingFractionalDetector>(conf); // First iteration. Result<QoSCorrections> corrections = pipeline->run(mockSlaveUsage.usage().get()); EXPECT_NONE(corrections); // Second iteration is used for manually configured load. ResourceUsage usage = mockSlaveUsage.usage().get(); const int32_t LOAD_ITERATIONS = 14; LoadGenerator loadGen( [](double_t iter) { return 3000000000; }, new ZeroNoise(), LOAD_ITERATIONS); for (; loadGen.end(); loadGen++) { // Test scenario: After 10 iterations create drop in IPS for executor num 3. double ipsFor3Executor = (*loadGen)(); if (loadGen.iteration >= 11) { ipsFor3Executor /= 3.0; } usage.mutable_executors(PR_4CPUS)->CopyFrom( generateIPS(usage.executors(PR_4CPUS), ipsFor3Executor, (*loadGen).timestamp)); usage.mutable_executors(PR_2CPUS)->CopyFrom( generateIPS(usage.executors(PR_2CPUS), (*loadGen)(), (*loadGen).timestamp)); // Third iteration (repeated). corrections = pipeline->run(usage); if (loadGen.iteration >= 13) { EXPECT_SOME(corrections); ASSERT_EQ(slave::QoSCorrection_Type_KILL, corrections.get().front().type()); // Make sure that we do not kill PR tasks! EXPECT_NE("serenityPR", corrections.get().front().kill().executor_id().value()); EXPECT_NE("serenityPR2", corrections.get().front().kill().executor_id().value()); } else { EXPECT_SOME(corrections); EXPECT_TRUE(corrections.get().empty()); } } delete pipeline; }
TEST(QoSIpcPipelineTest, AssuranceFractionalDetectorTwoDropCorrectionsWithEma) { QoSPipelineConf conf; ChangePointDetectionState cpdState; // Detector configuration: // How far we look back in samples. cpdState.windowSize = 10; // How many iterations detector will wait with creating another // contention. cpdState.contentionCooldown = 4; // Defines how much (relatively to base point) value must drop to trigger // contention. // Most detectors will use that. cpdState.fractionalThreshold = 0.3; // Defines how to convert difference in values to CPU. // This option helps RollingFractionalDetector to estimate severity of // drop. cpdState.severityLevel = 1; cpdState.nearFraction = 0.1; conf.cpdState = cpdState; conf.emaAlpha = 0.9; conf.visualisation = false; // Let's start with QoS pipeline disabled. conf.valveOpened = true; MockSlaveUsage mockSlaveUsage(QOS_PIPELINE_FIXTURE2); QoSControllerPipeline* pipeline = new CpuQoSPipeline<AssuranceFractionalDetector>(conf); // First iteration. Result<QoSCorrections> corrections = pipeline->run(mockSlaveUsage.usage().get()); EXPECT_NONE(corrections); ResourceUsage usage = mockSlaveUsage.usage().get(); const int32_t LOAD_ITERATIONS = 17; LoadGenerator loadGen( [](double_t iter) { return 1; }, new ZeroNoise(), LOAD_ITERATIONS); for (; loadGen.end(); loadGen++) { // Test scenario: After 10 iterations create drop in IPC // for executor num 3. double_t ipcFor3Executor = (*loadGen)(); if (loadGen.iteration >= 11) { ipcFor3Executor /= 2.0; } usage.mutable_executors(PR_4CPUS)->CopyFrom( generateIPC(usage.executors(PR_4CPUS), ipcFor3Executor, (*loadGen).timestamp)); usage.mutable_executors(PR_2CPUS)->CopyFrom( generateIPC(usage.executors(PR_2CPUS), (*loadGen)(), (*loadGen).timestamp)); // Third iteration (repeated). corrections = pipeline->run(usage); // Assurance Detector will wait for signal to be returned to the // established state. if (loadGen.iteration == 11 || loadGen.iteration == 16) { EXPECT_SOME(corrections); ASSERT_EQ(slave::QoSCorrection_Type_KILL, corrections.get().front().type()); // Make sure that we do not kill PR tasks! EXPECT_NE("serenityPR", corrections.get().front().kill().executor_id().value()); EXPECT_NE("serenityPR2", corrections.get().front().kill().executor_id().value()); } else { EXPECT_SOME(corrections); EXPECT_TRUE(corrections.get().empty()); } } delete pipeline; }
TEST(QoSIpcPipelineTest, RollingDetectorOneDropCorrectionsWithEma) { uint64_t WINDOWS_SIZE = 10; uint64_t CONTENTION_COOLDOWN = 10; double_t RELATIVE_THRESHOLD = 0.3; MockSlaveUsage mockSlaveUsage(QOS_PIPELINE_FIXTURE2); QoSControllerPipeline* pipeline = new CpuQoSPipeline<RollingChangePointDetector>( QoSPipelineConf( ChangePointDetectionState::createForRollingDetector( WINDOWS_SIZE, CONTENTION_COOLDOWN, RELATIVE_THRESHOLD), 0.2, // Alpha = 1 means no smoothing. 0.2 means high smoothing. false, true)); // First iteration. Result<QoSCorrections> corrections = pipeline->run(mockSlaveUsage.usage().get()); EXPECT_NONE(corrections); ResourceUsage usage = mockSlaveUsage.usage().get(); const int32_t LOAD_ITERATIONS = 16; LoadGenerator loadGen( [](double_t iter) { return 1; }, new ZeroNoise(), LOAD_ITERATIONS); for (; loadGen.end(); loadGen++) { // Test scenario: After 10 iterations create drop in // IPC for executor num 3. double_t ipcFor3Executor = (*loadGen)(); if (loadGen.iteration >= 11) { ipcFor3Executor /= 2.0; } usage.mutable_executors(PR_4CPUS)->CopyFrom( generateIPC(usage.executors(PR_4CPUS), ipcFor3Executor, (*loadGen).timestamp)); usage.mutable_executors(PR_2CPUS)->CopyFrom( generateIPC(usage.executors(PR_2CPUS), (*loadGen)(), (*loadGen).timestamp)); // Third iteration (repeated). corrections = pipeline->run(usage); if (loadGen.iteration >= 15) { EXPECT_SOME(corrections); ASSERT_EQ(slave::QoSCorrection_Type_KILL, corrections.get().front().type()); // Make sure that we do not kill PR tasks! EXPECT_NE("serenityPR", corrections.get().front().kill().executor_id().value()); EXPECT_NE("serenityPR2", corrections.get().front().kill().executor_id().value()); } else { EXPECT_SOME(corrections); EXPECT_TRUE(corrections.get().empty()); } } delete pipeline; }
// Tests that the common validation code for the // `Environment` message works as expected. TEST(AgentValidationTest, Environment) { // Validate a variable of SECRET type. { Environment environment; Environment::Variable* variable = environment.mutable_variables()->Add(); variable->set_type(mesos::Environment::Variable::SECRET); variable->set_name("ENV_VAR_KEY"); Option<Error> error = validateEnvironment(environment); EXPECT_SOME(error); EXPECT_EQ( "Environment variable 'ENV_VAR_KEY' of type " "'SECRET' must have a secret set", error->message); Secret secret; secret.set_type(Secret::VALUE); secret.mutable_value()->set_data("SECRET_VALUE"); variable->mutable_secret()->CopyFrom(secret); variable->set_value("ENV_VAR_VALUE"); error = validateEnvironment(environment); EXPECT_SOME(error); EXPECT_EQ( "Environment variable 'ENV_VAR_KEY' of type 'SECRET' " "must not have a value set", error->message); variable->clear_value(); char invalid_secret[5] = {'a', 'b', '\0', 'c', 'd'}; variable->mutable_secret()->mutable_value()->set_data( std::string(invalid_secret, 5)); error = validateEnvironment(environment); EXPECT_SOME(error); EXPECT_EQ( "Environment variable 'ENV_VAR_KEY' specifies a secret containing " "null bytes, which is not allowed in the environment", error->message); // Test the valid case. variable->mutable_secret()->mutable_value()->set_data("SECRET_VALUE"); error = validateEnvironment(environment); EXPECT_NONE(error); } // Validate a variable of VALUE type. { // The default type for an environment variable // should be VALUE, so we do not set the type here. Environment environment; Environment::Variable* variable = environment.mutable_variables()->Add(); variable->set_name("ENV_VAR_KEY"); Option<Error> error = validateEnvironment(environment); EXPECT_SOME(error); EXPECT_EQ( "Environment variable 'ENV_VAR_KEY' of type 'VALUE' " "must have a value set", error->message); variable->set_value("ENV_VAR_VALUE"); Secret secret; secret.set_type(Secret::VALUE); secret.mutable_value()->set_data("SECRET_VALUE"); variable->mutable_secret()->CopyFrom(secret); error = validateEnvironment(environment); EXPECT_SOME(error); EXPECT_EQ( "Environment variable 'ENV_VAR_KEY' of type 'VALUE' " "must not have a secret set", error->message); // Test the valid case. variable->clear_secret(); error = validateEnvironment(environment); EXPECT_NONE(error); } // Validate a variable of UNKNOWN type. { Environment environment; Environment::Variable* variable = environment.mutable_variables()->Add(); variable->set_type(mesos::Environment::Variable::UNKNOWN); variable->set_name("ENV_VAR_KEY"); variable->set_value("ENV_VAR_VALUE"); Option<Error> error = validateEnvironment(environment); EXPECT_SOME(error); EXPECT_EQ( "Environment variable of type 'UNKNOWN' is not allowed", error->message); } }
// TODO(karya): Replace constructor/destructor with SetUp/TearDown. // Currently, using SetUp/TearDown causes VerifySlave* test to // fail with a duplicate slave id message. However, everything // seems normal when using this construction/destructor combo. HookTest() { // Install hooks. EXPECT_SOME(HookManager::initialize(HOOK_MODULE_NAME)); }