1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Copyright (c) 2013 Intel Corporation. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
6 package org.xwalk.test.util;
8 import android.annotation.TargetApi;
9 import android.app.Activity;
10 import android.content.Context;
11 import android.content.Intent;
12 import android.os.Build;
13 import android.test.ActivityInstrumentationTestCase2;
15 import java.io.IOException;
16 import java.lang.Process;
17 import java.lang.Runtime;
18 import java.lang.StringBuffer;
19 import java.util.concurrent.atomic.AtomicReference;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22 import java.util.Timer;
23 import java.util.TimerTask;
25 import org.chromium.content.browser.test.util.Criteria;
26 import org.chromium.content.browser.test.util.CriteriaHelper;
28 * Test helper for Runtime client APIs.
30 public class RuntimeClientApiTestBase<T extends Activity> {
31 private XWalkRuntimeClientTestUtilBase mTestUtil;
32 private ActivityInstrumentationTestCase2<T> mTestCase;
33 private Timer mTimer = new Timer();
34 private String mSocketName;
35 private String mUrl = "file:///android_asset/index.html";
43 public RuntimeClientApiTestBase(XWalkRuntimeClientTestUtilBase testUtil,
44 ActivityInstrumentationTestCase2<T> testCase) {
49 public String getTitleOnUiThread() {
50 mTestCase.getInstrumentation().waitForIdleSync();
51 final AtomicReference<String> title = new AtomicReference<String>();
52 mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
55 title.set(mTestUtil.getTestedView().getTitleForTest());
61 public void compareTitle(String prevTitle, String title, String msg, Relation relation) {
62 if (prevTitle == null) prevTitle = "";
63 if (title == null) title = "";
67 mTestCase.assertTrue(msg, title.equals(prevTitle));
70 mTestCase.assertTrue(msg, title.compareTo(prevTitle) > 0);
77 public void waitForTimerFinish(int timer) throws Throwable {
78 Object notify = new Object();
79 synchronized (notify) {
80 NotifyTask testTask = new NotifyTask(notify);
81 mTimer.schedule(testTask, timer);
86 public class NotifyTask extends TimerTask {
89 public NotifyTask(Object obj) {
102 public void sendBroadCast(Activity activity, Context context, String extra) throws Throwable {
103 mSocketName = activity.getPackageName();
104 Intent intent = new Intent().setAction("org.xwalk.intent").putExtra("remotedebugging", extra);
105 context.sendBroadcast(intent);
108 public int getSocketNameIndex() {
110 // Try to find the abstract socket name opened for remote debugging
111 // from the output of 'cat /proc/net/unix' command. Actually, the
112 // best way to test DevToolsServer is to connect the server socket
113 // by android.net.LocalSocket and communicate with it (e.g. send
114 // http request to query all inspectable pages). However, since
115 // the socket of devtools server is enforced to be connected only
116 // if the user is authenticated. On a non-rooted device, it only
117 // authenticates 'shell' user which is reserved for adb connecction.
118 Process process = Runtime.getRuntime().exec("cat /proc/net/unix");
120 final int BUFFER_SIZE = 1024;
121 byte[] bytes = new byte[BUFFER_SIZE];
122 StringBuffer buffer = new StringBuffer(4 * BUFFER_SIZE);
124 int bytesReceived = process.getInputStream().read(bytes, 0, BUFFER_SIZE);
125 while (bytesReceived > 0) {
126 String tmp = new String(bytes, 0, bytesReceived);
128 bytesReceived = process.getInputStream().read(bytes, 0, BUFFER_SIZE);
133 String contents = new String(buffer);
134 int index = contents.indexOf(mSocketName + "_devtools_remote");
136 } catch (IOException e) {
137 mTestCase.fail("error occurs in testDevTools: " + e);
142 // For loadAppFromUrl.
143 public void testLoadAppFromUrl() throws Throwable {
144 final String expectedTitle = "Crosswalk Sample Application";
146 mTestUtil.loadUrlSync("file:///android_asset/index.html");
147 mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
150 String title = mTestUtil.getTestedView().getTitleForTest();
151 mTestCase.assertEquals(expectedTitle, title);
156 // For loadAppFromManifest.
157 public void testLoadAppFromManifest() throws Throwable {
158 final String expectedTitle = "Crosswalk Sample Application";
160 mTestUtil.loadManifestSync("file:///android_asset/manifest.json");
162 mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
165 String title = mTestUtil.getTestedView().getTitleForTest();
166 mTestCase.assertEquals(expectedTitle, title);
172 public void testCSP() throws Throwable {
173 final String originalTitle = "Original Title";
174 final String newTitle = "New Title";
175 final String host = mTestCase.getActivity().getPackageName();
176 mTestUtil.loadManifestSync("file:///android_asset/www/manifest_self.json");
177 mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
180 String title = mTestUtil.getTestedView().getTitleForTest();
181 mTestCase.assertEquals(originalTitle, title);
185 mTestUtil.loadManifestSync("app://" + host + "/manifest_self.json");
187 mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
190 String title = mTestUtil.getTestedView().getTitleForTest();
191 mTestCase.assertEquals(originalTitle, title);
195 mTestUtil.loadManifestSync("file:///android_asset/www/manifest_inline_script.json");
196 mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
199 String title = mTestUtil.getTestedView().getTitleForTest();
200 mTestCase.assertEquals(newTitle, title);
204 mTestUtil.loadManifestSync("app://" + host + "/manifest_inline_script.json");
206 mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
209 String title = mTestUtil.getTestedView().getTitleForTest();
210 mTestCase.assertEquals(newTitle, title);
215 // For internal extension implementation of Contacts.
216 public void testContacts() throws Throwable {
217 String title = mTestUtil.loadAssetFileAndWaitForTitle("contacts.html");
218 mTestCase.assertEquals("Pass", title);
221 // For internal extension implementation of DeviceCapabilities.
222 public void testDeviceCapabilities() throws Throwable {
223 String title = mTestUtil.loadAssetFileAndWaitForTitle("device_capabilities.html");
224 mTestCase.assertEquals("Pass", title);
227 // For internal extension implementation of ScreenOrientation.
228 public void testScreenOrientation() throws Throwable {
229 String title = mTestUtil.loadAssetFileAndWaitForTitle("screen_orientation.html");
230 mTestCase.assertEquals("Pass", title);
233 // For internal extension implementation of Presentation.
234 public void testPresentationDisplayAvailable() throws Throwable {
235 String title = mTestUtil.loadAssetFileAndWaitForTitle("displayAvailableTest.html");
236 if (isSecondaryDisplayAvailable()) {
237 mTestCase.assertEquals("Available", title);
239 mTestCase.assertEquals("Unavailable", title);
243 // For external extension mechanism: async mode.
244 public void testExternalExtensionAsync() throws Throwable {
245 String title = mTestUtil.loadAssetFileAndWaitForTitle("echo.html");
246 mTestCase.assertEquals("Pass", title);
249 // For external extension mechanism: sync mode.
250 public void testExternalExtensionSync() throws Throwable {
251 mTestUtil.loadAssetFile("echoSync.html");
252 mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
255 String title = mTestUtil.getTestedView().getTitleForTest();
256 mTestCase.assertEquals("Pass", title);
261 // For internal extension implementation of Messaging.
262 public void testMessaging() throws Throwable {
263 String title = mTestUtil.loadAssetFileAndWaitForTitle("messaging_mini.html");
264 mTestCase.assertEquals("Pass", title);
266 // For onPause, onResume.
267 public void testPauseAndResume() throws Throwable {
269 String prevTitle = "";
270 String nextTitle = "";
273 title = mTestUtil.loadAssetFileAndWaitForTitle("timer.html");
274 mTestCase.assertNotNull(title);
277 msg = "The second title should be equal to the first title.";
278 // wait for the pause is finished.
279 waitForTimerFinish(5000);
280 prevTitle = getTitleOnUiThread();
281 waitForTimerFinish(200);
282 nextTitle = getTitleOnUiThread();
283 compareTitle(prevTitle, nextTitle, msg, Relation.EQUAL);
285 mTestUtil.onResume();
286 msg = "The second title should be greater than the first title.";
287 // wait for the resume is finished.
288 waitForTimerFinish(5000);
289 prevTitle = getTitleOnUiThread();
290 waitForTimerFinish(200);
291 nextTitle = getTitleOnUiThread();
292 compareTitle(prevTitle, nextTitle, msg, Relation.GREATERTHAN);
295 // For enable the remote debugging.
296 public void testEnableRemoteDebugging(Activity activity, Context context) throws Throwable {
297 sendBroadCast(activity, context, "true");
298 mTestUtil.loadUrlSync(mUrl);
299 int index = getSocketNameIndex();
300 mTestCase.assertTrue (index != -1);
301 sendBroadCast(activity, context, "false");
304 // For disable the remote debugging.
305 public void testDisableRemoteDebugging(Activity activity, Context context) throws Throwable {
306 sendBroadCast(activity, context, "false");
307 mTestUtil.loadUrlSync(mUrl);
308 int index = getSocketNameIndex();
309 mTestCase.assertTrue (index < 0);
313 public void testGetVersion() throws Throwable {
314 String version = mTestUtil.getTestedView().getVersion();
316 Pattern pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+");
317 Matcher matcher = pattern.matcher(version);
318 mTestCase.assertTrue("The version is invalid.", matcher.find());
321 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
322 private boolean isSecondaryDisplayAvailable() {
324 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
325 value = android.provider.Settings.Global.getString(
326 mTestCase.getActivity().getContentResolver(),
327 "overlay_display_devices");
332 if (value != null && value.length() > 0) {