OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "remoting/ios/bridge/client_instance.h" | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/run_loop.h" | |
9 #include "base/mac/scoped_nsobject.h" | |
10 #include "base/synchronization/waitable_event.h" | |
11 #include "remoting/protocol/libjingle_transport_factory.h" | |
12 #import "testing/gtest_mac.h" | |
13 | |
14 #include "remoting/ios/data_store.h" | |
15 #include "remoting/ios/bridge/client_proxy.h" | |
16 #include "remoting/ios/bridge/client_proxy_delegate_wrapper.h" | |
17 | |
18 @interface ClientProxyDelegateForClientInstanceTester | |
19 : NSObject<ClientProxyDelegate> | |
20 | |
21 - (void)resetDidReceiveSomething; | |
22 | |
23 // Validating what was received is outside of the scope for this test unit. See | |
24 // ClientProxyUnittest for those tests. | |
25 @property(nonatomic, assign) BOOL didReceiveSomething; | |
26 | |
27 @end | |
28 | |
29 @implementation ClientProxyDelegateForClientInstanceTester | |
30 | |
31 @synthesize didReceiveSomething = _didReceiveSomething; | |
32 | |
33 - (void)resetDidReceiveSomething { | |
34 _didReceiveSomething = false; | |
35 } | |
36 | |
37 - (void)requestHostPin:(BOOL)pairingSupported { | |
38 _didReceiveSomething = true; | |
39 } | |
40 | |
41 - (void)connected { | |
42 _didReceiveSomething = true; | |
43 } | |
44 | |
45 - (void)connectionStatus:(NSString*)statusMessage { | |
46 _didReceiveSomething = true; | |
47 } | |
48 | |
49 - (void)connectionFailed:(NSString*)errorMessage { | |
50 _didReceiveSomething = true; | |
51 } | |
52 | |
53 - (void)applyFrame:(const webrtc::DesktopSize&)size | |
54 stride:(NSInteger)stride | |
55 data:(uint8_t*)data | |
56 regions:(const std::vector<webrtc::DesktopRect>&)regions { | |
57 _didReceiveSomething = true; | |
58 } | |
59 | |
60 - (void)applyCursor:(const webrtc::DesktopSize&)size | |
61 hotspot:(const webrtc::DesktopVector&)hotspot | |
62 cursorData:(uint8_t*)data { | |
63 _didReceiveSomething = true; | |
64 } | |
65 | |
66 @end | |
67 | |
68 namespace remoting { | |
69 | |
70 namespace { | |
71 | |
72 const std::string kHostId = "HostIdTest"; | |
73 const std::string kPairingId = "PairingIdTest"; | |
74 const std::string kPairingSecret = "PairingSecretTest"; | |
75 const std::string kSecretPin = "SecretPinTest"; | |
76 | |
77 // TODO(aboone) should be able to call RunLoop().RunUntilIdle() instead but | |
78 // MessagePumpUIApplication::DoRun is marked NOTREACHED() | |
79 void RunCFMessageLoop() { | |
80 int result; | |
81 do { // Repeat until no messages remain | |
82 result = CFRunLoopRunInMode( | |
83 kCFRunLoopDefaultMode, | |
84 0, // Execute queued messages, do not wait for additional messages | |
85 YES); // Do only one message at a time | |
86 } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished && | |
87 result != kCFRunLoopRunTimedOut); | |
88 } | |
89 | |
90 void SecretPinCallBack(const std::string& secret) { | |
91 ASSERT_STREQ(kSecretPin.c_str(), secret.c_str()); | |
92 } | |
93 | |
94 } // namespace | |
95 | |
96 class ClientInstanceTest : public ::testing::Test { | |
97 protected: | |
98 virtual void SetUp() OVERRIDE { | |
99 testDelegate_.reset( | |
100 [[ClientProxyDelegateForClientInstanceTester alloc] init]); | |
101 proxy_.reset(new ClientProxy( | |
102 [ClientProxyDelegateWrapper wrapDelegate:testDelegate_])); | |
103 instance_ = | |
104 new ClientInstance(proxy_->AsWeakPtr(), "", "", "", "", "", "", ""); | |
105 } | |
106 virtual void TearDown() OVERRIDE { | |
107 // Ensure memory is not leaking | |
108 // Notice Cleanup is safe to call, regardless of if Start() was ever called. | |
109 instance_->Cleanup(); | |
110 RunCFMessageLoop(); | |
111 // An object on the network thread which owns a reference to |instance_| may | |
112 // be cleaned up 'soon', but not immediately. Lets wait it out, up to 1 | |
113 // second. | |
114 for (int i = 0; i < 100; i++) { | |
115 if (!instance_->HasOneRef()) { | |
116 [NSThread sleepForTimeInterval:.01]; | |
117 } else { | |
118 break; | |
119 } | |
120 } | |
121 | |
122 // Remove the last reference from |instance_|, and destructor is called. | |
123 ASSERT_TRUE(instance_->HasOneRef()); | |
124 instance_ = NULL; | |
125 } | |
126 | |
127 void AssertAcknowledged(BOOL wasAcknowledged) { | |
128 ASSERT_EQ(wasAcknowledged, [testDelegate_ didReceiveSomething]); | |
129 // Reset for the next test | |
130 [testDelegate_ resetDidReceiveSomething]; | |
131 } | |
132 | |
133 void TestStatusAndError(protocol::ConnectionToHost::State state, | |
134 protocol::ErrorCode error) { | |
135 instance_->OnConnectionState(state, error); | |
136 AssertAcknowledged(true); | |
137 } | |
138 | |
139 void TestConnectionStatus(protocol::ConnectionToHost::State state) { | |
140 TestStatusAndError(state, protocol::ErrorCode::OK); | |
141 TestStatusAndError(state, protocol::ErrorCode::PEER_IS_OFFLINE); | |
142 TestStatusAndError(state, protocol::ErrorCode::SESSION_REJECTED); | |
143 TestStatusAndError(state, protocol::ErrorCode::INCOMPATIBLE_PROTOCOL); | |
144 TestStatusAndError(state, protocol::ErrorCode::AUTHENTICATION_FAILED); | |
145 TestStatusAndError(state, protocol::ErrorCode::CHANNEL_CONNECTION_ERROR); | |
146 TestStatusAndError(state, protocol::ErrorCode::SIGNALING_ERROR); | |
147 TestStatusAndError(state, protocol::ErrorCode::SIGNALING_TIMEOUT); | |
148 TestStatusAndError(state, protocol::ErrorCode::HOST_OVERLOAD); | |
149 TestStatusAndError(state, protocol::ErrorCode::UNKNOWN_ERROR); | |
150 } | |
151 | |
152 base::scoped_nsobject<ClientProxyDelegateForClientInstanceTester> | |
153 testDelegate_; | |
154 scoped_ptr<ClientProxy> proxy_; | |
155 scoped_refptr<ClientInstance> instance_; | |
156 }; | |
157 | |
158 TEST_F(ClientInstanceTest, Create) { | |
159 // This is a test for memory leaking. Ensure a completely unused instance of | |
160 // ClientInstance is destructed. | |
161 | |
162 ASSERT_TRUE(instance_ != NULL); | |
163 ASSERT_TRUE(instance_->HasOneRef()); | |
164 } | |
165 | |
166 TEST_F(ClientInstanceTest, CreateAndStart) { | |
167 // This is a test for memory leaking. Ensure a properly used instance of | |
168 // ClientInstance is destructed. | |
169 | |
170 ASSERT_TRUE(instance_ != NULL); | |
171 ASSERT_TRUE(instance_->HasOneRef()); | |
172 | |
173 instance_->Start(); | |
174 RunCFMessageLoop(); | |
175 ASSERT_TRUE(!instance_->HasOneRef()); // more than one | |
176 } | |
177 | |
178 TEST_F(ClientInstanceTest, SecretPin) { | |
179 NSString* hostId = [NSString stringWithUTF8String:kHostId.c_str()]; | |
180 NSString* pairingId = [NSString stringWithUTF8String:kPairingId.c_str()]; | |
181 NSString* pairingSecret = | |
182 [NSString stringWithUTF8String:kPairingSecret.c_str()]; | |
183 | |
184 DataStore* store = [DataStore sharedStore]; | |
185 | |
186 const HostPreferences* host = [store createHost:hostId]; | |
187 host.pairId = pairingId; | |
188 host.pairSecret = pairingSecret; | |
189 [store saveChanges]; | |
190 | |
191 // Suggesting that our pairing Id is known, but since its obviously not we | |
192 // expect it to be discarded when requesting the PIN. | |
193 instance_ = new ClientInstance( | |
194 proxy_->AsWeakPtr(), "", "", "", kHostId, "", kPairingId, kPairingSecret); | |
195 | |
196 instance_->Start(); | |
197 RunCFMessageLoop(); | |
198 | |
199 instance_->FetchSecret(false, base::Bind(&SecretPinCallBack)); | |
200 RunCFMessageLoop(); | |
201 AssertAcknowledged(true); | |
202 | |
203 // The pairing information was discarded | |
204 host = [store getHostForId:hostId]; | |
205 ASSERT_NSEQ(@"", host.pairId); | |
206 ASSERT_NSEQ(@"", host.pairSecret); | |
207 | |
208 instance_->ProvideSecret(kSecretPin, false); | |
209 RunCFMessageLoop(); | |
210 } | |
211 | |
212 TEST_F(ClientInstanceTest, NoProxy) { | |
213 // After the proxy is released, we still expect quite a few functions to be | |
214 // able to run, but not produce any output. Some of these are just being | |
215 // executed for code coverage, the outputs are not pertinent to this test | |
216 // unit. | |
217 proxy_.reset(); | |
218 | |
219 instance_->Start(); | |
220 RunCFMessageLoop(); | |
221 | |
222 instance_->FetchSecret(false, base::Bind(&SecretPinCallBack)); | |
223 AssertAcknowledged(false); | |
224 | |
225 instance_->ProvideSecret(kSecretPin, false); | |
226 AssertAcknowledged(false); | |
227 | |
228 instance_->PerformMouseAction( | |
229 webrtc::DesktopVector(0, 0), webrtc::DesktopVector(0, 0), 0, false); | |
230 AssertAcknowledged(false); | |
231 | |
232 instance_->PerformKeyboardAction(0, false); | |
233 AssertAcknowledged(false); | |
234 | |
235 instance_->OnConnectionState(protocol::ConnectionToHost::State::CONNECTED, | |
236 protocol::ErrorCode::OK); | |
237 AssertAcknowledged(false); | |
238 | |
239 instance_->OnConnectionReady(false); | |
240 AssertAcknowledged(false); | |
241 | |
242 instance_->OnRouteChanged("", protocol::TransportRoute()); | |
243 AssertAcknowledged(false); | |
244 | |
245 // SetCapabilities requires a host connection to be established | |
246 // instance_->SetCapabilities(""); | |
247 // AssertAcknowledged(false); | |
248 | |
249 instance_->SetPairingResponse(protocol::PairingResponse()); | |
250 AssertAcknowledged(false); | |
251 | |
252 instance_->DeliverHostMessage(protocol::ExtensionMessage()); | |
253 AssertAcknowledged(false); | |
254 | |
255 ASSERT_TRUE(instance_->GetClipboardStub() != NULL); | |
256 ASSERT_TRUE(instance_->GetCursorShapeStub() != NULL); | |
257 ASSERT_TRUE(instance_->GetTokenFetcher("") == NULL); | |
258 | |
259 instance_->InjectClipboardEvent(protocol::ClipboardEvent()); | |
260 AssertAcknowledged(false); | |
261 | |
262 instance_->SetCursorShape(protocol::CursorShapeInfo()); | |
263 AssertAcknowledged(false); | |
264 } | |
265 | |
266 TEST_F(ClientInstanceTest, OnConnectionStateINITIALIZING) { | |
267 TestConnectionStatus(protocol::ConnectionToHost::State::INITIALIZING); | |
268 } | |
269 | |
270 TEST_F(ClientInstanceTest, OnConnectionStateCONNECTING) { | |
271 TestConnectionStatus(protocol::ConnectionToHost::State::CONNECTING); | |
272 } | |
273 | |
274 TEST_F(ClientInstanceTest, OnConnectionStateAUTHENTICATED) { | |
275 TestConnectionStatus(protocol::ConnectionToHost::State::AUTHENTICATED); | |
276 } | |
277 | |
278 TEST_F(ClientInstanceTest, OnConnectionStateCONNECTED) { | |
279 TestConnectionStatus(protocol::ConnectionToHost::State::CONNECTED); | |
280 } | |
281 | |
282 TEST_F(ClientInstanceTest, OnConnectionStateFAILED) { | |
283 TestConnectionStatus(protocol::ConnectionToHost::State::FAILED); | |
284 } | |
285 | |
286 TEST_F(ClientInstanceTest, OnConnectionStateCLOSED) { | |
287 TestConnectionStatus(protocol::ConnectionToHost::State::CLOSED); | |
288 } | |
289 | |
290 TEST_F(ClientInstanceTest, OnConnectionReady) { | |
291 instance_->OnConnectionReady(true); | |
292 AssertAcknowledged(false); | |
293 instance_->OnConnectionReady(false); | |
294 AssertAcknowledged(false); | |
295 } | |
296 | |
297 TEST_F(ClientInstanceTest, OnRouteChanged) { | |
298 // Not expecting anything to happen | |
299 protocol::TransportRoute route; | |
300 | |
301 route.type = protocol::TransportRoute::DIRECT; | |
302 instance_->OnRouteChanged("", route); | |
303 AssertAcknowledged(false); | |
304 | |
305 route.type = protocol::TransportRoute::STUN; | |
306 instance_->OnRouteChanged("", route); | |
307 AssertAcknowledged(false); | |
308 | |
309 route.type = protocol::TransportRoute::RELAY; | |
310 instance_->OnRouteChanged("", route); | |
311 AssertAcknowledged(false); | |
312 } | |
313 | |
314 TEST_F(ClientInstanceTest, SetCursorShape) { | |
315 instance_->SetCursorShape(protocol::CursorShapeInfo()); | |
316 AssertAcknowledged(true); | |
317 } | |
318 | |
319 } // namespace remoting | |
OLD | NEW |