blob: 13f7daa0a750f4ce592e1a1625c2bc21c5375f79 [file] [log] [blame]
Ben Kwaaac9e2e2015-04-16 18:14:35 -07001/*
2 * Copyright (C) 2015 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.documentsui;
18
19import static com.android.documentsui.model.DocumentInfo.getCursorString;
20
21import android.app.NotificationManager;
22import android.content.ContentProviderClient;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.ContextWrapper;
26import android.content.Intent;
27import android.database.Cursor;
28import android.net.Uri;
29import android.os.ParcelFileDescriptor;
30import android.os.Parcelable;
31import android.os.RemoteException;
32import android.provider.DocumentsContract;
33import android.provider.DocumentsContract.Document;
34import android.test.MoreAsserts;
35import android.test.ServiceTestCase;
36import android.util.Log;
37
38import com.android.documentsui.model.DocumentInfo;
39import com.android.documentsui.model.DocumentStack;
40import com.android.documentsui.model.RootInfo;
41import com.google.common.collect.Lists;
42
43import libcore.io.IoUtils;
44import libcore.io.Streams;
45
46import org.mockito.Mockito;
47
48import java.io.FileNotFoundException;
49import java.io.InputStream;
50import java.io.OutputStream;
51import java.util.ArrayList;
52import java.util.Arrays;
53import java.util.List;
54
55public class CopyTest extends ServiceTestCase<CopyService> {
56
57 public CopyTest() {
58 super(CopyService.class);
59 }
60
61 private static String TAG = "CopyTest";
62 // This must match the authority for the StubProvider.
63 private static String AUTHORITY = "com.android.documentsui.stubprovider";
64 private List<RootInfo> mRoots;
65 private Context mContext;
66 private ContentResolver mResolver;
67 private ContentProviderClient mClient;
68 private NotificationManager mNotificationManager;
69
70 @Override
71 protected void setUp() throws Exception {
72 super.setUp();
73 setupTestContext();
74
75 mResolver = mContext.getContentResolver();
76 mClient = mResolver.acquireContentProviderClient(AUTHORITY);
77
78 // Reset the stub provider's storage.
79 mClient.call("clear", "", null);
80
81 mRoots = Lists.newArrayList();
82 Uri queryUri = DocumentsContract.buildRootsUri(AUTHORITY);
83 Cursor cursor = null;
84 try {
85 cursor = mClient.query(queryUri, null, null, null, null);
86 while (cursor.moveToNext()) {
87 final RootInfo root = RootInfo.fromRootsCursor(AUTHORITY, cursor);
88 final String id = root.rootId;
89 mRoots.add(root);
90 }
91 } finally {
92 IoUtils.closeQuietly(cursor);
93 }
94
95 }
96
97 @Override
98 protected void tearDown() throws Exception {
99 mClient.release();
100 super.tearDown();
101 }
102
103 public List<Uri> setupTestFiles() throws Exception {
104 Uri rootUri = DocumentsContract.buildDocumentUri(AUTHORITY, mRoots.get(0).documentId);
105 List<Uri> testFiles = Lists.newArrayList(
106 DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test0.txt"),
107 DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test1.txt"),
108 DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test2.txt")
109 );
110 String testContent[] = {
111 "The five boxing wizards jump quickly",
112 "The quick brown fox jumps over the lazy dog",
113 "Jackdaws love my big sphinx of quartz"
114 };
115 for (int i = 0; i < testFiles.size(); ++i) {
116 ParcelFileDescriptor pfd = null;
117 OutputStream out = null;
118 try {
119 pfd = mClient.openFile(testFiles.get(i), "w");
120 out = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
121 out.write(testContent[i].getBytes());
122 } finally {
123 IoUtils.closeQuietly(out);
124 }
125 }
126 return testFiles;
127 }
128
129 /**
130 * Test copying a single file.
131 */
132 public void testCopyFile() throws Exception {
133 Uri testFile = setupTestFiles().get(0);
134
135 // Just copy one file.
136 copyToDestination(Lists.newArrayList(testFile));
137
138 // A call to NotificationManager.cancel marks the end of the copy operation.
139 Mockito.verify(mNotificationManager, Mockito.timeout(1000)).cancel(Mockito.anyString(),
140 Mockito.anyInt());
141
142 // Verify that one file was copied; check file contents.
143 assertDstFileCountEquals(1);
144 assertCopied(testFile);
145 }
146
147 /**
148 * Test copying multiple files.
149 */
150 public void testCopyMultipleFiles() throws Exception {
151 List<Uri> testFiles = setupTestFiles();
152 // Copy all the test files.
153 copyToDestination(testFiles);
154
155 // A call to NotificationManager.cancel marks the end of the copy operation.
156 Mockito.verify(mNotificationManager, Mockito.timeout(1000)).cancel(Mockito.anyString(),
157 Mockito.anyInt());
158
159 assertDstFileCountEquals(3);
160 for (Uri testFile : testFiles) {
161 assertCopied(testFile);
162 }
163 }
164
165 /**
166 * Copies the given files to a pre-determined destination.
167 *
168 * @throws FileNotFoundException
169 */
170 private void copyToDestination(List<Uri> srcs) throws FileNotFoundException {
171 final ArrayList<DocumentInfo> srcDocs = Lists.newArrayList();
172 for (Uri src : srcs) {
173 srcDocs.add(DocumentInfo.fromUri(mResolver, src));
174 }
175
176 final Uri dst = DocumentsContract.buildDocumentUri(AUTHORITY, mRoots.get(1).documentId);
177 DocumentStack stack = new DocumentStack();
178 stack.push(DocumentInfo.fromUri(mResolver, dst));
179 final Intent copyIntent = new Intent(mContext, CopyService.class);
180 copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST, srcDocs);
181 copyIntent.putExtra(CopyService.EXTRA_STACK, (Parcelable) stack);
182
183 startService(copyIntent);
184 }
185
186 /**
187 * Returns a count of the files in the given directory.
188 */
189 private void assertDstFileCountEquals(int expected) throws RemoteException {
190 final Uri queryUri = DocumentsContract.buildChildDocumentsUri(AUTHORITY,
191 mRoots.get(1).documentId);
192 Cursor c = null;
193 int count = 0;
194 try {
195 c = mClient.query(queryUri, null, null, null, null);
196 count = c.getCount();
197 } finally {
198 IoUtils.closeQuietly(c);
199 }
200 assertEquals("Incorrect file count after copy", expected, count);
201 }
202
203 /**
204 * Verifies that the file pointed to by the given URI was correctly copied to the destination.
205 */
206 private void assertCopied(Uri src) throws Exception {
207 Cursor cursor = null;
208 String srcName = null;
209 try {
210 cursor = mClient.query(src, null, null, null, null);
211 if (cursor.moveToFirst()) {
212 srcName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
213 }
214 } finally {
215 IoUtils.closeQuietly(cursor);
216 }
217 Uri dst = getDstFileUri(srcName);
218
219 InputStream in0 = null;
220 InputStream in1 = null;
221 try {
222 in0 = new ParcelFileDescriptor.AutoCloseInputStream(mClient.openFile(src, "r"));
223 in1 = new ParcelFileDescriptor.AutoCloseInputStream(mClient.openFile(dst, "r"));
224
225 byte[] buffer0 = Streams.readFully(in0);
226 byte[] buffer1 = Streams.readFully(in1);
227
228 MoreAsserts.assertEquals(buffer0, buffer1);
229 } finally {
230 IoUtils.closeQuietly(in0);
231 IoUtils.closeQuietly(in1);
232 }
233 }
234
235 /**
236 * Generates a file URI from a given filename. This assumes the file already exists in the
237 * destination root.
238 */
239 private Uri getDstFileUri(String filename) throws RemoteException {
240 final Uri dstFileQuery = DocumentsContract.buildChildDocumentsUri(AUTHORITY,
241 mRoots.get(1).documentId);
242 Cursor cursor = null;
243 try {
244 // StubProvider doesn't seem to support query strings; filter the results manually.
245 cursor = mClient.query(dstFileQuery, null, null, null, null);
246 while (cursor.moveToNext()) {
247 if (filename.equals(getCursorString(cursor, Document.COLUMN_DISPLAY_NAME))) {
248 return DocumentsContract.buildDocumentUri(AUTHORITY,
249 getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
250 }
251 }
252 } finally {
253 IoUtils.closeQuietly(cursor);
254 }
255 return null;
256 }
257
258 /**
259 * Sets up a ContextWrapper that substitutes a stub NotificationManager. This allows the test to
260 * listen for notification events, to gauge copy progress.
261 */
262 private void setupTestContext() {
263 mContext = getSystemContext();
264 System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
265
266 mNotificationManager = Mockito.spy((NotificationManager) mContext
267 .getSystemService(Context.NOTIFICATION_SERVICE));
268
269 // Insert a stub NotificationManager that enables us to listen for when copying is complete.
270 setContext(new ContextWrapper(mContext) {
271 @Override
272 public Object getSystemService(String name) {
273 if (Context.NOTIFICATION_SERVICE.equals(name)) {
274 return mNotificationManager;
275 } else {
276 return super.getSystemService(name);
277 }
278 }
279 });
280 }
281}