blob: 28f5e3c6c2e6ebaea3634aadb9ffb7e1ca67d894 [file] [log] [blame]
Tomasz Mikolajewskidc235d22017-01-25 15:07:31 +09001/*
2 * Copyright (C) 2017 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.archives;
18
19import com.android.documentsui.archives.WriteableArchive;
20import com.android.documentsui.tests.R;
21
22import android.database.Cursor;
23import android.content.Context;
24import android.net.Uri;
25import android.os.ParcelFileDescriptor;
26import android.provider.DocumentsContract.Document;
27import android.support.test.InstrumentationRegistry;
28import android.test.AndroidTestCase;
29import android.test.suitebuilder.annotation.MediumTest;
30
31import java.io.File;
32import java.io.FileOutputStream;
33import java.io.IOException;
34import java.io.InputStream;
35import java.util.Enumeration;
36import java.util.Scanner;
37import java.util.concurrent.ExecutorService;
38import java.util.concurrent.Executors;
39import java.util.concurrent.TimeUnit;
40import java.util.zip.ZipEntry;
41import java.util.zip.ZipFile;
42
43@MediumTest
44public class WriteableArchiveTest extends AndroidTestCase {
45 private static final Uri ARCHIVE_URI = Uri.parse("content://i/love/strawberries");
46 private static final String NOTIFICATION_URI = "content://notification-uri";
47 private ExecutorService mExecutor = null;
48 private Archive mArchive = null;
49 private TestUtils mTestUtils = null;
50 private File mFile = null;
51
52 @Override
53 public void setUp() throws Exception {
54 super.setUp();
55 mExecutor = Executors.newSingleThreadExecutor();
56 mTestUtils = new TestUtils(InstrumentationRegistry.getTargetContext(),
57 InstrumentationRegistry.getContext(), mExecutor);
58 mFile = mTestUtils.createTemporaryFile();
59
60 mArchive = WriteableArchive.createForParcelFileDescriptor(
61 InstrumentationRegistry.getTargetContext(),
62 ParcelFileDescriptor.open(mFile, ParcelFileDescriptor.MODE_WRITE_ONLY),
63 ARCHIVE_URI,
64 ParcelFileDescriptor.MODE_WRITE_ONLY,
65 Uri.parse(NOTIFICATION_URI));
66 }
67
68 @Override
69 public void tearDown() throws Exception {
70 mExecutor.shutdown();
71 assertTrue(mExecutor.awaitTermination(3 /* timeout */, TimeUnit.SECONDS));
72 if (mFile != null) {
73 mFile.delete();
74 }
75 if (mArchive != null) {
76 mArchive.close();
77 }
78 super.tearDown();
79 }
80
81 public static ArchiveId createArchiveId(String path) {
82 return new ArchiveId(ARCHIVE_URI, ParcelFileDescriptor.MODE_WRITE_ONLY, path);
83 }
84
85 public void testCreateDocument() throws IOException {
86 final String dirDocumentId = mArchive.createDocument(createArchiveId("/").toDocumentId(),
87 Document.MIME_TYPE_DIR, "dir");
88 assertEquals(createArchiveId("/dir/").toDocumentId(), dirDocumentId);
89
90 final String documentId = mArchive.createDocument(dirDocumentId, "image/jpeg", "test.jpeg");
91 assertEquals(createArchiveId("/dir/test.jpeg").toDocumentId(), documentId);
92
93 try {
94 mArchive.createDocument(dirDocumentId,
95 "image/jpeg", "test.jpeg");
96 fail("Creating should fail, as the document already exists.");
97 } catch (IllegalStateException e) {
98 // Expected.
99 }
100
101 try {
102 mArchive.createDocument(createArchiveId("/").toDocumentId(),
103 "image/jpeg", "test.jpeg/");
104 fail("Creating should fail, as the document name is invalid.");
105 } catch (IllegalStateException e) {
106 // Expected.
107 }
108
109 try {
110 mArchive.createDocument(createArchiveId("/").toDocumentId(),
111 Document.MIME_TYPE_DIR, "test/");
112 fail("Creating should fail, as the document name is invalid.");
113 } catch (IllegalStateException e) {
114 // Expected.
115 }
116
117 try {
118 mArchive.createDocument(createArchiveId("/").toDocumentId(),
119 Document.MIME_TYPE_DIR, "..");
120 fail("Creating should fail, as the document name is invalid.");
121 } catch (IllegalStateException e) {
122 // Expected.
123 }
124
125 try {
126 mArchive.createDocument(createArchiveId("/").toDocumentId(),
127 Document.MIME_TYPE_DIR, ".");
128 fail("Creating should fail, as the document name is invalid.");
129 } catch (IllegalStateException e) {
130 // Expected.
131 }
132
133 try {
134 mArchive.createDocument(createArchiveId("/").toDocumentId(),
135 Document.MIME_TYPE_DIR, "");
136 fail("Creating should fail, as the document name is invalid.");
137 } catch (IllegalStateException e) {
138 // Expected.
139 }
140
141 try {
142 mArchive.createDocument(createArchiveId("/").toDocumentId(),
143 "image/jpeg", "a/b.jpeg");
144 fail("Creating should fail, as the document name is invalid.");
145 } catch (IllegalStateException e) {
146 // Expected.
147 }
148 }
149
150 public void testAddDirectory() throws IOException {
151 final String documentId = mArchive.createDocument(createArchiveId("/").toDocumentId(),
152 Document.MIME_TYPE_DIR, "dir");
153
154 {
155 final Cursor cursor = mArchive.queryDocument(documentId, null);
156 assertTrue(cursor.moveToFirst());
157 assertEquals(documentId,
158 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
159 assertEquals("dir",
160 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
161 assertEquals(Document.MIME_TYPE_DIR,
162 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
163 assertEquals(0,
164 cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
165 }
166
167 {
168 final Cursor cursor = mArchive.queryChildDocuments(
169 createArchiveId("/").toDocumentId(), null, null);
170
171 assertTrue(cursor.moveToFirst());
172 assertEquals(documentId,
173 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
174 assertEquals("dir",
175 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
176 assertEquals(Document.MIME_TYPE_DIR,
177 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
178 assertEquals(0,
179 cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
180 }
181
182 mArchive.close();
183
184 // Verify archive.
185 ZipFile zip = null;
186 try {
187 zip = new ZipFile(mFile);
188 final Enumeration<? extends ZipEntry> entries = zip.entries();
189 assertTrue(entries.hasMoreElements());
190 final ZipEntry entry = entries.nextElement();
191 assertEquals("dir/", entry.getName());
192 assertFalse(entries.hasMoreElements());
193 } finally {
194 if (zip != null) {
195 zip.close();
196 }
197 }
198 }
199
200 public void testAddFile() throws IOException, InterruptedException {
201 final String documentId = mArchive.createDocument(createArchiveId("/").toDocumentId(),
202 "text/plain", "hoge.txt");
203
204 {
205 final Cursor cursor = mArchive.queryDocument(documentId, null);
206 assertTrue(cursor.moveToFirst());
207 assertEquals(documentId,
208 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DOCUMENT_ID)));
209 assertEquals("hoge.txt",
210 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_DISPLAY_NAME)));
211 assertEquals("text/plain",
212 cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)));
213 assertEquals(0,
214 cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
215 }
216
217 try {
218 mArchive.openDocument(documentId, "r", null);
219 fail("Should fail when opened for reading!");
220 } catch (IllegalArgumentException e) {
221 // Expected.
222 }
223
224 final ParcelFileDescriptor fd = mArchive.openDocument(documentId, "w", null);
225 try (final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
226 new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
227 outputStream.write("Hello world!".getBytes());
228 }
229
230 try {
231 mArchive.openDocument(documentId, "w", null);
232 fail("Should fail when opened for the second time!");
233 } catch (IllegalStateException e) {
234 // Expected.
235 }
236
237 // Wait until the pipe thread fully writes all the data from the pipe.
238 // TODO: Maybe add some method in WriteableArchive to wait until the executor
239 // completes the job?
240 Thread.sleep(500);
241
242 {
243 final Cursor cursor = mArchive.queryDocument(documentId, null);
244 assertTrue(cursor.moveToFirst());
245 assertEquals(12,
246 cursor.getInt(cursor.getColumnIndexOrThrow(Document.COLUMN_SIZE)));
247 }
248
249 mArchive.close();
250
251 // Verify archive.
252 ZipFile zip = null;
253 try {
254 try {
255 zip = new ZipFile(mFile);
256 } catch (Exception e) {
257 throw new IOException(mFile.getAbsolutePath());
258 }
259 final Enumeration<? extends ZipEntry> entries = zip.entries();
260 assertTrue(entries.hasMoreElements());
261 final ZipEntry entry = entries.nextElement();
262 assertEquals("hoge.txt", entry.getName());
263 assertFalse(entries.hasMoreElements());
264 final InputStream inputStream = zip.getInputStream(entry);
265 final Scanner scanner = new Scanner(inputStream);
266 assertEquals("Hello world!", scanner.nextLine());
267 assertFalse(scanner.hasNext());
268 } finally {
269 if (zip != null) {
270 zip.close();
271 }
272 }
273 }
274
275 public void testAddFile_empty() throws IOException, Exception {
276 final String documentId = mArchive.createDocument(createArchiveId("/").toDocumentId(),
277 "text/plain", "hoge.txt");
278 mArchive.close();
279
280 // Verify archive.
281 ZipFile zip = null;
282 try {
283 try {
284 zip = new ZipFile(mFile);
285 } catch (Exception e) {
286 throw new IOException(mFile.getAbsolutePath());
287 }
288 final Enumeration<? extends ZipEntry> entries = zip.entries();
289 assertTrue(entries.hasMoreElements());
290 final ZipEntry entry = entries.nextElement();
291 assertEquals("hoge.txt", entry.getName());
292 assertFalse(entries.hasMoreElements());
293 final InputStream inputStream = zip.getInputStream(entry);
294 final Scanner scanner = new Scanner(inputStream);
295 assertFalse(scanner.hasNext());
296 } finally {
297 if (zip != null) {
298 zip.close();
299 }
300 }
301 }
302}