Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1860)

Unified Diff: remoting/host/mock_callback.h

Issue 719983002: Reporting of policy errors via host-offline-reason: part 3 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@hor-nohoststatussender
Patch Set: git cl format Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « remoting/host/minimum_heartbeat_supporter.cc ('k') | remoting/host/mock_callback_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/host/mock_callback.h
diff --git a/remoting/host/mock_callback.h b/remoting/host/mock_callback.h
index ca3feb6d06a415f1853b363e7b089f8b0a03ad7a..8f6bedfa44f06ef5b4e86dc0ba1e3ab6516556b8 100644
--- a/remoting/host/mock_callback.h
+++ b/remoting/host/mock_callback.h
@@ -10,11 +10,69 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace remoting {
+// MockCallback<Sig> can be used to mock Callback<Sig> from base/callback.h
+//
+// Basic usage example:
+//
+// MockCallback<void(int)> mock_callback;
+// EXPECT_CALL(mock_callback, Run(123)).Times(2);
+// base::Callback<void(int)> callback = mock_callback.GetCallback();
Wez 2014/12/03 19:45:49 Is it important that GetCallback() is only called
Łukasz Anforowicz 2014/12/03 22:00:44 Sort of. EXPECT_CALL is not thread-safe wrt Callb
+//
+// // Use |callback| in the remainder of the test.
+// // GMock will enforce the expectations from above.
+//
+// HasRemainingCallbacks usage example:
Wez 2014/12/03 19:45:49 HasRemainingCallbacks has not been introduced yet,
Łukasz Anforowicz 2014/12/03 22:00:44 Good point. I am not sure about this - Some tests
+//
+// MockCallback<int()> mock_callback;
+// EXPECT_CALL(mock_callback, Run()).WillOnce(Return(123));
+// HypotheticalFunctionUnderTest(mock_callback.GetCallback());
+// EXPECT_FALSE(mock_callback.HasRemainingCallbacks())
+// << "Verify that FunctionUnderTest didn't store the callback "
+// << "and therefore callers of FunctionUnderTest don't have to "
+// << "worry about lifetime of arguments bound to the callback";
Wez 2014/12/03 19:45:49 You need to be very clear on the threading semanti
Łukasz Anforowicz 2014/12/03 22:00:44 I don't understand: - HasRemainingCallbacks is thr
+//
+// Thread safety notes:
+//
+// Calling Run on a Callback returned from MockCallback::GetCallback
+// - Is *not* thread-safe wrt setting default actions and expectations (via
+// ON_CALL and EXPECT_CALL gMock macros).
Wez 2014/12/03 19:45:49 This is not very clear; you mean that the call exp
Łukasz Anforowicz 2014/12/03 22:00:44 One cannot call EXPECT_CALL and Run in parallel.
+// - Is thread-safe wrt other Run calls and destroying MockCallback.
Wez 2014/12/03 19:45:49 What are the semantics if a callback still exists
Łukasz Anforowicz 2014/12/03 22:00:44 This is documented in "What happens when Callback:
+//
+// This is similar to the guarantees described at
+// https://code.google.com/p/googlemock/wiki/CookBook#Using_Google_Mock_and_Threads
+// except that the guarantees hold on all platforms.
+//
+// What happens when Callback::Run is called after MockCallback is destroyed:
Wez 2014/12/03 19:45:49 This contradicts the GetCallback comment, though.
Łukasz Anforowicz 2014/12/03 22:00:44 Acknowledged.
+//
+// - gTest EXPECT failure will be triggered
+// - gMock's default return value will be returned - see:
+// https://code.google.com/p/googlemock/wiki/CookBook#Setting_the_Default_Value_for_a_Return_Type
+
+// Implementation notes:
+//
+// WeakPtr-like code
+// -----------------
+//
+// Relationship between MockCallback and MockCallbackTracker is similar
+// to the relationship between WeakPtrFactory<T> and WeakPtr<T>. We don't
+// use WeakPtrFactory<T> and WeakPtr<T>, because:
Wez 2014/12/03 19:45:49 This comment is very confusing; it's not clear wha
+// - WeakPtrs can only bind to methods without return values
+// (enforced by a static assert in bind_internal.h:402).
+// - WeakPtr impose task-specific, thread-safety-restrictions that are
+// not present in Callback that MockCallback is mocking.
+// - For MockCallback we don't necessarily want the behavior where Callbacks
+// bound to WeakPtr are translated into no-ops, before the bound function
+// gets to execute. In MockCallback case we want the test to have control of
+// what happens in this case (i.e. gtest EXPECT, rather than a no-op;
+// note that we cannot use gtest ASSERT for non-void-returning Run method).
+
template <typename Sig>
class MockCallback;
@@ -23,16 +81,114 @@ class MockCallback<R()> {
public:
MOCK_CONST_METHOD0_T(Run, R());
- MockCallback() {
+ MockCallback() : mock_callback_tracker_(new MockCallbackTracker(this)) {}
+
+ ~MockCallback() { mock_callback_tracker_->MarkMockCallbackAsDead(); }
+
+ // Caller of GetCallback has to guarantee that the returned callback
+ // will not be run after |this| is destroyed.
+ base::Callback<R()> GetCallback() const {
+ return base::Bind(&MockCallbackTracker::Run, mock_callback_tracker_);
+ }
+
+ // Returns |true| if callbacks returned by |GetCallback| have not been
+ // destroyed yet.
+ bool HasRemainingCallbacks() const {
+ bool is_tracker_field_the_only_ref = mock_callback_tracker_->HasOneRef();
+ return !is_tracker_field_the_only_ref;
}
+ private:
+ class MockCallbackTracker
+ : public base::RefCountedThreadSafe<MockCallbackTracker> {
+ public:
+ MockCallbackTracker(MockCallback* mock_callback)
+ : mock_callback_(mock_callback), is_mock_callback_alive_(true) {}
+
+ R Run() {
+ base::AutoLock auto_lock(lock_);
+ EXPECT_TRUE(is_mock_callback_alive_)
+ << "MockCallback should be alive when Callback::Run happens.";
+ return is_mock_callback_alive_ ? mock_callback_->Run()
+ : testing::DefaultValue<R>::Get();
+ }
+
+ void MarkMockCallbackAsDead() {
+ base::AutoLock auto_lock(lock_);
+ is_mock_callback_alive_ = false;
+ mock_callback_ = nullptr;
+ }
+
+ private:
+ // Ref-counting helpers.
+ friend class base::RefCountedThreadSafe<MockCallbackTracker>;
+ ~MockCallbackTracker() {}
+
+ MockCallback<R()>* mock_callback_;
+ base::Lock lock_;
+ bool is_mock_callback_alive_;
+ };
+
+ scoped_refptr<MockCallbackTracker> mock_callback_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockCallback);
+};
+
+template <typename R, typename A1>
+class MockCallback<R(A1)> {
+ public:
+ MOCK_CONST_METHOD1_T(Run, R(A1));
+
+ MockCallback() : mock_callback_tracker_(new MockCallbackTracker(this)) {}
+
+ ~MockCallback() { mock_callback_tracker_->MarkMockCallbackAsDead(); }
+
// Caller of GetCallback has to guarantee that the returned callback
// will not be run after |this| is destroyed.
- base::Callback<R()> GetCallback() {
- return base::Bind(&MockCallback<R()>::Run, base::Unretained(this));
+ base::Callback<R(A1)> GetCallback() const {
+ return base::Bind(&MockCallbackTracker::Run, mock_callback_tracker_);
+ }
+
+ // Returns |true| if callbacks returned by |GetCallback| have not been
+ // destroyed yet.
+ bool HasRemainingCallbacks() const {
+ bool is_tracker_field_the_only_ref = mock_callback_tracker_->HasOneRef();
+ return !is_tracker_field_the_only_ref;
}
private:
+ class MockCallbackTracker
+ : public base::RefCountedThreadSafe<MockCallbackTracker> {
+ public:
+ MockCallbackTracker(MockCallback* mock_callback)
+ : mock_callback_(mock_callback), is_mock_callback_alive_(true) {}
+
+ R Run(A1 a1) {
+ base::AutoLock auto_lock(lock_);
+ EXPECT_TRUE(is_mock_callback_alive_)
+ << "MockCallback should be alive when Callback::Run happens.";
+ return is_mock_callback_alive_ ? mock_callback_->Run(a1)
+ : testing::DefaultValue<R>::Get();
+ }
+
+ void MarkMockCallbackAsDead() {
+ base::AutoLock auto_lock(lock_);
+ is_mock_callback_alive_ = false;
+ mock_callback_ = nullptr;
+ }
+
+ private:
+ // Ref-counting helpers.
+ friend class base::RefCountedThreadSafe<MockCallbackTracker>;
+ ~MockCallbackTracker() {}
+
+ MockCallback<R(A1)>* mock_callback_;
+ base::Lock lock_;
+ bool is_mock_callback_alive_;
+ };
+
+ scoped_refptr<MockCallbackTracker> mock_callback_tracker_;
+
DISALLOW_COPY_AND_ASSIGN(MockCallback);
};
« no previous file with comments | « remoting/host/minimum_heartbeat_supporter.cc ('k') | remoting/host/mock_callback_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698