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