tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 1 | // Copyright 2015 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 | |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 5 | #include "base/bind.h" |
tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 6 | #include "base/command_line.h" |
joedow | 910989d | 2016-12-02 21:15:32 | [diff] [blame] | 7 | #include "base/feature_list.h" |
tonychun | 8815bf7 | 2015-06-25 23:29:37 | [diff] [blame] | 8 | #include "base/files/file_path.h" |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 9 | #include "base/logging.h" |
| 10 | #include "base/message_loop/message_loop.h" |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 11 | #include "base/strings/stringprintf.h" |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 12 | #include "base/test/launcher/unit_test_launcher.h" |
tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 13 | #include "base/test/test_suite.h" |
| 14 | #include "base/test/test_switches.h" |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 15 | #include "google_apis/google_api_keys.h" |
| 16 | #include "net/base/escape.h" |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 17 | #include "remoting/test/chromoting_test_driver_environment.h" |
tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 18 | #include "testing/gtest/include/gtest/gtest.h" |
| 19 | |
| 20 | namespace switches { |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 21 | const char kAuthCodeSwitchName[] = "authcode"; |
| 22 | const char kHelpSwitchName[] = "help"; |
| 23 | const char kHostNameSwitchName[] = "hostname"; |
anandc | 44945a9 | 2015-12-11 00:10:01 | [diff] [blame] | 24 | const char kHostJidSwitchName[] = "hostjid"; |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 25 | const char kLoggingLevelSwitchName[] = "verbosity"; |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 26 | const char kPinSwitchName[] = "pin"; |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 27 | const char kRefreshTokenPathSwitchName[] = "refresh-token-path"; |
tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 28 | const char kSingleProcessTestsSwitchName[] = "single-process-tests"; |
joedow | 910989d | 2016-12-02 21:15:32 | [diff] [blame] | 29 | const char kTestEnvironmentSwitchName[] = "use-test-env"; |
tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 30 | const char kUserNameSwitchName[] = "username"; |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 31 | } |
| 32 | |
| 33 | namespace { |
| 34 | const char kChromotingAuthScopeValues[] = |
| 35 | "https://www.googleapis.com/auth/chromoting " |
| 36 | "https://www.googleapis.com/auth/googletalk " |
| 37 | "https://www.googleapis.com/auth/userinfo.email"; |
| 38 | |
| 39 | std::string GetAuthorizationCodeUri() { |
| 40 | // Replace space characters with a '+' sign when formatting. |
| 41 | bool use_plus = true; |
| 42 | return base::StringPrintf( |
| 43 | "https://accounts.google.com/o/oauth2/auth" |
| 44 | "?scope=%s" |
| 45 | "&redirect_uri=https://chromoting-oauth.talkgadget.google.com/" |
| 46 | "talkgadget/oauth/chrome-remote-desktop/dev" |
| 47 | "&response_type=code" |
| 48 | "&client_id=%s" |
| 49 | "&access_type=offline" |
| 50 | "&approval_prompt=force", |
| 51 | net::EscapeUrlEncodedData(kChromotingAuthScopeValues, use_plus).c_str(), |
| 52 | net::EscapeUrlEncodedData( |
| 53 | google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING), |
| 54 | use_plus).c_str()); |
| 55 | } |
| 56 | |
| 57 | void PrintUsage() { |
| 58 | printf("\n************************************\n"); |
| 59 | printf("*** Chromoting Test Driver Usage ***\n"); |
| 60 | printf("************************************\n"); |
| 61 | |
| 62 | printf("\nUsage:\n"); |
tonychun | e3fe984 | 2015-07-10 18:45:30 | [diff] [blame] | 63 | printf(" chromoting_test_driver --username=<[email protected]> [options]" |
| 64 | " --hostname=<example hostname>\n"); |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 65 | printf("\nRequired Parameters:\n"); |
| 66 | printf(" %s: Specifies which account to use when running tests\n", |
| 67 | switches::kUserNameSwitchName); |
tonychun | e3fe984 | 2015-07-10 18:45:30 | [diff] [blame] | 68 | printf(" %s: Specifies which host to connect to when running tests\n", |
| 69 | switches::kHostNameSwitchName); |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 70 | printf("\nOptional Parameters:\n"); |
| 71 | printf(" %s: Exchanged for a refresh and access token for authentication\n", |
| 72 | switches::kAuthCodeSwitchName); |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 73 | printf(" %s: Displays additional usage information\n", |
| 74 | switches::kHelpSwitchName); |
tonychun | e3fe984 | 2015-07-10 18:45:30 | [diff] [blame] | 75 | printf(" %s: Path to a JSON file containing username/refresh_token KVPs\n", |
| 76 | switches::kRefreshTokenPathSwitchName); |
| 77 | printf(" %s: Specifies the optional logging level of the tool (0-3)." |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 78 | " [default: off]\n", switches::kLoggingLevelSwitchName); |
joedow | 910989d | 2016-12-02 21:15:32 | [diff] [blame] | 79 | printf( |
| 80 | " %s: Specifies that the test environment APIs should be used." |
| 81 | " [default: false]\n", |
| 82 | switches::kTestEnvironmentSwitchName); |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | void PrintAuthCodeInfo() { |
| 86 | printf("\n*******************************\n"); |
| 87 | printf("*** Auth Code Example Usage ***\n"); |
| 88 | printf("*******************************\n\n"); |
| 89 | |
| 90 | printf("If this is the first time you are running the tool,\n"); |
| 91 | printf("you will need to provide an authorization code.\n"); |
| 92 | printf("This code will be exchanged for a long term refresh token which\n"); |
| 93 | printf("will be stored locally and used to acquire a short lived access\n"); |
| 94 | printf("token to connect to the remoting service apis and establish a\n"); |
| 95 | printf("remote host connection.\n\n"); |
| 96 | |
| 97 | printf("Note: You may need to repeat this step if the stored refresh token"); |
| 98 | printf("\n has been revoked or expired.\n"); |
| 99 | printf(" Passing in the same auth code twice will result in an error\n"); |
| 100 | |
tonychun | e3fe984 | 2015-07-10 18:45:30 | [diff] [blame] | 101 | printf("\nFollow these steps to produce an auth code:\n" |
| 102 | " - Open the Authorization URL link shown below in your browser\n" |
| 103 | " - Approve the requested permissions for the tool\n" |
| 104 | " - Copy the 'code' value in the redirected URL\n" |
| 105 | " - Run the tool and pass in copied auth code as a parameter\n"); |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 106 | |
| 107 | printf("\nAuthorization URL:\n"); |
| 108 | printf("%s\n", GetAuthorizationCodeUri().c_str()); |
| 109 | |
| 110 | printf("\nRedirected URL Example:\n"); |
tonychun | e3fe984 | 2015-07-10 18:45:30 | [diff] [blame] | 111 | printf("https://chromoting-oauth.talkgadget.google.com/talkgadget/oauth/" |
| 112 | "chrome-remote-desktop/dev?code=4/AKtf...\n"); |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 113 | |
| 114 | printf("\nTool usage example with the newly created auth code:\n"); |
tonychun | e3fe984 | 2015-07-10 18:45:30 | [diff] [blame] | 115 | printf("chromoting_test_driver --%[email protected] --%s=example_host_name" |
| 116 | " --%s=4/AKtf...\n\n", |
| 117 | switches::kUserNameSwitchName, |
| 118 | switches::kHostNameSwitchName, |
| 119 | switches::kAuthCodeSwitchName); |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 120 | } |
| 121 | |
| 122 | void PrintJsonFileInfo() { |
| 123 | printf("\n****************************************\n"); |
| 124 | printf("*** Refresh Token File Example Usage ***\n"); |
| 125 | printf("****************************************\n\n"); |
| 126 | |
| 127 | printf("In order to use this option, a valid JSON file must exist, be\n"); |
| 128 | printf("properly formatted, and contain a username/token KVP.\n"); |
| 129 | printf("Contents of example_file.json\n"); |
| 130 | printf("{\n"); |
| 131 | printf(" \"[email protected]\": \"1/3798Gsdf898shksdvfyi8sshad\",\n"); |
| 132 | printf(" \"[email protected]\": \"1/8974sdf87asdgadfgaerhfRsAa\",\n"); |
| 133 | printf("}\n\n"); |
| 134 | |
| 135 | printf("\nTool usage example:\n"); |
tonychun | e3fe984 | 2015-07-10 18:45:30 | [diff] [blame] | 136 | printf("chromoting_test_driver --%s=%s --%s=example_host_name" |
| 137 | " --%s=./example_file.json\n\n", |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 138 | switches::kUserNameSwitchName, "[email protected]", |
tonychun | e3fe984 | 2015-07-10 18:45:30 | [diff] [blame] | 139 | switches::kHostNameSwitchName, switches::kRefreshTokenPathSwitchName); |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 140 | } |
| 141 | |
tonychun | e3fe984 | 2015-07-10 18:45:30 | [diff] [blame] | 142 | } // namespace |
| 143 | |
tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 144 | int main(int argc, char* argv[]) { |
jam | 5ccf985d | 2015-12-11 02:23:27 | [diff] [blame] | 145 | base::TestSuite test_suite(argc, argv); |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 146 | base::MessageLoopForIO message_loop; |
joedow | 910989d | 2016-12-02 21:15:32 | [diff] [blame] | 147 | base::FeatureList::InitializeInstance(std::string(), std::string()); |
tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 148 | |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 149 | if (!base::CommandLine::InitializedForCurrentProcess()) { |
| 150 | if (!base::CommandLine::Init(argc, argv)) { |
| 151 | LOG(ERROR) << "Failed to initialize command line singleton."; |
| 152 | return -1; |
| 153 | } |
| 154 | } |
| 155 | |
tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 156 | base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| 157 | DCHECK(command_line); |
| 158 | |
| 159 | // Do not retry if tests fails. |
| 160 | command_line->AppendSwitchASCII(switches::kTestLauncherRetryLimit, "0"); |
| 161 | |
| 162 | // Different tests may require access to the same host if run in parallel. |
| 163 | // To avoid shared resource contention, tests will be run one at a time. |
| 164 | command_line->AppendSwitch(switches::kSingleProcessTestsSwitchName); |
| 165 | |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 166 | // If the user passed in the help flag, then show the help info for this tool |
| 167 | // and 'run' the tests which will print the gtest specific help and then exit. |
| 168 | // NOTE: We do this check after updating the switches as otherwise the gtest |
| 169 | // help is written in parallel with our text and can appear interleaved. |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 170 | if (command_line->HasSwitch(switches::kHelpSwitchName)) { |
| 171 | PrintUsage(); |
| 172 | PrintJsonFileInfo(); |
| 173 | PrintAuthCodeInfo(); |
nicholss | 1b5df0c | 2016-10-25 16:04:49 | [diff] [blame] | 174 | #if defined(OS_IOS) |
| 175 | return base::LaunchUnitTests( |
| 176 | argc, argv, |
| 177 | base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); |
| 178 | #else |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 179 | return base::LaunchUnitTestsSerially( |
jam | 5ccf985d | 2015-12-11 02:23:27 | [diff] [blame] | 180 | argc, argv, |
| 181 | base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); |
nicholss | 1b5df0c | 2016-10-25 16:04:49 | [diff] [blame] | 182 | #endif |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 183 | } |
| 184 | |
tonychun | 684d1414 | 2015-07-31 00:05:49 | [diff] [blame] | 185 | // Update the logging verbosity level if user specified one. |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 186 | std::string verbosity_level( |
| 187 | command_line->GetSwitchValueASCII(switches::kLoggingLevelSwitchName)); |
| 188 | if (!verbosity_level.empty()) { |
| 189 | // Turn on logging for the test_driver and remoting components. |
| 190 | // This switch is parsed during logging::InitLogging. |
| 191 | command_line->AppendSwitchASCII("vmodule", |
| 192 | "*/remoting/*=" + verbosity_level); |
| 193 | logging::LoggingSettings logging_settings; |
| 194 | logging::InitLogging(logging_settings); |
| 195 | } |
| 196 | |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 197 | remoting::test::ChromotingTestDriverEnvironment::EnvironmentOptions options; |
| 198 | |
| 199 | options.user_name = |
tonychun | 8815bf7 | 2015-06-25 23:29:37 | [diff] [blame] | 200 | command_line->GetSwitchValueASCII(switches::kUserNameSwitchName); |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 201 | if (options.user_name.empty()) { |
tonychun | 8815bf7 | 2015-06-25 23:29:37 | [diff] [blame] | 202 | LOG(ERROR) << "No username passed in, can't authenticate or run tests!"; |
tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 203 | return -1; |
| 204 | } |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 205 | VLOG(1) << "Running chromoting tests as: " << options.user_name; |
tonychun | 61931fe6 | 2015-06-10 23:28:40 | [diff] [blame] | 206 | |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 207 | // Check to see if the user passed in a one time use auth_code for |
| 208 | // refreshing their credentials. |
| 209 | std::string auth_code = |
| 210 | command_line->GetSwitchValueASCII(switches::kAuthCodeSwitchName); |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 211 | options.refresh_token_file_path = |
tonychun | 8815bf7 | 2015-06-25 23:29:37 | [diff] [blame] | 212 | command_line->GetSwitchValuePath(switches::kRefreshTokenPathSwitchName); |
| 213 | |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 214 | // The host name determines which host to initiate a session with from the |
| 215 | // host list returned from the directory service. |
| 216 | options.host_name = |
tonychun | 8815bf7 | 2015-06-25 23:29:37 | [diff] [blame] | 217 | command_line->GetSwitchValueASCII(switches::kHostNameSwitchName); |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 218 | |
| 219 | if (options.host_name.empty()) { |
| 220 | LOG(ERROR) << "No hostname passed in, connect to host requires hostname!"; |
tonychun | 8815bf7 | 2015-06-25 23:29:37 | [diff] [blame] | 221 | return -1; |
| 222 | } |
joedow | afb0295 | 2016-04-05 23:13:31 | [diff] [blame] | 223 | VLOG(1) << "host_name: '" << options.host_name << "'"; |
anandc | 44945a9 | 2015-12-11 00:10:01 | [diff] [blame] | 224 | |
| 225 | options.host_jid = |
| 226 | command_line->GetSwitchValueASCII(switches::kHostJidSwitchName); |
joedow | afb0295 | 2016-04-05 23:13:31 | [diff] [blame] | 227 | VLOG(1) << "host_jid: '" << options.host_jid << "'"; |
tonychun | 8815bf7 | 2015-06-25 23:29:37 | [diff] [blame] | 228 | |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 229 | options.pin = command_line->GetSwitchValueASCII(switches::kPinSwitchName); |
tonychun | f21b41e | 2015-07-20 20:29:11 | [diff] [blame] | 230 | |
joedow | 910989d | 2016-12-02 21:15:32 | [diff] [blame] | 231 | options.use_test_environment = |
| 232 | command_line->HasSwitch(switches::kTestEnvironmentSwitchName); |
| 233 | |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 234 | // Create and register our global test data object. It will handle |
| 235 | // retrieving an access token or host list for the user. The GTest framework |
| 236 | // will own the lifetime of this object once it is registered below. |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 237 | std::unique_ptr<remoting::test::ChromotingTestDriverEnvironment> shared_data( |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 238 | new remoting::test::ChromotingTestDriverEnvironment(options)); |
tonychun | 8815bf7 | 2015-06-25 23:29:37 | [diff] [blame] | 239 | |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 240 | if (!shared_data->Initialize(auth_code)) { |
joedow | afb0295 | 2016-04-05 23:13:31 | [diff] [blame] | 241 | VLOG(1) << "Failed to initialize ChromotingTestDriverEnvironment instance."; |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 242 | // If we failed to initialize our shared data object, then bail. |
tonychun | 8815bf7 | 2015-06-25 23:29:37 | [diff] [blame] | 243 | return -1; |
| 244 | } |
| 245 | |
joedow | afb0295 | 2016-04-05 23:13:31 | [diff] [blame] | 246 | // This method is necessary as there are occasional propagation delays in the |
| 247 | // backend and we don't want the test to fail because of that. |
| 248 | if (!shared_data->WaitForHostOnline(options.host_jid, options.host_name)) { |
| 249 | VLOG(1) << "The expected host was not available for connections."; |
| 250 | // Host is not online. No point running further tests. |
anandc | 44945a9 | 2015-12-11 00:10:01 | [diff] [blame] | 251 | return -1; |
| 252 | } |
| 253 | |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 254 | // Since we've successfully set up our shared_data object, we'll assign the |
| 255 | // value to our global* and transfer ownership to the framework. |
| 256 | remoting::test::g_chromoting_shared_data = shared_data.release(); |
| 257 | testing::AddGlobalTestEnvironment(remoting::test::g_chromoting_shared_data); |
tonychun | 08cd3e8 | 2015-06-29 16:49:13 | [diff] [blame] | 258 | |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 259 | // Running the tests serially will avoid clients from connecting to the same |
| 260 | // host. |
nicholss | 1b5df0c | 2016-10-25 16:04:49 | [diff] [blame] | 261 | #if defined(OS_IOS) |
| 262 | return base::LaunchUnitTests( |
| 263 | argc, argv, |
| 264 | base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); |
| 265 | #else |
tonychun | 4495971 | 2015-07-28 17:38:24 | [diff] [blame] | 266 | return base::LaunchUnitTestsSerially( |
jam | 5ccf985d | 2015-12-11 02:23:27 | [diff] [blame] | 267 | argc, argv, |
| 268 | base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); |
nicholss | 1b5df0c | 2016-10-25 16:04:49 | [diff] [blame] | 269 | #endif |
wittman | 97692ba6c | 2015-06-25 21:38:59 | [diff] [blame] | 270 | } |