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