c27b828918c81eb877d52205071a80284e7a9670
[platform/framework/web/crosswalk.git] / src / xwalk / test / android / util / runtime_client / src / org / xwalk / test / util / RuntimeClientApiTestBase.java
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.
5
6 package org.xwalk.test.util;
7
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;
14
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;
24
25 import org.chromium.content.browser.test.util.Criteria;
26 import org.chromium.content.browser.test.util.CriteriaHelper;
27 /**
28  * Test helper for Runtime client APIs.
29  */
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";
36     enum Relation {
37         EQUAL,
38         GREATERTHAN,
39         LESSSTHAN,
40         NONE
41     }
42
43     public RuntimeClientApiTestBase(XWalkRuntimeClientTestUtilBase testUtil,
44             ActivityInstrumentationTestCase2<T> testCase) {
45         mTestUtil = testUtil;
46         mTestCase = testCase;
47     }
48
49     public String getTitleOnUiThread() {
50         mTestCase.getInstrumentation().waitForIdleSync();
51         final AtomicReference<String> title = new AtomicReference<String>();
52         mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
53             @Override
54             public void run() {
55                 title.set(mTestUtil.getTestedView().getTitleForTest());
56             }
57         });
58         return title.get();
59     }
60
61     public void compareTitle(String prevTitle, String title, String msg, Relation relation) {
62         if (prevTitle == null) prevTitle = "";
63         if (title == null) title = "";
64
65         switch (relation) {
66             case EQUAL:
67                 mTestCase.assertTrue(msg, title.equals(prevTitle));
68                 break;
69             case GREATERTHAN:
70                 mTestCase.assertTrue(msg, title.compareTo(prevTitle) > 0);
71                 break;
72             default:
73                 break;
74         }
75     }
76
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);
82             notify.wait();
83         }
84     }
85
86     public class NotifyTask extends TimerTask {
87         private Object mObj;
88
89         public NotifyTask(Object obj) {
90             super();
91             mObj = obj;
92         }
93
94         @Override
95         public void run() {
96             synchronized (mObj) {
97                 mObj.notify();
98             }
99         }
100     }
101
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);
106     }
107
108     public int getSocketNameIndex() {
109         try {
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");
119
120             final int BUFFER_SIZE = 1024;
121             byte[] bytes = new byte[BUFFER_SIZE];
122             StringBuffer buffer = new StringBuffer(4 * BUFFER_SIZE);
123
124             int bytesReceived = process.getInputStream().read(bytes, 0, BUFFER_SIZE);
125             while (bytesReceived > 0) {
126                 String tmp = new String(bytes, 0, bytesReceived);
127                 buffer.append(tmp);
128                 bytesReceived = process.getInputStream().read(bytes, 0, BUFFER_SIZE);
129             }
130
131             process.destroy();
132
133             String contents = new String(buffer);
134             int index = contents.indexOf(mSocketName + "_devtools_remote");
135             return index;
136         } catch (IOException e) {
137             mTestCase.fail("error occurs in testDevTools: " + e);
138             return 0;
139         }
140     }
141
142     // For loadAppFromUrl.
143     public void testLoadAppFromUrl() throws Throwable {
144         final String expectedTitle = "Crosswalk Sample Application";
145
146         mTestUtil.loadUrlSync("file:///android_asset/index.html");
147         mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
148             @Override
149             public void run() {
150                 String title = mTestUtil.getTestedView().getTitleForTest();
151                 mTestCase.assertEquals(expectedTitle, title);
152             }
153         });
154     }
155
156     // For loadAppFromManifest.
157     public void testLoadAppFromManifest() throws Throwable {
158         final String expectedTitle = "Crosswalk Sample Application";
159
160         mTestUtil.loadManifestSync("file:///android_asset/manifest.json");
161
162         mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
163             @Override
164             public void run() {
165                 String title = mTestUtil.getTestedView().getTitleForTest();
166                 mTestCase.assertEquals(expectedTitle, title);
167             }
168         });
169     }
170
171    // For testCSP.
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() {
178             @Override
179             public void run() {
180                 String title = mTestUtil.getTestedView().getTitleForTest();
181                 mTestCase.assertEquals(originalTitle, title);
182             }
183         });
184
185         mTestUtil.loadManifestSync("app://" + host + "/manifest_self.json");
186         Thread.sleep(2000);
187         mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
188             @Override
189             public void run() {
190                 String title = mTestUtil.getTestedView().getTitleForTest();
191                 mTestCase.assertEquals(originalTitle, title);
192             }
193         });
194
195         mTestUtil.loadManifestSync("file:///android_asset/www/manifest_inline_script.json");
196         mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
197             @Override
198             public void run() {
199                 String title = mTestUtil.getTestedView().getTitleForTest();
200                 mTestCase.assertEquals(newTitle, title);
201             }
202         });
203
204         mTestUtil.loadManifestSync("app://" + host + "/manifest_inline_script.json");
205         Thread.sleep(2000);
206         mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
207             @Override
208             public void run() {
209                 String title = mTestUtil.getTestedView().getTitleForTest();
210                 mTestCase.assertEquals(newTitle, title);
211             }
212         });
213     }
214
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);
219     }
220
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);
225     }
226
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);
231     }
232
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);
238         } else {
239             mTestCase.assertEquals("Unavailable", title);
240         }
241     }
242
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);
247     }
248
249     // For external extension mechanism: sync mode.
250     public void testExternalExtensionSync() throws Throwable {
251         mTestUtil.loadAssetFile("echoSync.html");
252         mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
253             @Override
254             public void run() {
255                 String title = mTestUtil.getTestedView().getTitleForTest();
256                 mTestCase.assertEquals("Pass", title);
257             }
258         });
259     }
260
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);
265     }
266     // For onPause, onResume.
267     public void testPauseAndResume() throws Throwable {
268         String title = "";
269         String prevTitle = "";
270         String nextTitle = "";
271         String msg = "";
272
273         title = mTestUtil.loadAssetFileAndWaitForTitle("timer.html");
274         mTestCase.assertNotNull(title);
275
276         mTestUtil.onPause();
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);
284
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);
293     }
294
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");
302     }
303
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);
310     }
311
312     // For getVersion.
313     public void testGetVersion() throws Throwable {
314         String version = mTestUtil.getTestedView().getVersion();
315
316         Pattern pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+");
317         Matcher matcher = pattern.matcher(version);
318         mTestCase.assertTrue("The version is invalid.", matcher.find());
319     }
320
321     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
322     private boolean isSecondaryDisplayAvailable() {
323         String value;
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");
328         } else {
329             value = null;
330         }
331
332         if (value != null && value.length() > 0) {
333             return true;
334         }
335         return false;
336     }
337 }