1// Copyright 2013 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
5package org.chromium.android_webview.test;
6
7import android.test.suitebuilder.annotation.LargeTest;
8import android.util.Pair;
9import android.webkit.ValueCallback;
10
11import org.chromium.android_webview.AwContents;
12import org.chromium.android_webview.AwQuotaManagerBridge;
13import org.chromium.android_webview.AwSettings;
14import org.chromium.android_webview.test.util.AwQuotaManagerBridgeTestUtil;
15import org.chromium.base.test.util.Feature;
16import org.chromium.content.browser.test.util.CallbackHelper;
17import org.chromium.net.test.util.TestWebServer;
18
19import java.util.ArrayList;
20import java.util.List;
21import java.util.concurrent.Callable;
22
23/**
24 * Tests for the AwQuotaManagerBridge.
25 */
26public class AwQuotaManagerBridgeTest extends AwTestBase {
27    private TestAwContentsClient mContentsClient;
28    private AwTestContainerView mTestView;
29    private AwContents mAwContents;
30    private TestWebServer mWebServer;
31    private String mOrigin;
32
33    @Override
34    public void setUp() throws Exception {
35        super.setUp();
36        mContentsClient = new TestAwContentsClient();
37        mTestView = createAwTestContainerViewOnMainSync(mContentsClient);
38        mAwContents = mTestView.getAwContents();
39        mWebServer = new TestWebServer(false);
40        mOrigin = mWebServer.getBaseUrl();
41
42        AwSettings settings = getAwSettingsOnUiThread(mAwContents);
43        settings.setJavaScriptEnabled(true);
44        settings.setDomStorageEnabled(true);
45        settings.setAppCacheEnabled(true);
46        settings.setAppCachePath("whatever");  // Enables AppCache.
47    }
48
49    @Override
50    public void tearDown() throws Exception {
51        deleteAllData();
52        if (mWebServer != null) {
53            mWebServer.shutdown();
54        }
55        super.tearDown();
56    }
57
58    private void deleteAllData() throws Exception {
59        final AwQuotaManagerBridge bridge =
60                AwQuotaManagerBridgeTestUtil.getQuotaManagerBridge(this);
61        getInstrumentation().runOnMainSync(new Runnable() {
62            @Override
63            public void run() {
64                bridge.deleteAllData();
65            }
66        });
67    }
68
69    private void deleteOrigin(final String origin) throws Exception {
70        final AwQuotaManagerBridge bridge =
71                AwQuotaManagerBridgeTestUtil.getQuotaManagerBridge(this);
72        getInstrumentation().runOnMainSync(new Runnable() {
73            @Override
74            public void run() {
75                bridge.deleteOrigin(origin);
76            }
77        });
78    }
79
80    private static class LongValueCallbackHelper extends CallbackHelper {
81        private long mValue;
82
83        public void notifyCalled(long value) {
84            mValue = value;
85            notifyCalled();
86        }
87
88        public long getValue() {
89            assert getCallCount() > 0;
90            return mValue;
91        }
92    }
93
94    private long getQuotaForOrigin(final String origin) throws Exception {
95        final LongValueCallbackHelper callbackHelper = new LongValueCallbackHelper();
96        final AwQuotaManagerBridge bridge =
97                AwQuotaManagerBridgeTestUtil.getQuotaManagerBridge(this);
98
99        int callCount = callbackHelper.getCallCount();
100        getInstrumentation().runOnMainSync(new Runnable() {
101            @Override
102            public void run() {
103                bridge.getQuotaForOrigin("foo.com",
104                    new ValueCallback<Long>() {
105                        @Override
106                        public void onReceiveValue(Long quota) {
107                            callbackHelper.notifyCalled(quota);
108                        }
109                    }
110                );
111            }
112        });
113        callbackHelper.waitForCallback(callCount);
114
115        return callbackHelper.getValue();
116    }
117
118    private long getUsageForOrigin(final String origin) throws Exception {
119        final LongValueCallbackHelper callbackHelper = new LongValueCallbackHelper();
120        final AwQuotaManagerBridge bridge =
121                AwQuotaManagerBridgeTestUtil.getQuotaManagerBridge(this);
122
123        int callCount = callbackHelper.getCallCount();
124        getInstrumentation().runOnMainSync(new Runnable() {
125            @Override
126            public void run() {
127                bridge.getUsageForOrigin(origin,
128                    new ValueCallback<Long>() {
129                        @Override
130                        public void onReceiveValue(Long usage) {
131                            callbackHelper.notifyCalled(usage);
132                        }
133                    }
134                );
135            }
136        });
137        callbackHelper.waitForCallback(callCount);
138
139        return callbackHelper.getValue();
140    }
141
142    private void useAppCache() throws Exception {
143        final String cachedFilePath = "/foo.js";
144        final String cachedFileContents = "1 + 1;";
145        mWebServer.setResponse(cachedFilePath, cachedFileContents, null);
146
147        final String manifestPath = "/foo.manifest";
148        final String manifestContents = "CACHE MANIFEST\nCACHE:\n" + cachedFilePath;
149        List<Pair<String, String>> manifestHeaders = new ArrayList<Pair<String, String>>();
150        manifestHeaders.add(Pair.create("Content-Disposition", "text/cache-manifest"));
151        mWebServer.setResponse(manifestPath, manifestContents, manifestHeaders);
152
153        final String pagePath = "/appcache.html";
154        final String pageContents = "<html manifest=\"" + manifestPath + "\">" +
155                "<head><script src=\"" + cachedFilePath + "\"></script></head></html>";
156        String url = mWebServer.setResponse(pagePath, pageContents, null);
157
158        loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url);
159        executeJavaScriptAndWaitForResult(mAwContents, mContentsClient,
160              "window.applicationCache.update();");
161    }
162
163    @LargeTest
164    @Feature({"AndroidWebView", "WebStore"})
165    public void testDeleteAllWithAppCache() throws Exception {
166        final long initialUsage = getUsageForOrigin(mOrigin);
167
168        useAppCache();
169        poll(new Callable<Boolean>() {
170            @Override
171            public Boolean call() throws Exception {
172                return getUsageForOrigin(mOrigin) > initialUsage;
173            }
174        });
175
176        deleteAllData();
177        poll(new Callable<Boolean>() {
178            @Override
179            public Boolean call() throws Exception {
180                return getUsageForOrigin(mOrigin) == 0;
181            }
182        });
183    }
184
185    @LargeTest
186    @Feature({"AndroidWebView", "WebStore"})
187    public void testDeleteOriginWithAppCache() throws Exception {
188        final long initialUsage = getUsageForOrigin(mOrigin);
189
190        useAppCache();
191        poll(new Callable<Boolean>() {
192            @Override
193            public Boolean call() throws Exception {
194                return getUsageForOrigin(mOrigin) > initialUsage;
195            }
196        });
197
198        deleteOrigin(mOrigin);
199        poll(new Callable<Boolean>() {
200            @Override
201            public Boolean call() throws Exception {
202                return getUsageForOrigin(mOrigin) == 0;
203            }
204        });
205    }
206
207    @LargeTest
208    @Feature({"AndroidWebView", "WebStore"})
209    public void testGetResultsMatch() throws Exception {
210        useAppCache();
211
212        poll(new Callable<Boolean>() {
213            @Override
214            public Boolean call() throws Exception {
215                return AwQuotaManagerBridgeTestUtil.getOrigins(
216                            AwQuotaManagerBridgeTest.this).mOrigins.length > 0;
217            }
218        });
219
220        AwQuotaManagerBridge.Origins origins = AwQuotaManagerBridgeTestUtil.getOrigins(this);
221        assertEquals(origins.mOrigins.length, origins.mUsages.length);
222        assertEquals(origins.mOrigins.length, origins.mQuotas.length);
223
224        for (int i = 0; i < origins.mOrigins.length; ++i) {
225            assertEquals(origins.mUsages[i], getUsageForOrigin(origins.mOrigins[i]));
226            assertEquals(origins.mQuotas[i], getQuotaForOrigin(origins.mOrigins[i]));
227        }
228    }
229}
230