Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / shell / android / javatests / src / org / chromium / content_shell_apk / ContentShellTestBase.java
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 static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
8
9 import android.content.ComponentName;
10 import android.content.Intent;
11 import android.net.Uri;
12 import android.test.ActivityInstrumentationTestCase2;
13 import android.text.TextUtils;
14 import android.view.ViewGroup;
15
16 import org.chromium.base.ThreadUtils;
17 import org.chromium.base.test.util.UrlUtils;
18 import org.chromium.content.browser.ContentView;
19 import org.chromium.content.browser.ContentViewCore;
20 import org.chromium.content.browser.test.util.CallbackHelper;
21 import org.chromium.content.browser.test.util.Criteria;
22 import org.chromium.content.browser.test.util.CriteriaHelper;
23 import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
24 import org.chromium.content_public.browser.LoadUrlParams;
25 import org.chromium.content_public.browser.NavigationController;
26 import org.chromium.content_public.browser.WebContents;
27 import org.chromium.content_shell.Shell;
28
29 import java.lang.annotation.ElementType;
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 import java.lang.annotation.Target;
33 import java.lang.reflect.Method;
34 import java.util.concurrent.TimeUnit;
35 import java.util.concurrent.atomic.AtomicBoolean;
36
37 /**
38  * Base test class for all ContentShell based tests.
39  */
40 public class ContentShellTestBase extends ActivityInstrumentationTestCase2<ContentShellActivity> {
41
42     /** The maximum time the waitForActiveShellToBeDoneLoading method will wait. */
43     private static final long WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT = scaleTimeout(10000);
44
45     protected static final long WAIT_PAGE_LOADING_TIMEOUT_SECONDS = scaleTimeout(15);
46
47     public ContentShellTestBase() {
48         super(ContentShellActivity.class);
49     }
50
51     /**
52      * Starts the ContentShell activity and loads the given URL.
53      * The URL can be null, in which case will default to ContentShellActivity.DEFAULT_SHELL_URL.
54      */
55     protected ContentShellActivity launchContentShellWithUrl(String url) {
56         return launchContentShellWithUrlAndCommandLineArgs(url, null);
57     }
58
59     /**
60      * Starts the ContentShell activity appending the provided command line arguments
61      * and loads the given URL. The URL can be null, in which case will default to
62      * ContentShellActivity.DEFAULT_SHELL_URL.
63      */
64     protected ContentShellActivity launchContentShellWithUrlAndCommandLineArgs(String url,
65             String[] commandLineArgs) {
66         Intent intent = new Intent(Intent.ACTION_MAIN);
67         intent.addCategory(Intent.CATEGORY_LAUNCHER);
68         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
69         if (url != null) intent.setData(Uri.parse(url));
70         intent.setComponent(new ComponentName(getInstrumentation().getTargetContext(),
71                 ContentShellActivity.class));
72         if (commandLineArgs != null) {
73             intent.putExtra(ContentShellActivity.COMMAND_LINE_ARGS_KEY, commandLineArgs);
74         }
75         setActivityIntent(intent);
76         return getActivity();
77     }
78
79     // TODO(cjhopman): These functions are inconsistent with launchContentShell***. Should be
80     // startContentShell*** and should use the url exactly without the getTestFileUrl call. Possibly
81     // these two ways of starting the activity (launch* and start*) should be merged into one.
82     /**
83      * Starts the content shell activity with the provided test url.
84      * The url is synchronously loaded.
85      * @param url Test url to load.
86      */
87     protected void startActivityWithTestUrl(String url) throws Throwable {
88         launchContentShellWithUrl(UrlUtils.getTestFileUrl(url));
89         assertNotNull(getActivity());
90         assertTrue(waitForActiveShellToBeDoneLoading());
91         assertEquals(UrlUtils.getTestFileUrl(url), getContentViewCore().getWebContents().getUrl());
92     }
93
94     /**
95      * Starts the content shell activity with the provided test url and optional command line
96      * arguments to append.
97      * The url is synchronously loaded.
98      * @param url Test url to load.
99      * @param commandLineArgs Optional command line args to append when launching the activity.
100      */
101     protected void startActivityWithTestUrlAndCommandLineArgs(
102             String url, String[] commandLineArgs) throws Throwable {
103         launchContentShellWithUrlAndCommandLineArgs(
104                 UrlUtils.getTestFileUrl(url), commandLineArgs);
105         assertNotNull(getActivity());
106         assertTrue(waitForActiveShellToBeDoneLoading());
107     }
108
109     /**
110      * Returns the current ContentViewCore or null if there is no ContentView.
111      */
112     protected ContentViewCore getContentViewCore() {
113         return getActivity().getActiveShell().getContentViewCore();
114     }
115
116     /**
117      * Returns the WebContents of this Shell.
118      */
119     protected WebContents getWebContents() {
120         return getActivity().getActiveShell().getWebContents();
121     }
122
123     /**
124      * Waits for the Active shell to finish loading.  This times out after
125      * WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT milliseconds and it shouldn't be used for long
126      * loading pages. Instead it should be used more for test initialization. The proper way
127      * to wait is to use a TestCallbackHelperContainer after the initial load is completed.
128      * @return Whether or not the Shell was actually finished loading.
129      * @throws InterruptedException
130      */
131     protected boolean waitForActiveShellToBeDoneLoading() throws InterruptedException {
132         final ContentShellActivity activity = getActivity();
133
134         // Wait for the Content Shell to be initialized.
135         return CriteriaHelper.pollForCriteria(new Criteria() {
136             @Override
137             public boolean isSatisfied() {
138                 try {
139                     final AtomicBoolean isLoaded = new AtomicBoolean(false);
140                     runTestOnUiThread(new Runnable() {
141                         @Override
142                         public void run() {
143                             Shell shell = activity.getActiveShell();
144                             if (shell != null) {
145                                 // There are two cases here that need to be accounted for.
146                                 // The first is that we've just created a Shell and it isn't
147                                 // loading because it has no URL set yet.  The second is that
148                                 // we've set a URL and it actually is loading.
149                                 isLoaded.set(!shell.isLoading()
150                                         && !TextUtils.isEmpty(shell.getContentViewCore()
151                                                 .getWebContents().getUrl()));
152                             } else {
153                                 isLoaded.set(false);
154                             }
155                         }
156                     });
157
158                     return isLoaded.get();
159                 } catch (Throwable e) {
160                     return false;
161                 }
162             }
163         }, WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
164     }
165
166     /**
167      * Loads a URL in the specified content view.
168      *
169      * @param viewCore The content view core to load the URL in.
170      * @param callbackHelperContainer The callback helper container used to monitor progress.
171      * @param params The URL params to use.
172      */
173     protected void loadUrl(
174             final NavigationController navigationController,
175             TestCallbackHelperContainer callbackHelperContainer,
176             final LoadUrlParams params) throws Throwable {
177         handleBlockingCallbackAction(
178                 callbackHelperContainer.getOnPageFinishedHelper(),
179                 new Runnable() {
180                     @Override
181                     public void run() {
182                         navigationController.loadUrl(params);
183                     }
184                 });
185     }
186
187     /**
188      * Handles performing an action on the UI thread that will return when the specified callback
189      * is incremented.
190      *
191      * @param callbackHelper The callback helper that will be blocked on.
192      * @param action The action to be performed on the UI thread.
193      */
194     protected void handleBlockingCallbackAction(
195             CallbackHelper callbackHelper, Runnable action) throws Throwable {
196         int currentCallCount = callbackHelper.getCallCount();
197         runTestOnUiThread(action);
198         callbackHelper.waitForCallback(
199                 currentCallCount, 1, WAIT_PAGE_LOADING_TIMEOUT_SECONDS, TimeUnit.SECONDS);
200     }
201
202     // TODO(aelias): This method needs to be removed once http://crbug.com/179511 is fixed.
203     // Meanwhile, we have to wait if the page has the <meta viewport> tag.
204     /**
205      * Waits till the ContentViewCore receives the expected page scale factor
206      * from the compositor and asserts that this happens.
207      */
208     protected void assertWaitForPageScaleFactorMatch(final float expectedScale)
209             throws InterruptedException {
210         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
211             @Override
212             public boolean isSatisfied() {
213                 return getContentViewCore().getScale() == expectedScale;
214             }
215         }));
216     }
217
218     /**
219      * Replaces the {@link ContentViewCore#mContainerView} with a newly created
220      * {@link ContentView}.
221      */
222     @SuppressWarnings("javadoc")
223     protected void replaceContainerView() throws Throwable {
224         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
225                 @Override
226             public void run() {
227                 ContentView cv = ContentView.newInstance(getActivity(), getContentViewCore());
228                 ((ViewGroup) getContentViewCore().getContainerView().getParent()).addView(cv);
229                 getContentViewCore().setContainerView(cv);
230                 getContentViewCore().setContainerViewInternals(cv);
231                 cv.requestFocus();
232             }
233         });
234     }
235
236     @Override
237     protected void runTest() throws Throwable {
238         super.runTest();
239         try {
240             Method method = getClass().getMethod(getName(), (Class[]) null);
241             if (method.isAnnotationPresent(RerunWithUpdatedContainerView.class)) {
242                 replaceContainerView();
243                 super.runTest();
244             }
245         } catch (Throwable e) {
246             throw new Throwable("@RerunWithUpdatedContainerView failed."
247                     + " See ContentShellTestBase#runTest.", e);
248         }
249     }
250
251     /**
252      * Annotation for tests that should be executed a second time after replacing
253      * the ContentViewCore's container view (see {@link #runTest()}).
254      *
255      * <p>Please note that {@link #setUp()} is only invoked once before both runs,
256      * and that any state changes produced by the first run are visible to the second run.
257      */
258     @Target(ElementType.METHOD)
259     @Retention(RetentionPolicy.RUNTIME)
260     public @interface RerunWithUpdatedContainerView {
261     }
262 }