TEST(CacheTest, LRUEviction) { Cache<int, std::string> cache(2); cache.put(1, "a"); cache.put(2, "b"); cache.put(3, "c"); EXPECT_NONE(cache.get(1)); // 'Get' makes '2' the most-recently used (MRU) item. cache.get(2); cache.put(4, "d"); EXPECT_NONE(cache.get(3)); EXPECT_SOME_EQ("b", cache.get(2)); EXPECT_SOME_EQ("d", cache.get(4)); // 'Put' also makes '2' MRU. cache.put(2, "x"); cache.put(5, "e"); EXPECT_NONE(cache.get(4)); EXPECT_SOME_EQ("x", cache.get(2)); EXPECT_SOME_EQ("e", cache.get(5)); // 'Erase' the LRU. cache.erase(2); cache.put(6, "f"); cache.put(7, "g"); EXPECT_NONE(cache.get(5)); }
TEST(DurationTest, ParseAndTry) { EXPECT_SOME_EQ(Hours(3), Duration::parse("3hrs")); EXPECT_SOME_EQ(Hours(3) + Minutes(30), Duration::parse("3.5hrs")); EXPECT_SOME_EQ(Nanoseconds(3141592653), Duration::create(3.141592653)); // Duration can hold only 9.22337e9 seconds. EXPECT_ERROR(Duration::create(10 * 1e9)); EXPECT_ERROR(Duration::create(-10 * 1e9)); }
TEST(NumifyTest, DecNumberTest) { Try<unsigned int> num1 = numify<unsigned int>("10"); EXPECT_SOME_EQ(10u, num1); Try<int> num2 = numify<int>("-10"); EXPECT_SOME_EQ(-10, num2); EXPECT_ERROR(numify<unsigned int>("")); EXPECT_ERROR(numify<int>("-10.")); EXPECT_ERROR(numify<unsigned int>("123xyz")); }
// Tests the archive APIs for archiving/unarchiving a directory for GZIP // compression. This test specifically tests for the use case of changing // directory before archiving. TEST_F(TarTest, GZIPChangeDirectory) { // Create a top directory where the directory to be archived will be placed. const Path topDir("top_dir"); const Path testDir("test_dir"); const Path testFile(path::join(testDir, "testfile")); // Create a test file in the test directory. ASSERT_SOME(createTestFile(testFile, topDir)); // Archive the test directory. const Path outputTarFile("test_dir.tar"); AWAIT_ASSERT_READY(command::tar( testDir, outputTarFile, topDir, command::Compression::GZIP)); ASSERT_TRUE(os::exists(outputTarFile)); // Remove the top directory to make sure untar process creates new directory. ASSERT_SOME(os::rmdir(topDir)); ASSERT_FALSE(os::exists(topDir)); // Untar the tarball and verify that the original file is created. AWAIT_ASSERT_READY(command::untar(outputTarFile)); ASSERT_TRUE(os::exists(testDir)); // Verify that the top directory was not created. ASSERT_FALSE(os::exists(topDir)); // Verify that the content is same as original file. EXPECT_SOME_EQ("test", os::read(testFile)); }
// Tests the archive APIs for archiving/unarchiving a simple file for BZIP2 // compression. TEST_F(TarTest, BZIP2CompressFile) { // Create a test file. const Path testFile("testfile"); ASSERT_SOME(createTestFile(testFile)); // Archive the test file. const Path outputTarFile("test.tar"); AWAIT_ASSERT_READY(command::tar( testFile, outputTarFile, None(), command::Compression::BZIP2)); ASSERT_TRUE(os::exists(outputTarFile)); // Remove the test file to make sure untar process creates new test file. ASSERT_SOME(os::rm(testFile)); ASSERT_FALSE(os::exists(testFile)); // Untar the tarball and verify that the original file is created. AWAIT_ASSERT_READY(command::untar(outputTarFile)); ASSERT_TRUE(os::exists(testFile)); // Verify that the content is same as original file. EXPECT_SOME_EQ("test", os::read(testFile)); }
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(CacheTest, Update) { Cache<int, std::string> cache(1); cache.put(1, "a"); cache.put(1, "b"); EXPECT_SOME_EQ("b", cache.get(1)); EXPECT_EQ(1, cache.size()); }
TEST(BytesTest, Parse) { EXPECT_SOME_EQ(Terabytes(1), Bytes::parse("1TB")); EXPECT_SOME_EQ(Gigabytes(1), Bytes::parse("1GB")); EXPECT_SOME_EQ(Megabytes(1), Bytes::parse("1MB")); EXPECT_SOME_EQ(Kilobytes(1), Bytes::parse("1KB")); EXPECT_SOME_EQ(Bytes(1), Bytes::parse("1B")); // Cannot have fractional bytes. EXPECT_ERROR(Bytes::parse("1.5B")); // Parsing fractions is unsupported. EXPECT_ERROR(Bytes::parse("1.5GB")); // Unknown unit. EXPECT_ERROR(Bytes::parse("1PB")); }
TEST(CacheTest, Erase) { Cache<int, std::string> cache(2); cache.put(1, "a"); cache.put(2, "b"); EXPECT_NONE(cache.erase(44)); EXPECT_SOME_EQ("b", cache.erase(2)); EXPECT_EQ(1, cache.size()); EXPECT_NONE(cache.erase(2)); EXPECT_EQ(1, cache.size()); EXPECT_SOME_EQ("a", cache.erase(1)); EXPECT_EQ(0, cache.size()); }
TEST(CacheTest, Insert) { Cache<int, std::string> cache(1); EXPECT_EQ(0, cache.size()); cache.put(1, "a"); EXPECT_SOME_EQ("a", cache.get(1)); EXPECT_EQ(1, cache.size()); }
TEST(NumifyTest, HexNumberTest) { Try<unsigned int> num1 = numify<unsigned int>("0xdeadbeef"); EXPECT_SOME_EQ(0xdeadbeefu, num1); Try<unsigned int> num2 = numify<unsigned int>("0x10"); EXPECT_SOME_EQ(16u, num2); // TODO(neilc): This is inconsistent with the handling of non-hex numbers. EXPECT_ERROR(numify<int>("-0x10")); EXPECT_ERROR(numify<unsigned int>("")); EXPECT_ERROR(numify<unsigned int>("0xxyz")); EXPECT_ERROR(numify<unsigned int>("abc")); EXPECT_ERROR(numify<unsigned int>("0x0x1")); EXPECT_ERROR(numify<double>("0x10.9")); EXPECT_ERROR(numify<double>("0x1p-5")); }
TEST_F(ZooKeeperTest, LeaderDetector) { Group group(server->connectString(), NO_TIMEOUT, "/test/"); // Initialize two members. Future<Group::Membership> membership1 = group.join("member 1"); AWAIT_READY(membership1); Future<Group::Membership> membership2 = group.join("member 2"); AWAIT_READY(membership2); LeaderDetector detector(&group); // Detect the leader. Future<Option<Group::Membership> > leader = detector.detect(None()); AWAIT_READY(leader); ASSERT_SOME_EQ(membership1.get(), leader.get()); // Detect next leader change. leader = detector.detect(leader.get()); EXPECT_TRUE(leader.isPending()); // Leader doesn't change after cancelling the follower. Future<bool> cancellation = group.cancel(membership2.get()); AWAIT_READY(cancellation); EXPECT_TRUE(cancellation.get()); EXPECT_TRUE(leader.isPending()); // Join member 2 back. membership2 = group.join("member 2"); AWAIT_READY(membership2); EXPECT_TRUE(leader.isPending()); // Cancelling the incumbent leader allows member 2 to be elected. cancellation = group.cancel(membership1.get()); AWAIT_READY(cancellation); EXPECT_TRUE(cancellation.get()); AWAIT_READY(leader); EXPECT_SOME_EQ(membership2.get(), leader.get()); // Cancelling the only member results in no leader elected. leader = detector.detect(leader.get().get()); EXPECT_TRUE(leader.isPending()); cancellation = group.cancel(membership2.get()); AWAIT_READY(cancellation); EXPECT_TRUE(cancellation.get()); AWAIT_READY(leader); ASSERT_TRUE(leader.get().isNone()); }
// 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())); }
JSON::Object Metrics() { process::UPID upid("metrics", process::address()); process::Future<process::http::Response> response = process::http::get(upid, "snapshot"); AWAIT_EXPECT_RESPONSE_STATUS_EQ(process::http::OK().status, response); EXPECT_SOME_EQ( "application/json", response.get().headers.get("Content-Type")); Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body); CHECK_SOME(parse); return parse.get(); }
// This test does not set any Accept header for the subscribe call. // The default response media type should be "application/json" in // this case. TEST_P(ExecutorHttpApiTest, NoAcceptHeader) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); AWAIT_READY(__recover); // Wait for recovery to be complete. Clock::pause(); Clock::settle(); // Retrieve the parameter passed as content type to this test. const ContentType contentType = GetParam(); // No 'Accept' header leads to all media types considered // acceptable. JSON will be chosen by default. process::http::Headers headers; // Only subscribe needs to 'Accept' JSON or protobuf. Call call; call.set_type(Call::SUBSCRIBE); call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("dummy_executor_id"); Future<Response> response = process::http::streaming::post( slave.get(), "api/v1/executor", headers, serialize(contentType, call), stringify(contentType)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); EXPECT_SOME_EQ(APPLICATION_JSON, response.get().headers.get("Content-Type")); Shutdown(); }
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(); }
// Tests CopyFetcher plugin for fetching a valid file. TEST_F(CopyFetcherPluginTest, FetchExistingFile) { const string file = path::join(os::getcwd(), "file"); ASSERT_SOME(os::write(file, "abc")); // Create a URI for the test file. const URI uri = uri::file(file); // Use the file fetcher to fetch the URI. Try<Owned<uri::Fetcher>> fetcher = uri::fetcher::create(); ASSERT_SOME(fetcher); const string dir = path::join(os::getcwd(), "dir"); AWAIT_READY(fetcher.get()->fetch(uri, dir)); // Validate the fetched file's content. EXPECT_SOME_EQ("abc", os::read(path::join(dir, "file"))); }
TEST_F(HadoopFetcherPluginTest, FetchExistingFile) { string file = path::join(os::getcwd(), "file"); ASSERT_SOME(os::write(file, "abc")); URI uri = uri::hdfs(file); uri::fetcher::Flags flags; flags.hadoop_client = hadoop; Try<Owned<uri::Fetcher>> fetcher = uri::fetcher::create(flags); ASSERT_SOME(fetcher); string dir = path::join(os::getcwd(), "dir"); AWAIT_READY(fetcher.get()->fetch(uri, dir)); EXPECT_SOME_EQ("abc", os::read(path::join(dir, "file"))); }
// This test sends in a Accept:*/* header meaning it would Accept any // media type as response. We return the default "application/json" // media type as response. TEST_P(ExecutorHttpApiTest, DefaultAccept) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); Try<PID<Slave>> slave = StartSlave(); ASSERT_SOME(slave); Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover); AWAIT_READY(__recover); hashmap<string, string> headers; headers["Accept"] = "*/*"; // Only subscribe needs to 'Accept' JSON or protobuf. Call call; call.set_type(Call::SUBSCRIBE); call.mutable_framework_id()->set_value("dummy_framework_id"); call.mutable_executor_id()->set_value("dummy_executor_id"); // Retrieve the parameter passed as content type to this test. const ContentType contentType = GetParam(); Future<Response> response = process::http::streaming::post( slave.get(), "api/v1/executor", headers, serialize(contentType, call), stringify(contentType)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); EXPECT_SOME_EQ(APPLICATION_JSON, response.get().headers.get("Content-Type")); Shutdown(); }
// Tests the archive APIs for a simple directory. TEST_F(TarTest, Directory) { const Path testDir("test_dir"); const Path testFile(path::join(testDir, "testfile")); // Create a test file in the test directory. ASSERT_SOME(createTestFile(testFile)); // Archive the test directory. const Path outputTarFile("test_dir.tar"); AWAIT_ASSERT_READY(command::tar(testDir, outputTarFile, None())); ASSERT_TRUE(os::exists(outputTarFile)); // Remove the test directory to make sure untar process creates new test file. ASSERT_SOME(os::rmdir(testDir)); ASSERT_FALSE(os::exists(testDir)); // Untar the tarball and verify that the original directory is created. AWAIT_ASSERT_READY(command::untar(outputTarFile)); ASSERT_TRUE(os::exists(testDir)); // Verify that the content is same as original file. EXPECT_SOME_EQ("test", os::read(testFile)); }
// This test does not set any Accept header for the subscribe call. // The default response media type should be "application/json" in // this case. TEST_P(ExecutorHttpApiTest, NoAcceptHeader) { Try<PID<Master>> master = StartMaster(); ASSERT_SOME(master); ExecutorID executorId = DEFAULT_EXECUTOR_ID; MockExecutor exec(executorId); Try<PID<Slave>> slave = StartSlave(&exec); ASSERT_SOME(slave); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); Future<FrameworkID> frameworkId; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureArg<1>(&frameworkId)); Future<vector<Offer>> offers; EXPECT_CALL(sched, resourceOffers(&driver, _)) .WillOnce(FutureArg<1>(&offers)); Future<Nothing> statusUpdate; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureSatisfy(&statusUpdate)); driver.start(); AWAIT_READY(frameworkId); AWAIT_READY(offers); ASSERT_EQ(1u, offers.get().size()); EXPECT_CALL(exec, registered(_, _, _, _)) .Times(1); EXPECT_CALL(exec, launchTask(_, _)) .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING)); TaskInfo taskInfo = createTask(offers.get()[0], "", executorId); driver.launchTasks(offers.get()[0].id(), {taskInfo}); // Wait until status update is received on the scheduler before sending // an executor subscribe request. AWAIT_READY(statusUpdate); // Only subscribe needs to 'Accept' JSON or protobuf. Call call; call.mutable_framework_id()->CopyFrom(evolve(frameworkId.get())); call.mutable_executor_id()->CopyFrom(evolve(executorId)); call.set_type(Call::SUBSCRIBE); call.mutable_subscribe(); // Retrieve the parameter passed as content type to this test. const ContentType contentType = GetParam(); // No 'Accept' header leads to all media types considered // acceptable. JSON will be chosen by default. process::http::Headers headers; Future<Response> response = process::http::streaming::post( slave.get(), "api/v1/executor", headers, serialize(contentType, call), stringify(contentType)); AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); EXPECT_SOME_EQ(APPLICATION_JSON, response.get().headers.get("Content-Type")); Shutdown(); }