OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/sync/notifier/chrome_sync_notification_bridge.h" | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/memory/weak_ptr.h" | |
9 #include "base/message_loop.h" | |
10 #include "base/synchronization/waitable_event.h" | |
11 #include "base/test/test_timeouts.h" | |
12 #include "base/threading/thread.h" | |
13 #include "chrome/browser/sync/syncable/model_type.h" | |
14 #include "chrome/browser/sync/syncable/model_type_payload_map.h" | |
15 #include "chrome/browser/sync/notifier/mock_sync_notifier_observer.h" | |
16 #include "chrome/browser/sync/notifier/sync_notifier_observer.h" | |
17 #include "chrome/common/chrome_notification_types.h" | |
18 #include "chrome/test/base/profile_mock.h" | |
19 #include "content/public/browser/notification_service.h" | |
20 #include "content/public/browser/notification_details.h" | |
21 #include "content/test/test_browser_thread.h" | |
22 #include "testing/gmock/include/gmock/gmock.h" | |
23 #include "testing/gtest/include/gtest/gtest.h" | |
24 | |
25 namespace sync_notifier { | |
26 namespace { | |
27 | |
28 using ::testing::Mock; | |
29 using ::testing::NiceMock; | |
30 using ::testing::StrictMock; | |
31 using content::BrowserThread; | |
32 | |
33 // Receives a ChromeSyncNotificationBridge to register to, and an expected | |
34 // ModelTypePayloadMap. ReceivedProperNotification() will return true only | |
35 // if the observer has received a notification with the proper source and | |
36 // payload. | |
37 // Note: Because this object lives on the IO thread, we use a fake (vs a mock) | |
38 // so we don't have to worry about possible thread safety issues within | |
39 // GTest/GMock. | |
40 class FakeSyncNotifierObserverIO : public SyncNotifierObserver { | |
41 public: | |
42 FakeSyncNotifierObserverIO( | |
43 ChromeSyncNotificationBridge* bridge, | |
44 const syncable::ModelTypePayloadMap& expected_payloads) | |
45 : bridge_(bridge), | |
46 received_improper_notification_(false), | |
47 notification_count_(0), | |
48 expected_payloads_(expected_payloads) { | |
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
50 bridge_->AddObserver(this); | |
51 } | |
52 virtual ~FakeSyncNotifierObserverIO() { | |
53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
54 bridge_->RemoveObserver(this); | |
55 } | |
56 | |
57 // SyncNotifierObserver implementation. | |
58 virtual void OnIncomingNotification( | |
59 const syncable::ModelTypePayloadMap& type_payloads, | |
60 IncomingNotificationSource source) OVERRIDE { | |
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
62 notification_count_++; | |
63 if (source != LOCAL_NOTIFICATION) { | |
64 LOG(ERROR) << "Received notification with wrong source."; | |
65 received_improper_notification_ = true; | |
66 } | |
67 if (expected_payloads_ != type_payloads) { | |
68 LOG(ERROR) << "Received wrong payload."; | |
69 received_improper_notification_ = true; | |
70 } | |
71 } | |
72 virtual void OnNotificationStateChange(bool notifications_enabled) { | |
73 NOTREACHED(); | |
74 } | |
75 virtual void StoreState(const std::string& state) OVERRIDE { | |
76 NOTREACHED(); | |
77 } | |
78 | |
79 bool ReceivedProperNotification() const { | |
80 return (notification_count_ == 1) && !received_improper_notification_; | |
81 } | |
82 | |
83 private: | |
84 ChromeSyncNotificationBridge* bridge_; | |
85 bool received_improper_notification_; | |
86 size_t notification_count_; | |
87 syncable::ModelTypePayloadMap expected_payloads_; | |
88 }; | |
89 | |
90 class ChromeSyncNotificationBridgeTest : public testing::Test { | |
91 public: | |
92 ChromeSyncNotificationBridgeTest() | |
93 : ui_thread_(BrowserThread::UI, &ui_loop_), | |
94 io_thread_(BrowserThread::IO), | |
95 io_observer_(NULL), | |
96 io_observer_notification_failure_(false), | |
97 bridge_(&mock_profile_), | |
98 done_(true, false) { | |
99 io_thread_.StartIOThread(); | |
100 } | |
101 virtual ~ChromeSyncNotificationBridgeTest() {} | |
102 | |
103 protected: | |
104 virtual void TearDown() OVERRIDE { | |
105 io_thread_.Stop(); | |
106 ui_loop_.RunAllPending(); | |
107 EXPECT_EQ(NULL, io_observer_); | |
108 if (io_observer_notification_failure_) | |
109 ADD_FAILURE() << "IO Observer did not receive proper notification."; | |
110 } | |
111 | |
112 void VerifyAndDestroyObserverOnIOThread() { | |
113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
114 if (!io_observer_) { | |
115 io_observer_notification_failure_ = true; | |
116 } else { | |
117 io_observer_notification_failure_ = | |
118 !io_observer_->ReceivedProperNotification(); | |
119 delete io_observer_; | |
120 io_observer_ = NULL; | |
121 } | |
122 } | |
123 | |
124 void VerifyAndDestroyObserver() { | |
125 ASSERT_TRUE(BrowserThread::PostTask( | |
126 BrowserThread::IO, | |
127 FROM_HERE, | |
128 base::Bind(&ChromeSyncNotificationBridgeTest:: | |
129 VerifyAndDestroyObserverOnIOThread, | |
130 base::Unretained(this)))); | |
131 } | |
132 | |
133 void CreateObserverOnIOThread( | |
134 syncable::ModelTypePayloadMap expected_payloads) { | |
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
136 io_observer_ = new FakeSyncNotifierObserverIO(&bridge_, | |
137 expected_payloads); | |
138 } | |
139 | |
140 void CreateObserverWithExpectedPayload( | |
141 syncable::ModelTypePayloadMap expected_payloads) { | |
142 ASSERT_TRUE(BrowserThread::PostTask( | |
143 BrowserThread::IO, | |
144 FROM_HERE, | |
145 base::Bind(&ChromeSyncNotificationBridgeTest::CreateObserverOnIOThread, | |
146 base::Unretained(this), | |
147 expected_payloads))); | |
148 BlockForIOThread(); | |
149 } | |
150 | |
151 void SignalOnIOThread() { | |
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
153 done_.Signal(); | |
154 } | |
155 | |
156 void BlockForIOThread() { | |
157 done_.Reset(); | |
158 BrowserThread::PostTask( | |
159 BrowserThread::IO, | |
160 FROM_HERE, | |
161 base::Bind(&ChromeSyncNotificationBridgeTest::SignalOnIOThread, | |
162 base::Unretained(this))); | |
163 done_.TimedWait(TestTimeouts::action_timeout()); | |
164 if (!done_.IsSignaled()) | |
165 ADD_FAILURE() << "Timed out waiting for IO thread."; | |
166 } | |
167 | |
168 void TriggerRefreshNotification() { | |
169 const syncable::ModelType type = syncable::SESSIONS; | |
170 content::NotificationService::current()->Notify( | |
171 chrome::NOTIFICATION_SYNC_REFRESH, | |
172 content::Source<Profile>(&mock_profile_), | |
173 content::Details<const syncable::ModelType>(&type)); | |
174 } | |
175 | |
176 MessageLoop ui_loop_; | |
177 content::TestBrowserThread ui_thread_; | |
178 content::TestBrowserThread io_thread_; | |
179 NiceMock<ProfileMock> mock_profile_; | |
180 // Created/used/destroyed on I/O thread. | |
181 FakeSyncNotifierObserverIO* io_observer_; | |
182 bool io_observer_notification_failure_; | |
183 ChromeSyncNotificationBridge bridge_; | |
184 base::WaitableEvent done_; | |
185 }; | |
186 | |
187 // Adds an observer on the UI thread, triggers a refresh notification, and | |
188 // ensures the bridge posts a LOCAL_NOTIFICATION with the proper payload to it. | |
189 TEST_F(ChromeSyncNotificationBridgeTest, Basic) { | |
190 syncable::ModelTypePayloadMap payload_map; | |
191 payload_map[syncable::SESSIONS] = ""; | |
192 StrictMock<MockSyncNotifierObserver> observer; | |
193 EXPECT_CALL(observer, | |
194 OnIncomingNotification(payload_map, LOCAL_NOTIFICATION)); | |
195 bridge_.AddObserver(&observer); | |
196 TriggerRefreshNotification(); | |
197 ui_loop_.RunAllPending(); | |
198 Mock::VerifyAndClearExpectations(&observer); | |
199 } | |
200 | |
201 // Adds an observer on the I/O thread. Then triggers a refresh notification on | |
202 // the UI thread. We finally verify the proper notification was received by the | |
203 // observer and destroy it on the I/O thread. | |
204 TEST_F(ChromeSyncNotificationBridgeTest, BasicThreaded) { | |
205 syncable::ModelTypePayloadMap payload_map; | |
206 payload_map[syncable::SESSIONS] = ""; | |
207 CreateObserverWithExpectedPayload(payload_map); | |
208 TriggerRefreshNotification(); | |
209 VerifyAndDestroyObserver(); | |
210 } | |
211 | |
212 } // namespace | |
213 } // namespace sync_notifier | |
OLD | NEW |