1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.providers.downloads; 18 19 import android.content.ComponentName; 20 import android.content.ContentResolver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.database.ContentObserver; 24 import android.database.Cursor; 25 import android.net.Uri; 26 import android.provider.Downloads; 27 import android.test.MoreAsserts; 28 import android.test.RenamingDelegatingContext; 29 import android.test.ServiceTestCase; 30 import android.test.mock.MockContentResolver; 31 import android.util.Log; 32 import tests.http.MockResponse; 33 import tests.http.MockWebServer; 34 import tests.http.RecordedRequest; 35 36 import java.io.BufferedReader; 37 import java.io.File; 38 import java.io.IOException; 39 import java.io.InputStream; 40 import java.io.InputStreamReader; 41 import java.net.MalformedURLException; 42 import java.util.Arrays; 43 import java.util.HashSet; 44 import java.util.Set; 45 46 public abstract class AbstractDownloadManagerFunctionalTest extends 47 ServiceTestCase<DownloadService> { 48 49 protected static final String LOG_TAG = "DownloadManagerFunctionalTest"; 50 private static final String PROVIDER_AUTHORITY = "downloads"; 51 protected static final long RETRY_DELAY_MILLIS = 61 * 1000; 52 protected static final String FILE_CONTENT = "hello world hello world hello world hello world"; 53 protected static final int HTTP_OK = 200; 54 protected static final int HTTP_PARTIAL_CONTENT = 206; 55 protected static final int HTTP_NOT_FOUND = 404; 56 protected static final int HTTP_SERVICE_UNAVAILABLE = 503; 57 58 protected MockWebServer mServer; 59 protected MockContentResolverWithNotify mResolver; 60 protected TestContext mTestContext; 61 protected FakeSystemFacade mSystemFacade; 62 63 static class MockContentResolverWithNotify extends MockContentResolver { 64 public boolean mNotifyWasCalled = false; 65 resetNotified()66 public synchronized void resetNotified() { 67 mNotifyWasCalled = false; 68 } 69 70 @Override notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork)71 public synchronized void notifyChange(Uri uri, ContentObserver observer, 72 boolean syncToNetwork) { 73 mNotifyWasCalled = true; 74 notifyAll(); 75 } 76 } 77 78 /** 79 * Context passed to the provider and the service. Allows most methods to pass through to the 80 * real Context (this is a LargeTest), with a few exceptions, including renaming file operations 81 * to avoid file and DB conflicts (via RenamingDelegatingContext). 82 */ 83 static class TestContext extends RenamingDelegatingContext { 84 private static final String FILENAME_PREFIX = "test."; 85 86 private Context mRealContext; 87 private Set<String> mAllowedSystemServices; 88 private ContentResolver mResolver; 89 90 boolean mHasServiceBeenStarted = false; 91 TestContext(Context realContext)92 public TestContext(Context realContext) { 93 super(realContext, FILENAME_PREFIX); 94 mRealContext = realContext; 95 mAllowedSystemServices = new HashSet<String>(Arrays.asList(new String[] { 96 Context.NOTIFICATION_SERVICE, 97 Context.POWER_SERVICE, 98 })); 99 } 100 setResolver(ContentResolver resolver)101 public void setResolver(ContentResolver resolver) { 102 mResolver = resolver; 103 } 104 105 /** 106 * Direct DownloadService to our test instance of DownloadProvider. 107 */ 108 @Override getContentResolver()109 public ContentResolver getContentResolver() { 110 assert mResolver != null; 111 return mResolver; 112 } 113 114 /** 115 * Stub some system services, allow access to others, and block the rest. 116 */ 117 @Override getSystemService(String name)118 public Object getSystemService(String name) { 119 if (mAllowedSystemServices.contains(name)) { 120 return mRealContext.getSystemService(name); 121 } 122 return super.getSystemService(name); 123 } 124 125 /** 126 * Record when DownloadProvider starts DownloadService. 127 */ 128 @Override startService(Intent service)129 public ComponentName startService(Intent service) { 130 if (service.getComponent().getClassName().equals(DownloadService.class.getName())) { 131 mHasServiceBeenStarted = true; 132 return service.getComponent(); 133 } 134 throw new UnsupportedOperationException("Unexpected service: " + service); 135 } 136 } 137 AbstractDownloadManagerFunctionalTest(FakeSystemFacade systemFacade)138 public AbstractDownloadManagerFunctionalTest(FakeSystemFacade systemFacade) { 139 super(DownloadService.class); 140 mSystemFacade = systemFacade; 141 } 142 143 @Override setUp()144 protected void setUp() throws Exception { 145 super.setUp(); 146 147 Context realContext = getContext(); 148 mTestContext = new TestContext(realContext); 149 setupProviderAndResolver(); 150 assert isDatabaseEmpty(); // ensure we're not messing with real data 151 152 mTestContext.setResolver(mResolver); 153 setContext(mTestContext); 154 setupService(); 155 getService().mSystemFacade = mSystemFacade; 156 157 mServer = new MockWebServer(); 158 mServer.play(); 159 } 160 161 @Override tearDown()162 protected void tearDown() throws Exception { 163 cleanUpDownloads(); 164 super.tearDown(); 165 } 166 isDatabaseEmpty()167 private boolean isDatabaseEmpty() { 168 Cursor cursor = mResolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, 169 null, null, null, null); 170 try { 171 return cursor.getCount() == 0; 172 } finally { 173 cursor.close(); 174 } 175 } 176 setupProviderAndResolver()177 void setupProviderAndResolver() { 178 DownloadProvider provider = new DownloadProvider(); 179 provider.mSystemFacade = mSystemFacade; 180 provider.attachInfo(mTestContext, null); 181 mResolver = new MockContentResolverWithNotify(); 182 mResolver.addProvider(PROVIDER_AUTHORITY, provider); 183 } 184 185 /** 186 * Remove any downloaded files and delete any lingering downloads. 187 */ cleanUpDownloads()188 void cleanUpDownloads() { 189 if (mResolver == null) { 190 return; 191 } 192 String[] columns = new String[] {Downloads._DATA}; 193 Cursor cursor = mResolver.query(Downloads.CONTENT_URI, columns, null, null, null); 194 try { 195 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 196 String filePath = cursor.getString(0); 197 if (filePath == null) continue; 198 Log.d(LOG_TAG, "Deleting " + filePath); 199 new File(filePath).delete(); 200 } 201 } finally { 202 cursor.close(); 203 } 204 mResolver.delete(Downloads.CONTENT_URI, null, null); 205 } 206 207 /** 208 * Enqueue a response from the MockWebServer. 209 */ enqueueResponse(int status, String body)210 MockResponse enqueueResponse(int status, String body) { 211 MockResponse response = new MockResponse() 212 .setResponseCode(status) 213 .setBody(body) 214 .addHeader("Content-type", "text/plain") 215 .setCloseConnectionAfter(true); 216 mServer.enqueue(response); 217 return response; 218 } 219 enqueueEmptyResponse(int status)220 MockResponse enqueueEmptyResponse(int status) { 221 return enqueueResponse(status, ""); 222 } 223 224 /** 225 * Fetch the last request received by the MockWebServer. 226 */ takeRequest()227 protected RecordedRequest takeRequest() throws InterruptedException { 228 RecordedRequest request = mServer.takeRequestWithTimeout(0); 229 assertNotNull("Expected request was not made", request); 230 return request; 231 } 232 getServerUri(String path)233 String getServerUri(String path) throws MalformedURLException { 234 return mServer.getUrl(path).toString(); 235 } 236 runService()237 public void runService() throws Exception { 238 startService(null); 239 mSystemFacade.runAllThreads(); 240 mServer.checkForExceptions(); 241 } 242 readStream(InputStream inputStream)243 protected String readStream(InputStream inputStream) throws IOException { 244 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); 245 try { 246 char[] buffer = new char[1024]; 247 int length = reader.read(buffer); 248 assertTrue("Failed to read anything from input stream", length > -1); 249 return String.valueOf(buffer, 0, length); 250 } finally { 251 reader.close(); 252 } 253 } 254 assertStartsWith(String expectedPrefix, String actual)255 protected void assertStartsWith(String expectedPrefix, String actual) { 256 String regex = "^" + expectedPrefix + ".*"; 257 MoreAsserts.assertMatchesRegex(regex, actual); 258 } 259 } 260