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