1 // Copyright 2012 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.content_shell_apk; 6 7 import android.content.ComponentName; 8 import android.content.Intent; 9 import android.net.Uri; 10 import android.test.ActivityInstrumentationTestCase2; 11 import android.text.TextUtils; 12 13 import static org.chromium.base.test.util.ScalableTimeout.ScaleTimeout; 14 15 import org.chromium.base.test.util.UrlUtils; 16 import org.chromium.content.browser.ContentView; 17 import org.chromium.content.browser.ContentViewCore; 18 import org.chromium.content.browser.LoadUrlParams; 19 import org.chromium.content.browser.test.util.CallbackHelper; 20 import org.chromium.content.browser.test.util.Criteria; 21 import org.chromium.content.browser.test.util.CriteriaHelper; 22 import org.chromium.content.browser.test.util.TestCallbackHelperContainer; 23 import org.chromium.content_shell.Shell; 24 25 import java.util.concurrent.TimeUnit; 26 import java.util.concurrent.atomic.AtomicBoolean; 27 28 /** 29 * Base test class for all ContentShell based tests. 30 */ 31 public class ContentShellTestBase extends ActivityInstrumentationTestCase2<ContentShellActivity> { 32 33 /** The maximum time the waitForActiveShellToBeDoneLoading method will wait. */ 34 private static final long WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT = ScaleTimeout(10000); 35 36 protected static final long WAIT_PAGE_LOADING_TIMEOUT_SECONDS = ScaleTimeout(15); 37 38 public ContentShellTestBase() { 39 super(ContentShellActivity.class); 40 } 41 42 /** 43 * Starts the ContentShell activity and loads the given URL. 44 * The URL can be null, in which case will default to ContentShellActivity.DEFAULT_SHELL_URL. 45 */ 46 protected ContentShellActivity launchContentShellWithUrl(String url) { 47 return launchContentShellWithUrlAndCommandLineArgs(url, null); 48 } 49 50 /** 51 * Starts the ContentShell activity appending the provided command line arguments 52 * and loads the given URL. The URL can be null, in which case will default to 53 * ContentShellActivity.DEFAULT_SHELL_URL. 54 */ 55 protected ContentShellActivity launchContentShellWithUrlAndCommandLineArgs(String url, 56 String[] commandLineArgs) { 57 Intent intent = new Intent(Intent.ACTION_MAIN); 58 intent.addCategory(Intent.CATEGORY_LAUNCHER); 59 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 60 if (url != null) intent.setData(Uri.parse(url)); 61 intent.setComponent(new ComponentName(getInstrumentation().getTargetContext(), 62 ContentShellActivity.class)); 63 if (commandLineArgs != null) { 64 intent.putExtra(ContentShellActivity.COMMAND_LINE_ARGS_KEY, commandLineArgs); 65 } 66 setActivityIntent(intent); 67 return getActivity(); 68 } 69 70 // TODO(cjhopman): These functions are inconsistent with launchContentShell***. Should be 71 // startContentShell*** and should use the url exactly without the getTestFileUrl call. Possibly 72 // these two ways of starting the activity (launch* and start*) should be merged into one. 73 /** 74 * Starts the content shell activity with the provided test url. 75 * The url is synchronously loaded. 76 * @param url Test url to load. 77 */ 78 protected void startActivityWithTestUrl(String url) throws Throwable { 79 launchContentShellWithUrl(UrlUtils.getTestFileUrl(url)); 80 assertNotNull(getActivity()); 81 assertTrue(waitForActiveShellToBeDoneLoading()); 82 assertEquals(UrlUtils.getTestFileUrl(url), getContentView().getUrl()); 83 } 84 85 /** 86 * Starts the content shell activity with the provided test url and optional command line 87 * arguments to append. 88 * The url is synchronously loaded. 89 * @param url Test url to load. 90 * @param commandLineArgs Optional command line args to append when launching the activity. 91 */ 92 protected void startActivityWithTestUrlAndCommandLineArgs( 93 String url, String[] commandLineArgs) throws Throwable { 94 launchContentShellWithUrlAndCommandLineArgs( 95 UrlUtils.getTestFileUrl(url), commandLineArgs); 96 assertNotNull(getActivity()); 97 assertTrue(waitForActiveShellToBeDoneLoading()); 98 } 99 100 /** 101 * Returns the current ContentView. 102 */ 103 protected ContentView getContentView() { 104 return getActivity().getActiveShell().getContentView(); 105 } 106 107 /** 108 * Returns the current ContentViewCore or null if there is no ContentView. 109 */ 110 protected ContentViewCore getContentViewCore() { 111 return getContentView() == null ? null : getContentView().getContentViewCore(); 112 } 113 114 /** 115 * Waits for the Active shell to finish loading. This times out after 116 * WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT milliseconds and it shouldn't be used for long 117 * loading pages. Instead it should be used more for test initialization. The proper way 118 * to wait is to use a TestCallbackHelperContainer after the initial load is completed. 119 * @return Whether or not the Shell was actually finished loading. 120 * @throws InterruptedException 121 */ 122 protected boolean waitForActiveShellToBeDoneLoading() throws InterruptedException { 123 final ContentShellActivity activity = getActivity(); 124 125 // Wait for the Content Shell to be initialized. 126 return CriteriaHelper.pollForCriteria(new Criteria() { 127 @Override 128 public boolean isSatisfied() { 129 try { 130 final AtomicBoolean isLoaded = new AtomicBoolean(false); 131 runTestOnUiThread(new Runnable() { 132 @Override 133 public void run() { 134 Shell shell = activity.getActiveShell(); 135 if (shell != null) { 136 // There are two cases here that need to be accounted for. 137 // The first is that we've just created a Shell and it isn't 138 // loading because it has no URL set yet. The second is that 139 // we've set a URL and it actually is loading. 140 isLoaded.set(!shell.isLoading() 141 && !TextUtils.isEmpty(shell.getContentView().getUrl())); 142 } else { 143 isLoaded.set(false); 144 } 145 } 146 }); 147 148 return isLoaded.get(); 149 } catch (Throwable e) { 150 return false; 151 } 152 } 153 }, WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL); 154 } 155 156 /** 157 * Loads a URL in the specified content view. 158 * 159 * @param contentView The content view to load the URL in. 160 * @param callbackHelperContainer The callback helper container used to monitor progress. 161 * @param params The URL params to use. 162 */ 163 protected void loadUrl( 164 final ContentView contentView, TestCallbackHelperContainer callbackHelperContainer, 165 final LoadUrlParams params) throws Throwable { 166 handleBlockingCallbackAction( 167 callbackHelperContainer.getOnPageFinishedHelper(), 168 new Runnable() { 169 @Override 170 public void run() { 171 contentView.loadUrl(params); 172 } 173 }); 174 } 175 176 /** 177 * Handles performing an action on the UI thread that will return when the specified callback 178 * is incremented. 179 * 180 * @param callbackHelper The callback helper that will be blocked on. 181 * @param action The action to be performed on the UI thread. 182 */ 183 protected void handleBlockingCallbackAction( 184 CallbackHelper callbackHelper, Runnable action) throws Throwable { 185 int currentCallCount = callbackHelper.getCallCount(); 186 runTestOnUiThread(action); 187 callbackHelper.waitForCallback( 188 currentCallCount, 1, WAIT_PAGE_LOADING_TIMEOUT_SECONDS, TimeUnit.SECONDS); 189 } 190 191 // TODO(aelias): This method needs to be removed once http://crbug.com/179511 is fixed. 192 // Meanwhile, we have to wait if the page has the <meta viewport> tag. 193 /** 194 * Waits till the ContentViewCore receives the expected page scale factor 195 * from the compositor and asserts that this happens. 196 */ 197 protected void assertWaitForPageScaleFactorMatch(final float expectedScale) 198 throws InterruptedException { 199 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { 200 @Override 201 public boolean isSatisfied() { 202 return getContentViewCore().getScale() == expectedScale; 203 } 204 })); 205 } 206 } 207