Index: chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestBase.java |
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestBase.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6d516e24e2a2a17bcc778726ccdd9f52e0194b5f |
--- /dev/null |
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestBase.java |
@@ -0,0 +1,271 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.chrome.browser.download; |
+ |
+import android.app.DownloadManager; |
+import android.content.BroadcastReceiver; |
+import android.content.Context; |
+import android.content.Intent; |
+import android.content.IntentFilter; |
+import android.database.Cursor; |
+import android.os.Environment; |
+import android.os.Handler; |
+import android.util.Log; |
+ |
+import org.chromium.base.ThreadUtils; |
+import org.chromium.base.annotations.SuppressFBWarnings; |
+import org.chromium.chrome.browser.ChromeActivity; |
+import org.chromium.chrome.test.ChromeActivityTestCaseBase; |
+import org.chromium.content.browser.DownloadController; |
+import org.chromium.content.browser.DownloadInfo; |
+import org.chromium.content.browser.test.util.ApplicationUtils; |
+import org.chromium.content.browser.test.util.CallbackHelper; |
+ |
+import java.io.File; |
+import java.io.FileInputStream; |
+import java.io.IOException; |
+import java.util.concurrent.TimeUnit; |
+import java.util.concurrent.TimeoutException; |
+ |
+/** |
+ * Base case for tests that need to download a file. |
+ * |
+ * This has to be a base class because some classes (like BrowserEvent) are exposed only |
+ * to children of ChromeActivityTestCaseBase. It is a very broken approach to sharing |
+ * but the only other option is to refactor the ChromeActivityTestCaseBase implementation |
+ * and all of our test cases. |
+ * |
+ */ |
+public abstract class DownloadTestBase extends ChromeActivityTestCaseBase<ChromeActivity> { |
+ private static final String TAG = "DownloadTestBase"; |
+ private static final File DOWNLOAD_DIRECTORY = |
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); |
+ public static final long UPDATE_DELAY_MILLIS = 1000; |
+ |
+ public DownloadTestBase() { |
+ super(ChromeActivity.class); |
+ } |
+ |
+ /** |
+ * Check the download exists in DownloadManager by matching the local file |
+ * path. |
+ * |
+ * @param fileName Expected file name. Path is built by appending filename to |
+ * the system downloads path. |
+ * |
+ * @param expectedContents Expected contents of the file, or null if the contents should not be |
+ * checked. |
+ */ |
+ public boolean hasDownload(String fileName, String expectedContents) throws IOException { |
+ File downloadedFile = new File(DOWNLOAD_DIRECTORY, fileName); |
+ if (!downloadedFile.exists()) { |
+ Log.d(TAG, "The file " + fileName + " does not exist"); |
+ return false; |
+ } |
+ |
+ String fullPath = downloadedFile.getAbsolutePath(); |
+ |
+ DownloadManager manager = |
+ (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE); |
+ Cursor cursor = manager.query(new DownloadManager.Query()); |
+ |
+ cursor.moveToFirst(); |
+ boolean result = false; |
+ while (!cursor.isAfterLast()) { |
+ if (fullPath.equals(getPathFromCursor(cursor))) { |
+ if (expectedContents != null) { |
+ FileInputStream stream = new FileInputStream(new File(fullPath)); |
+ byte[] data = new byte[expectedContents.getBytes().length]; |
+ try { |
+ assertEquals(stream.read(data), data.length); |
+ String contents = new String(data); |
+ assertEquals(expectedContents, contents); |
+ } finally { |
+ stream.close(); |
+ } |
+ } |
+ result = true; |
+ break; |
+ } |
+ cursor.moveToNext(); |
+ } |
+ cursor.close(); |
+ return result; |
+ } |
+ |
+ /** |
+ * Check the last download matches the given name and exists in DownloadManager. |
+ */ |
+ public void checkLastDownload(String fileName) throws IOException { |
+ String lastDownload = getLastDownloadFile(); |
+ assertTrue(isSameDownloadFile(fileName, lastDownload)); |
+ assertTrue(hasDownload(lastDownload, null)); |
+ } |
+ |
+ /** |
+ * Delete all download entries in DownloadManager and delete the corresponding files. |
+ */ |
+ @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") |
+ private void cleanUpAllDownloads() { |
+ DownloadManager manager = |
+ (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE); |
+ Cursor cursor = manager.query(new DownloadManager.Query()); |
+ int idColumnIndex = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID); |
+ cursor.moveToFirst(); |
+ while (!cursor.isAfterLast()) { |
+ long id = cursor.getLong(idColumnIndex); |
+ String fileName = getPathFromCursor(cursor); |
+ manager.remove(id); |
+ |
+ if (fileName != null) { // Somehow fileName can be null for some entries. |
+ // manager.remove does not remove downloaded file. |
+ File localFile = new File(fileName); |
+ if (localFile.exists()) { |
+ localFile.delete(); |
+ } |
+ } |
+ |
+ cursor.moveToNext(); |
+ } |
+ cursor.close(); |
+ } |
+ |
+ /** |
+ * Retrieve the path of the downloaded file from a DownloadManager cursor. |
+ */ |
+ private String getPathFromCursor(Cursor cursor) { |
+ int columnId = cursor.getColumnIndex("local_filename"); |
+ return cursor.getString(columnId); |
+ } |
+ |
+ private String getPathForDownload(long downloadId) { |
+ DownloadManager manager = |
+ (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE); |
+ DownloadManager.Query query = new DownloadManager.Query(); |
+ query.setFilterById(downloadId); |
+ Cursor cursor = null; |
+ try { |
+ cursor = manager.query(query); |
+ if (!cursor.moveToFirst()) { |
+ return null; |
+ } |
+ return getPathFromCursor(cursor); |
+ } finally { |
+ if (cursor != null) cursor.close(); |
+ } |
+ } |
+ |
+ private CallbackHelper mHttpGetDownloadFinished; |
+ private String mLastDownloadFilePath; |
+ private CallbackHelper mHttpDownloadFinished; |
+ private DownloadManagerService mSavedDownloadManagerService; |
+ |
+ protected String getLastDownloadFile() { |
+ return new File(mLastDownloadFilePath).getName(); |
+ } |
+ |
+ // The Android DownloadManager sometimes appends a number to a file name when it downloads it |
+ // ex: google.png becomes google-23.png |
+ // This happens even when there is no other prior download with that name, it could be a bug. |
+ // TODO(jcivelli): investigate if we can isolate that behavior and file a bug to Android. |
+ protected boolean isSameDownloadFile(String originalName, String downloadName) { |
+ String fileName = originalName; |
+ String extension = ""; |
+ int dotIndex = originalName.lastIndexOf('.'); |
+ if (dotIndex != -1 && dotIndex < originalName.length()) { |
+ fileName = originalName.substring(0, dotIndex); |
+ extension = originalName.substring(dotIndex); // We include the '.' |
+ } |
+ return downloadName.startsWith(fileName) && downloadName.endsWith(extension); |
+ } |
+ |
+ public boolean waitForGetDownloadToFinish() throws InterruptedException { |
+ mLastDownloadFilePath = null; |
+ boolean eventReceived = true; |
+ try { |
+ mHttpGetDownloadFinished.waitForCallback(0); |
+ } catch (TimeoutException e) { |
+ eventReceived = false; |
+ } |
+ mHttpGetDownloadFinished = new CallbackHelper(); |
+ return eventReceived; |
+ } |
+ |
+ public boolean waitForChromeDownloadToFinish() throws InterruptedException { |
+ boolean eventReceived = true; |
+ try { |
+ mHttpDownloadFinished.waitForCallback(0, 1, 5, TimeUnit.SECONDS); |
+ } catch (TimeoutException e) { |
+ eventReceived = false; |
+ } |
+ mHttpDownloadFinished = new CallbackHelper(); |
+ return eventReceived; |
+ } |
+ |
+ @Override |
+ protected void setUp() throws Exception { |
+ super.setUp(); |
+ cleanUpAllDownloads(); |
+ |
+ try { |
+ assertTrue(ApplicationUtils.waitForLibraryDependencies(getInstrumentation())); |
+ } catch (InterruptedException e) { |
+ fail("Library dependencies were never initialized."); |
+ } |
+ final Context context = getInstrumentation().getTargetContext().getApplicationContext(); |
+ |
+ ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
+ @Override |
+ public void run() { |
+ mSavedDownloadManagerService = DownloadManagerService.setDownloadManagerService( |
+ new DownloadManagerService(context, |
+ new SystemDownloadNotifier(context), new Handler(), |
+ UPDATE_DELAY_MILLIS) { |
+ @Override |
+ protected void broadcastDownloadSuccessful(DownloadInfo downloadInfo) { |
+ super.broadcastDownloadSuccessful(downloadInfo); |
+ mLastDownloadFilePath = downloadInfo.getFilePath(); |
+ mHttpDownloadFinished.notifyCalled(); |
+ } |
+ }); |
+ DownloadController.setDownloadNotificationService( |
+ DownloadManagerService.getDownloadManagerService(context)); |
+ } |
+ }); |
+ |
+ mHttpGetDownloadFinished = new CallbackHelper(); |
+ mHttpDownloadFinished = new CallbackHelper(); |
+ |
+ context.registerReceiver(new BroadcastReceiver() { |
+ @Override |
+ public void onReceive(Context context, Intent intent) { |
+ String action = intent.getAction(); |
+ if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) { |
+ // The name of the download does not seem to always be what we asked for |
+ // (ex: google.png becomes google-23.png). Probably a bug in the Android |
+ // DownloadManager. Make sure we always retrieve the actual download name. |
+ long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); |
+ assertTrue("No download id with download finished intent", downloadId != -1); |
+ mLastDownloadFilePath = getPathForDownload(downloadId); |
+ assertNotNull("Download path not found", mLastDownloadFilePath); |
+ mHttpGetDownloadFinished.notifyCalled(); |
+ } |
+ } |
+ }, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); |
+ } |
+ |
+ @Override |
+ protected void tearDown() throws Exception { |
+ cleanUpAllDownloads(); |
+ ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
+ @Override |
+ public void run() { |
+ DownloadManagerService.setDownloadManagerService(mSavedDownloadManagerService); |
+ DownloadController.setDownloadNotificationService(mSavedDownloadManagerService); |
+ } |
+ }); |
+ super.tearDown(); |
+ } |
+} |