blob: 45f89e4e1ffd18a293189fc76660c8db3dd8ab63 [file] [log] [blame]
Daichi Hirono6baa16e2015-08-12 13:51:59 +09001/*
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.mtp;
18
19import android.content.Context;
20import android.database.Cursor;
Tomasz Mikolajewskibb430fa2015-08-25 18:34:30 +090021import android.mtp.MtpObjectInfo;
Daichi Hirono6baa16e2015-08-12 13:51:59 +090022import android.net.Uri;
23import android.provider.DocumentsContract;
24import android.test.AndroidTestCase;
Daichi Hirono4604b742015-11-12 12:12:48 +090025import android.test.suitebuilder.annotation.MediumTest;
Daichi Hirono6baa16e2015-08-12 13:51:59 +090026
27import java.io.IOException;
Daichi Hirono6baa16e2015-08-12 13:51:59 +090028import java.util.HashMap;
29import java.util.Map;
30import java.util.concurrent.CountDownLatch;
31
Daichi Hirono4604b742015-11-12 12:12:48 +090032@MediumTest
Daichi Hirono6baa16e2015-08-12 13:51:59 +090033public class DocumentLoaderTest extends AndroidTestCase {
Daichi Hirono47eb1922015-11-16 13:01:31 +090034 private MtpDatabase mDatabase;
Tomasz Mikolajewskibb430fa2015-08-25 18:34:30 +090035 private BlockableTestMtpManager mManager;
Daichi Hirono6baa16e2015-08-12 13:51:59 +090036 private TestContentResolver mResolver;
37 private DocumentLoader mLoader;
Daichi Hirono6a5ea7e2016-02-02 16:35:03 +090038 final private Identifier mParentIdentifier = new Identifier(
Daichi Hirono619afda2016-02-07 14:23:43 +090039 0, 0, 0, "2", MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE);
Daichi Hirono6baa16e2015-08-12 13:51:59 +090040
41 @Override
Daichi Hirono619afda2016-02-07 14:23:43 +090042 public void setUp() throws Exception {
Daichi Hirono47eb1922015-11-16 13:01:31 +090043 mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
Daichi Hirono619afda2016-02-07 14:23:43 +090044
45 mDatabase.getMapper().startAddingDocuments(null);
46 mDatabase.getMapper().putDeviceDocument(
Daichi Hirono4e94b8d2016-02-21 22:42:41 +090047 new MtpDeviceRecord(0, "Device", null, true, new MtpRoot[0], null, null));
Daichi Hirono619afda2016-02-07 14:23:43 +090048 mDatabase.getMapper().stopAddingDocuments(null);
49
50 mDatabase.getMapper().startAddingDocuments("1");
Daichi Hirono0f325372016-02-21 15:50:30 +090051 mDatabase.getMapper().putStorageDocuments("1", new int[0], new MtpRoot[] {
Daichi Hironof83ccbd2016-02-04 16:58:55 +090052 new MtpRoot(0, 0, "Storage", 1000, 1000, "")
Daichi Hirono47eb1922015-11-16 13:01:31 +090053 });
Daichi Hirono619afda2016-02-07 14:23:43 +090054 mDatabase.getMapper().stopAddingDocuments("1");
55
Tomasz Mikolajewskibb430fa2015-08-25 18:34:30 +090056 mManager = new BlockableTestMtpManager(getContext());
Daichi Hirono6baa16e2015-08-12 13:51:59 +090057 mResolver = new TestContentResolver();
Daichi Hirono47eb1922015-11-16 13:01:31 +090058 }
59
60 @Override
Daichi Hirono4e94b8d2016-02-21 22:42:41 +090061 public void tearDown() throws Exception {
62 mLoader.close();
Daichi Hirono47eb1922015-11-16 13:01:31 +090063 mDatabase.close();
Daichi Hirono6baa16e2015-08-12 13:51:59 +090064 }
65
Daichi Hirono8b9024f2015-08-12 12:59:09 +090066 public void testBasic() throws Exception {
Daichi Hirono678ed362016-03-18 15:05:53 +090067 setUpLoader();
68
Daichi Hirono6baa16e2015-08-12 13:51:59 +090069 final Uri uri = DocumentsContract.buildChildDocumentsUri(
Daichi Hirono9e8a4fa2015-11-19 16:13:38 +090070 MtpDocumentsProvider.AUTHORITY, mParentIdentifier.mDocumentId);
Daichi Hirono6baa16e2015-08-12 13:51:59 +090071 setUpDocument(mManager, 40);
72 mManager.blockDocument(0, 15);
73 mManager.blockDocument(0, 35);
74
75 {
76 final Cursor cursor = mLoader.queryChildDocuments(
77 MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier);
78 assertEquals(DocumentLoader.NUM_INITIAL_ENTRIES, cursor.getCount());
79 }
80
81 Thread.sleep(DocumentLoader.NOTIFY_PERIOD_MS);
82 mManager.unblockDocument(0, 15);
83 mResolver.waitForNotification(uri, 1);
84
85 {
86 final Cursor cursor = mLoader.queryChildDocuments(
87 MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier);
88 assertEquals(
89 DocumentLoader.NUM_INITIAL_ENTRIES + DocumentLoader.NUM_LOADING_ENTRIES,
90 cursor.getCount());
91 }
92
93 mManager.unblockDocument(0, 35);
94 mResolver.waitForNotification(uri, 2);
95
96 {
97 final Cursor cursor = mLoader.queryChildDocuments(
98 MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier);
99 assertEquals(40, cursor.getCount());
100 }
101
102 assertEquals(2, mResolver.getChangeCount(uri));
103 }
104
Daichi Hirono678ed362016-03-18 15:05:53 +0900105 public void testError_GetObjectHandles() throws Exception {
106 mManager = new BlockableTestMtpManager(getContext()) {
107 @Override
108 int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
109 throws IOException {
110 throw new IOException();
111 }
112 };
113 setUpLoader();
114 mManager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, null);
115 try {
116 try (final Cursor cursor = mLoader.queryChildDocuments(
117 MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {}
118 fail();
119 } catch (IOException exception) {
120 // Expect exception.
121 }
122 }
123
124 public void testError_GetObjectInfo() throws Exception {
125 mManager = new BlockableTestMtpManager(getContext()) {
126 @Override
127 MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
128 if (objectHandle == DocumentLoader.NUM_INITIAL_ENTRIES) {
129 throw new IOException();
130 } else {
131 return super.getObjectInfo(deviceId, objectHandle);
132 }
133 }
134 };
135 setUpLoader();
136 setUpDocument(mManager, DocumentLoader.NUM_INITIAL_ENTRIES);
137 try (final Cursor cursor = mLoader.queryChildDocuments(
138 MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {
139 // Even if MtpManager returns an error for a document, loading must complete.
140 assertFalse(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING));
141 }
142 }
143
144 private void setUpLoader() {
145 mLoader = new DocumentLoader(
146 new MtpDeviceRecord(
147 0, "Device", "Key", true, new MtpRoot[0],
148 TestUtil.OPERATIONS_SUPPORTED, new int[0]),
149 mManager,
150 mResolver,
151 mDatabase);
152 }
153
Daichi Hirono6baa16e2015-08-12 13:51:59 +0900154 private void setUpDocument(TestMtpManager manager, int count) {
155 int[] childDocuments = new int[count];
156 for (int i = 0; i < childDocuments.length; i++) {
157 final int objectHandle = i + 1;
158 childDocuments[i] = objectHandle;
Tomasz Mikolajewskibb430fa2015-08-25 18:34:30 +0900159 manager.setObjectInfo(0, new MtpObjectInfo.Builder()
160 .setObjectHandle(objectHandle)
Daichi Hirono47eb1922015-11-16 13:01:31 +0900161 .setName(Integer.toString(i))
Tomasz Mikolajewskibb430fa2015-08-25 18:34:30 +0900162 .build());
Daichi Hirono6baa16e2015-08-12 13:51:59 +0900163 }
164 manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
165 }
166
Tomasz Mikolajewskibb430fa2015-08-25 18:34:30 +0900167 private static class BlockableTestMtpManager extends TestMtpManager {
Daichi Hirono6baa16e2015-08-12 13:51:59 +0900168 final private Map<String, CountDownLatch> blockedDocuments = new HashMap<>();
169
Tomasz Mikolajewskibb430fa2015-08-25 18:34:30 +0900170 BlockableTestMtpManager(Context context) {
Daichi Hirono6baa16e2015-08-12 13:51:59 +0900171 super(context);
172 }
173
174 void blockDocument(int deviceId, int objectHandle) {
175 blockedDocuments.put(pack(deviceId, objectHandle), new CountDownLatch(1));
176 }
177
178 void unblockDocument(int deviceId, int objectHandle) {
179 blockedDocuments.get(pack(deviceId, objectHandle)).countDown();
180 }
181
182 @Override
Tomasz Mikolajewskibb430fa2015-08-25 18:34:30 +0900183 MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
Daichi Hirono6baa16e2015-08-12 13:51:59 +0900184 final CountDownLatch latch = blockedDocuments.get(pack(deviceId, objectHandle));
185 if (latch != null) {
186 try {
187 latch.await();
188 } catch(InterruptedException e) {
189 fail();
190 }
191 }
Tomasz Mikolajewskibb430fa2015-08-25 18:34:30 +0900192 return super.getObjectInfo(deviceId, objectHandle);
Daichi Hirono6baa16e2015-08-12 13:51:59 +0900193 }
194 }
195}