diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6ba265a284592e3672280c4bdf7c0aa14a25109d..b71b2cbc5981f0b48c4089899005654eda611351 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,7 @@ image: "registry.gitlab.e.foundation:5000/e/apps/docker-android-apps-cicd:latest" stages: +- test - build before_script: @@ -9,15 +10,32 @@ before_script: - export GRADLE_USER_HOME=$(pwd)/.gradle - chmod +x ./gradlew + cache: key: ${CI_PROJECT_ID} paths: - .gradle/ + +test: + allow_failure: true + stage: test + script: + - ls /usr/lib/jvm/ + - ./gradlew test -Dorg.gradle.java.home=/usr/lib/jvm/java-8-openjdk-amd64 -PtestAccountName="$testAccountName" -PtestAccountPwd="$testAccountPwd" -PtestServerUrl="$testServerUrl" + artifacts: + when: always + paths: + - app/build/test-results/*/TEST-*.xml + - app/build/reports/tests/* + reports: + junit: app/build/test-results/*/TEST-*.xml + + build: stage: build script: - - ./gradlew build + - ./gradlew build -x test artifacts: paths: - app/build/outputs/apk/ diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 73f2520ea0453ae3c2a7d931f8596f3124c8d27f..0000000000000000000000000000000000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 5b312b6a558f631c50b1676e97ba4c3fdce24957..c93eb509511055cacde6495a8b826e2845631a45 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,6 +9,18 @@ def buildTime() { return df.format(new Date()) } +def getTestProp(String propName) { + def result = "" + if(project.hasProperty(propName)){ + result =project.property(propName).toString() + }else if(project.rootProject.file('local.properties').exists()){ + Properties properties = new Properties() + properties.load(project.rootProject.file('local.properties').newReader()) + result = properties.getProperty(propName) + } + return result +} + android { compileSdkVersion 26 @@ -19,7 +31,9 @@ android { //versionName "1.0" versionName "beta-${versionMajor}-build-o-${buildTime()}" setProperty("archivesBaseName", "$applicationId.$versionName") - + buildConfigField "String", "testAccountName", "\""+getTestProp("testAccountName")+"\"" + buildConfigField "String", "testAccountPWd", "\""+getTestProp("testAccountPwd")+"\"" + buildConfigField "String", "testServerUrl", "\""+getTestProp("testServerUrl")+"\"" } buildTypes { release { @@ -34,19 +48,37 @@ android { testOptions { - unitTests.returnDefaultValues = true + unitTests { + returnDefaultValues = true + //includeAndroidResources = true + } } + } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:26.1.0' - testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:rules:1.0.2' androidTestImplementation 'com.android.support:support-annotations:27.1.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' api 'com.android.support:support-annotations:27.1.1' api project(':NextcloudLib') + + //start to add lib for test - 1/4/21 + //@TODO: add junit runner as lib for testImplementation + + testImplementation 'com.android.support.test:runner:1.0.2' + testImplementation 'com.android.support.test:rules:1.0.2' + testImplementation 'junit:junit:4.12' + //testImplementation 'org.robolectric:robolectric:4.4' //need AndroidX + testImplementation "org.robolectric:robolectric:3.8" + testImplementation('org.mockito:mockito-inline:3.4.0') + + //testImplementation Libs.AndroidX.Test.archCoreTesting //TODO: replace by not android X version + //implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0' + androidTestImplementation 'junit:junit:4.12' } diff --git a/app/src/androidTest/java/foundation/e/drive/ExampleInstrumentedTest.java b/app/src/androidTest/java/foundation/e/drive/ExampleInstrumentedTest.java deleted file mode 100644 index e6c481cdcd194c3e4b10af9498f7f5325993bf15..0000000000000000000000000000000000000000 --- a/app/src/androidTest/java/foundation/e/drive/ExampleInstrumentedTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright © Vincent Bourgmayer (/e/ foundation). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - */ - - -package foundation.e.drive; - -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() throws Exception { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - - assertEquals("foundation.e.drive", appContext.getPackageName()); - } -} diff --git a/app/src/androidTest/java/foundation/e/drive/services/ObserverServiceInstrumentedTest.java b/app/src/androidTest/java/foundation/e/drive/services/ObserverServiceInstrumentedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bd5fe22cd23116c10c5b0b339b4a18eb8ba736dc --- /dev/null +++ b/app/src/androidTest/java/foundation/e/drive/services/ObserverServiceInstrumentedTest.java @@ -0,0 +1,100 @@ +package foundation.e.drive.services; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Environment; +import android.support.test.InstrumentationRegistry; +import android.support.test.rule.ServiceTestRule; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.concurrent.TimeoutException; + +import static android.support.test.InstrumentationRegistry.getContext; +import static org.junit.Assert.*; + + + + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ObserverServiceInstrumentedTest { + private final static String NEW_SMALL_FILE_PATH = Environment.getExternalStorageDirectory() + File.separator + Environment.DIRECTORY_DOCUMENTS+File.separator+"test-small-file.txt"; + private final static String ACCOUNT_NAME= ""; + private final static String ACCOUNT_PASS=""; + private final static String ACCOUNT_TYPE=""; + + + @Rule + public final ServiceTestRule mServiceRule = new ServiceTestRule(); + + + @Before + public void RegisterAccount() throws Exception { + final Account account = new Account(ACCOUNT_NAME, ACCOUNT_TYPE); + AccountManager.get(getContext()).addAccountExplicitly(account, ACCOUNT_PASS, null); + + } + + + /** + * Souldn't it be more for a unit test ? + * @throws IOException + */ + @Before + public void createLocalSmallFile() throws IOException { + + File file = new File(NEW_SMALL_FILE_PATH); + file.createNewFile(); + String content = "this a very small content"; +//write the bytes in file + if(file.exists()) + { + OutputStream fo = new FileOutputStream(file); + fo.write(content.getBytes()); + fo.close(); + System.out.println("file created: "+file); + } + } + + + @After + public void deleteLocalSmallFile(){ + File file = new File(NEW_SMALL_FILE_PATH); + //deleting the file + file.delete(); + } + + + @Test + public void testWithStartedService() throws TimeoutException { + mServiceRule.startService( + new Intent(InstrumentationRegistry.getTargetContext(), ObserverService.class)); + //do something + } + + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + + assertEquals("foundation.e.drive", appContext.getPackageName()); + } +} diff --git a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java index 88276a6b9703b773b4bdaf40e115b3b11e4e59e0..515ce35f4ab8a548244d5f63d48b85f740e1561b 100644 --- a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java @@ -11,6 +11,7 @@ package foundation.e.drive.operations; import android.content.Context; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.VisibleForTesting; import android.util.Log; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.UserInfo; @@ -217,7 +218,8 @@ public class UploadFileOperation extends RemoteOperation implements ComparableOp * @param client OwnCloudClient * @return RemoteOperationResult */ - private RemoteOperationResult checkAvailableSpace(OwnCloudClient client, long fileSize){ + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + public RemoteOperationResult checkAvailableSpace(OwnCloudClient client, long fileSize){ GetRemoteUserInfoOperation getRemoteUserInfoOperation = new GetRemoteUserInfoOperation(); RemoteOperationResult ocsResult = getRemoteUserInfoOperation.execute(client); if(ocsResult.isSuccess() && ocsResult.getData() != null){ diff --git a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java index 2d1c16e2075583f573ec17e3d5845d66938b3a93..b6de97e44b0d2ea228d2db038c3e039357f6de12 100644 --- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java @@ -17,6 +17,7 @@ import android.content.ContentResolver; import android.content.Context; import android.media.MediaScannerConnection; import android.net.ConnectivityManager; +import android.net.Network; import android.net.NetworkInfo; import android.net.Uri; import android.support.annotation.NonNull; @@ -54,7 +55,7 @@ public abstract class CommonUtils { public static void setServiceUnCaughtExceptionHandler(Service service) { Thread.UncaughtExceptionHandler defaultUEH = Thread.getDefaultUncaughtExceptionHandler(); - if (defaultUEH.getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())) { + if (defaultUEH != null && ServiceExceptionHandler.class.getSimpleName().equals(defaultUEH.getClass().getSimpleName())) { Log.d("ObserverService", "ServiceExceptionHandler already set!"); ((ServiceExceptionHandler) defaultUEH).setService(service); } else { @@ -206,10 +207,10 @@ public abstract class CommonUtils { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo[] netInfo = cm.getAllNetworkInfo(); for (NetworkInfo ni : netInfo) { - if (ni.getTypeName().equalsIgnoreCase("WIFI")) + if (ni.getType()== ConnectivityManager.TYPE_WIFI) // Replaced the ni.getTypeName by ni.getType to make the test from ObserverServiceTest to work. But looks a better solution in all case if (ni.isConnected()) haveConnectedWifi = true; - if (ni.getTypeName().equalsIgnoreCase("MOBILE")) + if (ni.getType()== ConnectivityManager.TYPE_MOBILE) if (ni.isConnected()) haveConnectedMobile = true; } diff --git a/app/src/test/java/foundation/e/drive/Test/CommonUtilsUnitTest.java b/app/src/test/java/foundation/e/drive/Test/CommonUtilsUnitTest.java deleted file mode 100644 index e76ac1e6d2451257e97a8e5a6439ba0abd8a2203..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/drive/Test/CommonUtilsUnitTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright © Vincent Bourgmayer (/e/ foundation). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - */ -package foundation.e.drive.Test; -import android.accounts.Account; - -import org.junit.Assert; -import org.junit.Test; - -/** - * @author Vincent Bourgmayer - * raw mock will be replace ASAP to use mockito or other similar framework - */ -public class CommonUtilsUnitTest { - - @Test - public void testIsThisSyncAllowed(){ - - boolean isMediaType = true; //sfs is media element - - MockAccount account = new MockAccount("allowed", "allowed"); //Both type sync are allowed - - Assert.assertNotNull("Assert account not null", account); - - Assert.assertTrue(isThisSyncAllowed(account, isMediaType)); - - account = new MockAccount("allowed", "not allowed"); //Only Media sync is enabled - Assert.assertTrue(isThisSyncAllowed(account, isMediaType)); - - account = new MockAccount("not allowed", "allowed"); //Only settings sync is enabled - Assert.assertFalse(isThisSyncAllowed(account, isMediaType)); - - account = new MockAccount("not allowed", "not allowed"); //no sync is enabled - Assert.assertFalse(isThisSyncAllowed(account, isMediaType)); - - isMediaType = false; - Assert.assertFalse(isThisSyncAllowed(account, isMediaType)); - - account = new MockAccount("allowed", "not allowed"); //Only Media sync is enabled - Assert.assertFalse(isThisSyncAllowed(account, isMediaType)); - - account = new MockAccount("not allowed", "allowed"); //Only settings sync is enabled - Assert.assertTrue(isThisSyncAllowed(account, isMediaType)); - - account = new MockAccount("allowed", "allowed"); //no sync is enabled - Assert.assertTrue(isThisSyncAllowed(account, isMediaType)); - - } - - - static boolean isThisSyncAllowed(MockAccount account, boolean syncedFileStateIsMedia){ - return ( syncedFileStateIsMedia && mockedIsMediaSyncEnabled(account) ) - || ( !syncedFileStateIsMedia && mockedIsSettingsSyncEnabled(account) ) ; - } - - //@mock tmp - static boolean mockedIsMediaSyncEnabled(MockAccount account){ - return account.mockName.equals("allowed"); - } - - //@mock tmp - static boolean mockedIsSettingsSyncEnabled(MockAccount account){ - return account.mockType.equals("allowed"); - } - - - /** - * Tmp mock class - */ - public class MockAccount extends Account{ - - String mockName; - String mockType; - MockAccount(String name, String type) { - super(name, type); - this.mockName = name; - this.mockType = type; - } - } -} diff --git a/app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java b/app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java deleted file mode 100644 index 69950012771be37419c515ddc87f2d6a6a45ab7a..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package foundation.e.drive.Test.FileFilterTest; - -import org.junit.Assert; -import org.junit.Test; - -public class CrashlogFileFilterTest { - - private String mockFileName(String target, String prefix, String extension){ - return prefix+target+extension; - } - - private String extractTimestamp(String fileName, String prefix, String extension){ - return fileName.substring(prefix.length(), (fileName.length() - extension.length())); - } - - @Test - public void extractTimeStampFromFileNameTest(){ - String prefix = "edrive-"; - String extension = ".log"; - String target = ""; - //Case 1 Empty Target - String base = mockFileName(target, prefix, extension); - Assert.assertEquals("Base length is incorrect", prefix.length()+extension.length(), base.length()); - - String fileTimestamp = extractTimestamp(base, prefix, extension); - Assert.assertEquals("result is not empty String", "", fileTimestamp); - - //Case 2: Prefix is empty - prefix = ""; - target = "1234"; - base = mockFileName(target, prefix, extension); - Assert.assertEquals("Base length is incorrect", prefix.length()+target.length()+extension.length(), base.length()); - - fileTimestamp = extractTimestamp(base, prefix, extension); - Assert.assertEquals("result is not empty String", target, fileTimestamp); - - //Case 3: extension is empty - - prefix = "edrive-"; - extension = ""; - - base = mockFileName(target, prefix, extension); - Assert.assertEquals("Base length is incorrect", prefix.length()+target.length(), base.length()); - - fileTimestamp = extractTimestamp(base, prefix, extension); - Assert.assertEquals("result is not empty String", target, fileTimestamp); - } -} \ No newline at end of file diff --git a/app/src/test/java/foundation/e/drive/Test/FileFilterTest/FileFilterUnitTest.java b/app/src/test/java/foundation/e/drive/Test/FileFilterTest/FileFilterUnitTest.java deleted file mode 100644 index 6d3d3051ada390ca6b943440546fa6df25cebdb2..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/drive/Test/FileFilterTest/FileFilterUnitTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright © Vincent Bourgmayer (/e/ foundation). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - */ - - -package foundation.e.drive.Test.FileFilterTest; - -import junit.framework.Assert; - -import org.junit.Test; - -import foundation.e.drive.utils.AppConstants; -/** - * @author Vincent Bourgmayer - */ -public class FileFilterUnitTest { - - @Test - public void SettingsFileFilterUnitTest(){ - //Directory situation - Assert.assertFalse(mockSettingFileFilterAcceptMethod("", false)); - Assert.assertFalse(mockSettingFileFilterAcceptMethod("", true)); - Assert.assertFalse(mockSettingFileFilterAcceptMethod("settings_foo.xml", false)); - Assert.assertFalse(mockSettingFileFilterAcceptMethod(AppConstants.APPLICATIONS_LIST_FILE_NAME, false)); - Assert.assertFalse(mockSettingFileFilterAcceptMethod("settings_", true)); - Assert.assertFalse(mockSettingFileFilterAcceptMethod(".xml", true)); - Assert.assertFalse(mockSettingFileFilterAcceptMethod("settings_"+AppConstants.APPLICATIONS_LIST_FILE_NAME, true)); - - - Assert.assertTrue(mockSettingFileFilterAcceptMethod("settings_.xml", true)); - Assert.assertTrue(mockSettingFileFilterAcceptMethod("settings_foo.xml", true)); - Assert.assertTrue(mockSettingFileFilterAcceptMethod(AppConstants.APPLICATIONS_LIST_FILE_NAME, true)); - } - - private boolean mockSettingFileFilterAcceptMethod(String name, boolean isFile){ - return ( isFile && - ( ( name.startsWith("settings_") && name.endsWith(".xml") ) - || name.equals( AppConstants.APPLICATIONS_LIST_FILE_NAME ) ) ); - } -} diff --git a/app/src/test/java/foundation/e/drive/Test/MD5Test.java b/app/src/test/java/foundation/e/drive/Test/MD5Test.java deleted file mode 100644 index c68da4cf5a0a2ccd32e6696102c0668d97eaa5aa..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/drive/Test/MD5Test.java +++ /dev/null @@ -1,85 +0,0 @@ -package foundation.e.drive.Test; - - -/* - * Copyright (C) 2012 The CyanogenMod Project - * - * * Licensed under the GNU GPLv2 license - * - * The text of the license can be found in the LICENSE file - * or at https://www.gnu.org/licenses/gpl-2.0.txt - */ - - import android.text.TextUtils; - import android.util.Log; - - import java.io.File; - import java.io.FileInputStream; - import java.io.FileNotFoundException; - import java.io.IOException; - import java.io.InputStream; - import java.math.BigInteger; - import java.security.MessageDigest; - import java.security.NoSuchAlgorithmException; - -public class MD5Test { - private static final String TAG = "MD5"; - - public static boolean checkMD5(String md5, File updateFile) { - if (TextUtils.isEmpty(md5) || updateFile == null) { - Log.e(TAG, "MD5 string empty or updateFile null"); - return false; - } - - String calculatedDigest = calculateMD5(updateFile); - if (calculatedDigest == null) { - Log.e(TAG, "calculatedDigest null"); - return false; - } - - Log.v(TAG, "Calculated digest: " + calculatedDigest); - Log.v(TAG, "Provided digest: " + md5); - - return calculatedDigest.equalsIgnoreCase(md5); - } - - public static String calculateMD5(File updateFile) { - MessageDigest digest; - try { - digest = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - Log.e(TAG, "Exception while getting digest", e); - return null; - } - - InputStream is; - try { - is = new FileInputStream(updateFile); - } catch (FileNotFoundException e) { - Log.e(TAG, "Exception while getting FileInputStream", e); - return null; - } - - byte[] buffer = new byte[8192]; - int read; - try { - while ((read = is.read(buffer)) > 0) { - digest.update(buffer, 0, read); - } - byte[] md5sum = digest.digest(); - BigInteger bigInt = new BigInteger(1, md5sum); - String output = bigInt.toString(16); - // Fill to 32 chars - output = String.format("%32s", output).replace(' ', '0'); - return output; - } catch (IOException e) { - throw new RuntimeException("Unable to process file for MD5", e); - } finally { - try { - is.close(); - } catch (IOException e) { - Log.e(TAG, "Exception on closing MD5 input stream", e); - } - } - } -} \ No newline at end of file diff --git a/app/src/test/java/foundation/e/drive/Test/ObserverServiceUnitTest.java b/app/src/test/java/foundation/e/drive/Test/ObserverServiceUnitTest.java deleted file mode 100644 index e96d74031bd3410806a2e4e8f1e3a33d518dd5cf..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/drive/Test/ObserverServiceUnitTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright © Vincent Bourgmayer (/e/ foundation). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - */ -package foundation.e.drive.Test; - -import org.junit.Assert; -import org.junit.Test; -import java.io.File; -import java.util.ArrayList; -import java.util.List; - - -/** - * @author Vincent Bourgmayer - */ - -public class ObserverServiceUnitTest { - - public File[] mockCachedFile(){ - File[] mockFile= new File[5]; - for(int i = 0; i < 5; ++i){ - mockFile[i] = new File("/emulated/storage/0/android/data/toto"+i+".jpg"); - } - return mockFile; - } - - public List mockUsedFilePath (){ - List stringList = new ArrayList<>(); - System.out.println("Stringset:"+( (stringList == null)? false: true) ); - boolean a1 = stringList.add( new String("/emulated/storage/0/DCIM/Camera/toto1.jpg") ); - boolean a2 = stringList.add( new String("/emulated/storage/0/DCIM/Camera/toto2.jpg") ); - //boolean a3 = stringSet.add( new String("/emulated/storage/0/DCIM/Camera/toto4.jpg") ); - Assert.assertNotNull(stringList); - return stringList; - } - - @Test - public void handleCachedFile(){ - //Load subfiles into external cache file - //Mock this - File[] fileArray = mockCachedFile(); - - Assert.assertNotNull(fileArray); - //Mock this; - List usedFilePath = mockUsedFilePath(); - - Assert.assertNotNull(usedFilePath); - boolean toRemove = true; - for(int i =0; i < fileArray.length; ++i){ - toRemove = true; - //System.out.println( fileArray[i] ); - for(String filePath : usedFilePath){ - - if(filePath.endsWith(fileArray[i].getName())){ - System.out.println("TRUE"); - toRemove = false; - }else - System.out.println("FALSE"); - } - if(toRemove){ - System.out.println("Deletion of file: "+fileArray[i].getName() ); - } - } - } -} diff --git a/app/src/test/java/foundation/e/drive/Test/SyncedFolderUnitTest.java b/app/src/test/java/foundation/e/drive/Test/SyncedFolderUnitTest.java deleted file mode 100644 index d56228ec6f68ef258d8f590c83b5a38d0104a7ee..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/drive/Test/SyncedFolderUnitTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © Vincent Bourgmayer (/e/ foundation). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - */ -package foundation.e.drive.Test; - -import junit.framework.Assert; - -import org.junit.Test; - -import java.util.Arrays; -import java.util.List; - -import foundation.e.drive.models.SyncedFolder; - -import static foundation.e.drive.utils.AppConstants.MEDIA_SYNCABLE_CATEGORIES; - -/** - * @author Vincent Bourgmayer - */ - -public class SyncedFolderUnitTest { - - @Test - public void childCreationTest(){ - SyncedFolder parent = new SyncedFolder("dummy", "/storage/emulated/0/dummy/", "/dummy/", true, true, true, true); - Assert.assertNotNull(parent); - parent.setId(6); - parent.setLastModified(123456789); - - Assert.assertEquals("dummy", parent.getLibelle() ); - - SyncedFolder child = new SyncedFolder(parent, "sub_dummy/", 234678965, ""); - Assert.assertNotNull("child is null", child); - Assert.assertEquals("LocalPath isn't valid", "/storage/emulated/0/dummy/sub_dummy/", child.getLocalFolder()); - Assert.assertEquals("remotePath isn't valid", "/dummy/sub_dummy/", child.getRemoteFolder() ); - Assert.assertTrue("lastModified aren't different", child.getLastModified() != parent.getLastModified() ); - Assert.assertEquals("child libelle isn't valid", parent.getLibelle(), child.getLibelle() ); - Assert.assertTrue("Id are the same", parent.getId() != child.getId() ); - } - - @Test - public void testArrayToList(){ - List arrays = Arrays.asList(MEDIA_SYNCABLE_CATEGORIES); - - Assert.assertEquals(MEDIA_SYNCABLE_CATEGORIES.length, arrays.size()); - - } -} diff --git a/app/src/test/java/foundation/e/drive/Test/doTest.java b/app/src/test/java/foundation/e/drive/Test/doTest.java deleted file mode 100644 index b1aa1589e3df6a2f29b37020df0b30bcc7ca6c50..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/drive/Test/doTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package foundation.e.drive.Test; - -public class doTest { -} diff --git a/app/src/test/java/foundation/e/drive/Test/mockObject/mockContext.java b/app/src/test/java/foundation/e/drive/Test/mockObject/mockContext.java deleted file mode 100644 index 9e782f6c009a1f553e48588520303f9923a815c6..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/drive/Test/mockObject/mockContext.java +++ /dev/null @@ -1,565 +0,0 @@ -package foundation.e.drive.Test.mockObject; - -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.IntentSender; -import android.content.ServiceConnection; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.database.DatabaseErrorHandler; -import android.database.sqlite.SQLiteDatabase; -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.UserHandle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.view.Display; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -public class mockContext extends Context{ - - public mockContext(){ - - } - @Override - public AssetManager getAssets() { - return null; - } - - @Override - public Resources getResources() { - return null; - } - - @Override - public PackageManager getPackageManager() { - return null; - } - - @Override - public ContentResolver getContentResolver() { - return null; - } - - @Override - public Looper getMainLooper() { - return null; - } - - @Override - public Context getApplicationContext() { - return null; - } - - @Override - public void setTheme(int resid) { - - } - - @Override - public Resources.Theme getTheme() { - return null; - } - - @Override - public ClassLoader getClassLoader() { - return null; - } - - @Override - public String getPackageName() { - return null; - } - - @Override - public ApplicationInfo getApplicationInfo() { - return null; - } - - @Override - public String getPackageResourcePath() { - return null; - } - - @Override - public String getPackageCodePath() { - return null; - } - - @Override - public SharedPreferences getSharedPreferences(String name, int mode) { - return null; - } - - @Override - public boolean moveSharedPreferencesFrom(Context sourceContext, String name) { - return false; - } - - @Override - public boolean deleteSharedPreferences(String name) { - return false; - } - - @Override - public FileInputStream openFileInput(String name) throws FileNotFoundException { - return null; - } - - @Override - public FileOutputStream openFileOutput(String name, int mode) throws FileNotFoundException { - return null; - } - - @Override - public boolean deleteFile(String name) { - return false; - } - - @Override - public File getFileStreamPath(String name) { - return null; - } - - @Override - public File getDataDir() { - return null; - } - - @Override - public File getFilesDir() { - return null; - } - - @Override - public File getNoBackupFilesDir() { - return null; - } - - @Nullable - @Override - public File getExternalFilesDir(@Nullable String type) { - return null; - } - - @Override - public File[] getExternalFilesDirs(String type) { - return new File[0]; - } - - @Override - public File getObbDir() { - return null; - } - - @Override - public File[] getObbDirs() { - return new File[0]; - } - - @Override - public File getCacheDir() { - return null; - } - - @Override - public File getCodeCacheDir() { - return null; - } - - @Nullable - @Override - public File getExternalCacheDir() { - return null; - } - - @Override - public File[] getExternalCacheDirs() { - return new File[0]; - } - - @Override - public File[] getExternalMediaDirs() { - return new File[0]; - } - - @Override - public String[] fileList() { - return new String[0]; - } - - @Override - public File getDir(String name, int mode) { - return null; - } - - @Override - public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) { - return null; - } - - @Override - public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, @Nullable DatabaseErrorHandler errorHandler) { - return null; - } - - @Override - public boolean moveDatabaseFrom(Context sourceContext, String name) { - return false; - } - - @Override - public boolean deleteDatabase(String name) { - return false; - } - - @Override - public File getDatabasePath(String name) { - return null; - } - - @Override - public String[] databaseList() { - return new String[0]; - } - - @Override - public Drawable getWallpaper() { - return null; - } - - @Override - public Drawable peekWallpaper() { - return null; - } - - @Override - public int getWallpaperDesiredMinimumWidth() { - return 0; - } - - @Override - public int getWallpaperDesiredMinimumHeight() { - return 0; - } - - @Override - public void setWallpaper(Bitmap bitmap) throws IOException { - - } - - @Override - public void setWallpaper(InputStream data) throws IOException { - - } - - @Override - public void clearWallpaper() throws IOException { - - } - - @Override - public void startActivity(Intent intent) { - - } - - @Override - public void startActivity(Intent intent, @Nullable Bundle options) { - - } - - @Override - public void startActivities(Intent[] intents) { - - } - - @Override - public void startActivities(Intent[] intents, Bundle options) { - - } - - @Override - public void startIntentSender(IntentSender intent, @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags) throws IntentSender.SendIntentException { - - } - - @Override - public void startIntentSender(IntentSender intent, @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, @Nullable Bundle options) throws IntentSender.SendIntentException { - - } - - @Override - public void sendBroadcast(Intent intent) { - - } - - @Override - public void sendBroadcast(Intent intent, @Nullable String receiverPermission) { - - } - - @Override - public void sendOrderedBroadcast(Intent intent, @Nullable String receiverPermission) { - - } - - @Override - public void sendOrderedBroadcast(@NonNull Intent intent, @Nullable String receiverPermission, @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) { } - @Override - public void sendBroadcastAsUser(Intent intent, UserHandle user) { - - } - - @Override - public void sendBroadcastAsUser(Intent intent, UserHandle user, @Nullable String receiverPermission) { - - } - - @Override - public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, @Nullable String receiverPermission, BroadcastReceiver - resultReceiver, @Nullable Handler scheduler, int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) { - - } - - @Override - public void sendStickyBroadcast(Intent intent) { - - } - - @Override - public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) { - - } - - @Override - public void removeStickyBroadcast(Intent intent) { - - } - - @Override - public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) { - - } - - @Override - public void sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user, BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) { - - } - - @Override - public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) { - - } - - @Nullable - @Override - public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) { - return null; - } - - @Nullable - @Override - public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter, int flags) { - return null; - } - - @Nullable - @Override - public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, @Nullable String broadcastPermission, @Nullable Handler scheduler) { - return null; - } - - @Nullable - @Override - public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, @Nullable String broadcastPermission, @Nullable Handler scheduler, int flags) { - return null; - } - - @Override - public void unregisterReceiver(BroadcastReceiver receiver) { - - } - - @Nullable - @Override - public ComponentName startService(Intent service) { - return null; - } - - @Nullable - @Override - public ComponentName startForegroundService(Intent service) { - return null; - } - - @Override - public boolean stopService(Intent service) { - return false; - } - - @Override - public boolean bindService(Intent service, @NonNull ServiceConnection conn, int flags) { - return false; - } - - @Override - public void unbindService(@NonNull ServiceConnection conn) { - - } - - @Override - public boolean startInstrumentation(@NonNull ComponentName className, @Nullable String profileFile, @Nullable Bundle arguments) { - return false; - } - - @Nullable - @Override - public Object getSystemService(@NonNull String name) { - return null; - } - - @Nullable - @Override - public String getSystemServiceName(@NonNull Class serviceClass) { - return null; - } - - @Override - public int checkPermission(@NonNull String permission, int pid, int uid) { - return 0; - } - - @Override - public int checkCallingPermission(@NonNull String permission) { - return 0; - } - - @Override - public int checkCallingOrSelfPermission(@NonNull String permission) { - return 0; - } - - @Override - public int checkSelfPermission(@NonNull String permission) { - return 0; - } - - @Override - public void enforcePermission(@NonNull String permission, int pid, int uid, @Nullable String message) { - - } - - @Override - public void enforceCallingPermission(@NonNull String permission, @Nullable String message) { - - } - - @Override - public void enforceCallingOrSelfPermission(@NonNull String permission, @Nullable String message) { - - } - - @Override - public void grantUriPermission(String toPackage, Uri uri, int modeFlags) { - - } - - @Override - public void revokeUriPermission(Uri uri, int modeFlags) { - - } - - @Override - public void revokeUriPermission(String toPackage, Uri uri, int modeFlags) { - - } - - @Override - public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) { - return 0; - } - - @Override - public int checkCallingUriPermission(Uri uri, int modeFlags) { - return 0; - } - - @Override - public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) { - return 0; - } - - @Override - public int checkUriPermission(@Nullable Uri uri, @Nullable String readPermission, @Nullable String writePermission, int pid, int uid, int modeFlags) { - return 0; - } - - @Override - public void enforceUriPermission(Uri uri, int pid, int uid, int modeFlags, String message) { - - } - - @Override - public void enforceCallingUriPermission(Uri uri, int modeFlags, String message) { - - } - - @Override - public void enforceCallingOrSelfUriPermission(Uri uri, int modeFlags, String message) { - - } - - @Override - public void enforceUriPermission(@Nullable Uri uri, @Nullable String readPermission, @Nullable String writePermission, int pid, int uid, int modeFlags, @Nullable String message) { - - } - - @Override - public Context createPackageContext(String packageName, int flags) throws PackageManager.NameNotFoundException { - return null; - } - - @Override - public Context createContextForSplit(String splitName) throws PackageManager.NameNotFoundException { - return null; - } - - @Override - public Context createConfigurationContext(@NonNull Configuration overrideConfiguration) { - return null; - } - - @Override - public Context createDisplayContext(@NonNull Display display) { - return null; - } - - @Override - public Context createDeviceProtectedStorageContext() { - return null; - } - - @Override - public boolean isDeviceProtectedStorage() { - return false; - } - } - diff --git a/app/src/test/java/foundation/e/drive/Test/mockObject/mockRemoteFile.java b/app/src/test/java/foundation/e/drive/Test/mockObject/mockRemoteFile.java deleted file mode 100644 index fcdedb31f2adb6ddc50b1f833e0d1b0bab136c4d..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/drive/Test/mockObject/mockRemoteFile.java +++ /dev/null @@ -1,7 +0,0 @@ -package foundation.e.drive.Test.mockObject; - -import com.owncloud.android.lib.resources.files.model.RemoteFile; - -public class mockRemoteFile extends RemoteFile { - public mockRemoteFile(){}; -} diff --git a/app/src/test/java/foundation/e/drive/Test/mockObject/mockSfs.java b/app/src/test/java/foundation/e/drive/Test/mockObject/mockSfs.java deleted file mode 100644 index 01d69d08bf72d2d1f86df8dab731723c32ddd09a..0000000000000000000000000000000000000000 --- a/app/src/test/java/foundation/e/drive/Test/mockObject/mockSfs.java +++ /dev/null @@ -1,7 +0,0 @@ -package foundation.e.drive.Test.mockObject; - -import foundation.e.drive.models.SyncedFileState; - -public class mockSfs extends SyncedFileState { - public mockSfs(){} -} diff --git a/app/src/test/java/foundation/e/drive/TestUtils.java b/app/src/test/java/foundation/e/drive/TestUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..159609daf5f2e89b8cf930eecca215734652220b --- /dev/null +++ b/app/src/test/java/foundation/e/drive/TestUtils.java @@ -0,0 +1,147 @@ +package foundation.e.drive; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.network.CertificateCombinedException; +import com.owncloud.android.lib.common.network.NetworkUtils; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation; + +import org.junit.BeforeClass; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import static com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_BASE_URL; +import static org.junit.Assert.assertTrue; +import static org.robolectric.Shadows.shadowOf; + +public abstract class TestUtils { + public static final String TEST_LOCAL_ROOT_FOLDER_PATH = "/tmp/eDrive/test/"; //THis is where test file and folder for synchronisatio will be stored + public static final String TEST_REMOTE_ROOT_FOLDER_PATH ="/eDrive-test/"; + public static String TEST_ACCOUNT_TYPE ="eelo"; + public static String TEST_SERVER_URI; + public static String TEST_ACCOUNT_NAME; + + private static String TEST_ACCOUNT_PASSWORD; //Shouldn't be accessible from outside + private static Account validAccount; + + + /** + * This method execute before the class, it assure that credentials are available + */ + public static void loadServerCredentials(){ + TEST_ACCOUNT_PASSWORD = BuildConfig.testAccountPWd; + TEST_ACCOUNT_NAME = BuildConfig.testAccountName; + TEST_SERVER_URI = BuildConfig.testServerUrl; + } + + + /** + * Get the valid Account object. Create it if it isn't already instanciated + * @return + */ + public static Account getValidAccount(){ + if(validAccount == null){ + System.out.println("Account name = "+TEST_ACCOUNT_NAME); + validAccount = new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE); + } + return validAccount; + } + + /** + * register in accountManager an account with name, password, type and server url provided at build + */ + public static void prepareValidAccount(AccountManager accountManager){ + storeAccountInManager(getValidAccount(), TEST_ACCOUNT_PASSWORD, TEST_SERVER_URI, accountManager); + } + + + public static void storeAccountInManager(Account account, String password, String serverUrl, AccountManager manager){ + shadowOf(manager).addAccount(account); // Commenting this make failure due to JobUtils.stopScheduleJob()" method... + shadowOf(manager).setPassword(account, password); + shadowOf(manager).setUserData(account, KEY_OC_BASE_URL, serverUrl); + } + + /** + * Test the connexion to the server + * Add the certificate to the knownServerCertificateStore if required + * @throws KeyStoreException + * @throws CertificateException + * @throws NoSuchAlgorithmException + * @throws IOException + * @throws InterruptedException + */ + public static void testConnection(OwnCloudClient client, Context context) throws KeyStoreException, + CertificateException, + NoSuchAlgorithmException, + IOException, + InterruptedException{ + + GetRemoteStatusOperation getStatus = new GetRemoteStatusOperation(context); + + RemoteOperationResult result = getStatus.execute(client); + + if (result.isSuccess()) { + Log_OC.d("AbstractIT", "Connection to server successful"); + } else { + if (RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED.equals(result.getCode())) { + Log_OC.d("AbstractIT", "Accepting certificate"); + + CertificateCombinedException exception = (CertificateCombinedException) result.getException(); + X509Certificate certificate = exception.getServerCertificate(); + + NetworkUtils.addCertToKnownServersStore(certificate, context); + Thread.sleep(1000); + + // retry + getStatus = new GetRemoteStatusOperation(context); + result = getStatus.execute(client); + + if (!result.isSuccess()) { + throw new RuntimeException("No connection to server possible, even with accepted cert"); + } + + } else { + throw new RuntimeException("No connection to server possible"); + } + } + } + + + /** + * Method adapted from https://github.com/nextcloud/android/blob/master/src/androidTest/java/com/owncloud/android/AbstractIT.java + * @param filePath path of the file to create + * @param iteration number of time to write dummy content + * @return the File instance + * @throws IOException + * @throws SecurityException + */ + public static File createFile(String filePath, int iteration) throws IOException, SecurityException{ + File file = new File(filePath); + if (!file.getParentFile().exists()) { + assertTrue(file.getParentFile().mkdirs()); + } + + file.createNewFile(); + + FileWriter writer = new FileWriter(file); + + for (int i = 0; i < iteration; i++) { + writer.write("123123123123123123123123123\n"); + } + writer.flush(); + writer.close(); + + return file; + } +} diff --git a/app/src/test/java/foundation/e/drive/operations/UploadFileOperationTest.java b/app/src/test/java/foundation/e/drive/operations/UploadFileOperationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1c01da6f62b5e358f9ca67a8150611380e996e57 --- /dev/null +++ b/app/src/test/java/foundation/e/drive/operations/UploadFileOperationTest.java @@ -0,0 +1,272 @@ +package foundation.e.drive.operations; + +import android.accounts.AccountManager; +import android.os.Build; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.UserInfo; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation; + +import junit.framework.Assert; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowLog; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import foundation.e.drive.BuildConfig; +import foundation.e.drive.database.DbHelper; +import foundation.e.drive.models.SyncedFileState; +import foundation.e.drive.models.SyncedFolder; +import foundation.e.drive.TestUtils; +import foundation.e.drive.utils.CommonUtils; + + +@RunWith(RobolectricTestRunner.class) +@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.O, manifest = Config.NONE) +public class UploadFileOperationTest { + + private List syncedFileStates= new ArrayList<>(); + private OwnCloudClient client; + private AccountManager accountManager; + + private long userFreeQuota; + + public UploadFileOperationTest(){ + TestUtils.loadServerCredentials(); + accountManager = AccountManager.get(RuntimeEnvironment.application); + TestUtils.prepareValidAccount(accountManager); + ShadowLog.stream = System.out; + client = CommonUtils.getOwnCloudClient(CommonUtils.getAccount(TestUtils.TEST_ACCOUNT_NAME, TestUtils.TEST_ACCOUNT_TYPE, accountManager), RuntimeEnvironment.application); + + try { + TestUtils.testConnection(client, RuntimeEnvironment.application); + }catch(Exception e){ + System.out.println("test connection failed: "+e.getMessage()); + } + userFreeQuota = getUserRemoteFreeQuota(); + } + + @Before + public void setUp(){ + prepareDB(); //Create DB + Assert.assertNotNull("Client is null. unexpected!", client); + } + + @After + public void tearDown(){ + } + + /** + * Prepare content of database for test + */ + private void prepareDB(){ + //Insert three test folder: small, medium, large + + + DbHelper.insertSyncedFolder(createSyncedFolder("small"), RuntimeEnvironment.application); + DbHelper.insertSyncedFolder(createSyncedFolder("medium"), RuntimeEnvironment.application); + DbHelper.insertSyncedFolder(createSyncedFolder("large"), RuntimeEnvironment.application); + + //Insert at least one file for each folder + Assert.assertEquals("There isn't three folder in DB as expected", 3, DbHelper.getSyncedFolderList(RuntimeEnvironment.application, true).size()); + } + + /** + * Create the syncedFolder instance + * @param name the name of the folder + * @return SyncedFolder instance + */ + private SyncedFolder createSyncedFolder(String name){ + return new SyncedFolder(name, TestUtils.TEST_LOCAL_ROOT_FOLDER_PATH+name+"/", TestUtils.TEST_REMOTE_ROOT_FOLDER_PATH+name+"/", true, true, true, true); + } + + /** + * Create local file to use for upload test + */ + private void createSmallFile(){ + + final String smallDummyFilePath = TestUtils.TEST_LOCAL_ROOT_FOLDER_PATH+"small/dummy.txt"; + try { + TestUtils.createFile(smallDummyFilePath, 2); + } catch (IOException | SecurityException e ) { + Assert.fail(e.getMessage()); + } + + final SyncedFileState sfs = new SyncedFileState(-1, "dummy.txt", TestUtils.TEST_LOCAL_ROOT_FOLDER_PATH+"small/dummy.txt", TestUtils.TEST_REMOTE_ROOT_FOLDER_PATH+"small/dummy.txt", "", 0l, 0, true); + sfs.setId(DbHelper.manageSyncedFileStateDB(sfs, "INSERT", RuntimeEnvironment.application)); + + syncedFileStates.add(sfs); + } + + /** + * Remove SmallFile locally and remotly if it exist + * This method has just been made to make basic test to work + * It should be refactored for next state, and test improvement + * @return true if file deleted or if it doesn't exist + */ + private boolean removeSmallFile(){ + if(!syncedFileStates.isEmpty()) { + final SyncedFileState sfs = syncedFileStates.get(0); + if (sfs != null) { + RemoveFileOperation removeRemoteFileOp = new RemoveFileOperation(sfs); + removeRemoteFileOp.execute(client); + } + } + + final String smallDummyFilePath = TestUtils.TEST_LOCAL_ROOT_FOLDER_PATH+"small/dummy.txt"; + File smallFile = new File(smallDummyFilePath); + if(smallFile.exists()){ + return smallFile.delete(); + }else return true; + } + + private long getUserRemoteFreeQuota(){ + GetRemoteUserInfoOperation getRemoteUserInfoOperation = new GetRemoteUserInfoOperation(); + RemoteOperationResult ocsResult = getRemoteUserInfoOperation.execute(client); + + if(ocsResult.isSuccess() && ocsResult.getData() != null) { + UserInfo userInfo = (UserInfo) ocsResult.getData().get(0); + System.out.println("User free Quotas: "+userInfo.getQuota().getFree()); + System.out.println("User Total Quotas: "+userInfo.getQuota().getTotal()); + + return userInfo.getQuota().getFree(); + } + return -1; + } + + /** + * test upload of a file and check that it's ok + */ + @Test + public void uploadNewSmallFile_shouldwork(){ + //tearDown + removeSmallFile(); //clean the environnement + createSmallFile(); //preparation + + final SyncedFileState sfs_fromDB = DbHelper.loadSyncedFile(RuntimeEnvironment.application, syncedFileStates.get(0).getLocalPath(), true); + Assert.assertTrue("SyncedFileState loaded from DB must have an empty Etag", sfs_fromDB.getLastETAG().isEmpty()); + + + boolean checkEtag = false; + UploadFileOperation testOperation = new UploadFileOperation(syncedFileStates.get(0), checkEtag); + testOperation.setContext(RuntimeEnvironment.application); //Without it, it won't update database + + RemoteOperationResult result = testOperation.execute(client); + String errorMsg = "The upload failed:\n http code: "+result.getHttpCode() + +"\n, is success ?"+result.isSuccess() + +"\n, log msg: "+result.getLogMessage() + +"\n, is server fail ? "+result.isServerFail(); + if(result.getException() != null){ + errorMsg += "\n, exception msg: "+result.getException().getMessage(); + } + Assert.assertTrue( errorMsg, result.isSuccess()); + + final SyncedFileState sfs_fromDBAfterUpload = DbHelper.loadSyncedFile(RuntimeEnvironment.application, syncedFileStates.get(0).getLocalPath(), true); + Assert.assertFalse("After upload, the database must store the etag of the syncedFileState. But here it is empty", sfs_fromDBAfterUpload.getLastETAG().isEmpty()); + } + + + + + /** + * Try to upload a file with a null SyncedFileState instance + * Must return a "Forbidden" result code + */ + @Ignore("Ignored until UploadFileOperation has fixed the NPE") + @Test + public void nullSyncedFileState_shouldFail(){ + + //Test fails at the moment because of UploadFileOperation's constructor not checking for syncedFileState is null) + // check https://gitlab.e.foundation/e/apps/eDrive/-/issues/120 + UploadFileOperation testOperation = new UploadFileOperation(null, false); + testOperation.setContext(RuntimeEnvironment.application); + + RemoteOperationResult result = testOperation.execute(client); + Assert.assertEquals("Expected result code was FORBIDDEN but got: "+result.getCode().name(), RemoteOperationResult.ResultCode.FORBIDDEN, result.getCode()); + } + + + /** + * Try to upload local file that has been removed between uploadOperation's creation and + * ploadOperation execution + */ + @Test + public void localFileRemovedBeforeUpload_shouldFail(){ + removeSmallFile(); //clean the environnement + createSmallFile(); //preparation + + final SyncedFileState sfs_fromDB = DbHelper.loadSyncedFile(RuntimeEnvironment.application, syncedFileStates.get(0).getLocalPath(), true); + Assert.assertTrue("SyncedFileState loaded from DB must have an empty Etag", sfs_fromDB.getLastETAG().isEmpty()); + + boolean checkEtag = false; + UploadFileOperation testOperation = new UploadFileOperation(syncedFileStates.get(0), checkEtag); + + File smallFile = new File(sfs_fromDB.getLocalPath()); + Assert.assertTrue("Local file deletion return false instead of true", smallFile.delete()); + + RemoteOperationResult result = testOperation.execute(client); + Assert.assertEquals("Expected result code was FORBIDDEN but got: "+result.getCode().name(), RemoteOperationResult.ResultCode.FORBIDDEN, result.getCode()); + } + + + /** + * Assert that uploading a file that is bigger than free quotas isn't allowed + */ + @Test + public void fileSizeBiggerThanFreeQuota_shouldnotBeAllowed(){ + //long freeQuota = getUserRemoteFreeQuota(); + Assert.assertFalse("Reading remote free quota fails"+userFreeQuota, -1 == userFreeQuota); + //We don't care of parameter of UploadFileOperation's constructor + RemoteOperationResult actualResult = new UploadFileOperation(Mockito.mock(SyncedFileState.class), false) + .checkAvailableSpace(client, (userFreeQuota+1)); + Assert.assertEquals("Quota check ("+ userFreeQuota+"vs"+(userFreeQuota+1)+") failed", RemoteOperationResult.ResultCode.QUOTA_EXCEEDED, actualResult.getCode()); + } + + /** + * Assert that uploading a file which size is exactly the amount of free quota isn't allowed + * + */ + @Test + public void fileSizeEqualToFreeQuota_shouldnotBeAllowed(){ + //I don't know why but it always fail for this test. + //long freeQuota = getUserRemoteFreeQuota(); + Assert.assertFalse("Reading remote free quota fails"+userFreeQuota, -1 == userFreeQuota); + + RemoteOperationResult actualResult = new UploadFileOperation(Mockito.mock(SyncedFileState.class), false) + .checkAvailableSpace(client, userFreeQuota); + Assert.assertEquals("Quota check ("+ userFreeQuota+" vs "+userFreeQuota+") failed", + RemoteOperationResult.ResultCode.QUOTA_EXCEEDED, + actualResult.getCode()); + } + + + /** + * Assert that uploading a file which size is lower than the amount of free quota is allowed + * + */ + @Test + public void fileSizeSmallerThanFreeQuota_shouldBeAllowed(){ + //long freeQuota = getUserRemoteFreeQuota(); + Assert.assertFalse("Reading remote free quota fails "+userFreeQuota, -1 == userFreeQuota); + + RemoteOperationResult actualResult = new UploadFileOperation(Mockito.mock(SyncedFileState.class), false) + .checkAvailableSpace(client, (userFreeQuota-1)); + Assert.assertEquals("Quota check ("+ userFreeQuota+" vs "+(userFreeQuota-1)+") failed", + RemoteOperationResult.ResultCode.OK, + actualResult.getCode()); + + } +} \ No newline at end of file diff --git a/app/src/test/java/foundation/e/drive/services/AbstractServiceIT.java b/app/src/test/java/foundation/e/drive/services/AbstractServiceIT.java new file mode 100644 index 0000000000000000000000000000000000000000..810a7640c7ffd828cc734fa02aab028dddfa6079 --- /dev/null +++ b/app/src/test/java/foundation/e/drive/services/AbstractServiceIT.java @@ -0,0 +1,121 @@ +package foundation.e.drive.services; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.Service; +import android.app.job.JobScheduler; +import android.content.ContentResolver; +import android.content.Context; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.os.Build; + +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.android.controller.ServiceController; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowLog; + +import foundation.e.drive.BuildConfig; +import foundation.e.drive.TestUtils; +import foundation.e.drive.database.DbHelper; +import foundation.e.drive.utils.AppConstants; +import static foundation.e.drive.TestUtils.TEST_ACCOUNT_NAME; +import static foundation.e.drive.TestUtils.TEST_ACCOUNT_TYPE; +import static foundation.e.drive.utils.AppConstants.MEDIASYNC_PROVIDER_AUTHORITY; +import static foundation.e.drive.utils.AppConstants.SETTINGSYNC_PROVIDER_AUTHORITY; + +@RunWith(RobolectricTestRunner.class) +@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.O, manifest = Config.NONE) +public abstract class AbstractServiceIT { + + /** + * By making the below field static it is done once + * for all test class that extends this instead of + * one time by class. + */ + protected static Context context; + + protected T mService; + protected ServiceController mServiceController; + + protected AccountManager accountManager; + protected ContentResolver contentResolver; + protected SharedPreferences sharedPreferences; + protected ConnectivityManager connectivityManager; + protected JobScheduler jobScheduler; + protected DbHelper dbHelper; + + protected int initial_folder_number=0; //number of folders to sync at initialization + protected long last_sync_time=0l; //Timestamp of the end of the last synchronisation + protected boolean init_done = true; //true if InitializerService did its job + protected boolean oms_running=false; //true if OperationManagerService is already running + + @BeforeClass + public static void beforeAll(){ + TestUtils.loadServerCredentials(); + ShadowLog.stream = System.out; //give access to log + } + + /** + * Create and register one validAccount + */ + protected void prepareValidAccount(){ + TestUtils.prepareValidAccount(accountManager); + } + + /** + * enable Media & settings sync + */ + protected void enableMediaAndSettingsSync(Account account){ //replace this by robolectric the contentResolver + contentResolver.setSyncAutomatically(account, MEDIASYNC_PROVIDER_AUTHORITY, true); + contentResolver.setSyncAutomatically(account, SETTINGSYNC_PROVIDER_AUTHORITY, true); + } + + /** + * disable Media & enable settings sync + */ + protected void disableMediaSync(Account account){ //replace this by robolectric the contentResolver + contentResolver.setSyncAutomatically(account, MEDIASYNC_PROVIDER_AUTHORITY, false); + contentResolver.setSyncAutomatically(account, SETTINGSYNC_PROVIDER_AUTHORITY, true); + } + + /** + * enable Media and disable settings sync + */ + protected void disableSettingsSync(Account account){ //replace this by robolectric the contentResolver + contentResolver.setSyncAutomatically(account, MEDIASYNC_PROVIDER_AUTHORITY, true); + contentResolver.setSyncAutomatically(account, SETTINGSYNC_PROVIDER_AUTHORITY, false); + } + + /** + * disable Media & settings sync + */ + protected void disableMediaAndSettingsSync(Account account){ //replace this by robolectric the contentResolver + contentResolver.setSyncAutomatically(account, MEDIASYNC_PROVIDER_AUTHORITY, false); + contentResolver.setSyncAutomatically(account, SETTINGSYNC_PROVIDER_AUTHORITY, false); + } + + /** + * Register sharedPreferences common to all services + * - OMS is working (bool) + * - Account name (String) + * - Account type (String) + * - initial folders number (int) + * - last sync time (long) + * - Initialization has been done (bool) + * + * Use default value of the instance field + * So update the field before to call this to store specific value + */ + protected void registerSharedPref(){ + sharedPreferences.edit().putBoolean( AppConstants.INITIALIZATION_HAS_BEEN_DONE, init_done) + .putBoolean(AppConstants.KEY_OMS_IS_WORKING, oms_running) + .putString(AccountManager.KEY_ACCOUNT_NAME, TEST_ACCOUNT_NAME) + .putString(AccountManager.KEY_ACCOUNT_TYPE, TEST_ACCOUNT_TYPE) + .putInt(AppConstants.INITIALFOLDERS_NUMBER, initial_folder_number) + .putLong(AppConstants.KEY_LAST_SYNC_TIME, last_sync_time) + .commit(); + } +} diff --git a/app/src/test/java/foundation/e/drive/services/InitializerServiceTest.java b/app/src/test/java/foundation/e/drive/services/InitializerServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0de9195bbe24fae76a613541de3f63be5d74e5d9 --- /dev/null +++ b/app/src/test/java/foundation/e/drive/services/InitializerServiceTest.java @@ -0,0 +1,119 @@ +package foundation.e.drive.services; + + +import android.accounts.AccountManager; +import android.app.job.JobScheduler; +import android.content.Context; +import android.net.ConnectivityManager; + +import junit.framework.Assert; + +import org.junit.Test; +import org.robolectric.Robolectric; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowLog; + +import foundation.e.drive.TestUtils; +import foundation.e.drive.database.DbHelper; +import foundation.e.drive.utils.AppConstants; + +import static org.robolectric.Shadows.shadowOf; + + +public class InitializerServiceTest extends AbstractServiceIT{ + + public InitializerServiceTest(){ + + mServiceController = Robolectric.buildService(InitializerService.class); + mService = mServiceController.get(); + context = RuntimeEnvironment.application; + accountManager = AccountManager.get(context); + jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + contentResolver = context.getContentResolver(); + sharedPreferences = context.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); + connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + dbHelper = new DbHelper(context); + + init_done = false; + } + + /** + * Check that the initializer service stops if the Initialization parameters + * is setted to true + */ + @Test + public void InitAlreadyDone_shouldStop(){ + init_done = true; + registerSharedPref(); + + Assert.assertTrue("SharedPreferences.INITIALIZATION_HAS_BEEN_DONE expected to be true but was false", sharedPreferences.getBoolean(AppConstants.INITIALIZATION_HAS_BEEN_DONE, false)); + + mServiceController.create().startCommand(0,0); + String lastLog = ShadowLog.getLogs().get(ShadowLog.getLogs().size()-1).msg; + Assert.assertEquals("lastLog expected to be 'Initializer has already been run' but was "+lastLog, "Initializer has already been run", lastLog); + Assert.assertEquals("service should have schedule a job but pending job contains "+jobScheduler.getAllPendingJobs().size(),1, jobScheduler.getAllPendingJobs().size()); + //Teardown + jobScheduler.cancelAll(); + } + + /** + * This check the case where InitializationService stopped previously after + * account registration but before folder initializations. + */ + @Test + public void initNotDoneButAccountRegistered_shouldWork(){ + registerSharedPref(); + prepareValidAccount(); + enableMediaAndSettingsSync(TestUtils.getValidAccount()); + /*try { + testConnection(CommonUtils.getOwnCloudClient(validAccount, context)); + }catch(Exception e){ + Assert.fail(e.getMessage()); + }*/ + mServiceController.create().startCommand(0,0); + //mService.onRemoteOperationFinish(new CreateInitialFolderRemoteOperation(null, true, context), new RemoteOperationResult(true, new MkColMethod(""))); + + //Assert.fail("Not yet implemented"); + } + + /** + * This check the case where no account where provided with the intent + * and initialization hadn't been run before + */ + @Test + public void noAccountInIntentNorInPrefs_shouldstop(){ + registerSharedPref(); + sharedPreferences.edit().putString(AccountManager.KEY_ACCOUNT_NAME, "") + .putString(AccountManager.KEY_ACCOUNT_TYPE, "").commit(); + enableMediaAndSettingsSync(TestUtils.getValidAccount()); + mServiceController.create().startCommand(0,0); + + String lastLog = ShadowLog.getLogs().get(ShadowLog.getLogs().size()-1).msg; + Assert.assertEquals("lastLog expected to be 'Account's name not found. Neither in shared prefs nor in intent's extras' but was "+lastLog, "Account's name not found. Neither in shared prefs nor in intent's extras", lastLog); + } + + + /** + * Check that InitializerService stops if media & settings sync are disabled + */ + @Test + public void settingsAndMediaSyncDisabled_shouldStop(){ + initial_folder_number = -1; + init_done = false; + registerSharedPref(); + final int initFolderCount_pretest = sharedPreferences.getInt(AppConstants.INITIALFOLDERS_NUMBER, 0); + Assert.assertEquals("Initial folders count expected to be -1 but got "+initFolderCount_pretest, -1, initFolderCount_pretest); + + prepareValidAccount(); + disableMediaAndSettingsSync(TestUtils.getValidAccount()); + + mServiceController.create(); + mServiceController.startCommand(0,0); + + final int initFolderCount = sharedPreferences.getInt(AppConstants.INITIALFOLDERS_NUMBER, -1); + Assert.assertEquals("Initial folders count expected to be 0 but got "+initFolderCount, 0, initFolderCount); + + final boolean initialization_done = sharedPreferences.getBoolean(AppConstants.INITIALIZATION_HAS_BEEN_DONE, false); + Assert.assertTrue("sharedPref initialization_done expected to be true but was false"+initialization_done, initialization_done); + } +} diff --git a/app/src/test/java/foundation/e/drive/services/ObserverServiceTest.java b/app/src/test/java/foundation/e/drive/services/ObserverServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a01a141ed51d933cbef4ee0c783979ae807d66da --- /dev/null +++ b/app/src/test/java/foundation/e/drive/services/ObserverServiceTest.java @@ -0,0 +1,308 @@ +package foundation.e.drive.services; + +import android.accounts.AccountManager; +import android.app.job.JobScheduler; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; + +import junit.framework.Assert; + +import org.junit.Ignore; +import org.junit.Test; +import org.robolectric.Robolectric; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowLog; +import org.robolectric.shadows.ShadowNetworkInfo; + +import java.io.File; +import java.util.List; + +import foundation.e.drive.TestUtils; +import foundation.e.drive.database.DbHelper; +import foundation.e.drive.models.SyncedFolder; +import foundation.e.drive.operations.CreateInitialFolderRemoteOperation; +import foundation.e.drive.utils.AppConstants; +import foundation.e.drive.utils.CommonUtils; +import foundation.e.drive.utils.JobUtils; + +import static foundation.e.drive.TestUtils.TEST_LOCAL_ROOT_FOLDER_PATH; +import static foundation.e.drive.TestUtils.TEST_REMOTE_ROOT_FOLDER_PATH; +import static foundation.e.drive.TestUtils.getValidAccount; +import static foundation.e.drive.utils.AppConstants.INITIALIZATION_HAS_BEEN_DONE; +import static foundation.e.drive.utils.AppConstants.MEDIA_SYNCABLE_CATEGORIES; +import static org.robolectric.Shadows.shadowOf; + +/** + * The RunWith & Config annotation are done in the AbstractServiceIT + */ +public class ObserverServiceTest extends AbstractServiceIT { + + public ObserverServiceTest(){ + mServiceController = Robolectric.buildService(ObserverService.class); + mService = mServiceController.get(); + context = RuntimeEnvironment.application; + accountManager = AccountManager.get(context); + jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + contentResolver = context.getContentResolver(); + sharedPreferences = context.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); + connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + dbHelper = new DbHelper(context); + } + + /** + * Schedule a ScannerJob instance in JobScheduler + */ + private void registerScannerJobInJobScheduler(){ + Assert.assertTrue("jobScheduler expected to be have no pending job",jobScheduler.getAllPendingJobs().isEmpty()); + + JobUtils.scheduleScannerJob(context); + int scheduledJobListSize = jobScheduler.getAllPendingJobs().size(); + Assert.assertEquals("PendingJob size expected to be 1 but was:"+scheduledJobListSize,1, scheduledJobListSize ); + + } + + + /** + * Set the network status to an available wifi + */ + private void setWifiNetworkStatus(){ + NetworkInfo netInfo = ShadowNetworkInfo.newInstance(null, + ConnectivityManager.TYPE_WIFI, 0, true, NetworkInfo.State.CONNECTED); + Assert.assertEquals("NetworkInfo type is invalid",ConnectivityManager.TYPE_WIFI,netInfo.getType()); + shadowOf(connectivityManager).setActiveNetworkInfo(netInfo); + } + + /** + * Create a network status where no connection is available + */ + private void setUnavailableWifiNetworkStatus(){ + //shadowOf(connectivityManager).clearAllNetworks(); // doesn't work... + + /*for(Network network : shadowOf (connectivityManager).getAllNetworks()){ + shadowOf(connectivityManager).removeNetwork(network); // doesn't work... + }*/ + + NetworkInfo netInfo = ShadowNetworkInfo.newInstance(null, + ConnectivityManager.TYPE_WIFI, 0, true, NetworkInfo.State.DISCONNECTED); + Assert.assertEquals("NetworkInfo type is invalid",ConnectivityManager.TYPE_WIFI,netInfo.getType()); + + shadowOf(connectivityManager).setActiveNetworkInfo(netInfo); + } + + /** + * Create a single 'SyncedFolder' instance for 'eDrive-test' folder + * @return SyncedFolder instance + */ + private SyncedFolder createSingleTestSyncedFolder(){ + final File folder = new File(TEST_LOCAL_ROOT_FOLDER_PATH); + try{ + folder.mkdirs(); + }catch(SecurityException e){ + Assert.fail(e.getMessage()); + } + final SyncedFolder sFolder = new SyncedFolder(MEDIA_SYNCABLE_CATEGORIES[0], TEST_LOCAL_ROOT_FOLDER_PATH, TEST_REMOTE_ROOT_FOLDER_PATH, true); + + return sFolder; + } + + + /** + * Send request to server to create the remote folder of the given syncedFolder + * @param folder the local folder metadata to create + */ + private void createRemoteFolder(SyncedFolder folder){ + OwnCloudClient client = CommonUtils.getOwnCloudClient(getValidAccount(), context); + + try { + TestUtils.testConnection(client, context); + }catch(Exception e){ + System.out.println("Test connection failed :"+e.getMessage()); + } + + CreateInitialFolderRemoteOperation op = new CreateInitialFolderRemoteOperation(folder, true, context); + RemoteOperationResult result = op.execute(client); //Give SSL issue + + Assert.assertTrue("Creation of remote test folder failed",result.isSuccess()); + + final int dbFolderListSize =DbHelper.getAllSyncedFolders(context).size(); + Assert.assertEquals("Expected DB's SyncedFolder table content was 1, but got:"+dbFolderListSize, 1, dbFolderListSize); + + + initial_folder_number =1; + } + + + /** + * Run a test which correspond to a non blocking context + */ + @Ignore("Ignore until a correct assertion has been found") + @Test + public void shouldWork() { + setWifiNetworkStatus(); + prepareValidAccount(); + enableMediaAndSettingsSync(getValidAccount()); + createRemoteFolder(createSingleTestSyncedFolder()); + registerScannerJobInJobScheduler(); + registerSharedPref(); + + //Start the service + mServiceController.create().startCommand(0, 0); + + List logs = ShadowLog.getLogs(); + ShadowLog.LogItem lastLog = logs.get(logs.size()-3); + + Assert.assertEquals("expected: 'Going to scan remote files' but found: '"+lastLog.msg, "Going to scan remote files", lastLog.msg); + + //Tear down + mService.deleteDatabase(DbHelper.DATABASE_NAME); + //Assert.assertTrue("Database hasn't been removed", myService.deleteDatabase(DbHelper.DATABASE_NAME)); + } + + + + + /** + * This assert that ObserverService doesn't start scanning remote or local if there is no network + */ + @Ignore("Ignore until a way to prepare unavailable Network has been founded") + @Test + public void noNetwork_shouldStop(){ + //setWifiNetworkStatus(); Make the test to fail as expected + //setUnavailableWifiNetworkStatus(); //Doesn't give the expected result at the moment so the test fails! + prepareValidAccount(); + enableMediaAndSettingsSync(getValidAccount()); + //createRemoteSyncedFolder(createSingleTestSyncedFolder()); + registerScannerJobInJobScheduler(); + registerSharedPref(); + + boolean haveNetworkConnexion = CommonUtils.haveNetworkConnexion(RuntimeEnvironment.application); + String msg = "CommonUtils.haveNetworkConnexion should return false but return "+haveNetworkConnexion; + Assert.assertFalse(msg, haveNetworkConnexion); + + mServiceController.create().startCommand(0, 0); + + List logs = ShadowLog.getLogs(); + ShadowLog.LogItem lastLog = logs.get(logs.size()-1); + Assert.assertEquals("Last log isn't the one expected", "There is no Internet connexion.", lastLog.msg); + + } + + + /** + * This assert that ObserverService won't start if the minimum delay between two sync isn't over + */ + @Test + public void lastSyncWasLessThan15minAgo_shouldStop(){ + last_sync_time = System.currentTimeMillis() - 899900; + setWifiNetworkStatus(); + prepareValidAccount(); + enableMediaAndSettingsSync(getValidAccount()); + //createRemoteSyncedFolder(createSingleTestSyncedFolder()); + registerScannerJobInJobScheduler(); + registerSharedPref(); + + //Start the service + mServiceController.create().startCommand(0, 0); + + //How to assert this... ? + + List logs = ShadowLog.getLogs(); + ShadowLog.LogItem lastLog = logs.get(logs.size()-1); + + //Note: Checking log is the only way I've found to check that the service stopped as expected + Assert.assertEquals("Last log isn't the one expected", "Delay between now and last call is too short", lastLog.msg); + + } + + /** + * This assert that ObserverService will do its job if the minimum delay between two sync is over + */ + @Test + public void lastSync15minAnd30secAgo_shouldStart(){ + //decrease 15min and 30sec + last_sync_time = System.currentTimeMillis() - 930000; + setWifiNetworkStatus(); + prepareValidAccount(); + enableMediaAndSettingsSync(getValidAccount()); + //createRemoteSyncedFolder(createSingleTestSyncedFolder()); + registerScannerJobInJobScheduler(); + registerSharedPref(); + + //Start the service + mServiceController.create().startCommand(0, 0); + + List logs = ShadowLog.getLogs(); + for(ShadowLog.LogItem log : logs){ + Assert.assertFalse("Log shouldn't contains 'delay between now and last call is too short' but it does", log.msg.equals("Delay between now and last call is too short")); //There isn't assertNotEquals + } + } + + /** + * This assert that ObserverService won't start if it's already running + */ + @Ignore("Not yet implemented") + @Test + public void syncAlreadyStarted_shouldStop(){ + //@TODO need to find how to access the "isRunning" private field inside the ObserverService for this test + Assert.fail("Not yet implemented "); + } + + + /** + * Check that service stop if no account provided + */ + @Test + public void noAccount_shouldStop(){ + registerScannerJobInJobScheduler(); //Assert that the ScheduledJob is present + + mServiceController.create().startCommand(0, 0); + + List logs = ShadowLog.getLogs(); + ShadowLog.LogItem lastLog = logs.get(logs.size()-1); + + Assert.assertEquals("Last expected log wasn't: 'No account registered' but "+lastLog.msg, "No account registered",lastLog.msg ); + Assert.assertTrue("jobScheduler expected to be have no pending job",jobScheduler.getAllPendingJobs().isEmpty()); + } + + /** + * This test will assert that the ObserverService won't do its job + * if Initialization hasn't been done + */ + @Test + public void InitializationNotDone_shouldStop(){ + init_done = false; //This is the key settings for this test + + setWifiNetworkStatus(); + prepareValidAccount(); + enableMediaAndSettingsSync(getValidAccount()); + //createRemoteSyncedFolder(createSingleTestSyncedFolder()); + registerScannerJobInJobScheduler(); + registerSharedPref(); + + + Assert.assertFalse("SharedPref doesn't contains the expected value for Initialization_has_been_done key", sharedPreferences.getBoolean(INITIALIZATION_HAS_BEEN_DONE, true)); + + mServiceController.create().startCommand(0, 0); + //How to assert this... ? + + Intent expectedIntent = new Intent(mService, InitializerService.class); + Intent actualIntent = shadowOf(RuntimeEnvironment.application).getNextStartedService(); + + Assert.assertEquals("Checked intent not the expected one", expectedIntent.getComponent(), actualIntent.getComponent()); + + List logs = ShadowLog.getLogs(); + ShadowLog.LogItem lastLog = logs.get(logs.size()-1); + + //Note: Checking log is the only way I've found to check that the service stopped as expected + Assert.assertEquals("Last log isn't the one expected", "Initialization hasn't been done", lastLog.msg); + //Assert.assertTrue(logs.contains()); //@TODO how to assert that logs doesn't contain the expecteed message ? + + //tearDown - Remove DB if it had been created + mService.deleteDatabase(DbHelper.DATABASE_NAME); + } +} \ No newline at end of file diff --git a/app/src/test/java/foundation/e/drive/services/OperationManagerServiceTest.java b/app/src/test/java/foundation/e/drive/services/OperationManagerServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0a2fb8f73f1790b30fd3d68758ec7f818d3d7c35 --- /dev/null +++ b/app/src/test/java/foundation/e/drive/services/OperationManagerServiceTest.java @@ -0,0 +1,108 @@ +package foundation.e.drive.services; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.job.JobScheduler; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; + +import com.owncloud.android.lib.resources.files.model.RemoteFile; + +import junit.framework.Assert; + +import org.junit.Test; +import org.robolectric.Robolectric; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowLog; + +import java.util.List; + +import foundation.e.drive.TestUtils; +import foundation.e.drive.database.DbHelper; +import foundation.e.drive.models.SyncedFileState; +import foundation.e.drive.operations.DownloadFileOperation; +import foundation.e.drive.utils.AppConstants; + + +public class OperationManagerServiceTest extends AbstractServiceIT{ + + public OperationManagerServiceTest(){ + mServiceController = Robolectric.buildService(OperationManagerService.class); + mService = mServiceController.get(); + context = RuntimeEnvironment.application; + accountManager = AccountManager.get(context); + jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + contentResolver = context.getContentResolver(); + sharedPreferences = context.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); + connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + dbHelper = new DbHelper(context); + } + + + /** + * Check that the service stop quickly if no intent is provided + */ + @Test + public void noIntent_shouldStop(){ + mServiceController.create(); + mService.onStartCommand(null,0, 0); + + List logs = ShadowLog.getLogs(); + ShadowLog.LogItem lastLog = logs.get(logs.size()-2); + + Assert.assertEquals("Expected last log was: 'intent was null, flags=0 bits=0' but got:"+lastLog.msg, "intent was null, flags=0 bits=0", lastLog.msg); + } + + + /** + * Start the service with an intent that doesn't contains list of extra data + * (meaning no account and no synchronisation to perform) + */ + @Test + public void intentWithoutExtras_shouldStop(){ + mServiceController.create(); + mService.onStartCommand(new Intent(), 0, 0); + + List logs = ShadowLog.getLogs(); + ShadowLog.LogItem lastLog = logs.get(logs.size()-1); + + Assert.assertEquals("Expected last log was: 'Intent's extras is null.' but got:"+lastLog.msg, "Intent's extras is null.", lastLog.msg); + } + + + /** + * Start the OperationmanagerService with File to upload but no account provided + * in the intent. + * Failure is expected + */ + @Test + public void noAccount_shouldFail(){ + prepareValidAccount(); + final Account account = TestUtils.getValidAccount(); + final Intent intent = new Intent("dummyAction"); + + intent.putExtra("0", + new DownloadFileOperation( + new RemoteFile("/eDrive-test/coco.txt"), + new SyncedFileState(3, "coco.txt", "/tmp/eDrive-test/", "/eDrive-test/coco.txt","", -1, 1, true ) + ) + ); + + + intent.putExtra("account", account); + + final boolean accountRemoved = accountManager.removeAccountExplicitly(account); + Assert.assertTrue("Account removal should return true but returned false", accountRemoved); + + mServiceController.create(); + mService.onStartCommand(intent, 0,0); + + List logs = ShadowLog.getLogs(); + ShadowLog.LogItem lastLog = logs.get(logs.size()-1); + Assert.assertEquals("Expected last log was: 'No Client, Can't Work!' but got:"+lastLog.msg, "No Client, Can't Work!", lastLog.msg); + + } + + +} diff --git a/build.gradle b/build.gradle index 88560b47dc768e6a7cbefe8c44a977b32623aa94..3378f0cd90a587b6f781e45f221ba00f97f51ebf 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.3' + classpath 'com.android.tools.build:gradle:4.1.3' // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 54f9e46602f2b5e51d1294b2d243fc60ca32c500..46b275d78fb233a28426185786ef96bde557b078 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip diff --git a/nextcloud-android-lib b/nextcloud-android-lib index 880099c889253f30969b81c5e07750f070bfb65c..353568a74c0708496b36614b3ff69b9fafe9af0b 160000 --- a/nextcloud-android-lib +++ b/nextcloud-android-lib @@ -1 +1 @@ -Subproject commit 880099c889253f30969b81c5e07750f070bfb65c +Subproject commit 353568a74c0708496b36614b3ff69b9fafe9af0b