blob: 16242983f1f76bc470b83d25e1eddf3a6ff75dff [file] [log] [blame]
Torne (Richard Coles)cedac222014-06-03 10:58:34 +01001// 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#if !defined(__has_feature) || !__has_feature(objc_arc)
6#error "This file requires ARC support."
7#endif
8
9#import "remoting/ios/bridge/client_proxy.h"
10
11#import "base/compiler_specific.h"
12#import "testing/gtest_mac.h"
13
14#import "remoting/ios/data_store.h"
15#import "remoting/ios/bridge/client_proxy_delegate_wrapper.h"
16
17@interface ClientProxyDelegateTester : NSObject<ClientProxyDelegate>
18@property(nonatomic, assign) BOOL isConnected;
19@property(nonatomic, copy) NSString* statusMessage;
20@property(nonatomic, copy) NSString* errorMessage;
21@property(nonatomic, assign) BOOL isPairingSupported;
22@property(nonatomic, assign) webrtc::DesktopSize size;
23@property(nonatomic, assign) NSInteger stride;
24@property(nonatomic, assign) uint8_t* data;
25@property(nonatomic, assign) std::vector<webrtc::DesktopRect> regions;
26@property(nonatomic, assign) webrtc::DesktopVector hotspot;
27@end
28
29@implementation ClientProxyDelegateTester
30
31@synthesize isConnected = _isConnected;
32@synthesize statusMessage = _statusMessage;
33@synthesize errorMessage = _errorMessage;
34@synthesize isPairingSupported = _isPairingSupported;
35@synthesize size = _size;
36@synthesize stride = _stride;
37@synthesize data = _data;
38@synthesize regions = _regions;
39@synthesize hotspot = _hotspot;
40
41- (void)connected {
42 _isConnected = true;
43}
44
45- (void)connectionStatus:(NSString*)statusMessage {
46 _statusMessage = statusMessage;
47}
48
49- (void)connectionFailed:(NSString*)errorMessage {
50 _errorMessage = errorMessage;
51}
52
53- (void)requestHostPin:(BOOL)pairingSupported {
54 _isPairingSupported = pairingSupported;
55}
56
57- (void)applyFrame:(const webrtc::DesktopSize&)size
58 stride:(NSInteger)stride
59 data:(uint8_t*)data
60 regions:(const std::vector<webrtc::DesktopRect>&)regions {
61 _size = size;
62 _stride = stride;
63 _data = data;
64 _regions.assign(regions.begin(), regions.end());
65}
66
67- (void)applyCursor:(const webrtc::DesktopSize&)size
68 hotspot:(const webrtc::DesktopVector&)hotspot
69 cursorData:(uint8_t*)data {
70 _size = size;
71 _hotspot = hotspot;
72 _data = data;
73}
74
75@end
76
77namespace remoting {
78
79namespace {
80
81NSString* kStatusINITIALIZING = @"Initializing connection";
82NSString* kStatusCONNECTING = @"Connecting";
83NSString* kStatusAUTHENTICATED = @"Authenticated";
84NSString* kStatusCONNECTED = @"Connected";
85NSString* kStatusFAILED = @"Connection Failed";
86NSString* kStatusCLOSED = @"Connection closed";
87NSString* kStatusDEFAULT = @"Unknown connection state";
88
89NSString* kErrorPEER_IS_OFFLINE = @"Requested host is offline.";
90NSString* kErrorSESSION_REJECTED = @"Session was rejected by the host.";
91NSString* kErrorINCOMPATIBLE_PROTOCOL = @"Incompatible Protocol.";
92NSString* kErrorAUTHENTICATION_FAILED = @"Authentication Failed.";
93NSString* kErrorCHANNEL_CONNECTION_ERROR = @"Channel Connection Error";
94NSString* kErrorSIGNALING_ERROR = @"Signaling Error";
95NSString* kErrorSIGNALING_TIMEOUT = @"Signaling Timeout";
96NSString* kErrorHOST_OVERLOAD = @"Host Overload";
97NSString* kErrorUNKNOWN_ERROR =
98 @"An unknown error has occurred, preventing the session from opening.";
99NSString* kErrorDEFAULT = @"An unknown error code has occurred.";
100
101const webrtc::DesktopSize kFrameSize(100, 100);
102
103// Note these are disjoint regions. Testing intersecting regions is beyond the
104// scope of this test class.
105const webrtc::DesktopRect kFrameSubRect1 =
106 webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10);
107const webrtc::DesktopRect kFrameSubRect2 =
108 webrtc::DesktopRect::MakeXYWH(11, 11, 10, 10);
109const webrtc::DesktopRect kFrameSubRect3 =
110 webrtc::DesktopRect::MakeXYWH(22, 22, 10, 10);
111
112const int kCursorHeight = 10;
113const int kCursorWidth = 20;
114const int kCursorHotSpotX = 4;
115const int kCursorHotSpotY = 8;
116// |kCursorDataLength| is assumed to be evenly divisible by 4
117const int kCursorDataLength = kCursorHeight * kCursorWidth;
118const uint32_t kCursorDataPattern = 0xF0E1D2C3;
119
120const std::string kHostName = "ClientProxyHostNameTest";
121const std::string kPairingId = "ClientProxyPairingIdTest";
122const std::string kPairingSecret = "ClientProxyPairingSecretTest";
123
124} // namespace
125
126class ClientProxyTest : public ::testing::Test {
127 protected:
128 virtual void SetUp() OVERRIDE {
129 delegateTester_ = [[ClientProxyDelegateTester alloc] init];
130 clientProxy_.reset(new ClientProxy(
131 [ClientProxyDelegateWrapper wrapDelegate:delegateTester_]));
132 }
133
134 void ResetIsConnected() { delegateTester_.isConnected = false; }
135
136 void TestConnnectionStatus(protocol::ConnectionToHost::State state,
137 NSString* expectedStatusMsg) {
138 ResetIsConnected();
139 clientProxy_->ReportConnectionStatus(state, protocol::ErrorCode::OK);
140 EXPECT_NSEQ(expectedStatusMsg, delegateTester_.statusMessage);
141
142 if (state == protocol::ConnectionToHost::State::CONNECTED) {
143 EXPECT_TRUE(delegateTester_.isConnected);
144 } else {
145 EXPECT_FALSE(delegateTester_.isConnected);
146 }
147
148 TestErrorMessages(state, expectedStatusMsg);
149 }
150
151 void TestForError(protocol::ConnectionToHost::State state,
152 protocol::ErrorCode errorCode,
153 NSString* expectedStatusMsg,
154 NSString* expectedErrorMsg) {
155 ResetIsConnected();
156 clientProxy_->ReportConnectionStatus(state, errorCode);
157 EXPECT_FALSE(delegateTester_.isConnected);
158 EXPECT_NSEQ(expectedStatusMsg, delegateTester_.statusMessage);
159 EXPECT_NSEQ(expectedErrorMsg, delegateTester_.errorMessage);
160 }
161
162 void TestErrorMessages(protocol::ConnectionToHost::State state,
163 NSString* expectedStatusMsg) {
164 TestForError(state,
165 protocol::ErrorCode::AUTHENTICATION_FAILED,
166 expectedStatusMsg,
167 kErrorAUTHENTICATION_FAILED);
168 TestForError(state,
169 protocol::ErrorCode::CHANNEL_CONNECTION_ERROR,
170 expectedStatusMsg,
171 kErrorCHANNEL_CONNECTION_ERROR);
172 TestForError(state,
173 protocol::ErrorCode::HOST_OVERLOAD,
174 expectedStatusMsg,
175 kErrorHOST_OVERLOAD);
176 TestForError(state,
177 protocol::ErrorCode::INCOMPATIBLE_PROTOCOL,
178 expectedStatusMsg,
179 kErrorINCOMPATIBLE_PROTOCOL);
180 TestForError(state,
181 protocol::ErrorCode::PEER_IS_OFFLINE,
182 expectedStatusMsg,
183 kErrorPEER_IS_OFFLINE);
184 TestForError(state,
185 protocol::ErrorCode::SESSION_REJECTED,
186 expectedStatusMsg,
187 kErrorSESSION_REJECTED);
188 TestForError(state,
189 protocol::ErrorCode::SIGNALING_ERROR,
190 expectedStatusMsg,
191 kErrorSIGNALING_ERROR);
192 TestForError(state,
193 protocol::ErrorCode::SIGNALING_TIMEOUT,
194 expectedStatusMsg,
195 kErrorSIGNALING_TIMEOUT);
196 TestForError(state,
197 protocol::ErrorCode::UNKNOWN_ERROR,
198 expectedStatusMsg,
199 kErrorUNKNOWN_ERROR);
200 TestForError(state,
201 static_cast<protocol::ErrorCode>(999),
202 expectedStatusMsg,
203 kErrorDEFAULT);
204 }
205
206 void ValidateHost(const std::string& hostName,
207 const std::string& pairingId,
208 const std::string& pairingSecret) {
209 DataStore* store = [DataStore sharedStore];
210 NSString* hostNameAsNSString =
211 [NSString stringWithUTF8String:hostName.c_str()];
212 const HostPreferences* host = [store getHostForId:hostNameAsNSString];
213 if (host != nil) {
214 [store removeHost:host];
215 }
216
217 clientProxy_->CommitPairingCredentials(hostName, pairingId, pairingSecret);
218
219 host = [store getHostForId:hostNameAsNSString];
220
221 ASSERT_TRUE(host != nil);
222 ASSERT_STREQ(hostName.c_str(), [host.hostId UTF8String]);
223 ASSERT_STREQ(pairingId.c_str(), [host.pairId UTF8String]);
224 ASSERT_STREQ(pairingSecret.c_str(), [host.pairSecret UTF8String]);
225 }
226
227 scoped_ptr<ClientProxy> clientProxy_;
228 ClientProxyDelegateTester* delegateTester_;
229 ClientProxyDelegateWrapper* delegateWrapper_;
230};
231
232TEST_F(ClientProxyTest, ReportConnectionStatusINITIALIZING) {
233 TestConnnectionStatus(protocol::ConnectionToHost::State::INITIALIZING,
234 kStatusINITIALIZING);
235}
236
237TEST_F(ClientProxyTest, ReportConnectionStatusCONNECTING) {
238 TestConnnectionStatus(protocol::ConnectionToHost::State::CONNECTING,
239 kStatusCONNECTING);
240}
241
242TEST_F(ClientProxyTest, ReportConnectionStatusAUTHENTICATED) {
243 TestConnnectionStatus(protocol::ConnectionToHost::State::AUTHENTICATED,
244 kStatusAUTHENTICATED);
245}
246
247TEST_F(ClientProxyTest, ReportConnectionStatusCONNECTED) {
248 TestConnnectionStatus(protocol::ConnectionToHost::State::CONNECTED,
249 kStatusCONNECTED);
250}
251
252TEST_F(ClientProxyTest, ReportConnectionStatusFAILED) {
253 TestConnnectionStatus(protocol::ConnectionToHost::State::FAILED,
254 kStatusFAILED);
255}
256
257TEST_F(ClientProxyTest, ReportConnectionStatusCLOSED) {
258 TestConnnectionStatus(protocol::ConnectionToHost::State::CLOSED,
259 kStatusCLOSED);
260}
261
262TEST_F(ClientProxyTest, ReportConnectionStatusDEFAULT) {
263 TestConnnectionStatus(static_cast<protocol::ConnectionToHost::State>(999),
264 kStatusDEFAULT);
265}
266
267TEST_F(ClientProxyTest, DisplayAuthenticationPrompt) {
268 clientProxy_->DisplayAuthenticationPrompt(true);
269 ASSERT_TRUE(delegateTester_.isPairingSupported);
270 clientProxy_->DisplayAuthenticationPrompt(false);
271 ASSERT_FALSE(delegateTester_.isPairingSupported);
272}
273
274TEST_F(ClientProxyTest, CommitPairingCredentialsBasic) {
275 ValidateHost("", "", "");
276}
277
278TEST_F(ClientProxyTest, CommitPairingCredentialsExtended) {
279 ValidateHost(kHostName, kPairingId, kPairingSecret);
280}
281
282TEST_F(ClientProxyTest, RedrawCanvasBasic) {
283
284 webrtc::BasicDesktopFrame frame(webrtc::DesktopSize(1, 1));
285 webrtc::DesktopRegion regions;
286 regions.AddRect(webrtc::DesktopRect::MakeLTRB(0, 0, 1, 1));
287
288 clientProxy_->RedrawCanvas(webrtc::DesktopSize(1, 1), &frame, regions);
289
290 ASSERT_TRUE(webrtc::DesktopSize(1, 1).equals(delegateTester_.size));
291 ASSERT_EQ(4, delegateTester_.stride);
292 ASSERT_TRUE(delegateTester_.data != NULL);
293 ASSERT_EQ(1, delegateTester_.regions.size());
294 ASSERT_TRUE(delegateTester_.regions[0].equals(
295 webrtc::DesktopRect::MakeLTRB(0, 0, 1, 1)));
296}
297TEST_F(ClientProxyTest, RedrawCanvasExtended) {
298
299 webrtc::BasicDesktopFrame frame(kFrameSize);
300 webrtc::DesktopRegion regions;
301 regions.AddRect(kFrameSubRect1);
302 regions.AddRect(kFrameSubRect2);
303 regions.AddRect(kFrameSubRect3);
304
305 clientProxy_->RedrawCanvas(kFrameSize, &frame, regions);
306
307 ASSERT_TRUE(kFrameSize.equals(delegateTester_.size));
308 ASSERT_EQ(kFrameSize.width() * webrtc::DesktopFrame::kBytesPerPixel,
309 delegateTester_.stride);
310 ASSERT_TRUE(delegateTester_.data != NULL);
311 ASSERT_EQ(3, delegateTester_.regions.size());
312 ASSERT_TRUE(delegateTester_.regions[0].equals(kFrameSubRect1));
313 ASSERT_TRUE(delegateTester_.regions[1].equals(kFrameSubRect2));
314 ASSERT_TRUE(delegateTester_.regions[2].equals(kFrameSubRect3));
315}
316
317TEST_F(ClientProxyTest, UpdateCursorBasic) {
318 protocol::CursorShapeInfo cursor_proto;
319 cursor_proto.set_width(1);
320 cursor_proto.set_height(1);
321 cursor_proto.set_hotspot_x(0);
322 cursor_proto.set_hotspot_y(0);
323
324 char data[4];
325 memset(data, 0xFF, 4);
326
327 cursor_proto.set_data(data);
328
329 clientProxy_->UpdateCursorShape(cursor_proto);
330
331 ASSERT_EQ(1, delegateTester_.size.width());
332 ASSERT_EQ(1, delegateTester_.size.height());
333 ASSERT_EQ(0, delegateTester_.hotspot.x());
334 ASSERT_EQ(0, delegateTester_.hotspot.y());
335 ASSERT_TRUE(delegateTester_.data != NULL);
336 for (int i = 0; i < 4; i++) {
337 ASSERT_EQ(0xFF, delegateTester_.data[i]);
338 }
339}
340
341TEST_F(ClientProxyTest, UpdateCursorExtended) {
342 protocol::CursorShapeInfo cursor_proto;
343 cursor_proto.set_width(kCursorWidth);
344 cursor_proto.set_height(kCursorHeight);
345 cursor_proto.set_hotspot_x(kCursorHotSpotX);
346 cursor_proto.set_hotspot_y(kCursorHotSpotY);
347
348 char data[kCursorDataLength];
349 memset_pattern4(data, &kCursorDataPattern, kCursorDataLength);
350
351 cursor_proto.set_data(data);
352
353 clientProxy_->UpdateCursorShape(cursor_proto);
354
355 ASSERT_EQ(kCursorWidth, delegateTester_.size.width());
356 ASSERT_EQ(kCursorHeight, delegateTester_.size.height());
357 ASSERT_EQ(kCursorHotSpotX, delegateTester_.hotspot.x());
358 ASSERT_EQ(kCursorHotSpotY, delegateTester_.hotspot.y());
359 ASSERT_TRUE(delegateTester_.data != NULL);
360 for (int i = 0; i < kCursorDataLength / 4; i++) {
361 ASSERT_TRUE(memcmp(&delegateTester_.data[i * 4], &kCursorDataPattern, 4) ==
362 0);
363 }
364}
365
366} // namespace remoting