blob: db9e8688e82e32968ba780b889eda7c66b1e563f [file] [log] [blame]
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +09001/*
2 * Copyright (C) 2016 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.ArchivesProvider;
20import com.android.documentsui.archives.Archive;
21import com.android.documentsui.tests.R;
22
Tomasz Mikolajewskib19061c2017-02-13 17:33:42 +090023import android.content.ContentProviderClient;
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +090024import android.content.ContentResolver;
25import android.content.Context;
26import android.database.ContentObserver;
27import android.database.Cursor;
28import android.net.Uri;
29import android.os.Bundle;
30import android.os.ParcelFileDescriptor;
31import android.provider.DocumentsContract.Document;
32import android.provider.DocumentsContract;
33import android.support.test.InstrumentationRegistry;
34import android.test.AndroidTestCase;
35import android.test.suitebuilder.annotation.MediumTest;
36import android.text.TextUtils;
37
38import java.io.File;
39import java.io.FileOutputStream;
40import java.io.IOException;
41import java.io.InputStream;
42import java.util.Scanner;
43import java.util.concurrent.ExecutorService;
44import java.util.concurrent.Executors;
45import java.util.concurrent.TimeUnit;
46import java.util.concurrent.CountDownLatch;
47
48@MediumTest
49public class ArchivesProviderTest extends AndroidTestCase {
50 private static final Uri ARCHIVE_URI = Uri.parse("content://i/love/strawberries");
Tomasz Mikolajewski1bc12032017-02-28 13:27:27 +090051 private static final String NOTIFICATION_URI =
52 "content://com.android.documentsui.archives/notification-uri";
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +090053 private ExecutorService mExecutor = null;
54 private Archive mArchive = null;
55 private TestUtils mTestUtils = null;
56
57 @Override
58 public void setUp() throws Exception {
59 super.setUp();
60 mExecutor = Executors.newSingleThreadExecutor();
61 mTestUtils = new TestUtils(InstrumentationRegistry.getTargetContext(),
62 InstrumentationRegistry.getContext(), mExecutor);
63 }
64
65 @Override
66 public void tearDown() throws Exception {
67 mExecutor.shutdown();
68 assertTrue(mExecutor.awaitTermination(3 /* timeout */, TimeUnit.SECONDS));
69 super.tearDown();
70 }
71
Tomasz Mikolajewskif78d2052017-02-27 14:00:57 +090072 public void testQueryRoots() throws InterruptedException {
73 final ContentResolver resolver = getContext().getContentResolver();
74 final Uri rootsUri = DocumentsContract.buildRootsUri(ArchivesProvider.AUTHORITY);
75 try (final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
76 rootsUri)) {
77 final Cursor cursor = resolver.query(rootsUri, null, null, null, null, null);
78 assertNotNull("Cursor must not be null.", cursor);
79 assertEquals(0, cursor.getCount());
80 }
81 }
82
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +090083 public void testOpen_Success() throws InterruptedException {
84 final Uri sourceUri = DocumentsContract.buildDocumentUri(
85 ResourcesProvider.AUTHORITY, "archive.zip");
Tomasz Mikolajewskic8fb30f2017-01-24 18:54:42 +090086 final Uri archiveUri = ArchivesProvider.buildUriForArchive(sourceUri,
87 ParcelFileDescriptor.MODE_READ_ONLY);
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +090088
89 final Uri childrenUri = DocumentsContract.buildChildDocumentsUri(
90 ArchivesProvider.AUTHORITY, DocumentsContract.getDocumentId(archiveUri));
91
92 final ContentResolver resolver = getContext().getContentResolver();
93 final CountDownLatch latch = new CountDownLatch(1);
94
Tomasz Mikolajewskib19061c2017-02-13 17:33:42 +090095 final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
96 archiveUri);
97 ArchivesProvider.acquireArchive(client, archiveUri);
98
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +090099 {
100 final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
101 assertNotNull("Cursor must not be null. File not found?", cursor);
102
103 assertEquals(0, cursor.getCount());
104 final Bundle extras = cursor.getExtras();
105 assertEquals(true, extras.getBoolean(DocumentsContract.EXTRA_LOADING, false));
106 assertNull(extras.getString(DocumentsContract.EXTRA_ERROR));
107
108 final Uri notificationUri = cursor.getNotificationUri();
109 assertNotNull(notificationUri);
110
111 resolver.registerContentObserver(notificationUri, false, new ContentObserver(null) {
112 @Override
113 public void onChange(boolean selfChange, Uri uri) {
114 latch.countDown();
115 }
116 });
117 }
118
Tomasz Mikolajewski4665e632017-03-03 14:36:36 +0900119 latch.await(30, TimeUnit.SECONDS);
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +0900120 {
121 final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
122 assertNotNull("Cursor must not be null. File not found?", cursor);
123
124 assertEquals(3, cursor.getCount());
125 final Bundle extras = cursor.getExtras();
126 assertEquals(false, extras.getBoolean(DocumentsContract.EXTRA_LOADING, false));
127 assertNull(extras.getString(DocumentsContract.EXTRA_ERROR));
128 }
Tomasz Mikolajewskib19061c2017-02-13 17:33:42 +0900129
130 ArchivesProvider.releaseArchive(client, archiveUri);
131 client.release();
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +0900132 }
133
134 public void testOpen_Failure() throws InterruptedException {
135 final Uri sourceUri = DocumentsContract.buildDocumentUri(
136 ResourcesProvider.AUTHORITY, "broken.zip");
Tomasz Mikolajewskic8fb30f2017-01-24 18:54:42 +0900137 final Uri archiveUri = ArchivesProvider.buildUriForArchive(sourceUri,
138 ParcelFileDescriptor.MODE_READ_ONLY);
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +0900139
140 final Uri childrenUri = DocumentsContract.buildChildDocumentsUri(
141 ArchivesProvider.AUTHORITY, DocumentsContract.getDocumentId(archiveUri));
142
143 final ContentResolver resolver = getContext().getContentResolver();
144 final CountDownLatch latch = new CountDownLatch(1);
145
Tomasz Mikolajewskib19061c2017-02-13 17:33:42 +0900146 final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
147 archiveUri);
148 ArchivesProvider.acquireArchive(client, archiveUri);
149
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +0900150 {
Tomasz Mikolajewskib19061c2017-02-13 17:33:42 +0900151 // TODO: Close this and any other cursor in this file.
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +0900152 final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
153 assertNotNull("Cursor must not be null. File not found?", cursor);
154
155 assertEquals(0, cursor.getCount());
156 final Bundle extras = cursor.getExtras();
157 assertEquals(true, extras.getBoolean(DocumentsContract.EXTRA_LOADING, false));
158 assertNull(extras.getString(DocumentsContract.EXTRA_ERROR));
159
160 final Uri notificationUri = cursor.getNotificationUri();
161 assertNotNull(notificationUri);
162
163 resolver.registerContentObserver(notificationUri, false, new ContentObserver(null) {
164 @Override
165 public void onChange(boolean selfChange, Uri uri) {
166 latch.countDown();
167 }
168 });
169 }
170
Tomasz Mikolajewski4665e632017-03-03 14:36:36 +0900171 latch.await(30, TimeUnit.SECONDS);
Tomasz Mikolajewski55b6b482016-12-13 18:38:41 +0900172 {
173 final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
174 assertNotNull("Cursor must not be null. File not found?", cursor);
175
176 assertEquals(0, cursor.getCount());
177 final Bundle extras = cursor.getExtras();
178 assertEquals(false, extras.getBoolean(DocumentsContract.EXTRA_LOADING, false));
179 assertFalse(TextUtils.isEmpty(extras.getString(DocumentsContract.EXTRA_ERROR)));
180 }
Tomasz Mikolajewskib19061c2017-02-13 17:33:42 +0900181
182 ArchivesProvider.releaseArchive(client, archiveUri);
183 client.release();
184 }
185
186 public void testOpen_ClosesOnRelease() throws InterruptedException {
187 final Uri sourceUri = DocumentsContract.buildDocumentUri(
188 ResourcesProvider.AUTHORITY, "broken.zip");
189 final Uri archiveUri = ArchivesProvider.buildUriForArchive(sourceUri,
190 ParcelFileDescriptor.MODE_READ_ONLY);
191
192 final Uri childrenUri = DocumentsContract.buildChildDocumentsUri(
193 ArchivesProvider.AUTHORITY, DocumentsContract.getDocumentId(archiveUri));
194
195 final ContentResolver resolver = getContext().getContentResolver();
196 final CountDownLatch latch = new CountDownLatch(1);
197
198 final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
199 archiveUri);
200
201 // Acquire twice to ensure that the refcount works correctly.
202 ArchivesProvider.acquireArchive(client, archiveUri);
203 ArchivesProvider.acquireArchive(client, archiveUri);
204
205 {
206 final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
207 assertNotNull("Cursor must not be null. File not found?", cursor);
208 }
209
210 ArchivesProvider.releaseArchive(client, archiveUri);
211
212 {
213 final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
214 assertNotNull("Cursor must not be null. File not found?", cursor);
215 }
216
217 ArchivesProvider.releaseArchive(client, archiveUri);
218
219 try {
220 resolver.query(childrenUri, null, null, null, null, null);
221 fail("The archive was expected to be invalited on the last release call.");
222 } catch (IllegalStateException e) {
223 // Expected.
224 }
225
226 client.release();
227 }
228}