1 // 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 package org.chromium.chrome.shell; 6 7 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; 8 9 import android.content.ComponentName; 10 import android.content.Context; 11 import android.content.Intent; 12 import android.net.Uri; 13 import android.test.ActivityInstrumentationTestCase2; 14 import android.text.TextUtils; 15 import android.util.Log; 16 17 import org.chromium.base.CommandLine; 18 import org.chromium.base.ThreadUtils; 19 import org.chromium.base.library_loader.ProcessInitException; 20 import org.chromium.chrome.test.util.ApplicationData; 21 import org.chromium.content.browser.BrowserStartupController; 22 import org.chromium.content.browser.test.util.Criteria; 23 import org.chromium.content.browser.test.util.CriteriaHelper; 24 25 import java.util.concurrent.atomic.AtomicBoolean; 26 27 /** 28 * Base test class for all ChromeShell based tests. 29 */ 30 public class ChromeShellTestBase extends ActivityInstrumentationTestCase2<ChromeShellActivity> { 31 /** The maximum time the waitForActiveShellToBeDoneLoading method will wait. */ 32 private static final long WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT = scaleTimeout(10000); 33 private static final String TAG = "ChromeShellTestBase"; 34 35 public ChromeShellTestBase() { 36 super(ChromeShellActivity.class); 37 } 38 39 protected static void startChromeBrowserProcessSync(final Context targetContext) { 40 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 41 @Override 42 public void run() { 43 CommandLine.initFromFile("/data/local/tmp/chrome-shell-command-line"); 44 try { 45 BrowserStartupController.get(targetContext).startBrowserProcessesSync( 46 BrowserStartupController.MAX_RENDERERS_LIMIT); 47 } catch (ProcessInitException e) { 48 Log.e(TAG, "Unable to load native library.", e); 49 fail("Unable to load native library"); 50 } 51 } 52 }); 53 } 54 55 /** 56 * Starts the {@link ChromeShellActivity} and loads the given URL. 57 */ 58 protected ChromeShellActivity launchChromeShellWithUrl(String url) { 59 Intent intent = new Intent(Intent.ACTION_MAIN); 60 intent.addCategory(Intent.CATEGORY_LAUNCHER); 61 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 62 if (url != null) intent.setData(Uri.parse(url)); 63 intent.setComponent(new ComponentName(getInstrumentation().getTargetContext(), 64 ChromeShellActivity.class)); 65 setActivityIntent(intent); 66 return getActivity(); 67 } 68 69 /** 70 * Starts the {@link ChromeShellActivity} and loads a blank page. 71 */ 72 protected ChromeShellActivity launchChromeShellWithBlankPage() { 73 return launchChromeShellWithUrl("about:blank"); 74 } 75 76 /** 77 * Waits for the Active shell to finish loading. This times out after 78 * WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT milliseconds and it shouldn't be used for long 79 * loading pages. Instead it should be used more for test initialization. The proper way 80 * to wait is to use a TestCallbackHelperContainer after the initial load is completed. 81 * @return Whether or not the Shell was actually finished loading. 82 * @throws InterruptedException 83 */ 84 protected boolean waitForActiveShellToBeDoneLoading() throws InterruptedException { 85 final ChromeShellActivity activity = getActivity(); 86 87 // Wait for the Content Shell to be initialized. 88 return CriteriaHelper.pollForCriteria(new Criteria() { 89 @Override 90 public boolean isSatisfied() { 91 try { 92 final AtomicBoolean isLoaded = new AtomicBoolean(false); 93 runTestOnUiThread(new Runnable() { 94 @Override 95 public void run() { 96 ChromeShellTab tab = activity.getActiveTab(); 97 if (tab != null) { 98 isLoaded.set(!tab.isLoading() 99 && !TextUtils.isEmpty(tab.getContentViewCore().getUrl())); 100 } else { 101 isLoaded.set(false); 102 } 103 } 104 }); 105 106 return isLoaded.get(); 107 } catch (Throwable e) { 108 return false; 109 } 110 } 111 }, WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL); 112 } 113 114 /** 115 * Clear all files and folders in the ChromeShell's application directory except 'lib'. 116 * 117 * The 'cache' directory is recreated as an empty directory. 118 * 119 * @return Whether clearing the application data was successful. 120 */ 121 protected boolean clearAppData() throws InterruptedException { 122 return ApplicationData.clearAppData(getInstrumentation().getTargetContext()); 123 } 124 125 /** 126 * Navigates the currently active tab to a sanitized version of {@code url}. 127 * @param url The potentially unsanitized URL to navigate to. 128 */ 129 public void loadUrlWithSanitization(final String url) throws InterruptedException { 130 getInstrumentation().runOnMainSync(new Runnable() { 131 @Override 132 public void run() { 133 getActivity().getActiveTab().loadUrlWithSanitization(url); 134 } 135 }); 136 waitForActiveShellToBeDoneLoading(); 137 } 138 139 // TODO(aelias): This method needs to be removed once http://crbug.com/179511 is fixed. 140 // Meanwhile, we have to wait if the page has the <meta viewport> tag. 141 /** 142 * Waits till the ContentViewCore receives the expected page scale factor 143 * from the compositor and asserts that this happens. 144 */ 145 protected void assertWaitForPageScaleFactorMatch(final float expectedScale) 146 throws InterruptedException { 147 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { 148 @Override 149 public boolean isSatisfied() { 150 return getActivity().getActiveTab().getContentViewCore().getScale() == 151 expectedScale; 152 } 153 })); 154 } 155 } 156