UploadIT.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /*
  2. * Nextcloud - Android Client
  3. *
  4. * SPDX-FileCopyrightText: 2020 Tobias Kaminsky <tobias@kaminsky.me>
  5. * SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
  6. * SPDX-FileCopyrightText: 2020 Nextcloud GmbH
  7. * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
  8. */
  9. package com.owncloud.android;
  10. import android.os.NetworkOnMainThreadException;
  11. import com.nextcloud.client.account.UserAccountManagerImpl;
  12. import com.nextcloud.client.device.BatteryStatus;
  13. import com.nextcloud.client.device.PowerManagementService;
  14. import com.nextcloud.client.jobs.upload.FileUploadWorker;
  15. import com.nextcloud.client.network.Connectivity;
  16. import com.nextcloud.client.network.ConnectivityService;
  17. import com.owncloud.android.datamodel.OCFile;
  18. import com.owncloud.android.datamodel.UploadsStorageManager;
  19. import com.owncloud.android.db.OCUpload;
  20. import com.owncloud.android.files.services.NameCollisionPolicy;
  21. import com.owncloud.android.lib.common.accounts.AccountUtils;
  22. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  23. import com.owncloud.android.lib.resources.files.model.GeoLocation;
  24. import com.owncloud.android.lib.resources.files.model.ImageDimension;
  25. import com.owncloud.android.lib.resources.status.NextcloudVersion;
  26. import com.owncloud.android.operations.RefreshFolderOperation;
  27. import com.owncloud.android.operations.RemoveFileOperation;
  28. import com.owncloud.android.operations.UploadFileOperation;
  29. import com.owncloud.android.utils.FileStorageUtils;
  30. import org.junit.Before;
  31. import org.junit.Test;
  32. import java.io.File;
  33. import java.io.IOException;
  34. import java.nio.file.Files;
  35. import java.nio.file.attribute.BasicFileAttributes;
  36. import java.util.List;
  37. import java.util.concurrent.TimeUnit;
  38. import androidx.annotation.NonNull;
  39. import static junit.framework.TestCase.assertEquals;
  40. import static junit.framework.TestCase.assertFalse;
  41. import static junit.framework.TestCase.assertNotNull;
  42. import static junit.framework.TestCase.assertTrue;
  43. /**
  44. * Tests related to file uploads.
  45. */
  46. public class UploadIT extends AbstractOnServerIT {
  47. private static final String FOLDER = "/testUpload/";
  48. private UploadsStorageManager uploadsStorageManager =
  49. new UploadsStorageManager(UserAccountManagerImpl.fromContext(targetContext),
  50. targetContext.getContentResolver());
  51. private ConnectivityService connectivityServiceMock = new ConnectivityService() {
  52. @Override
  53. public boolean isNetworkAndServerAvailable() throws NetworkOnMainThreadException {
  54. return false;
  55. }
  56. @Override
  57. public boolean isConnected() {
  58. return false;
  59. }
  60. @Override
  61. public boolean isInternetWalled() {
  62. return false;
  63. }
  64. @Override
  65. public Connectivity getConnectivity() {
  66. return Connectivity.CONNECTED_WIFI;
  67. }
  68. @Override
  69. public void clearCachedResult() {
  70. }
  71. };
  72. private PowerManagementService powerManagementServiceMock = new PowerManagementService() {
  73. @Override
  74. public boolean isPowerSavingEnabled() {
  75. return false;
  76. }
  77. @Override
  78. public boolean isPowerSavingExclusionAvailable() {
  79. return false;
  80. }
  81. @NonNull
  82. @Override
  83. public BatteryStatus getBattery() {
  84. return new BatteryStatus(false, 0);
  85. }
  86. };
  87. @Before
  88. public void before() throws IOException {
  89. // make sure that every file is available, even after tests that remove source file
  90. createDummyFiles();
  91. }
  92. @Test
  93. public void testEmptyUpload() {
  94. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/empty.txt",
  95. FOLDER + "empty.txt",
  96. account.name);
  97. uploadOCUpload(ocUpload);
  98. }
  99. @Test
  100. public void testNonEmptyUpload() {
  101. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/nonEmpty.txt",
  102. FOLDER + "nonEmpty.txt",
  103. account.name);
  104. uploadOCUpload(ocUpload);
  105. }
  106. @Test
  107. public void testUploadWithCopy() {
  108. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/nonEmpty.txt",
  109. FOLDER + "nonEmpty.txt",
  110. account.name);
  111. uploadOCUpload(ocUpload, FileUploadWorker.LOCAL_BEHAVIOUR_COPY);
  112. File originalFile = new File(FileStorageUtils.getTemporalPath(account.name) + "/nonEmpty.txt");
  113. OCFile uploadedFile = fileDataStorageManager.getFileByDecryptedRemotePath(FOLDER + "nonEmpty.txt");
  114. assertTrue(originalFile.exists());
  115. assertTrue(new File(uploadedFile.getStoragePath()).exists());
  116. verifyStoragePath(uploadedFile);
  117. }
  118. @Test
  119. public void testUploadWithMove() {
  120. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/nonEmpty.txt",
  121. FOLDER + "nonEmpty.txt",
  122. account.name);
  123. uploadOCUpload(ocUpload, FileUploadWorker.LOCAL_BEHAVIOUR_MOVE);
  124. File originalFile = new File(FileStorageUtils.getTemporalPath(account.name) + "/nonEmpty.txt");
  125. OCFile uploadedFile = fileDataStorageManager.getFileByDecryptedRemotePath(FOLDER + "nonEmpty.txt");
  126. assertFalse(originalFile.exists());
  127. assertTrue(new File(uploadedFile.getStoragePath()).exists());
  128. verifyStoragePath(uploadedFile);
  129. }
  130. @Test
  131. public void testUploadWithForget() {
  132. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/nonEmpty.txt",
  133. FOLDER + "nonEmpty.txt",
  134. account.name);
  135. uploadOCUpload(ocUpload, FileUploadWorker.LOCAL_BEHAVIOUR_FORGET);
  136. File originalFile = new File(FileStorageUtils.getTemporalPath(account.name) + "/nonEmpty.txt");
  137. OCFile uploadedFile = fileDataStorageManager.getFileByDecryptedRemotePath(FOLDER + "nonEmpty.txt");
  138. assertTrue(originalFile.exists());
  139. assertFalse(new File(uploadedFile.getStoragePath()).exists());
  140. assertTrue(uploadedFile.getStoragePath().isEmpty());
  141. }
  142. @Test
  143. public void testUploadWithDelete() {
  144. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/nonEmpty.txt",
  145. FOLDER + "nonEmpty.txt",
  146. account.name);
  147. uploadOCUpload(ocUpload, FileUploadWorker.LOCAL_BEHAVIOUR_DELETE);
  148. File originalFile = new File(FileStorageUtils.getTemporalPath(account.name) + "/nonEmpty.txt");
  149. OCFile uploadedFile = fileDataStorageManager.getFileByDecryptedRemotePath(FOLDER + "nonEmpty.txt");
  150. assertFalse(originalFile.exists());
  151. assertFalse(new File(uploadedFile.getStoragePath()).exists());
  152. assertTrue(uploadedFile.getStoragePath().isEmpty());
  153. }
  154. @Test
  155. public void testChunkedUpload() {
  156. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/chunkedFile.txt",
  157. FOLDER + "chunkedFile.txt", account.name);
  158. uploadOCUpload(ocUpload);
  159. }
  160. @Test
  161. public void testUploadInNonExistingFolder() {
  162. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/empty.txt",
  163. FOLDER + "2/3/4/1.txt", account.name);
  164. uploadOCUpload(ocUpload);
  165. }
  166. @Test
  167. public void testUploadOnChargingOnlyButNotCharging() {
  168. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/empty.txt",
  169. FOLDER + "notCharging.txt", account.name);
  170. ocUpload.setWhileChargingOnly(true);
  171. UploadFileOperation newUpload = new UploadFileOperation(
  172. uploadsStorageManager,
  173. connectivityServiceMock,
  174. powerManagementServiceMock,
  175. user,
  176. null,
  177. ocUpload,
  178. NameCollisionPolicy.DEFAULT,
  179. FileUploadWorker.LOCAL_BEHAVIOUR_COPY,
  180. targetContext,
  181. false,
  182. true,
  183. getStorageManager()
  184. );
  185. newUpload.setRemoteFolderToBeCreated();
  186. newUpload.addRenameUploadListener(() -> {
  187. // dummy
  188. });
  189. RemoteOperationResult result = newUpload.execute(client);
  190. assertFalse(result.toString(), result.isSuccess());
  191. assertEquals(RemoteOperationResult.ResultCode.DELAYED_FOR_CHARGING, result.getCode());
  192. }
  193. @Test
  194. public void testUploadOnChargingOnlyAndCharging() {
  195. PowerManagementService powerManagementServiceMock = new PowerManagementService() {
  196. @Override
  197. public boolean isPowerSavingEnabled() {
  198. return false;
  199. }
  200. @Override
  201. public boolean isPowerSavingExclusionAvailable() {
  202. return false;
  203. }
  204. @NonNull
  205. @Override
  206. public BatteryStatus getBattery() {
  207. return new BatteryStatus(true, 100);
  208. }
  209. };
  210. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/empty.txt",
  211. FOLDER + "charging.txt", account.name);
  212. ocUpload.setWhileChargingOnly(true);
  213. UploadFileOperation newUpload = new UploadFileOperation(
  214. uploadsStorageManager,
  215. connectivityServiceMock,
  216. powerManagementServiceMock,
  217. user,
  218. null,
  219. ocUpload,
  220. NameCollisionPolicy.DEFAULT,
  221. FileUploadWorker.LOCAL_BEHAVIOUR_COPY,
  222. targetContext,
  223. false,
  224. true,
  225. getStorageManager()
  226. );
  227. newUpload.setRemoteFolderToBeCreated();
  228. newUpload.addRenameUploadListener(() -> {
  229. // dummy
  230. });
  231. RemoteOperationResult result = newUpload.execute(client);
  232. assertTrue(result.toString(), result.isSuccess());
  233. }
  234. @Test
  235. public void testUploadOnWifiOnlyButNoWifi() {
  236. ConnectivityService connectivityServiceMock = new ConnectivityService() {
  237. @Override
  238. public boolean isNetworkAndServerAvailable() throws NetworkOnMainThreadException {
  239. return false;
  240. }
  241. @Override
  242. public boolean isConnected() {
  243. return false;
  244. }
  245. @Override
  246. public boolean isInternetWalled() {
  247. return false;
  248. }
  249. @Override
  250. public Connectivity getConnectivity() {
  251. return new Connectivity(true, false, false, true);
  252. }
  253. @Override
  254. public void clearCachedResult() {
  255. }
  256. };
  257. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/empty.txt",
  258. FOLDER + "noWifi.txt", account.name);
  259. ocUpload.setUseWifiOnly(true);
  260. UploadFileOperation newUpload = new UploadFileOperation(
  261. uploadsStorageManager,
  262. connectivityServiceMock,
  263. powerManagementServiceMock,
  264. user,
  265. null,
  266. ocUpload,
  267. NameCollisionPolicy.DEFAULT,
  268. FileUploadWorker.LOCAL_BEHAVIOUR_COPY,
  269. targetContext,
  270. true,
  271. false,
  272. getStorageManager()
  273. );
  274. newUpload.setRemoteFolderToBeCreated();
  275. newUpload.addRenameUploadListener(() -> {
  276. // dummy
  277. });
  278. RemoteOperationResult result = newUpload.execute(client);
  279. assertFalse(result.toString(), result.isSuccess());
  280. assertEquals(RemoteOperationResult.ResultCode.DELAYED_FOR_WIFI, result.getCode());
  281. }
  282. @Test
  283. public void testUploadOnWifiOnlyAndWifi() {
  284. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/empty.txt",
  285. FOLDER + "wifi.txt", account.name);
  286. ocUpload.setWhileChargingOnly(true);
  287. UploadFileOperation newUpload = new UploadFileOperation(
  288. uploadsStorageManager,
  289. connectivityServiceMock,
  290. powerManagementServiceMock,
  291. user,
  292. null,
  293. ocUpload,
  294. NameCollisionPolicy.DEFAULT,
  295. FileUploadWorker.LOCAL_BEHAVIOUR_COPY,
  296. targetContext,
  297. true,
  298. false,
  299. getStorageManager()
  300. );
  301. newUpload.setRemoteFolderToBeCreated();
  302. newUpload.addRenameUploadListener(() -> {
  303. // dummy
  304. });
  305. RemoteOperationResult result = newUpload.execute(client);
  306. assertTrue(result.toString(), result.isSuccess());
  307. // cleanup
  308. new RemoveFileOperation(getStorageManager().getFileByDecryptedRemotePath(FOLDER),
  309. false,
  310. user,
  311. false,
  312. targetContext,
  313. getStorageManager())
  314. .execute(client);
  315. }
  316. @Test
  317. public void testUploadOnWifiOnlyButMeteredWifi() {
  318. ConnectivityService connectivityServiceMock = new ConnectivityService() {
  319. @Override
  320. public boolean isNetworkAndServerAvailable() throws NetworkOnMainThreadException {
  321. return false;
  322. }
  323. @Override
  324. public boolean isConnected() {
  325. return false;
  326. }
  327. @Override
  328. public boolean isInternetWalled() {
  329. return false;
  330. }
  331. @Override
  332. public Connectivity getConnectivity() {
  333. return new Connectivity(true, true, true, true);
  334. }
  335. @Override
  336. public void clearCachedResult() {
  337. }
  338. };
  339. OCUpload ocUpload = new OCUpload(FileStorageUtils.getTemporalPath(account.name) + "/empty.txt",
  340. FOLDER + "noWifi.txt",
  341. account.name);
  342. ocUpload.setUseWifiOnly(true);
  343. UploadFileOperation newUpload = new UploadFileOperation(
  344. uploadsStorageManager,
  345. connectivityServiceMock,
  346. powerManagementServiceMock,
  347. user,
  348. null,
  349. ocUpload,
  350. NameCollisionPolicy.DEFAULT,
  351. FileUploadWorker.LOCAL_BEHAVIOUR_COPY,
  352. targetContext,
  353. true,
  354. false,
  355. getStorageManager()
  356. );
  357. newUpload.setRemoteFolderToBeCreated();
  358. newUpload.addRenameUploadListener(() -> {
  359. // dummy
  360. });
  361. RemoteOperationResult result = newUpload.execute(client);
  362. assertFalse(result.toString(), result.isSuccess());
  363. assertEquals(RemoteOperationResult.ResultCode.DELAYED_FOR_WIFI, result.getCode());
  364. }
  365. @Test
  366. public void testCreationAndUploadTimestamp() throws IOException, AccountUtils.AccountNotFoundException {
  367. testOnlyOnServer(NextcloudVersion.nextcloud_27);
  368. File file = getDummyFile("empty.txt");
  369. String remotePath = "/testFile.txt";
  370. OCUpload ocUpload = new OCUpload(file.getAbsolutePath(), remotePath, account.name);
  371. assertTrue(
  372. new UploadFileOperation(
  373. uploadsStorageManager,
  374. connectivityServiceMock,
  375. powerManagementServiceMock,
  376. user,
  377. null,
  378. ocUpload,
  379. NameCollisionPolicy.DEFAULT,
  380. FileUploadWorker.LOCAL_BEHAVIOUR_COPY,
  381. targetContext,
  382. false,
  383. false,
  384. getStorageManager()
  385. )
  386. .setRemoteFolderToBeCreated()
  387. .execute(client)
  388. .isSuccess()
  389. );
  390. long creationTimestamp = Files.readAttributes(file.toPath(), BasicFileAttributes.class)
  391. .creationTime()
  392. .to(TimeUnit.SECONDS);
  393. long uploadTimestamp = System.currentTimeMillis() / 1000;
  394. // RefreshFolderOperation
  395. assertTrue(new RefreshFolderOperation(getStorageManager().getFileByDecryptedRemotePath("/"),
  396. System.currentTimeMillis() / 1000,
  397. false,
  398. false,
  399. getStorageManager(),
  400. user,
  401. targetContext).execute(client).isSuccess());
  402. List<OCFile> files = getStorageManager().getFolderContent(getStorageManager().getFileByDecryptedRemotePath("/"),
  403. false);
  404. OCFile ocFile = files.get(0);
  405. assertEquals(remotePath, ocFile.getRemotePath());
  406. assertEquals(creationTimestamp, ocFile.getCreationTimestamp());
  407. assertTrue(uploadTimestamp - 10 < ocFile.getUploadTimestamp() ||
  408. uploadTimestamp + 10 > ocFile.getUploadTimestamp());
  409. }
  410. @Test
  411. public void testMetadata() throws IOException, AccountUtils.AccountNotFoundException {
  412. testOnlyOnServer(NextcloudVersion.nextcloud_27);
  413. File file = getFile("gps.jpg");
  414. String remotePath = "/metadata.jpg";
  415. OCUpload ocUpload = new OCUpload(file.getAbsolutePath(), remotePath, account.name);
  416. assertTrue(
  417. new UploadFileOperation(
  418. uploadsStorageManager,
  419. connectivityServiceMock,
  420. powerManagementServiceMock,
  421. user,
  422. null,
  423. ocUpload,
  424. NameCollisionPolicy.DEFAULT,
  425. FileUploadWorker.LOCAL_BEHAVIOUR_COPY,
  426. targetContext,
  427. false,
  428. false,
  429. getStorageManager()
  430. )
  431. .setRemoteFolderToBeCreated()
  432. .execute(client)
  433. .isSuccess()
  434. );
  435. // RefreshFolderOperation
  436. assertTrue(new RefreshFolderOperation(getStorageManager().getFileByDecryptedRemotePath("/"),
  437. System.currentTimeMillis() / 1000,
  438. false,
  439. false,
  440. getStorageManager(),
  441. user,
  442. targetContext).execute(client).isSuccess());
  443. List<OCFile> files = getStorageManager().getFolderContent(getStorageManager().getFileByDecryptedRemotePath("/"),
  444. false);
  445. OCFile ocFile = null;
  446. for (OCFile f : files) {
  447. if (f.getFileName().equals("metadata.jpg")) {
  448. ocFile = f;
  449. break;
  450. }
  451. }
  452. assertNotNull(ocFile);
  453. assertEquals(remotePath, ocFile.getRemotePath());
  454. assertEquals(new GeoLocation(64, -46), ocFile.getGeoLocation());
  455. assertEquals(new ImageDimension(300f, 200f), ocFile.getImageDimension());
  456. }
  457. private void verifyStoragePath(OCFile file) {
  458. assertEquals(FileStorageUtils.getSavePath(account.name) + FOLDER + file.getDecryptedFileName(),
  459. file.getStoragePath());
  460. }
  461. }