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 17package com.android.providers.downloads; 18 19import android.content.ComponentName; 20import android.content.ContentResolver; 21import android.content.Context; 22import android.content.Intent; 23import android.database.ContentObserver; 24import android.database.Cursor; 25import android.net.Uri; 26import android.provider.Downloads; 27import android.test.MoreAsserts; 28import android.test.RenamingDelegatingContext; 29import android.test.ServiceTestCase; 30import android.test.mock.MockContentResolver; 31import android.util.Log; 32import tests.http.MockResponse; 33import tests.http.MockWebServer; 34import tests.http.RecordedRequest; 35 36import java.io.BufferedReader; 37import java.io.File; 38import java.io.IOException; 39import java.io.InputStream; 40import java.io.InputStreamReader; 41import java.net.MalformedURLException; 42import java.util.Arrays; 43import java.util.HashSet; 44import java.util.Set; 45 46public 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 protected static String STRING_1K; 63 static { 64 StringBuilder buff = new StringBuilder(); 65 for (int i = 0; i < 1024; i++) { 66 buff.append("a" + i % 26); 67 } 68 STRING_1K = buff.toString(); 69 } 70 71 static class MockContentResolverWithNotify extends MockContentResolver { 72 public boolean mNotifyWasCalled = false; 73 74 public synchronized void resetNotified() { 75 mNotifyWasCalled = false; 76 } 77 78 @Override 79 public synchronized void notifyChange(Uri uri, ContentObserver observer, 80 boolean syncToNetwork) { 81 mNotifyWasCalled = true; 82 notifyAll(); 83 } 84 } 85 86 /** 87 * Context passed to the provider and the service. Allows most methods to pass through to the 88 * real Context (this is a LargeTest), with a few exceptions, including renaming file operations 89 * to avoid file and DB conflicts (via RenamingDelegatingContext). 90 */ 91 static class TestContext extends RenamingDelegatingContext { 92 private static final String FILENAME_PREFIX = "test."; 93 94 private Context mRealContext; 95 private Set<String> mAllowedSystemServices; 96 private ContentResolver mResolver; 97 98 boolean mHasServiceBeenStarted = false; 99 100 public TestContext(Context realContext) { 101 super(realContext, FILENAME_PREFIX); 102 mRealContext = realContext; 103 mAllowedSystemServices = new HashSet<String>(Arrays.asList(new String[] { 104 Context.NOTIFICATION_SERVICE, 105 Context.POWER_SERVICE, 106 })); 107 } 108 109 public void setResolver(ContentResolver resolver) { 110 mResolver = resolver; 111 } 112 113 /** 114 * Direct DownloadService to our test instance of DownloadProvider. 115 */ 116 @Override 117 public ContentResolver getContentResolver() { 118 assert mResolver != null; 119 return mResolver; 120 } 121 122 /** 123 * Stub some system services, allow access to others, and block the rest. 124 */ 125 @Override 126 public Object getSystemService(String name) { 127 if (mAllowedSystemServices.contains(name)) { 128 return mRealContext.getSystemService(name); 129 } 130 return super.getSystemService(name); 131 } 132 133 /** 134 * Record when DownloadProvider starts DownloadService. 135 */ 136 @Override 137 public ComponentName startService(Intent service) { 138 if (service.getComponent().getClassName().equals(DownloadService.class.getName())) { 139 mHasServiceBeenStarted = true; 140 return service.getComponent(); 141 } 142 throw new UnsupportedOperationException("Unexpected service: " + service); 143 } 144 } 145 146 public AbstractDownloadManagerFunctionalTest(FakeSystemFacade systemFacade) { 147 super(DownloadService.class); 148 mSystemFacade = systemFacade; 149 } 150 151 @Override 152 protected void setUp() throws Exception { 153 super.setUp(); 154 155 Context realContext = getContext(); 156 mTestContext = new TestContext(realContext); 157 setupProviderAndResolver(); 158 159 mTestContext.setResolver(mResolver); 160 setContext(mTestContext); 161 setupService(); 162 getService().mSystemFacade = mSystemFacade; 163 assertTrue(isDatabaseEmpty()); // ensure we're not messing with real data 164 mServer = new MockWebServer(); 165 mServer.play(); 166 } 167 168 @Override 169 protected void tearDown() throws Exception { 170 cleanUpDownloads(); 171 mServer.shutdown(); 172 super.tearDown(); 173 } 174 175 private boolean isDatabaseEmpty() { 176 Cursor cursor = mResolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, 177 null, null, null, null); 178 try { 179 return cursor.getCount() == 0; 180 } finally { 181 cursor.close(); 182 } 183 } 184 185 void setupProviderAndResolver() { 186 DownloadProvider provider = new DownloadProvider(); 187 provider.mSystemFacade = mSystemFacade; 188 provider.attachInfo(mTestContext, null); 189 mResolver = new MockContentResolverWithNotify(); 190 mResolver.addProvider(PROVIDER_AUTHORITY, provider); 191 } 192 193 /** 194 * Remove any downloaded files and delete any lingering downloads. 195 */ 196 void cleanUpDownloads() { 197 if (mResolver == null) { 198 return; 199 } 200 String[] columns = new String[] {Downloads.Impl._DATA}; 201 Cursor cursor = mResolver.query(Downloads.Impl.CONTENT_URI, columns, null, null, null); 202 try { 203 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 204 String filePath = cursor.getString(0); 205 if (filePath == null) continue; 206 Log.d(LOG_TAG, "Deleting " + filePath); 207 new File(filePath).delete(); 208 } 209 } finally { 210 cursor.close(); 211 } 212 mResolver.delete(Downloads.Impl.CONTENT_URI, null, null); 213 } 214 215 /** 216 * Enqueue a String response from the MockWebServer. 217 */ 218 MockResponse enqueueResponse(int status, String body) { 219 MockResponse response = new MockResponse() 220 .setResponseCode(status) 221 .setBody(body) 222 .addHeader("Content-type", "text/plain") 223 .setCloseConnectionAfter(true); 224 mServer.enqueue(response); 225 return response; 226 } 227 /** 228 * Enqueue a byte[] response from the MockWebServer. 229 */ 230 MockResponse enqueueResponse(int status, byte[] body) { 231 MockResponse response = new MockResponse() 232 .setResponseCode(status) 233 .setBody(body) 234 .addHeader("Content-type", "text/plain") 235 .setCloseConnectionAfter(true); 236 mServer.enqueue(response); 237 return response; 238 } 239 240 MockResponse enqueueEmptyResponse(int status) { 241 return enqueueResponse(status, ""); 242 } 243 244 /** 245 * Fetch the last request received by the MockWebServer. 246 */ 247 protected RecordedRequest takeRequest() throws InterruptedException { 248 RecordedRequest request = mServer.takeRequestWithTimeout(0); 249 assertNotNull("Expected request was not made", request); 250 return request; 251 } 252 253 String getServerUri(String path) throws MalformedURLException { 254 return mServer.getUrl(path).toString(); 255 } 256 257 public void runService() throws Exception { 258 startService(null); 259 mSystemFacade.runAllThreads(); 260 mServer.checkForExceptions(); 261 } 262 263 protected String readStream(InputStream inputStream) throws IOException { 264 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); 265 try { 266 char[] buffer = new char[1024]; 267 int length = reader.read(buffer); 268 assertTrue("Failed to read anything from input stream", length > -1); 269 return String.valueOf(buffer, 0, length); 270 } finally { 271 reader.close(); 272 } 273 } 274 275 protected void assertStartsWith(String expectedPrefix, String actual) { 276 String regex = "^" + expectedPrefix + ".*"; 277 MoreAsserts.assertMatchesRegex(regex, actual); 278 } 279} 280