Maintenance Primitives: Used V1 API for Master maintenance test. Review: https://reviews.apache.org/r/37283
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/bf82689f Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/bf82689f Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/bf82689f Branch: refs/heads/master Commit: bf82689f69a21286177d52d7d7e5d2f713c1e5b1 Parents: 388eaa5 Author: Joris Van Remoortere <[email protected]> Authored: Tue Aug 25 18:50:21 2015 -0400 Committer: Joris Van Remoortere <[email protected]> Committed: Mon Sep 14 13:58:37 2015 -0400 ---------------------------------------------------------------------- src/tests/master_maintenance_tests.cpp | 152 +++++++++++++++++++++------- 1 file changed, 118 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/bf82689f/src/tests/master_maintenance_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/master_maintenance_tests.cpp b/src/tests/master_maintenance_tests.cpp index a857ab9..8f39ac3 100644 --- a/src/tests/master_maintenance_tests.cpp +++ b/src/tests/master_maintenance_tests.cpp @@ -20,6 +20,12 @@ #include <mesos/maintenance/maintenance.hpp> +#include <mesos/v1/mesos.hpp> +#include <mesos/v1/resources.hpp> +#include <mesos/v1/scheduler.hpp> + +#include <mesos/v1/scheduler/scheduler.hpp> + #include <process/clock.hpp> #include <process/future.hpp> #include <process/http.hpp> @@ -37,6 +43,9 @@ #include "common/protobuf_utils.hpp" +#include "internal/devolve.hpp" +#include "internal/evolve.hpp" + #include "master/master.hpp" #include "slave/flags.hpp" @@ -48,9 +57,14 @@ using mesos::internal::master::Master; using mesos::internal::slave::Slave; +using mesos::v1::scheduler::Call; +using mesos::v1::scheduler::Event; +using mesos::v1::scheduler::Mesos; + using process::Clock; using process::Future; using process::PID; +using process::Queue; using process::Time; using process::http::BadRequest; @@ -65,6 +79,7 @@ using mesos::internal::protobuf::maintenance::createWindow; using std::string; using std::vector; +using testing::AtMost; using testing::DoAll; namespace mesos { @@ -111,9 +126,40 @@ public: // Default unavailability. Used when the test does not care // about the value of the unavailability. Unavailability unavailability; + +protected: + // Helper class for using EXPECT_CALL since the Mesos scheduler API + // is callback based. + class Callbacks + { + public: + MOCK_METHOD0(connected, void(void)); + MOCK_METHOD0(disconnected, void(void)); + MOCK_METHOD1(received, void(const std::queue<Event>&)); + }; }; +// Enqueues all received events into a libprocess queue. +// TODO(jmlvanre): Factor this common code out of tests into V1 +// helper. +ACTION_P(Enqueue, queue) +{ + std::queue<Event> events = arg0; + while (!events.empty()) { + // Note that we currently drop HEARTBEATs because most of these tests + // are not designed to deal with heartbeats. + // TODO(vinod): Implement DROP_HTTP_CALLS that can filter heartbeats. + if (events.front().type() == Event::HEARTBEAT) { + VLOG(1) << "Ignoring HEARTBEAT event"; + } else { + queue->put(events.front()); + } + events.pop(); + } +} + + // Posts valid and invalid schedules to the maintenance schedule endpoint. TEST_F(MasterMaintenanceTest, UpdateSchedule) { @@ -304,7 +350,10 @@ TEST_F(MasterMaintenanceTest, FailToUnscheduleDeactivatedMachines) // slave is scheduled to go down for maintenance. TEST_F(MasterMaintenanceTest, PendingUnavailabilityTest) { - Try<PID<Master>> master = StartMaster(); + master::Flags flags = CreateMasterFlags(); + flags.authenticate_frameworks = false; + + Try<PID<Master>> master = StartMaster(flags); ASSERT_SOME(master); MockExecutor exec(DEFAULT_EXECUTOR_ID); @@ -312,36 +361,49 @@ TEST_F(MasterMaintenanceTest, PendingUnavailabilityTest) Try<PID<Slave>> slave = StartSlave(&exec); ASSERT_SOME(slave); - MockScheduler sched; - MesosSchedulerDriver driver( - &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); + Callbacks callbacks; + + Future<Nothing> connected; + EXPECT_CALL(callbacks, connected()) + .WillOnce(FutureSatisfy(&connected)); - EXPECT_CALL(sched, registered(&driver, _, _)) - .Times(1); + Mesos mesos( + master.get(), + lambda::bind(&Callbacks::connected, lambda::ref(callbacks)), + lambda::bind(&Callbacks::disconnected, lambda::ref(callbacks)), + lambda::bind(&Callbacks::received, lambda::ref(callbacks), lambda::_1)); - // Intercept offers sent to the scheduler. - Future<vector<Offer>> normalOffers; - Future<vector<Offer>> unavailabilityOffers; - EXPECT_CALL(sched, resourceOffers(&driver, _)) - .WillOnce(FutureArg<1>(&normalOffers)) - .WillOnce(FutureArg<1>(&unavailabilityOffers)) - .WillRepeatedly(Return()); // Ignore subsequent offers. + AWAIT_READY(connected); - // The original offers should be rescinded when the unavailability - // is changed. - Future<Nothing> offerRescinded; - EXPECT_CALL(sched, offerRescinded(&driver, _)) - .WillOnce(FutureSatisfy(&offerRescinded)); + Queue<Event> events; + + EXPECT_CALL(callbacks, received(_)) + .WillRepeatedly(Enqueue(&events)); + + { + Call call; + call.set_type(Call::SUBSCRIBE); + + Call::Subscribe* subscribe = call.mutable_subscribe(); + subscribe->mutable_framework_info()->CopyFrom(DEFAULT_V1_FRAMEWORK_INFO); + + mesos.send(call); + } + + Future<Event> event = events.get(); + AWAIT_READY(event); + EXPECT_EQ(Event::SUBSCRIBED, event.get().type()); - // Start the test. - driver.start(); + v1::FrameworkID id(event.get().subscribed().framework_id()); - // Wait for some normal offers. - AWAIT_READY(normalOffers); - EXPECT_NE(0u, normalOffers.get().size()); + event = events.get(); + AWAIT_READY(event); + EXPECT_EQ(Event::OFFERS, event.get().type()); + EXPECT_NE(0, event.get().offers().offers().size()); + const size_t numberOfOffers = event.get().offers().offers().size(); - // Check that unavailability is not set. - foreach (const Offer& offer, normalOffers.get()) { + // Regular offers shouldn't have unavailability. + foreach (const v1::Offer& offer, event.get().offers().offers()) { EXPECT_FALSE(offer.has_unavailability()); } @@ -372,19 +434,41 @@ TEST_F(MasterMaintenanceTest, PendingUnavailabilityTest) AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); - // Wait for some offers. - AWAIT_READY(unavailabilityOffers); - EXPECT_NE(0u, unavailabilityOffers.get().size()); + // The original offers should be rescinded when the unavailability + // is changed. We expect as many rescind events as we received + // original offers. + for (size_t offerNumber = 0; offerNumber < numberOfOffers; ++offerNumber) { + event = events.get(); + AWAIT_READY(event); + EXPECT_EQ(Event::RESCIND, event.get().type()); + } - // Check that each offer has an unavailability. - foreach (const Offer& offer, unavailabilityOffers.get()) { + event = events.get(); + AWAIT_READY(event); + EXPECT_EQ(Event::OFFERS, event.get().type()); + EXPECT_NE(0, event.get().offers().offers().size()); + + // Make sure the new offers have the unavailability set. + foreach (const v1::Offer& offer, event.get().offers().offers()) { EXPECT_TRUE(offer.has_unavailability()); - EXPECT_EQ(unavailability.start(), offer.unavailability().start()); - EXPECT_EQ(unavailability.duration(), offer.unavailability().duration()); + EXPECT_EQ( + unavailability.start().nanoseconds(), + offer.unavailability().start().nanoseconds()); + + EXPECT_EQ( + unavailability.duration().nanoseconds(), + offer.unavailability().duration().nanoseconds()); } - driver.stop(); - driver.join(); + // We also expect an inverse offer for the slave to go under + // maintenance. + event = events.get(); + AWAIT_READY(event); + EXPECT_EQ(Event::OFFERS, event.get().type()); + EXPECT_NE(0, event.get().offers().inverse_offers().size()); + + EXPECT_CALL(exec, shutdown(_)) + .Times(AtMost(1)); Shutdown(); // Must shutdown before 'containerizer' gets deallocated. }
