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