blob: abf7a7756f96747c87798ce1d4faee75a0ec3cb3 [file] [log] [blame]
tonychun61931fe62015-06-10 23:28:401// 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
tonychun08cd3e82015-06-29 16:49:135#include "base/bind.h"
tonychun61931fe62015-06-10 23:28:406#include "base/command_line.h"
joedow910989d2016-12-02 21:15:327#include "base/feature_list.h"
tonychun8815bf72015-06-25 23:29:378#include "base/files/file_path.h"
tonychun08cd3e82015-06-29 16:49:139#include "base/logging.h"
10#include "base/message_loop/message_loop.h"
tonychun08cd3e82015-06-29 16:49:1311#include "base/strings/stringprintf.h"
tonychun44959712015-07-28 17:38:2412#include "base/test/launcher/unit_test_launcher.h"
tonychun61931fe62015-06-10 23:28:4013#include "base/test/test_suite.h"
14#include "base/test/test_switches.h"
tonychun08cd3e82015-06-29 16:49:1315#include "google_apis/google_api_keys.h"
16#include "net/base/escape.h"
tonychun44959712015-07-28 17:38:2417#include "remoting/test/chromoting_test_driver_environment.h"
tonychun61931fe62015-06-10 23:28:4018#include "testing/gtest/include/gtest/gtest.h"
19
20namespace switches {
tonychun08cd3e82015-06-29 16:49:1321const char kAuthCodeSwitchName[] = "authcode";
22const char kHelpSwitchName[] = "help";
23const char kHostNameSwitchName[] = "hostname";
anandc44945a92015-12-11 00:10:0124const char kHostJidSwitchName[] = "hostjid";
tonychun08cd3e82015-06-29 16:49:1325const char kLoggingLevelSwitchName[] = "verbosity";
tonychun44959712015-07-28 17:38:2426const char kPinSwitchName[] = "pin";
tonychun08cd3e82015-06-29 16:49:1327const char kRefreshTokenPathSwitchName[] = "refresh-token-path";
tonychun61931fe62015-06-10 23:28:4028const char kSingleProcessTestsSwitchName[] = "single-process-tests";
joedow910989d2016-12-02 21:15:3229const char kTestEnvironmentSwitchName[] = "use-test-env";
tonychun61931fe62015-06-10 23:28:4030const char kUserNameSwitchName[] = "username";
tonychun08cd3e82015-06-29 16:49:1331}
32
33namespace {
34const 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
39std::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
57void PrintUsage() {
58 printf("\n************************************\n");
59 printf("*** Chromoting Test Driver Usage ***\n");
60 printf("************************************\n");
61
62 printf("\nUsage:\n");
tonychune3fe9842015-07-10 18:45:3063 printf(" chromoting_test_driver --username=<[email protected]> [options]"
64 " --hostname=<example hostname>\n");
tonychun08cd3e82015-06-29 16:49:1365 printf("\nRequired Parameters:\n");
66 printf(" %s: Specifies which account to use when running tests\n",
67 switches::kUserNameSwitchName);
tonychune3fe9842015-07-10 18:45:3068 printf(" %s: Specifies which host to connect to when running tests\n",
69 switches::kHostNameSwitchName);
tonychun08cd3e82015-06-29 16:49:1370 printf("\nOptional Parameters:\n");
71 printf(" %s: Exchanged for a refresh and access token for authentication\n",
72 switches::kAuthCodeSwitchName);
tonychun08cd3e82015-06-29 16:49:1373 printf(" %s: Displays additional usage information\n",
74 switches::kHelpSwitchName);
tonychune3fe9842015-07-10 18:45:3075 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)."
tonychun44959712015-07-28 17:38:2478 " [default: off]\n", switches::kLoggingLevelSwitchName);
joedow910989d2016-12-02 21:15:3279 printf(
80 " %s: Specifies that the test environment APIs should be used."
81 " [default: false]\n",
82 switches::kTestEnvironmentSwitchName);
tonychun08cd3e82015-06-29 16:49:1383}
84
85void 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
tonychune3fe9842015-07-10 18:45:30101 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");
tonychun08cd3e82015-06-29 16:49:13106
107 printf("\nAuthorization URL:\n");
108 printf("%s\n", GetAuthorizationCodeUri().c_str());
109
110 printf("\nRedirected URL Example:\n");
tonychune3fe9842015-07-10 18:45:30111 printf("https://chromoting-oauth.talkgadget.google.com/talkgadget/oauth/"
112 "chrome-remote-desktop/dev?code=4/AKtf...\n");
tonychun08cd3e82015-06-29 16:49:13113
114 printf("\nTool usage example with the newly created auth code:\n");
tonychune3fe9842015-07-10 18:45:30115 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);
tonychun08cd3e82015-06-29 16:49:13120}
121
122void 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");
tonychune3fe9842015-07-10 18:45:30136 printf("chromoting_test_driver --%s=%s --%s=example_host_name"
137 " --%s=./example_file.json\n\n",
tonychun08cd3e82015-06-29 16:49:13138 switches::kUserNameSwitchName, "[email protected]",
tonychune3fe9842015-07-10 18:45:30139 switches::kHostNameSwitchName, switches::kRefreshTokenPathSwitchName);
tonychun08cd3e82015-06-29 16:49:13140}
141
tonychune3fe9842015-07-10 18:45:30142} // namespace
143
tonychun61931fe62015-06-10 23:28:40144int main(int argc, char* argv[]) {
jam5ccf985d2015-12-11 02:23:27145 base::TestSuite test_suite(argc, argv);
tonychun44959712015-07-28 17:38:24146 base::MessageLoopForIO message_loop;
joedow910989d2016-12-02 21:15:32147 base::FeatureList::InitializeInstance(std::string(), std::string());
tonychun61931fe62015-06-10 23:28:40148
tonychun44959712015-07-28 17:38:24149 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
tonychun61931fe62015-06-10 23:28:40156 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
tonychun44959712015-07-28 17:38:24166 // 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.
tonychun08cd3e82015-06-29 16:49:13170 if (command_line->HasSwitch(switches::kHelpSwitchName)) {
171 PrintUsage();
172 PrintJsonFileInfo();
173 PrintAuthCodeInfo();
nicholss1b5df0c2016-10-25 16:04:49174#if defined(OS_IOS)
175 return base::LaunchUnitTests(
176 argc, argv,
177 base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
178#else
tonychun44959712015-07-28 17:38:24179 return base::LaunchUnitTestsSerially(
jam5ccf985d2015-12-11 02:23:27180 argc, argv,
181 base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
nicholss1b5df0c2016-10-25 16:04:49182#endif
tonychun08cd3e82015-06-29 16:49:13183 }
184
tonychun684d14142015-07-31 00:05:49185 // Update the logging verbosity level if user specified one.
tonychun08cd3e82015-06-29 16:49:13186 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
tonychun44959712015-07-28 17:38:24197 remoting::test::ChromotingTestDriverEnvironment::EnvironmentOptions options;
198
199 options.user_name =
tonychun8815bf72015-06-25 23:29:37200 command_line->GetSwitchValueASCII(switches::kUserNameSwitchName);
tonychun44959712015-07-28 17:38:24201 if (options.user_name.empty()) {
tonychun8815bf72015-06-25 23:29:37202 LOG(ERROR) << "No username passed in, can't authenticate or run tests!";
tonychun61931fe62015-06-10 23:28:40203 return -1;
204 }
tonychun44959712015-07-28 17:38:24205 VLOG(1) << "Running chromoting tests as: " << options.user_name;
tonychun61931fe62015-06-10 23:28:40206
tonychun08cd3e82015-06-29 16:49:13207 // 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);
tonychun44959712015-07-28 17:38:24211 options.refresh_token_file_path =
tonychun8815bf72015-06-25 23:29:37212 command_line->GetSwitchValuePath(switches::kRefreshTokenPathSwitchName);
213
tonychun44959712015-07-28 17:38:24214 // 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 =
tonychun8815bf72015-06-25 23:29:37217 command_line->GetSwitchValueASCII(switches::kHostNameSwitchName);
tonychun44959712015-07-28 17:38:24218
219 if (options.host_name.empty()) {
220 LOG(ERROR) << "No hostname passed in, connect to host requires hostname!";
tonychun8815bf72015-06-25 23:29:37221 return -1;
222 }
joedowafb02952016-04-05 23:13:31223 VLOG(1) << "host_name: '" << options.host_name << "'";
anandc44945a92015-12-11 00:10:01224
225 options.host_jid =
226 command_line->GetSwitchValueASCII(switches::kHostJidSwitchName);
joedowafb02952016-04-05 23:13:31227 VLOG(1) << "host_jid: '" << options.host_jid << "'";
tonychun8815bf72015-06-25 23:29:37228
tonychun44959712015-07-28 17:38:24229 options.pin = command_line->GetSwitchValueASCII(switches::kPinSwitchName);
tonychunf21b41e2015-07-20 20:29:11230
joedow910989d2016-12-02 21:15:32231 options.use_test_environment =
232 command_line->HasSwitch(switches::kTestEnvironmentSwitchName);
233
tonychun44959712015-07-28 17:38:24234 // 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.
dcheng0765c492016-04-06 22:41:53237 std::unique_ptr<remoting::test::ChromotingTestDriverEnvironment> shared_data(
tonychun44959712015-07-28 17:38:24238 new remoting::test::ChromotingTestDriverEnvironment(options));
tonychun8815bf72015-06-25 23:29:37239
tonychun44959712015-07-28 17:38:24240 if (!shared_data->Initialize(auth_code)) {
joedowafb02952016-04-05 23:13:31241 VLOG(1) << "Failed to initialize ChromotingTestDriverEnvironment instance.";
tonychun44959712015-07-28 17:38:24242 // If we failed to initialize our shared data object, then bail.
tonychun8815bf72015-06-25 23:29:37243 return -1;
244 }
245
joedowafb02952016-04-05 23:13:31246 // 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.
anandc44945a92015-12-11 00:10:01251 return -1;
252 }
253
tonychun44959712015-07-28 17:38:24254 // 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);
tonychun08cd3e82015-06-29 16:49:13258
tonychun44959712015-07-28 17:38:24259 // Running the tests serially will avoid clients from connecting to the same
260 // host.
nicholss1b5df0c2016-10-25 16:04:49261#if defined(OS_IOS)
262 return base::LaunchUnitTests(
263 argc, argv,
264 base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
265#else
tonychun44959712015-07-28 17:38:24266 return base::LaunchUnitTestsSerially(
jam5ccf985d2015-12-11 02:23:27267 argc, argv,
268 base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
nicholss1b5df0c2016-10-25 16:04:49269#endif
wittman97692ba6c2015-06-25 21:38:59270}