1 /* 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 17 package com.android.documentsui.services; 18 19 import static com.google.common.collect.Lists.newArrayList; 20 21 import static org.junit.Assert.assertNotEquals; 22 23 import android.app.Notification; 24 import android.net.Uri; 25 import android.provider.DocumentsContract; 26 import android.text.format.DateUtils; 27 28 import androidx.test.filters.MediumTest; 29 30 import com.android.documentsui.R; 31 import com.android.documentsui.base.DocumentInfo; 32 import com.android.documentsui.services.FileOperationService.OpType; 33 34 import java.text.NumberFormat; 35 import java.util.List; 36 import java.util.stream.IntStream; 37 38 @MediumTest 39 public abstract class AbstractCopyJobTest<T extends CopyJob> extends AbstractJobTest<T> { 40 41 private final @OpType int mOpType; 42 AbstractCopyJobTest(@pType int opType)43 AbstractCopyJobTest(@OpType int opType) { 44 mOpType = opType; 45 } 46 runCopyFilesTest()47 public void runCopyFilesTest() throws Exception { 48 Uri testFile1 = mDocs.createDocument(mSrcRoot, "text/plain", "test1.txt"); 49 mDocs.writeDocument(testFile1, HAM_BYTES); 50 51 Uri testFile2 = mDocs.createDocument(mSrcRoot, "text/plain", "test2.txt"); 52 mDocs.writeDocument(testFile2, FRUITY_BYTES); 53 54 createJob(newArrayList(testFile1, testFile2)).run(); 55 mJobListener.waitForFinished(); 56 57 mDocs.assertChildCount(mDestRoot, 2); 58 mDocs.assertHasFile(mDestRoot, "test1.txt"); 59 mDocs.assertHasFile(mDestRoot, "test2.txt"); 60 mDocs.assertFileContents(mDestRoot.documentId, "test1.txt", HAM_BYTES); 61 mDocs.assertFileContents(mDestRoot.documentId, "test2.txt", FRUITY_BYTES); 62 } 63 runCopyVirtualTypedFileTest()64 public void runCopyVirtualTypedFileTest() throws Exception { 65 Uri testFile = mDocs.createVirtualFile( 66 mSrcRoot, "/virtual.sth", "virtual/mime-type", 67 FRUITY_BYTES, "application/pdf", "text/html"); 68 69 createJob(newArrayList(testFile)).run(); 70 71 waitForJobFinished(); 72 73 mDocs.assertChildCount(mDestRoot, 1); 74 mDocs.assertHasFile(mDestRoot, "virtual.sth.pdf"); // copy should convert file to PDF. 75 mDocs.assertFileContents(mDestRoot.documentId, "virtual.sth.pdf", FRUITY_BYTES); 76 } 77 runCopyVirtualNonTypedFileTest()78 public void runCopyVirtualNonTypedFileTest() throws Exception { 79 Uri testFile = mDocs.createVirtualFile( 80 mSrcRoot, "/virtual.sth", "virtual/mime-type", 81 FRUITY_BYTES); 82 83 createJob(newArrayList(testFile)).run(); 84 85 waitForJobFinished(); 86 mJobListener.assertFailed(); 87 mJobListener.assertFilesFailed(newArrayList("virtual.sth")); 88 89 mDocs.assertChildCount(mDestRoot, 0); 90 } 91 runCopyEmptyDirTest()92 public void runCopyEmptyDirTest() throws Exception { 93 Uri testDir = mDocs.createFolder(mSrcRoot, "emptyDir"); 94 95 CopyJob job = createJob(newArrayList(testDir)); 96 job.run(); 97 waitForJobFinished(); 98 99 Notification progressNotification = job.getProgressNotification(); 100 String copyPercentage = progressNotification.extras.getString(Notification.EXTRA_SUB_TEXT); 101 102 // the percentage representation should not be NaN. 103 assertNotEquals(copyPercentage.equals(NumberFormat.getPercentInstance().format(Double.NaN)), 104 "Percentage representation should not be NaN."); 105 106 mDocs.assertChildCount(mDestRoot, 1); 107 mDocs.assertHasDirectory(mDestRoot, "emptyDir"); 108 } 109 runCopyDirRecursivelyTest()110 public void runCopyDirRecursivelyTest() throws Exception { 111 112 Uri testDir1 = mDocs.createFolder(mSrcRoot, "dir1"); 113 mDocs.createDocument(testDir1, "text/plain", "test1.txt"); 114 115 Uri testDir2 = mDocs.createFolder(testDir1, "dir2"); 116 mDocs.createDocument(testDir2, "text/plain", "test2.txt"); 117 118 createJob(newArrayList(testDir1)).run(); 119 waitForJobFinished(); 120 121 DocumentInfo dir1Copy = mDocs.findDocument(mDestRoot.documentId, "dir1"); 122 123 mDocs.assertChildCount(dir1Copy.derivedUri, 2); 124 mDocs.assertHasDirectory(dir1Copy.derivedUri, "dir2"); 125 mDocs.assertHasFile(dir1Copy.derivedUri, "test1.txt"); 126 127 DocumentInfo dir2Copy = mDocs.findDocument(dir1Copy.documentId, "dir2"); 128 mDocs.assertChildCount(dir2Copy.derivedUri, 1); 129 mDocs.assertHasFile(dir2Copy.derivedUri, "test2.txt"); 130 } 131 runNoCopyDirToSelfTest()132 public void runNoCopyDirToSelfTest() throws Exception { 133 Uri testDir = mDocs.createFolder(mSrcRoot, "someDir"); 134 135 createJob(mOpType, 136 newArrayList(testDir), 137 DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId), 138 testDir).run(); 139 140 waitForJobFinished(); 141 mJobListener.assertFailed(); 142 mJobListener.assertFilesFailed(newArrayList("someDir")); 143 144 mDocs.assertChildCount(mDestRoot, 0); 145 } 146 runNoCopyDirToDescendentTest()147 public void runNoCopyDirToDescendentTest() throws Exception { 148 Uri testDir = mDocs.createFolder(mSrcRoot, "someDir"); 149 Uri destDir = mDocs.createFolder(testDir, "theDescendent"); 150 151 createJob(mOpType, 152 newArrayList(testDir), 153 DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId), 154 destDir).run(); 155 156 waitForJobFinished(); 157 mJobListener.assertFailed(); 158 mJobListener.assertFilesFailed(newArrayList("someDir")); 159 160 mDocs.assertChildCount(mDestRoot, 0); 161 } 162 runCopyFileWithReadErrorsTest()163 public void runCopyFileWithReadErrorsTest() throws Exception { 164 Uri testFile = mDocs.createDocument(mSrcRoot, "text/plain", "test1.txt"); 165 mDocs.writeDocument(testFile, HAM_BYTES); 166 167 String testId = DocumentsContract.getDocumentId(testFile); 168 mDocs.simulateReadErrorsForFile(testId, null); 169 170 createJob(newArrayList(testFile)).run(); 171 172 waitForJobFinished(); 173 mJobListener.assertFailed(); 174 mJobListener.assertFilesFailed(newArrayList("test1.txt")); 175 176 mDocs.assertChildCount(mDestRoot, 0); 177 } 178 runCopyProgressForFileCountTest()179 public void runCopyProgressForFileCountTest() throws Exception { 180 // Init FileCountProgressTracker with 10 docs required to copy. 181 TestCopyJobProcessTracker<CopyJob.FileCountProgressTracker> tracker = 182 new TestCopyJobProcessTracker(CopyJob.FileCountProgressTracker.class, 10, 183 createJob(newArrayList(mDocs.createFolder(mSrcRoot, "tempDir"))), 184 (completed) -> NumberFormat.getPercentInstance().format(completed), 185 (time) -> mContext.getString(R.string.copy_remaining, 186 DateUtils.formatDuration((Long) time))); 187 188 // Assert init progress is 0 & default remaining time is -1. 189 tracker.getProcessTracker().start(); 190 tracker.assertProgressTrackStarted(); 191 tracker.assertStartedProgressEquals(0); 192 tracker.assertStartedRemainingTimeEquals(-1); 193 194 // Progress 20%: 2 docs processed after 1 sec, no remaining time since first sample. 195 IntStream.range(0, 2).forEach(__ -> tracker.getProcessTracker().onDocumentCompleted()); 196 tracker.updateProgressAndRemainingTime(1000); 197 tracker.assertProgressEquals(0.2); 198 tracker.assertNoRemainingTime(); 199 200 // Progress 40%: 4 docs processed after 2 secs, expect remaining time is 3 secs. 201 IntStream.range(2, 4).forEach(__ -> tracker.getProcessTracker().onDocumentCompleted()); 202 tracker.updateProgressAndRemainingTime(2000); 203 tracker.assertProgressEquals(0.4); 204 tracker.assertReminingTimeEquals(3000L); 205 206 // progress 100%: 10 doc processed after 5 secs, expect no remaining time shown. 207 IntStream.range(4, 10).forEach(__ -> tracker.getProcessTracker().onDocumentCompleted()); 208 tracker.updateProgressAndRemainingTime(5000); 209 tracker.assertProgressEquals(1.0); 210 tracker.assertNoRemainingTime(); 211 } 212 runCopyProgressForByteCountTest()213 public void runCopyProgressForByteCountTest() throws Exception { 214 // Init ByteCountProgressTracker with 100 KBytes required to copy. 215 TestCopyJobProcessTracker<CopyJob.ByteCountProgressTracker> tracker = 216 new TestCopyJobProcessTracker(CopyJob.ByteCountProgressTracker.class, 100000, 217 createJob(newArrayList(mDocs.createFolder(mSrcRoot, "tempDir"))), 218 (completed) -> NumberFormat.getPercentInstance().format(completed), 219 (time) -> mContext.getString(R.string.copy_remaining, 220 DateUtils.formatDuration((Long) time))); 221 222 // Assert init progress is 0 & default remaining time is -1. 223 tracker.getProcessTracker().start(); 224 tracker.assertProgressTrackStarted(); 225 tracker.assertStartedProgressEquals(0); 226 tracker.assertStartedRemainingTimeEquals(-1); 227 228 // Progress 25%: 25 KBytes processed after 1 sec, no remaining time since first sample. 229 tracker.getProcessTracker().onBytesCopied(25000); 230 tracker.updateProgressAndRemainingTime(1000); 231 tracker.assertProgressEquals(0.25); 232 tracker.assertNoRemainingTime(); 233 234 // Progress 50%: 50 KBytes processed after 2 secs, expect remaining time is 2 secs. 235 tracker.getProcessTracker().onBytesCopied(25000); 236 tracker.updateProgressAndRemainingTime(2000); 237 tracker.assertProgressEquals(0.5); 238 tracker.assertReminingTimeEquals(2000L); 239 240 // Progress 100%: 100 KBytes processed after 4 secs, expect no remaining time shown. 241 tracker.getProcessTracker().onBytesCopied(50000); 242 tracker.updateProgressAndRemainingTime(4000); 243 tracker.assertProgressEquals(1.0); 244 tracker.assertNoRemainingTime(); 245 } 246 waitForJobFinished()247 void waitForJobFinished() throws Exception { 248 mJobListener.waitForFinished(); 249 mDocs.waitForWrite(); 250 } 251 252 /** 253 * Creates a job with a stack consisting to the default source and destination. 254 * TODO: Clean up, as mDestRoot.documentInfo may not really be the parent of 255 * srcs. 256 */ createJob(List<Uri> srcs)257 final T createJob(List<Uri> srcs) throws Exception { 258 Uri srcParent = DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId); 259 return createJob(srcs, srcParent); 260 } 261 createJob(List<Uri> srcs, Uri srcParent)262 final T createJob(List<Uri> srcs, Uri srcParent) throws Exception { 263 Uri destination = DocumentsContract.buildDocumentUri(AUTHORITY, mDestRoot.documentId); 264 return createJob(mOpType, srcs, srcParent, destination); 265 } 266 } 267