You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by as...@apache.org on 2020/09/03 16:05:44 UTC
[mesos] branch master updated (5274e97 -> 2bf7f5d)
This is an automated email from the ASF dual-hosted git repository.
asekretenko pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git.
from 5274e97 Added a test for discarding image pull on discard of getting image.
new 9bb35fe Extracted FrameworkInfo comparison logic from tests.
new 8839af8 Removed `bool operator==(const FrameworkInfo&, const FrameworkInfo&)`.
new 720cc70 Eliminated redundant update broadcasts in UPDATE_FRAMEWORK.
new 2bf7f5d Added a test of UPDATE_FRAMEWORK with the same FrameworkInfo.
The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
include/mesos/type_utils.hpp | 23 ++++-
include/mesos/v1/mesos.hpp | 23 ++++-
src/Makefile.am | 1 +
src/common/type_utils.cpp | 29 ++++++
src/common/type_utils_differencers.hpp | 53 +++++++++++
src/master/master.cpp | 24 ++++-
src/tests/api_tests.cpp | 14 ++-
src/tests/master/update_framework_tests.cpp | 143 +++++++++++++++++++++-------
src/tests/master_allocator_tests.cpp | 7 +-
src/tests/resources_tests.cpp | 4 +-
src/v1/mesos.cpp | 30 ++++++
11 files changed, 299 insertions(+), 52 deletions(-)
create mode 100644 src/common/type_utils_differencers.hpp
[mesos] 02/04: Removed `bool operator==(const FrameworkInfo&,
const FrameworkInfo&)`.
Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
asekretenko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 8839af89e2ace33c7b7223790a9a75e67cf43110
Author: Andrei Sekretenko <as...@mesosphere.com>
AuthorDate: Mon Aug 31 18:34:00 2020 +0200
Removed `bool operator==(const FrameworkInfo&, const FrameworkInfo&)`.
This patch removes the outdated `operator==` for `FrameworkInfo`
(which has been comparing only `name` and `user` fields)
and replaces it with `equivalent()` in the tests that need to compare
`FrameworkInfo`s.
Review: https://reviews.apache.org/r/72833
---
include/mesos/type_utils.hpp | 8 ++++----
include/mesos/v1/mesos.hpp | 8 ++++----
src/tests/api_tests.cpp | 14 ++++++++++++--
src/tests/master_allocator_tests.cpp | 7 +++----
src/tests/resources_tests.cpp | 4 +++-
5 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/include/mesos/type_utils.hpp b/include/mesos/type_utils.hpp
index 2745ff0..b3a4413 100644
--- a/include/mesos/type_utils.hpp
+++ b/include/mesos/type_utils.hpp
@@ -116,10 +116,10 @@ inline bool operator==(const FrameworkID& left, const FrameworkID& right)
}
-inline bool operator==(const FrameworkInfo& left, const FrameworkInfo& right)
-{
- return (left.name() == right.name()) && (left.user() == right.user());
-}
+// This operator, which was comparing only `user` and `name` fields,
+// has been deleted in favor of `typeutils::equivalent()` function (see below)
+// with different semantics.
+bool operator==(const FrameworkInfo& left, const FrameworkInfo& right) = delete;
namespace typeutils {
diff --git a/include/mesos/v1/mesos.hpp b/include/mesos/v1/mesos.hpp
index 853330a..6779825 100644
--- a/include/mesos/v1/mesos.hpp
+++ b/include/mesos/v1/mesos.hpp
@@ -100,10 +100,10 @@ inline bool operator==(const FrameworkID& left, const FrameworkID& right)
}
-inline bool operator==(const FrameworkInfo& left, const FrameworkInfo& right)
-{
- return (left.name() == right.name()) && (left.user() == right.user());
-}
+// This operator, which was comparing only `user` and `name` fields,
+// has been deleted in favor of `typeutils::equivalent()` function (see below)
+// with different semantics.
+bool operator==(const FrameworkInfo& left, const FrameworkInfo& right) = delete;
namespace typeutils {
diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp
index e0ce033..22435f7 100644
--- a/src/tests/api_tests.cpp
+++ b/src/tests/api_tests.cpp
@@ -84,6 +84,7 @@ using mesos::slave::ContainerTermination;
using mesos::v1::scheduler::Call;
using mesos::v1::scheduler::Event;
using mesos::v1::scheduler::Mesos;
+using mesos::v1::typeutils::diff;
using mesos::internal::devolve;
using mesos::internal::evolve;
@@ -3350,6 +3351,12 @@ TEST_P(MasterAPITest, FrameworksEvent)
// when it reconnects.
frameworkInfo.set_failover_timeout(Weeks(2).secs());
+ // We need to set `checkpoint` explicitly. Otherwise, `jsonify` in the
+ // scheduler driver sets it to the default value, which results in a spurious
+ // diff between the reported `FrameworkInfo` (`checkpoint == false`) and the
+ // one with which the scheduler has subscribed (`checkpoint` not set).
+ frameworkInfo.set_checkpoint(false);
+
mesos.send(v1::createCallSubscribe(frameworkInfo));
AWAIT_READY(subscribed);
@@ -3366,7 +3373,9 @@ TEST_P(MasterAPITest, FrameworksEvent)
const v1::master::Response::GetFrameworks::Framework& framework =
event.get()->framework_added().framework();
- EXPECT_EQ(frameworkInfo, framework.framework_info());
+ EXPECT_NONE(
+ mesos::v1::typeutils::diff(frameworkInfo, framework.framework_info()));
+
EXPECT_TRUE(framework.active());
EXPECT_TRUE(framework.connected());
@@ -3404,7 +3413,8 @@ TEST_P(MasterAPITest, FrameworksEvent)
const v1::master::Response::GetFrameworks::Framework& framework =
event.get()->framework_updated().framework();
- EXPECT_EQ(frameworkInfo, framework.framework_info());
+ EXPECT_NONE(
+ mesos::v1::typeutils::diff(frameworkInfo, framework.framework_info()));
EXPECT_EQ(registeredTime, framework.registered_time());
diff --git a/src/tests/master_allocator_tests.cpp b/src/tests/master_allocator_tests.cpp
index 416b7ba..b011a34 100644
--- a/src/tests/master_allocator_tests.cpp
+++ b/src/tests/master_allocator_tests.cpp
@@ -350,8 +350,9 @@ TYPED_TEST(MasterAllocatorTest, OutOfOrderDispatch)
MesosSchedulerDriver driver1(
&sched1, frameworkInfo1, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework_(_, Eq(frameworkInfo1), _, _, _))
- .WillOnce(InvokeAddFramework(&allocator));
+ EXPECT_CALL(allocator, addFramework_(_, _, _, _, _))
+ .Times(2)
+ .WillRepeatedly(InvokeAddFramework(&allocator));
Future<FrameworkID> frameworkId1;
EXPECT_CALL(sched1, registered(_, _, _))
@@ -419,8 +420,6 @@ TYPED_TEST(MasterAllocatorTest, OutOfOrderDispatch)
MesosSchedulerDriver driver2(
&sched2, frameworkInfo2, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework_(_, Eq(frameworkInfo2), _, _, _))
- .WillOnce(InvokeAddFramework(&allocator));
FrameworkID frameworkId2;
EXPECT_CALL(sched2, registered(_, _, _))
diff --git a/src/tests/resources_tests.cpp b/src/tests/resources_tests.cpp
index bd04431..b6127e3 100644
--- a/src/tests/resources_tests.cpp
+++ b/src/tests/resources_tests.cpp
@@ -3395,7 +3395,9 @@ TEST(ResourceFormatTest, DowngradeWithoutResources)
{
FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
EXPECT_SOME(downgradeResources(&frameworkInfo));
- EXPECT_EQ(DEFAULT_FRAMEWORK_INFO, frameworkInfo);
+ EXPECT_EQ(
+ DEFAULT_FRAMEWORK_INFO.SerializeAsString(),
+ frameworkInfo.SerializeAsString());
}
[mesos] 04/04: Added a test of UPDATE_FRAMEWORK with the same
FrameworkInfo.
Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
asekretenko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 2bf7f5d8dcb359845a663a011a941809ffc2366d
Author: Andrei Sekretenko <as...@mesosphere.com>
AuthorDate: Mon Aug 31 20:46:55 2020 +0200
Added a test of UPDATE_FRAMEWORK with the same FrameworkInfo.
This test verifies that calling UPDATE_FRAMEWORK with no changes in
`FrameworkInfo` (i.e. to change suppressed roles or offer constraints)
results in no API event FRAMEWORK_UPDATED sent to the subscribers and
no `UpdatedFrameworkMessage` broadcast to the agents.
Review: https://reviews.apache.org/r/72825
---
src/tests/master/update_framework_tests.cpp | 89 +++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)
diff --git a/src/tests/master/update_framework_tests.cpp b/src/tests/master/update_framework_tests.cpp
index 34e5a70..87bc3c7 100644
--- a/src/tests/master/update_framework_tests.cpp
+++ b/src/tests/master/update_framework_tests.cpp
@@ -437,6 +437,95 @@ TEST_F(UpdateFrameworkTest, MutableFieldsUpdateSuccessfully)
};
+// This test issues two UpdateFrameworkCalls: the first one with the same
+// `FrameworkInfo`, the second with mutated `FrameworkInfo`,
+// and verifies that the first call does NOT result in updates
+// to agents/subscribers.
+TEST_F(UpdateFrameworkTest, NoRedundantUpdates)
+{
+ Try<Owned<cluster::Master>> master = StartMaster(CreateMasterFlags());
+ ASSERT_SOME(master);
+
+ Owned<MasterDetector> detector = master->get()->createDetector();
+
+ // Subscribe to master v1 API.
+ MockMasterAPISubscriber masterAPISubscriber;
+ AWAIT_READY(masterAPISubscriber.subscribe(master.get()->pid));
+
+ Future<Nothing> agentAdded;
+ EXPECT_CALL(masterAPISubscriber, agentAdded(_))
+ .WillOnce(FutureSatisfy(&agentAdded));
+
+ // We need an agent to test the UpdateFrameworkMessage.
+ mesos::internal::slave::Flags slaveFlags = CreateSlaveFlags();
+ Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), slaveFlags);
+ ASSERT_SOME(slave);
+
+ // To test the UpdateFrameworkMessage, we should wait for the agent
+ // to be added before calling UPDATE_FRAMEWORK.
+ AWAIT_READY(agentAdded);
+
+ // Expect a single FRAMEWORK_UPDATED event.
+ Future<v1::master::Event::FrameworkUpdated> frameworkUpdated;
+ EXPECT_CALL(masterAPISubscriber, frameworkUpdated(_))
+ .WillOnce(FutureArg<0>(&frameworkUpdated));
+
+ // Expect UpdateFrameworkMessage to be sent from the master to the agent.
+ Future<UpdateFrameworkMessage> updateFrameworkMessage = FUTURE_PROTOBUF(
+ UpdateFrameworkMessage(), master->get()->pid, slave->get()->pid);
+
+ // Start the scheduler, wait for connection and then subscribe.
+ auto scheduler = std::make_shared<MockHTTPScheduler>();
+
+ Future<Nothing> connected;
+ EXPECT_CALL(*scheduler, connected(_))
+ .WillOnce(SendSubscribe(DEFAULT_FRAMEWORK_INFO));
+
+ EXPECT_CALL(*scheduler, heartbeat(_))
+ .WillRepeatedly(Return()); // Ignore heartbeats.
+
+ Future<Event::Subscribed> subscribed;
+ EXPECT_CALL(*scheduler, subscribed(_, _))
+ .WillOnce(FutureArg<1>(&subscribed));
+
+ TestMesos mesos(master->get()->pid, ContentType::PROTOBUF, scheduler);
+
+ // To send UPDATE_FRAMEWORK, we need to obtain a framework ID.
+ AWAIT_READY(subscribed);
+
+ // Issue an UPDATE_FRAMEWORK that does not touch `FrameworkInfo`.
+ FrameworkInfo update1 = DEFAULT_FRAMEWORK_INFO;
+ *update1.mutable_id() = subscribed->framework_id();
+ Future<APIResult> result1 = callUpdateFramework(&mesos, update1);
+
+ AWAIT_READY(result1);
+ ASSERT_EQ(result1->status_code(), 200u);
+
+ // Verify that the first update has not resulted in broadcasts to
+ // agents/subscribers.
+ Clock::pause();
+ Clock::settle();
+ ASSERT_TRUE(frameworkUpdated.isPending());
+ ASSERT_TRUE(updateFrameworkMessage.isPending());
+
+ // Change `FrameworkInfo` via UPDATE_FRAMEWORK.
+ const FrameworkInfo update2 = changeAllMutableFields(update1);
+ Future<APIResult> result2 = callUpdateFramework(&mesos, update2);
+
+ AWAIT_READY(result2);
+ EXPECT_EQ(result2->status_code(), 200u);
+
+ // Verify that the broadcasts report the second update.
+ AWAIT_READY(updateFrameworkMessage);
+ EXPECT_NONE(::mesos::v1::typeutils::diff(
+ evolve(updateFrameworkMessage->framework_info()), update2));
+
+ AWAIT_READY(frameworkUpdated);
+ EXPECT_NONE(::mesos::v1::typeutils::diff(
+ frameworkUpdated->framework().framework_info(), update2));
+};
+
+
// This tests that adding a role via UPDATE_FRAMEWORK to a framework which had
// no roles triggers allocation of an offer for that role.
TEST_F(UpdateFrameworkTest, OffersOnAddingRole)
[mesos] 03/04: Eliminated redundant update broadcasts in
UPDATE_FRAMEWORK.
Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
asekretenko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 720cc709339efb51a7c464bb3fc547cf0935c911
Author: Andrei Sekretenko <as...@mesosphere.com>
AuthorDate: Mon Aug 31 18:35:16 2020 +0200
Eliminated redundant update broadcasts in UPDATE_FRAMEWORK.
This patch makes the UPDATE_FRAMEWORK call avoid sending the
`UpdatedFrameworkMessage` to agents and the `FRAMEWORK_UPDATED`
event to V1 API subscribers when the FrameworkInfo is not changed
by the call.
Review: https://reviews.apache.org/r/72824
---
src/master/master.cpp | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 0272329..5b5d5c3 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -2844,12 +2844,21 @@ void Master::_subscribe(
std::move(options));
}
+ // TODO(asekretenko): Consider avoiding to broadcast `FrameworkInfo` to agents
+ // when it has not changed. Note that the API event FRAMEWORK_UPDATED needs
+ // to be sent to the subscribers regardless of that, and that agents must
+ // be notified about the scheduler PID removal when this call performs
+ // a V0->V1 upgrade.
sendFrameworkUpdates(*framework);
}
void Master::sendFrameworkUpdates(const Framework& framework)
{
+ LOG(INFO) << "Sending a FRAMEWORK_UPDATED event for framework " << framework
+ << " to all subscribers and broadcasting its up-to-date"
+ << " FrameworkInfo and PID to all registered agents";
+
if (!subscribers.subscribed.empty()) {
subscribers.send(
protobuf::master::event::createFrameworkUpdated(framework));
@@ -3206,6 +3215,9 @@ void Master::_subscribe(
std::move(options));
}
+ // TODO(asekretenko): Consider avoiding to broadcast `FrameworkInfo` and
+ // the V0 framework PID to agents when they have not changed. Note that the
+ // API event FRAMEWORK_UPDATED needs to be sent regardless regardless of that.
sendFrameworkUpdates(*framework);
}
@@ -3254,6 +3266,9 @@ Future<process::http::Response> Master::updateFramework(
"FrameworkInfo update is not valid: " + error->message);
}
+ const bool frameworkInfoChanged =
+ !typeutils::equivalent(framework->info, call.framework_info());
+
allocator::FrameworkOptions allocatorOptions;
if (call.has_offer_constraints()) {
// TODO(asekretenko): Validate roles in offer constraints (see MESOS-10176).
@@ -3294,7 +3309,14 @@ Future<process::http::Response> Master::updateFramework(
updateFramework(
framework, call.framework_info(), std::move(allocatorOptions));
- sendFrameworkUpdates(*framework);
+ if (frameworkInfoChanged) {
+ // NOTE: Among the framework properties that can be changed by this call
+ // (`FrameworkInfo`, suppressed roles and offer constraints),
+ // only the `FrameworkInfo` change needs to be forwarded to the agents
+ // and the API subscribers. This call changes neither the V0 framework PID
+ // nor the framework activeness or state (RECOVERED/CONNECTED/DISCONNECTED).
+ sendFrameworkUpdates(*framework);
+ }
return process::http::OK();
}
[mesos] 01/04: Extracted FrameworkInfo comparison logic from tests.
Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
asekretenko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 9bb35fe23fed7756af9ceebccea74bf175fa6e47
Author: Andrei Sekretenko <as...@mesosphere.com>
AuthorDate: Mon Aug 31 18:34:00 2020 +0200
Extracted FrameworkInfo comparison logic from tests.
This patch extracts the code that performs `FrameworkInfo` comparison
via protobuf `MessageDifferencer` from the framework update tests
into a set of general-purpose methods.
Review: https://reviews.apache.org/r/72822
---
include/mesos/type_utils.hpp | 15 ++++++++
include/mesos/v1/mesos.hpp | 15 ++++++++
src/Makefile.am | 1 +
src/common/type_utils.cpp | 29 ++++++++++++++++
src/common/type_utils_differencers.hpp | 53 ++++++++++++++++++++++++++++
src/tests/master/update_framework_tests.cpp | 54 ++++++++++-------------------
src/v1/mesos.cpp | 30 ++++++++++++++++
7 files changed, 161 insertions(+), 36 deletions(-)
diff --git a/include/mesos/type_utils.hpp b/include/mesos/type_utils.hpp
index da9fd96..2745ff0 100644
--- a/include/mesos/type_utils.hpp
+++ b/include/mesos/type_utils.hpp
@@ -30,6 +30,7 @@
#include <mesos/mesos.hpp>
+#include <stout/option.hpp>
#include <stout/stringify.hpp>
#include <stout/strings.hpp>
#include <stout/uuid.hpp>
@@ -121,6 +122,20 @@ inline bool operator==(const FrameworkInfo& left, const FrameworkInfo& right)
}
+namespace typeutils {
+
+// Returns whether two `FrameworkInfo`s are equivalent for framework
+// subscription purposes or not (i.e. whether subscribing a framework with the
+// `left` should have the same effects as with the `right`).
+bool equivalent(const FrameworkInfo& left, const FrameworkInfo& right);
+
+// Performs the same comparison as `equivalent()` and returns a human-readable
+// diff if the `FrameworkInfo`s are not equivalnt.
+Option<std::string> diff(const FrameworkInfo& left, const FrameworkInfo& right);
+
+} // namespace typeutils {
+
+
inline bool operator==(const OfferID& left, const OfferID& right)
{
return left.value() == right.value();
diff --git a/include/mesos/v1/mesos.hpp b/include/mesos/v1/mesos.hpp
index d8304f1..853330a 100644
--- a/include/mesos/v1/mesos.hpp
+++ b/include/mesos/v1/mesos.hpp
@@ -25,6 +25,7 @@
#include <mesos/v1/mesos.pb.h> // ONLY USEFUL AFTER RUNNING PROTOC.
+#include <stout/option.hpp>
#include <stout/strings.hpp>
// This file includes definitions for operators on public protobuf
@@ -105,6 +106,20 @@ inline bool operator==(const FrameworkInfo& left, const FrameworkInfo& right)
}
+namespace typeutils {
+
+// Returns whether two `FrameworkInfo`s are equivalent for framework
+// subscription purposes or not (i.e. whether subscribing a framework with the
+// `left` should have the same effects as with the `right`).
+bool equivalent(const FrameworkInfo& left, const FrameworkInfo& right);
+
+// Performs the same comparison as `equivalent()` and returns a human-readable
+// diff if the `FrameworkInfo`s are not equivalnt.
+Option<std::string> diff(const FrameworkInfo& left, const FrameworkInfo& right);
+
+} // namespace typeutils {
+
+
inline bool operator==(const OfferID& left, const OfferID& right)
{
return left.value() == right.value();
diff --git a/src/Makefile.am b/src/Makefile.am
index 1043c7b..673ea6c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1091,6 +1091,7 @@ libmesos_no_3rdparty_la_SOURCES += \
common/resources_utils.hpp \
common/roles.cpp \
common/status_utils.hpp \
+ common/type_utils_differencers.hpp \
common/type_utils.cpp \
common/validation.cpp \
common/validation.hpp \
diff --git a/src/common/type_utils.cpp b/src/common/type_utils.cpp
index bb43784..899fd6d 100644
--- a/src/common/type_utils.cpp
+++ b/src/common/type_utils.cpp
@@ -26,10 +26,14 @@
#include <stout/protobuf.hpp>
#include "messages/messages.hpp"
+#include "common/type_utils_differencers.hpp"
using std::ostream;
using std::string;
using std::vector;
+using std::unique_ptr;
+
+using ::mesos::typeutils::internal::createFrameworkInfoDifferencer;
namespace mesos {
@@ -678,6 +682,31 @@ bool operator!=(const CheckStatusInfo& left, const CheckStatusInfo& right)
}
+namespace typeutils {
+
+bool equivalent(const FrameworkInfo& left, const FrameworkInfo& right)
+{
+ return createFrameworkInfoDifferencer<FrameworkInfo>()->Compare(left, right);
+}
+
+
+Option<string> diff(const FrameworkInfo& left, const FrameworkInfo& right)
+{
+ unique_ptr<::google::protobuf::util::MessageDifferencer> differencer{
+ createFrameworkInfoDifferencer<FrameworkInfo>()};
+
+ string result;
+ differencer->ReportDifferencesToString(&result);
+ if (differencer->Compare(left, right)) {
+ return None();
+ }
+
+ return result;
+}
+
+} // namespace typeutils {
+
+
ostream& operator<<(ostream& stream, const CapabilityInfo& capabilityInfo)
{
return stream << JSON::protobuf(capabilityInfo);
diff --git a/src/common/type_utils_differencers.hpp b/src/common/type_utils_differencers.hpp
new file mode 100644
index 0000000..b106014
--- /dev/null
+++ b/src/common/type_utils_differencers.hpp
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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.
+
+#include <memory>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/util/message_differencer.h>
+
+namespace mesos {
+namespace typeutils {
+namespace internal {
+
+// Creates a protobuf `MessageDifferencer` specifically configured for
+// comparing `FrameworkInfo`s (either V0 or V1 ones).
+//
+// TODO(asekretenko): Remove the `unique_ptr` wrapper if `MessageDifferencer`
+// becomes move-constructible in future versions of protobuf.
+template <class TFrameworkInfo>
+std::unique_ptr<::google::protobuf::util::MessageDifferencer>
+createFrameworkInfoDifferencer()
+{
+ static const ::google::protobuf::Descriptor* descriptor =
+ TFrameworkInfo::descriptor();
+
+ CHECK_EQ(13, descriptor->field_count())
+ << "After adding a field to FrameworkInfo, please make sure "
+ << "that FrameworkInfoDifferencer handles this field properly;"
+ << "after that, adjust the expected fields count in this check.";
+
+ std::unique_ptr<::google::protobuf::util::MessageDifferencer> differencer{
+ new ::google::protobuf::util::MessageDifferencer()};
+
+ differencer->TreatAsSet(descriptor->FindFieldByName("capabilities"));
+ differencer->TreatAsSet(descriptor->FindFieldByName("roles"));
+ return differencer;
+}
+
+} // namespace internal {
+} // namespace typeutils {
+} // namespace mesos {
diff --git a/src/tests/master/update_framework_tests.cpp b/src/tests/master/update_framework_tests.cpp
index d2a63b6..34e5a70 100644
--- a/src/tests/master/update_framework_tests.cpp
+++ b/src/tests/master/update_framework_tests.cpp
@@ -19,8 +19,6 @@
#include <gmock/gmock.h>
-#include <google/protobuf/util/message_differencer.h>
-
#include <mesos/executor.hpp>
#include <mesos/v1/mesos.hpp>
@@ -119,28 +117,6 @@ static TFrameworkInfo changeAllMutableFields(const TFrameworkInfo& oldInfo)
return newInfo;
}
-
-template <class TFrameworkInfo>
-static Option<std::string> diff(
- const TFrameworkInfo& lhs, const TFrameworkInfo& rhs)
-{
- const google::protobuf::Descriptor* descriptor = TFrameworkInfo::descriptor();
- google::protobuf::util::MessageDifferencer differencer;
-
- differencer.TreatAsSet(descriptor->FindFieldByName("capabilities"));
- differencer.TreatAsSet(descriptor->FindFieldByName("roles"));
-
- string result;
- differencer.ReportDifferencesToString(&result);
-
- if (differencer.Compare(lhs, rhs)) {
- return None();
- }
-
- return result;
-}
-
-
namespace v1 {
@@ -257,10 +233,11 @@ TEST_F(UpdateFrameworkTest, UserChangeFails)
FrameworkInfo expected = DEFAULT_FRAMEWORK_INFO;
*expected.mutable_id() = subscribed->framework_id();
- EXPECT_NONE(diff(frameworks->frameworks(0).framework_info(), expected));
+ EXPECT_NONE(::mesos::v1::typeutils::diff(
+ frameworks->frameworks(0).framework_info(), expected));
// Sanity check for diff()
- EXPECT_SOME(diff(update, expected));
+ EXPECT_SOME(::mesos::v1::typeutils::diff(update, expected));
}
@@ -307,10 +284,11 @@ TEST_F(UpdateFrameworkTest, PrincipalChangeFails)
FrameworkInfo expected = DEFAULT_FRAMEWORK_INFO;
*expected.mutable_id() = subscribed->framework_id();
- EXPECT_NONE(diff(frameworks->frameworks(0).framework_info(), expected));
+ EXPECT_NONE(::mesos::v1::typeutils::diff(
+ frameworks->frameworks(0).framework_info(), expected));
// Sanity check for diff()
- EXPECT_SOME(diff(update, expected));
+ EXPECT_SOME(::mesos::v1::typeutils::diff(update, expected));
}
@@ -358,10 +336,11 @@ TEST_F(UpdateFrameworkTest, CheckpointingChangeFails)
FrameworkInfo expected = DEFAULT_FRAMEWORK_INFO;
*expected.mutable_id() = subscribed->framework_id();
- EXPECT_NONE(diff(frameworks->frameworks(0).framework_info(), expected));
+ EXPECT_NONE(::mesos::v1::typeutils::diff(
+ frameworks->frameworks(0).framework_info(), expected));
// Sanity check for diff()
- EXPECT_SOME(diff(update, expected));
+ EXPECT_SOME(::mesos::v1::typeutils::diff(update, expected));
}
@@ -446,13 +425,15 @@ TEST_F(UpdateFrameworkTest, MutableFieldsUpdateSuccessfully)
const FrameworkInfo& frameworkInfo =
frameworks->frameworks(0).framework_info();
- EXPECT_NONE(diff(frameworkInfo, update));
+ EXPECT_NONE(::mesos::v1::typeutils::diff(frameworkInfo, update));
AWAIT_READY(updateFrameworkMessage);
- EXPECT_NONE(diff(evolve(updateFrameworkMessage->framework_info()), update));
+ EXPECT_NONE(::mesos::v1::typeutils::diff(
+ evolve(updateFrameworkMessage->framework_info()), update));
AWAIT_READY(frameworkUpdated);
- EXPECT_NONE(diff(frameworkUpdated->framework().framework_info(), update));
+ EXPECT_NONE(::mesos::v1::typeutils::diff(
+ frameworkUpdated->framework().framework_info(), update));
};
@@ -995,10 +976,11 @@ TEST_F(UpdateFrameworkV0Test, MutableFieldsUpdateSuccessfully)
AWAIT_READY(updateFrameworkMessage);
- EXPECT_NONE(diff(updateFrameworkMessage->framework_info(), update));
+ EXPECT_NONE(::mesos::typeutils::diff(
+ updateFrameworkMessage->framework_info(), update));
AWAIT_READY(frameworkUpdated);
- EXPECT_NONE(diff(
+ EXPECT_NONE(::mesos::typeutils::diff(
devolve(frameworkUpdated->framework().framework_info()), update));
Future<v1::master::Response::GetFrameworks> frameworks =
@@ -1008,7 +990,7 @@ TEST_F(UpdateFrameworkV0Test, MutableFieldsUpdateSuccessfully)
const FrameworkInfo& reportedFrameworkInfo =
devolve(frameworks->frameworks(0).framework_info());
- EXPECT_NONE(diff(reportedFrameworkInfo, update));
+ EXPECT_NONE(::mesos::typeutils::diff(reportedFrameworkInfo, update));
driver.stop();
driver.join();
diff --git a/src/v1/mesos.cpp b/src/v1/mesos.cpp
index c2fb528..6e412e0 100644
--- a/src/v1/mesos.cpp
+++ b/src/v1/mesos.cpp
@@ -25,9 +25,14 @@
#include <mesos/v1/mesos.hpp>
#include <mesos/v1/resources.hpp>
+#include "common/type_utils_differencers.hpp"
+
using std::ostream;
using std::string;
using std::vector;
+using std::unique_ptr;
+
+using ::mesos::typeutils::internal::createFrameworkInfoDifferencer;
namespace mesos {
namespace v1 {
@@ -506,6 +511,31 @@ bool operator!=(const TaskStatus& left, const TaskStatus& right)
}
+namespace typeutils {
+
+bool equivalent(const FrameworkInfo& left, const FrameworkInfo& right)
+{
+ return createFrameworkInfoDifferencer<FrameworkInfo>()->Compare(left, right);
+}
+
+
+Option<string> diff(const FrameworkInfo& left, const FrameworkInfo& right)
+{
+ unique_ptr<::google::protobuf::util::MessageDifferencer> differencer{
+ createFrameworkInfoDifferencer<FrameworkInfo>()};
+
+ string result;
+ differencer->ReportDifferencesToString(&result);
+ if (differencer->Compare(left, right)) {
+ return None();
+ }
+
+ return result;
+}
+
+} // namespace typeutils {
+
+
ostream& operator<<(ostream& stream, const CapabilityInfo& capabilityInfo)
{
return stream << JSON::protobuf(capabilityInfo);