Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: chrome/test/android/javatests_staging/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
5 package org.chromium.chrome.test;
6
7 import android.app.Activity;
8 import android.app.ActivityManager;
9 import android.app.ActivityManager.AppTask;
10 import android.app.Instrumentation;
11 import android.content.ComponentName;
12 import android.content.Context;
13 import android.content.Intent;
14 import android.content.pm.PackageManager;
15 import android.net.Uri;
16 import android.os.AsyncTask;
17 import android.os.PowerManager;
18 import android.provider.Browser;
19 import android.text.TextUtils;
20 import android.util.Log;
21 import android.view.KeyEvent;
22 import android.view.View;
23 import android.widget.ListView;
24
25 import com.google.android.apps.chrome.R;
26
27 import junit.framework.Assert;
28
29 import org.chromium.base.PerfTraceEvent;
30 import org.chromium.base.ThreadUtils;
31 import org.chromium.base.annotations.SuppressFBWarnings;
32 import org.chromium.base.test.BaseActivityInstrumentationTestCase;
33 import org.chromium.base.test.util.CommandLineFlags;
34 import org.chromium.base.test.util.PerfTest;
35 import org.chromium.chrome.browser.ChromeActivity;
36 import org.chromium.chrome.browser.ChromeMobileApplication;
37 import org.chromium.chrome.browser.ChromeSwitches;
38 import org.chromium.chrome.browser.ChromeTabbedActivity;
39 import org.chromium.chrome.browser.DeferredStartupHandler;
40 import org.chromium.chrome.browser.EmptyTabObserver;
41 import org.chromium.chrome.browser.Tab;
42 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
43 import org.chromium.chrome.browser.document.DocumentActivity;
44 import org.chromium.chrome.browser.document.DocumentMetricIds;
45 import org.chromium.chrome.browser.document.DocumentUtils;
46 import org.chromium.chrome.browser.document.IncognitoDocumentActivity;
47 import org.chromium.chrome.browser.infobar.InfoBar;
48 import org.chromium.chrome.browser.ntp.NewTabPage;
49 import org.chromium.chrome.browser.omaha.OmahaClient;
50 import org.chromium.chrome.browser.omnibox.AutocompleteController;
51 import org.chromium.chrome.browser.omnibox.LocationBarLayout;
52 import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxResultIt em;
53 import org.chromium.chrome.browser.omnibox.OmniboxSuggestion;
54 import org.chromium.chrome.browser.omnibox.UrlBar;
55 import org.chromium.chrome.browser.preferences.NetworkPredictionOptions;
56 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
57 import org.chromium.chrome.browser.preferences.Preferences;
58 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
59 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
60 import org.chromium.chrome.browser.tabmodel.TabModel;
61 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
62 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
63 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
64 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
65 import org.chromium.chrome.browser.util.FeatureUtilities;
66 import org.chromium.chrome.test.util.ActivityUtils;
67 import org.chromium.chrome.test.util.ApplicationData;
68 import org.chromium.chrome.test.util.ChromeTabUtils;
69 import org.chromium.chrome.test.util.MenuUtils;
70 import org.chromium.chrome.test.util.NewTabPageTestUtils;
71 import org.chromium.chrome.test.util.OmniboxTestUtils;
72 import org.chromium.chrome.test.util.TestHttpServerClient;
73 import org.chromium.content.browser.test.util.CallbackHelper;
74 import org.chromium.content.browser.test.util.Criteria;
75 import org.chromium.content.browser.test.util.CriteriaHelper;
76 import org.chromium.content.browser.test.util.JavaScriptUtils;
77 import org.chromium.content.browser.test.util.KeyUtils;
78 import org.chromium.content.browser.test.util.RenderProcessLimit;
79 import org.chromium.content.browser.test.util.TestTouchUtils;
80 import org.chromium.content.browser.test.util.TouchCommon;
81 import org.chromium.content_public.browser.LoadUrlParams;
82 import org.chromium.ui.base.PageTransition;
83
84 import java.io.File;
85 import java.lang.reflect.Method;
86 import java.util.LinkedList;
87 import java.util.List;
88 import java.util.concurrent.Callable;
89 import java.util.concurrent.ExecutionException;
90 import java.util.concurrent.Semaphore;
91 import java.util.concurrent.TimeUnit;
92 import java.util.concurrent.TimeoutException;
93 import java.util.concurrent.atomic.AtomicBoolean;
94 import java.util.concurrent.atomic.AtomicInteger;
95
96 /**
97 * Base class for all Chrome instrumentation tests.
98 * All tests must inherit from this class and define their own test methods
99 * See ChromeTabbedActivityTestBase.java for example.
100 * @param <T> A {@link ChromeActivity} class
101 */
102 @CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)
103 public abstract class ChromeActivityTestCaseBase<T extends ChromeActivity>
104 extends BaseActivityInstrumentationTestCase<T> {
105
106 private static final String TAG = "ChromeActivityTestCaseBase";
107
108 // The number of ms to wait for the rendering activity to be started.
109 protected static final int ACTIVITY_START_TIMEOUT_MS = 1000;
110
111 private static final String PERF_NORUN_TAG = "--NORUN--";
112
113 private static final String PERF_ANNOTATION_FORMAT = "**PERFANNOTATION(%s):" ;
114
115 private static final String MEMORY_TRACE_GRAPH_SUFFIX = " - browser PSS";
116
117 private static final String PERF_OUTPUT_FILE = "PerfTestData.txt";
118
119 private static final long OMNIBOX_FIND_SUGGESTION_TIMEOUT_MS = 10 * 1000;
120
121 public ChromeActivityTestCaseBase(Class<T> activityClass) {
122 super(activityClass);
123 }
124
125 protected boolean mSkipClearAppData = false;
126 private PowerManager.WakeLock mWakeLock = null;
127 protected boolean mSkipCheckHttpServer = false;
128
129 @Override
130 protected void setUp() throws Exception {
131 super.setUp();
132
133 setActivityInitialTouchMode(false);
134 if (!mSkipClearAppData) {
135 // We shouldn't clear the data at the end of test, it is needed for debugging.
136 assertTrue("Unable to clear the app data", clearAppData());
137 if (FeatureUtilities.isDocumentMode(getInstrumentation().getTargetCo ntext())) {
138 closeAllChromeActivityAppTasks();
139 }
140 }
141 // Make sure the screen is on during test runs.
142 PowerManager pm = (PowerManager) getInstrumentation().getTargetContext()
143 .getSystemService(Context.POWER_SERVICE);
144 mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK
145 | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_REL EASE, TAG);
146 mWakeLock.acquire();
147
148 // Disable Omaha related activities.
149 OmahaClient.setEnableCommunication(false);
150 OmahaClient.setEnableUpdateDetection(false);
151
152 if (!mSkipCheckHttpServer) {
153 TestHttpServerClient.checkServerIsUp();
154 }
155 startMainActivity();
156 }
157
158 @Override
159 protected void tearDown() throws Exception {
160 assertNotNull("Uninitialized wake lock", mWakeLock);
161 mWakeLock.release();
162 super.tearDown();
163 }
164
165 /**
166 * Called to start the Main Activity, the subclass should implemented with i t desired start
167 * method.
168 * TODO: Make startMainActivityFromLauncher the default.
169 */
170 public abstract void startMainActivity() throws InterruptedException;
171
172 /**
173 * Matches testString against baseString.
174 * Returns 0 if there is no match, 1 if an exact match and 2 if a fuzzy matc h.
175 */
176 protected static int matchUrl(String baseString, String testString) {
177 if (baseString.equals(testString)) {
178 return 1;
179 }
180 if (baseString.contains(testString)) {
181 return 2;
182 }
183 return 0;
184 }
185
186 /**
187 * Invokes {@link Instrumentation#startActivitySync(Intent)} and sets the
188 * test case's activity to the result. See the documentation for
189 * {@link Instrumentation#startActivitySync(Intent)} on the timing of the
190 * return, but generally speaking the activity's "onCreate" has completed
191 * and the activity's main looper has become idle.
192 */
193 protected void startActivityCompletely(Intent intent) {
194 final Class<?> activityClazz =
195 FeatureUtilities.isDocumentMode(getInstrumentation().getTargetCo ntext())
196 ? DocumentActivity.class : ChromeTabbedActivity.class;
197 Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonito r(
198 activityClazz.getName(), null, false);
199 Activity activity = getInstrumentation().startActivitySync(intent);
200 assertNotNull("Main activity did not start", activity);
201 ChromeActivity chromeActivity = (ChromeActivity)
202 monitor.waitForActivityWithTimeout(ACTIVITY_START_TIMEOUT_MS);
203 assertNotNull("ChromeActivity did not start", chromeActivity);
204 setActivity(chromeActivity);
205 Log.d(TAG, "startActivityCompletely <<");
206 }
207
208 /**
209 * Clear all files and folders in the Chrome application directory except 'l ib'.
210 *
211 * The 'cache' directory is recreated as an empty directory.
212 *
213 * @return Whether clearing the application data was successful.
214 */
215 protected boolean clearAppData() throws InterruptedException {
216 return ApplicationData.clearAppData(getInstrumentation().getTargetContex t());
217 }
218
219 /**
220 * Closes all Chrome activity app tasks. This is for cleaning up Chrome task s in the recent,
221 * those are not necessarily associated with a live activity.
222 */
223 private void closeAllChromeActivityAppTasks() throws ClassNotFoundException {
224 ActivityManager am = (ActivityManager) getInstrumentation().getTargetCon text()
225 .getSystemService(Context.ACTIVITY_SERVICE);
226 PackageManager pm = getInstrumentation().getTargetContext().getPackageMa nager();
227 List<AppTask> taskList = am.getAppTasks();
228 for (AppTask task : taskList) {
229 String className = DocumentUtils.getTaskClassName(task, pm);
230 if (ChromeActivity.class.isAssignableFrom(Class.forName(className))) {
231 task.finishAndRemoveTask();
232 }
233 }
234 }
235
236 /**
237 * Lets tests specify whether they want prerendering turned on.
238 * It is on by default. Since in some places different code paths are used f or the same feature
239 * depending of whether instant is on or off (ex: infobars), it is necessary for some tests to
240 * test with and without instant.
241 *
242 * @param enabled whether prerender should be on.
243 */
244 protected void setAllowPrerender(final boolean enabled) {
245 getInstrumentation().runOnMainSync(new Runnable() {
246 @Override
247 public void run() {
248 PrefServiceBridge.getInstance().setNetworkPredictionOptions(enab led
249 ? NetworkPredictionOptions.NETWORK_PREDICTION_ALWAYS
250 : NetworkPredictionOptions.NETWORK_PREDICTION_NEVER);
251 }
252 });
253 }
254
255 /**
256 * Starts (synchronously) a drag motion. Normally followed by dragTo() and d ragEnd().
257 *
258 * @param x
259 * @param y
260 * @param downTime (in ms)
261 * @see TestTouchUtils
262 */
263 protected void dragStart(float x, float y, long downTime) {
264 TouchCommon.dragStart(getActivity(), x, y, downTime);
265 }
266
267 /**
268 * Drags / moves (synchronously) to the specified coordinates. Normally prec eeded by
269 * dragStart() and followed by dragEnd()
270 *
271 * @param fromX
272 * @param toX
273 * @param fromY
274 * @param toY
275 * @param stepCount
276 * @param downTime (in ms)
277 * @see TestTouchUtils
278 */
279 protected void dragTo(float fromX, float toX, float fromY,
280 float toY, int stepCount, long downTime) {
281 TouchCommon.dragTo(getActivity(), fromX, toX, fromY, toY, stepCount, dow nTime);
282 }
283
284 /**
285 * Finishes (synchronously) a drag / move at the specified coordinate.
286 * Normally preceeded by dragStart() and dragTo().
287 *
288 * @param x
289 * @param y
290 * @param downTime (in ms)
291 * @see TestTouchUtils
292 */
293 protected void dragEnd(float x, float y, long downTime) {
294 TouchCommon.dragEnd(getActivity(), x, y, downTime);
295 }
296
297 /**
298 * Sends (synchronously) a single click to an absolute screen coordinates.
299 *
300 * @param x screen absolute
301 * @param y screen absolute
302 * @see TestTouchUtils
303 */
304 public void singleClick(float x, float y) {
305 TouchCommon.singleClick(getActivity(), x, y);
306 }
307
308 /**
309 * Sends (synchronously) a single click to the View at the specified coordin ates.
310 *
311 * <p>
312 * Differs from
313 * {@link TestTouchUtils#singleClickView(android.app.Instrumentation, View, int, int)}
314 * as this does not rely on injecting events into the different activity. I njecting events has
315 * been unreliable for us and simulating the touch events in this manner is just as effective.
316 *
317 * @param v The view to be clicked.
318 * @param x Relative x location to v
319 * @param y Relative y location to v
320 */
321 public void singleClickView(View v, int x, int y) {
322 TouchCommon.singleClickView(v, x, y);
323 }
324
325 /**
326 * Sends (synchronously) a single click to the center of the View.
327 *
328 * <p>
329 * Differs from
330 * {@link TestTouchUtils#singleClickView(android.app.Instrumentation, View)}
331 * as this does not rely on injecting events into the different activity. I njecting events has
332 * been unreliable for us and simulating the touch events in this manner is just as effective.
333 *
334 * @param v The view to be clicked.
335 */
336 public void singleClickView(View v) {
337 TouchCommon.singleClickView(v);
338 }
339
340 /**
341 * Waits for {@link AsyncTask}'s that have been queued to finish. Note, this
342 * only waits for tasks that have been started using the default
343 * {@link java.util.concurrent.Executor}, which executes tasks serially.
344 *
345 * @param timeout how long to wait for tasks to complete
346 */
347 public void waitForAsyncTasks(long timeout) throws InterruptedException {
348 final Semaphore s = new Semaphore(0);
349 new AsyncTask<Void, Void, Void>() {
350 @Override
351 protected Void doInBackground(Void... arg0) {
352 s.release();
353 return null;
354 }
355 }.execute();
356 assertTrue(s.tryAcquire(timeout, TimeUnit.MILLISECONDS));
357 }
358
359 /**
360 * Navigates to a URL directly without going through the UrlBar. This bypass es the page
361 * preloading mechanism of the UrlBar.
362 * @param url The url to load in the current tab.
363 * @return FULL_PRERENDERED_PAGE_LOAD or PARTIAL_PRERENDERED_PAGE_LOAD if th e page has been
364 * prerendered. DEFAULT_PAGE_LOAD if it had not.
365 */
366 public int loadUrl(final String url) throws IllegalArgumentException, Interr uptedException {
367 return loadUrlInTab(url, PageTransition.TYPED | PageTransition.FROM_ADDR ESS_BAR,
368 getActivity().getActivityTab());
369 }
370
371 /**
372 * @param url The url of the page to load.
373 * @param pageTransition The type of transition. see
374 * {@link org.chromium.content.browser.PageTransition}
375 * for valid values.
376 * @param tab The tab to load the url into.
377 * @return FULL_PRERENDERED_PAGE_LOAD or PARTIAL_PRERENDERED_P AGE_LOAD if the
378 * page has been prerendered. DEFAULT_PAGE_LOAD if it had not.
379 */
380 public int loadUrlInTab(final String url, final int pageTransition, final Ta b tab)
381 throws InterruptedException {
382 assertNotNull("Cannot load the url in a null tab", tab);
383 final AtomicInteger result = new AtomicInteger();
384
385 ChromeTabUtils.waitForTabPageLoaded(tab, new Runnable() {
386 @Override
387 public void run() {
388 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
389 @Override
390 public void run() {
391 result.set(tab.loadUrl(
392 new LoadUrlParams(url, pageTransition)));
393 }
394 });
395 }
396 });
397 getInstrumentation().waitForIdleSync();
398 return result.get();
399 }
400
401 /**
402 * Load a url in a new tab. The {@link Tab} will pretend to be created from a link.
403 * @param url The url of the page to load.
404 */
405 public void loadUrlInNewTab(final String url) throws InterruptedException {
406 // TODO(mariakhomenko): There is no current tab creator in document mode , will need
407 // additional logic here for Document tests.
408 if (FeatureUtilities.isDocumentMode(getInstrumentation().getContext())) {
409 fail("Document mode not yet supported.");
410 }
411 try {
412 Tab tab = ThreadUtils.runOnUiThreadBlocking(new Callable<Tab>() {
413 @Override
414 public Tab call() throws Exception {
415 return getActivity().getCurrentTabCreator()
416 .launchUrl(url, TabLaunchType.FROM_LINK);
417 }
418 });
419
420 ChromeTabUtils.waitForTabPageLoaded(tab, url);
421 getInstrumentation().waitForIdleSync();
422 } catch (ExecutionException e) {
423 fail("Failed to create new tab");
424 }
425 }
426
427 /**
428 * Load a url in a new tab. The {@link Tab} will pretend to be created from a link.
429 * @param url The url of the page to load.
430 * @param incognito Whether the new tab should be incognito.
431 */
432 public void loadUrlInNewTab(final String url, final boolean incognito)
433 throws InterruptedException {
434 Tab tab = null;
435 if (FeatureUtilities.isDocumentMode(getInstrumentation().getContext())) {
436 Runnable activityTrigger = new Runnable() {
437 @Override
438 public void run() {
439 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
440 @Override
441 public void run() {
442 ChromeLauncherActivity.launchDocumentInstance(getAct ivity(), incognito,
443 ChromeLauncherActivity.LAUNCH_MODE_FOREGROUN D, url,
444 DocumentMetricIds.STARTED_BY_UNKNOWN,
445 PageTransition.AUTO_TOPLEVEL,
446 false, null);
447 }
448 });
449 }
450 };
451 final DocumentActivity activity = ActivityUtils.waitForActivity(
452 getInstrumentation(),
453 incognito ? IncognitoDocumentActivity.class : DocumentActivi ty.class,
454 activityTrigger);
455 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
456 @Override
457 public boolean isSatisfied() {
458 return activity.getActivityTab() != null;
459 }
460 });
461 tab = activity.getActivityTab();
462 } else {
463 try {
464 tab = ThreadUtils.runOnUiThreadBlocking(new Callable<Tab>() {
465 @Override
466 public Tab call() throws Exception {
467 return getActivity().getTabCreator(incognito)
468 .launchUrl(url, TabLaunchType.FROM_LINK);
469 }
470 });
471 } catch (ExecutionException e) {
472 fail("Failed to create new tab");
473 }
474 }
475 ChromeTabUtils.waitForTabPageLoaded(tab, url);
476 getInstrumentation().waitForIdleSync();
477 }
478
479 /**
480 * Simulates starting Main Activity from launcher, blocks until it is starte d.
481 */
482 protected void startMainActivityFromLauncher() throws InterruptedException {
483 startMainActivityWithURL(null);
484 }
485
486 /**
487 * Starts the Main activity on the specified URL. Passing a null URL ensures the default page is
488 * loaded, which is the NTP with a new profile .
489 */
490 protected void startMainActivityWithURL(String url) throws InterruptedExcept ion {
491 // Only launch Chrome.
492 Intent intent = new Intent(
493 TextUtils.isEmpty(url) ? Intent.ACTION_MAIN : Intent.ACTION_VIEW );
494 intent.addCategory(Intent.CATEGORY_LAUNCHER);
495 startMainActivityFromIntent(intent, url);
496 }
497
498 /**
499 * Starts the Main activity and open a blank page.
500 * This is faster and less flakyness-prone than starting on the NTP.
501 */
502 protected void startMainActivityOnBlankPage() throws InterruptedException {
503 startMainActivityWithURL("about:blank");
504 }
505
506 /**
507 * Starts the Main activity as if it was started from an external applicatio n, on the specified
508 * URL.
509 */
510 protected void startMainActivityFromExternalApp(String url, String appId)
511 throws InterruptedException {
512 Intent intent = new Intent(Intent.ACTION_VIEW);
513 if (appId != null) {
514 intent.putExtra(Browser.EXTRA_APPLICATION_ID, appId);
515 }
516 startMainActivityFromIntent(intent, url);
517 }
518
519 /**
520 * Starts the Main activity using the passed intent, and using the specified URL.
521 * This method waits for DEFERRED_STARTUP to fire as well as a subsequent
522 * idle-sync of the main looper thread, and the initial tab must either
523 * complete its load or it must crash before this method will return.
524 */
525 protected void startMainActivityFromIntent(Intent intent, String url)
526 throws InterruptedException {
527 prepareUrlIntent(intent, url);
528
529 final boolean isDocumentMode =
530 FeatureUtilities.isDocumentMode(getInstrumentation().getContext( ));
531
532 startActivityCompletely(intent);
533
534 assertTrue("Tab never selected/initialized.",
535 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
536 @Override
537 public boolean isSatisfied() {
538 return getActivity().getActivityTab() != null;
539 }
540 }));
541 Tab tab = getActivity().getActivityTab();
542
543 ChromeTabUtils.waitForTabPageLoaded(tab, (String) null);
544
545 if (!isDocumentMode && tab != null && NewTabPage.isNTPUrl(tab.getUrl())) {
546 boolean ntpReady = NewTabPageTestUtils.waitForNtpLoaded(tab);
547 if (!ntpReady && tab.isShowingSadTab()) {
548 fail("Renderer crashed before NTP finished loading. "
549 + "Look at logcat for renderer stack dump.");
550 }
551 assertTrue("Initial NTP never fully loaded.", ntpReady);
552 }
553
554 assertTrue("Deferred startup never completed",
555 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
556 @Override
557 public boolean isSatisfied() {
558 return DeferredStartupHandler.getInstance().isDeferredSt artupComplete();
559 }
560 }));
561
562 assertNotNull(tab);
563 assertNotNull(tab.getView());
564 getInstrumentation().waitForIdleSync();
565 }
566
567 /**
568 * Prepares a URL intent to start the activity.
569 * @param intent the intent to be modified
570 * @param url the URL to be used (may be null)
571 */
572 protected Intent prepareUrlIntent(Intent intent, String url) {
573 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
574 intent.setComponent(new ComponentName(getInstrumentation().getTargetCont ext(),
575 ChromeLauncherActivity.class));
576
577 if (url != null) {
578 intent.setData(Uri.parse(url));
579 }
580
581 try {
582 Method method = getClass().getMethod(getName(), (Class[]) null);
583 if (method.isAnnotationPresent(RenderProcessLimit.class)) {
584 RenderProcessLimit limit = method.getAnnotation(RenderProcessLim it.class);
585 intent.putExtra(ChromeTabbedActivity.INTENT_EXTRA_TEST_RENDER_PR OCESS_LIMIT,
586 limit.value());
587 }
588 } catch (Exception ex) {
589 // Ignore exception.
590 }
591 return intent;
592 }
593
594 /**
595 * Open an incognito tab by invoking the 'new incognito' menu item.
596 * Returns when receiving the 'PAGE_LOAD_FINISHED' notification.
597 */
598 protected void newIncognitoTabFromMenu() throws InterruptedException {
599 Tab tab = null;
600
601 if (FeatureUtilities.isDocumentMode(getInstrumentation().getContext())) {
602 final IncognitoDocumentActivity activity = ActivityUtils.waitForActi vity(
603 getInstrumentation(), IncognitoDocumentActivity.class,
604 new Runnable() {
605 @Override
606 public void run() {
607 MenuUtils.invokeCustomMenuActionSync(
608 getInstrumentation(), getActivity(),
609 R.id.new_incognito_tab_menu_id);
610 }
611 });
612
613 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
614 @Override
615 public boolean isSatisfied() {
616 return activity.getActivityTab() != null;
617 }
618 });
619
620 tab = activity.getActivityTab();
621 } else {
622 final CallbackHelper createdCallback = new CallbackHelper();
623 final CallbackHelper selectedCallback = new CallbackHelper();
624
625 TabModel incognitoTabModel = getActivity().getTabModelSelector().get Model(true);
626 TabModelObserver observer = new EmptyTabModelObserver() {
627 @Override
628 public void didAddTab(Tab tab, TabLaunchType type) {
629 createdCallback.notifyCalled();
630 }
631
632 @Override
633 public void didSelectTab(Tab tab, TabSelectionType type, int las tId) {
634 selectedCallback.notifyCalled();
635 }
636 };
637 incognitoTabModel.addObserver(observer);
638
639 MenuUtils.invokeCustomMenuActionSync(getInstrumentation(), getActivi ty(),
640 R.id.new_incognito_tab_menu_id);
641
642 try {
643 createdCallback.waitForCallback(0);
644 } catch (TimeoutException ex) {
645 fail("Never received tab created event");
646 }
647 try {
648 selectedCallback.waitForCallback(0);
649 } catch (TimeoutException ex) {
650 fail("Never received tab selected event");
651 }
652 incognitoTabModel.removeObserver(observer);
653
654 tab = getActivity().getActivityTab();
655 }
656
657 ChromeTabUtils.waitForTabPageLoaded(tab, (String) null);
658 Assert.assertTrue("NTP never fully loaded.",
659 NewTabPageTestUtils.waitForNtpLoaded(tab));
660 getInstrumentation().waitForIdleSync();
661 Log.d(TAG, "newIncognitoTabFromMenu <<");
662 }
663
664 /**
665 * New multiple incognito tabs by invoking the 'new incognito' menu item n t imes.
666 * @param n The number of tabs you want to create.
667 */
668 protected void newIncognitoTabsFromMenu(int n)
669 throws InterruptedException {
670 while (n > 0) {
671 newIncognitoTabFromMenu();
672 --n;
673 }
674 }
675
676 /**
677 * @return The number of incognito tabs currently open.
678 */
679 protected int incognitoTabsCount() {
680 return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Integer >() {
681 @Override
682 public Integer call() {
683 TabModelSelector tabModelSelector;
684 if (FeatureUtilities.isDocumentMode(getInstrumentation().getCont ext())) {
685 tabModelSelector = ChromeMobileApplication.getDocumentTabMod elSelector();
686 } else {
687 tabModelSelector = getActivity().getTabModelSelector();
688 }
689 return tabModelSelector.getModel(true).getCount();
690 }
691 });
692 }
693
694 /**
695 * Types the passed text in the omnibox to trigger a navigation. You can pas s a URL or a search
696 * term.
697 * <p>
698 * Note that this code triggers suggestions and prerendering. Unless you ar e testing these
699 * features specifically, you should use loadUrl() which is less prone to fl akyness.
700 * @param url The Url to navigate to.
701 * @return the url in the UrlBar.
702 * @throws InterruptedException
703 */
704 public String typeInOmniboxAndNavigate(final String url) throws InterruptedE xception {
705 final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
706 assertNotNull("urlBar is null", urlBar);
707 getInstrumentation().runOnMainSync(new Runnable() {
708 @Override
709 public void run() {
710 urlBar.requestFocus();
711 urlBar.setText(url);
712 }
713 });
714 final LocationBarLayout locationBar =
715 (LocationBarLayout) getActivity().findViewById(R.id.location_bar );
716 assertTrue("Omnibox Suggestions never shown.",
717 OmniboxTestUtils.waitForOmniboxSuggestions(locationBar));
718
719 Tab currentTab = getActivity().getActivityTab();
720 final CallbackHelper loadedCallback = new CallbackHelper();
721 final AtomicBoolean tabCrashReceived = new AtomicBoolean();
722 currentTab.addObserver(new EmptyTabObserver() {
723 @Override
724 public void onPageLoadFinished(Tab tab) {
725 loadedCallback.notifyCalled();
726 tab.removeObserver(this);
727 }
728
729 @Override
730 public void onCrash(Tab tab, boolean sadTabShown) {
731 tabCrashReceived.set(true);
732 tab.removeObserver(this);
733 }
734 });
735
736 // Loads the url.
737 KeyUtils.singleKeyEventView(getInstrumentation(), urlBar, KeyEvent.KEYCO DE_ENTER);
738
739 boolean pageLoadReceived = true;
740 try {
741 loadedCallback.waitForCallback(0);
742 } catch (TimeoutException ex) {
743 pageLoadReceived = false;
744 }
745
746 assertTrue("Neither PAGE_LOAD_FINISHED nor a TAB_CRASHED event was recei ved",
747 pageLoadReceived || tabCrashReceived.get());
748 getInstrumentation().waitForIdleSync();
749
750 // The title has been set before the page notification was broadcast, so it is safe to
751 // access the title.
752 return urlBar.getText().toString();
753 }
754
755 /**
756 * Looks up the Omnibox in the view hierarchy and types the specified
757 * text into it, requesting focus and using an inter-character delay of
758 * 200ms.
759 *
760 * @param oneCharAtATime Whether to type text one character at a time or all at once.
761 *
762 * @throws InterruptedException
763 */
764 public void typeInOmnibox(final String text, final boolean oneCharAtATime)
765 throws InterruptedException {
766 final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
767 assertNotNull(urlBar);
768
769 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
770 @Override
771 public void run() {
772 urlBar.requestFocus();
773 if (!oneCharAtATime) {
774 urlBar.setText(text);
775 }
776 }
777 });
778
779 if (oneCharAtATime) {
780 final Instrumentation instrumentation = getInstrumentation();
781 for (int i = 0; i < text.length(); ++i) {
782 instrumentation.sendStringSync(text.substring(i, i + 1));
783 // Let's put some delay between key strokes to simulate a user p ressing the keys.
784 Thread.sleep(20);
785 }
786 }
787 }
788
789 /**
790 * Searches for a given suggestion after typing given text in the Omnibox.
791 *
792 * @param inputText Input text to type into the Omnibox.
793 * @param displayText Suggestion text expected to be found. Passing in null ignores this field.
794 * @param url URL expected to be found. Passing in null ignores this field.
795 * @param type Type of suggestion expected to be found. Passing in null igno res this field.
796 *
797 * @throws InterruptedException
798 */
799 protected OmniboxSuggestion findOmniboxSuggestion(String inputText, String d isplayText,
800 String url, OmniboxSuggestion.Type type) throws InterruptedException {
801 long endTime = System.currentTimeMillis() + OMNIBOX_FIND_SUGGESTION_TIME OUT_MS;
802
803 // Multiple suggestion events may occur before the one we're interested in is received.
804 final CallbackHelper onSuggestionsReceivedHelper = new CallbackHelper();
805 final LocationBarLayout locationBar =
806 (LocationBarLayout) getActivity().findViewById(R.id.location_bar );
807 locationBar.setAutocompleteController(new AutocompleteController(locatio nBar) {
808 @Override
809 public void onSuggestionsReceived(
810 List<OmniboxSuggestion> suggestions,
811 String inlineAutocompleteText,
812 long currentNativeAutocompleteResult) {
813 super.onSuggestionsReceived(
814 suggestions, inlineAutocompleteText, currentNativeAutoco mpleteResult);
815 onSuggestionsReceivedHelper.notifyCalled();
816 }
817 });
818
819 try {
820 typeInOmnibox(inputText, false);
821
822 while (true) {
823 try {
824 int callbackCount = onSuggestionsReceivedHelper.getCallCount ();
825 onSuggestionsReceivedHelper.waitForCallback(
826 callbackCount, 1,
827 endTime - System.currentTimeMillis(), TimeUnit.MILLI SECONDS);
828 } catch (TimeoutException exception) {
829 return null;
830 }
831
832 // Wait for suggestions to show up.
833 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
834 @Override
835 public boolean isSatisfied() {
836 return ((LocationBarLayout) getActivity().findViewById(
837 R.id.location_bar)).getSuggestionList() != null;
838 }
839 }, 3000, 10));
840 final ListView suggestionListView = locationBar.getSuggestionLis t();
841 OmniboxResultItem popupItem = (OmniboxResultItem) suggestionList View
842 .getItemAtPosition(0);
843 OmniboxSuggestion suggestion = popupItem.getSuggestion();
844 if (suggestionListView.getCount() == 1
845 && suggestion.getDisplayText().equals(inputText)
846 && !suggestion.getDisplayText().equals(displayText)) {
847 // If there is only one suggestion and it's the same as inpu tText,
848 // wait for other suggestions before looking for the one we want.
849 CriteriaHelper.pollForCriteria(new Criteria() {
850 @Override
851 public boolean isSatisfied() {
852 return suggestionListView.getCount() > 1;
853 }
854 }, 3000, 10);
855 }
856 int count = suggestionListView.getCount();
857 for (int i = 0; i < count; i++) {
858 popupItem = (OmniboxResultItem) suggestionListView.getItemAt Position(i);
859 suggestion = popupItem.getSuggestion();
860 if (type != null && suggestion.getType() != type) {
861 continue;
862 }
863 if (displayText != null && !suggestion.getDisplayText().equa ls(displayText)) {
864 continue;
865 }
866 if (url != null && !suggestion.getUrl().equals(url)) {
867 continue;
868 }
869 return suggestion;
870 }
871 }
872 } finally {
873 locationBar.setAutocompleteController(new AutocompleteController(loc ationBar));
874 }
875 }
876
877 /**
878 * Returns the infobars being displayed by the current tab, or null if they don't exist.
879 */
880 protected List<InfoBar> getInfoBars() {
881 Tab currentTab = getActivity().getActivityTab();
882 if (currentTab == null) {
883 return null;
884 }
885
886 if (currentTab.getInfoBarContainer() != null) {
887 return currentTab.getInfoBarContainer().getInfoBars();
888 } else {
889 return null;
890 }
891 }
892
893 /**
894 * Launches the preferences menu and starts the preferences activity named f ragmentName.
895 * Returns the activity that was started.
896 */
897 protected Preferences startPreferences(String fragmentName) {
898 Context context = getInstrumentation().getTargetContext();
899 Intent intent = PreferencesLauncher.createIntentForSettingsPage(context, fragmentName);
900 Activity activity = getInstrumentation().startActivitySync(intent);
901 assertTrue(activity instanceof Preferences);
902 return (Preferences) activity;
903 }
904
905 /**
906 * Executes the given snippet of JavaScript code within the current tab. Ret urns the result of
907 * its execution in JSON format.
908 * @throws InterruptedException
909 */
910 protected String runJavaScriptCodeInCurrentTab(String code) throws Interrupt edException,
911 TimeoutException {
912 return JavaScriptUtils.executeJavaScriptAndWaitForResult(
913 getActivity().getCurrentContentViewCore().getWebContents(), code );
914 }
915
916 @Override
917 protected void runTest() throws Throwable {
918 boolean shouldRun = true;
919 String perfTagAnalysisString = "";
920 try {
921 shouldRun = RestrictedInstrumentationTestCase.shouldRunTest(this);
922 perfTagAnalysisString = setupPotentialPerfTest(shouldRun);
923 } catch (Exception e) {
924 // eat the exception here; super.runTest() will catch it again and h andle it properly
925 }
926
927 if (shouldRun) super.runTest();
928
929 endPerfTest(perfTagAnalysisString);
930 }
931
932 /**
933 * Waits till the ContentViewCore receives the expected page scale factor
934 * from the compositor and asserts that this happens.
935 *
936 * Upstream {@code ContentShellTestBase} has the same copy. Also, this is a temporary solution
937 * for waiting a page load. Please refer to the bug at the upstream function .
938 */
939 protected void assertWaitForPageScaleFactorMatch(final float expectedScale)
940 throws InterruptedException {
941 boolean scaleFactorMatch = CriteriaHelper.pollForCriteria(new Criteria() {
942 @Override
943 public boolean isSatisfied() {
944 return getActivity().getCurrentContentViewCore().getScale()
945 == expectedScale;
946 }
947 });
948 assertTrue("Expecting scale factor of: " + expectedScale + ", got: "
949 + getActivity().getCurrentContentViewCore().getScale(), scal eFactorMatch);
950 }
951
952 /**
953 * This method creates a special string that tells the python test harness w hat
954 * trace calls to track for this particular test run. It can support multip le trace calls for
955 * each test and will make a new graph entry for all of them. It should be noted that this
956 * method eats all exceptions. This is so that it can never be the cause of a test failure.
957 * We still need to call this method even if we know the test will not run ( ie: willTestRun is
958 * false). This is because this method lets the python test harness know no t to expect any
959 * perf output in this case. In the case that the autoTrace parameter is se t for the current
960 * test method, this will also start the PerfTrace facility automatically.
961 *
962 * @param willTestRun Whether or not this test will actually be run.
963 * @return A specially formatted string that contains which JSON perf marker s to look at. This
964 * will be analyzed by the perf test harness.
965 */
966 @SuppressFBWarnings({
967 "REC_CATCH_EXCEPTION",
968 "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE",
969 })
970 private String setupPotentialPerfTest(boolean willTestRun) {
971 File perfFile = getInstrumentation().getTargetContext().getFileStreamPat h(
972 PERF_OUTPUT_FILE);
973 perfFile.delete();
974 PerfTraceEvent.setOutputFile(perfFile);
975
976 String perfAnnotationString = "";
977
978 try {
979 Method method = getClass().getMethod(getName(), (Class[]) null);
980 PerfTest annotation = method.getAnnotation(PerfTest.class);
981 if (annotation != null) {
982 StringBuilder annotationData = new StringBuilder();
983 annotationData.append(String.format(PERF_ANNOTATION_FORMAT, meth od.getName()));
984
985 if (!willTestRun) {
986 annotationData.append(PERF_NORUN_TAG);
987 } else {
988 // Grab the minimum number of trace calls we will track (if names(),
989 // graphNames(), and graphValues() do not have the same numb er of elements, we
990 // will track as many as we can given the data available.
991 final int maxIndex = Math.min(annotation.traceNames().length , Math.min(
992 annotation.graphNames().length, annotation.seriesNam es().length));
993
994 List<String> allNames = new LinkedList<String>();
995 for (int i = 0; i < maxIndex; ++i) {
996 // Prune out all of ',' and ';' from the strings. Repla ce them with '-'.
997 String name = annotation.traceNames()[i].replaceAll("[,; ]", "-");
998 allNames.add(name);
999 String graphName = annotation.graphNames()[i].replaceAll ("[,;]", "-");
1000 String seriesName = annotation.seriesNames()[i].replaceA ll("[,;]", "-");
1001 if (annotation.traceTiming()) {
1002 annotationData.append(name).append(",")
1003 .append(graphName).append(",")
1004 .append(seriesName).append(';');
1005 }
1006
1007 // If memory tracing is enabled, add an additional graph for each one
1008 // defined to track timing perf that will track the corr esponding memory
1009 // usage.
1010 // Keep the series name the same, but just append a memo ry identifying
1011 // prefix to the graph.
1012 if (annotation.traceMemory()) {
1013 String memName = PerfTraceEvent.makeMemoryTraceNameF romTimingName(name);
1014 String memGraphName = PerfTraceEvent.makeSafeTraceNa me(
1015 graphName, MEMORY_TRACE_GRAPH_SUFFIX);
1016 annotationData.append(memName).append(",")
1017 .append(memGraphName).append(",")
1018 .append(seriesName).append(';');
1019 allNames.add(memName);
1020 }
1021 }
1022 // We only record perf trace events for the names explicitly listed.
1023 PerfTraceEvent.setFilter(allNames);
1024
1025 // Figure out if we should automatically start or stop the t race.
1026 if (annotation.autoTrace()) {
1027 PerfTraceEvent.setEnabled(true);
1028 }
1029 PerfTraceEvent.setTimingTrackingEnabled(annotation.traceTimi ng());
1030 PerfTraceEvent.setMemoryTrackingEnabled(annotation.traceMemo ry());
1031 }
1032
1033 perfAnnotationString = annotationData.toString();
1034 }
1035 } catch (Exception ex) {
1036 // Eat exception here.
1037 }
1038
1039 return perfAnnotationString;
1040 }
1041
1042 /**
1043 * This handles cleaning up the performance component of this test if it was a UI Perf test.
1044 * This includes potentially shutting down PerfTraceEvent. This method eats all exceptions so
1045 * that it can never be the cause of a test failure. The test harness will wait for
1046 * {@code perfTagAnalysisString} to show up in the logcat before processing the JSON perf file,
1047 * giving this method the chance to flush and dump the performance data befo re the harness reads
1048 * it.
1049 *
1050 * @param perfTagAnalysisString A specially formatted string that tells the perf test harness
1051 * which perf tags to analyze.
1052 */
1053 private void endPerfTest(String perfTagAnalysisString) {
1054 try {
1055 Method method = getClass().getMethod(getName(), (Class[]) null);
1056 PerfTest annotation = method.getAnnotation(PerfTest.class);
1057 if (annotation != null) {
1058 if (PerfTraceEvent.enabled()) {
1059 PerfTraceEvent.setEnabled(false);
1060 }
1061
1062 System.out.println(perfTagAnalysisString);
1063 }
1064 } catch (Exception ex) {
1065 // Eat exception here.
1066 }
1067 }
1068 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698