From 06740c9016bf1d7e226cab5150594995a7d31a78 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 14 Sep 2026 14:26:14 +0200 Subject: [PATCH 1/2] cover server versions for garm Signed-off-by: alperozturk96 --- .../assistant/AssistantRepositoryTests.kt | 3 + .../java/com/nextcloud/test/ServerVersion.kt | 13 + .../com/nextcloud/test/ServerVersionFilter.kt | 43 +++ .../java/com/nextcloud/test/SinceServer.kt | 11 + .../com/nextcloud/utils/AutoRenameTests.kt | 3 + .../nextcloud/utils/FileNameValidatorTests.kt | 11 + .../com/nextcloud/utils/UploadDateTests.kt | 255 ++++++++---------- .../java/com/owncloud/android/UploadIT.java | 4 + .../java/com/owncloud/android/ui/LoginIT.kt | 4 +- .../ui/preview/PreviewImageActivityIT.kt | 2 +- scripts/runCombinedTest.sh | 15 +- 11 files changed, 215 insertions(+), 149 deletions(-) create mode 100644 app/src/androidTest/java/com/nextcloud/test/ServerVersion.kt create mode 100644 app/src/androidTest/java/com/nextcloud/test/ServerVersionFilter.kt create mode 100644 app/src/androidTest/java/com/nextcloud/test/SinceServer.kt diff --git a/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt b/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt index 693724df360f..8ecd98763099 100644 --- a/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt +++ b/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt @@ -8,6 +8,8 @@ package com.nextcloud.client.assistant import com.nextcloud.client.assistant.repository.remote.AssistantRemoteRepositoryImpl +import com.nextcloud.test.ServerVersion +import com.nextcloud.test.SinceServer import com.owncloud.android.AbstractOnServerIT import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData import com.owncloud.android.lib.resources.status.NextcloudVersion @@ -17,6 +19,7 @@ import org.junit.Before import org.junit.Test @Suppress("MagicNumber") +@SinceServer(ServerVersion.NEXTCLOUD_28) class AssistantRepositoryTests : AbstractOnServerIT() { private var sut: AssistantRemoteRepositoryImpl? = null diff --git a/app/src/androidTest/java/com/nextcloud/test/ServerVersion.kt b/app/src/androidTest/java/com/nextcloud/test/ServerVersion.kt new file mode 100644 index 000000000000..6e1e8f944430 --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/test/ServerVersion.kt @@ -0,0 +1,13 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +package com.nextcloud.test + +object ServerVersion { + const val NEXTCLOUD_27 = 27 + const val NEXTCLOUD_28 = 28 + const val NEXTCLOUD_30 = 30 +} diff --git a/app/src/androidTest/java/com/nextcloud/test/ServerVersionFilter.kt b/app/src/androidTest/java/com/nextcloud/test/ServerVersionFilter.kt new file mode 100644 index 000000000000..0e3f1fb5a648 --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/test/ServerVersionFilter.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +package com.nextcloud.test + +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.runner.Description +import org.junit.runner.manipulation.Filter + +class ServerVersionFilter : Filter() { + + private val serverVersion: Int? by lazy { + InstrumentationRegistry + .getArguments() + .getString(SERVER_VERSION_ARGUMENT) + ?.toIntOrNull() + } + + override fun shouldRun(description: Description): Boolean { + val currentVersion = serverVersion ?: return true + + return when { + description.isTest -> description.requiredServerVersion() <= currentVersion + else -> description.children.any { shouldRun(it) } + } + } + + override fun describe(): String = "skip tests annotated with @SinceServer above server version $serverVersion" + + private fun Description.requiredServerVersion(): Int { + val onMethod = getAnnotation(SinceServer::class.java)?.majorVersion ?: ANY_SERVER + val onClass = testClass?.getAnnotation(SinceServer::class.java)?.majorVersion ?: ANY_SERVER + return maxOf(onMethod, onClass) + } + + companion object { + private const val SERVER_VERSION_ARGUMENT = "TEST_SERVER_VERSION" + private const val ANY_SERVER = 0 + } +} diff --git a/app/src/androidTest/java/com/nextcloud/test/SinceServer.kt b/app/src/androidTest/java/com/nextcloud/test/SinceServer.kt new file mode 100644 index 000000000000..79aca4863164 --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/test/SinceServer.kt @@ -0,0 +1,11 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +package com.nextcloud.test + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) +annotation class SinceServer(val majorVersion: Int) diff --git a/app/src/androidTest/java/com/nextcloud/utils/AutoRenameTests.kt b/app/src/androidTest/java/com/nextcloud/utils/AutoRenameTests.kt index bc8f39c0290e..79a8657b3a4a 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/AutoRenameTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/AutoRenameTests.kt @@ -8,6 +8,8 @@ package com.nextcloud.utils +import com.nextcloud.test.ServerVersion +import com.nextcloud.test.SinceServer import com.nextcloud.utils.autoRename.AutoRename import com.owncloud.android.AbstractOnServerIT import com.owncloud.android.datamodel.e2e.v2.decrypted.DecryptedFile @@ -18,6 +20,7 @@ import org.junit.Before import org.junit.Test @Suppress("TooManyFunctions") +@SinceServer(ServerVersion.NEXTCLOUD_30) class AutoRenameTests : AbstractOnServerIT() { private var capability: OCCapability = fileDataStorageManager.getCapability(account.name) diff --git a/app/src/androidTest/java/com/nextcloud/utils/FileNameValidatorTests.kt b/app/src/androidTest/java/com/nextcloud/utils/FileNameValidatorTests.kt index 89d4bb343ff7..46f7690647ba 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/FileNameValidatorTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/FileNameValidatorTests.kt @@ -7,6 +7,8 @@ package com.nextcloud.utils +import com.nextcloud.test.ServerVersion +import com.nextcloud.test.SinceServer import com.nextcloud.utils.fileNameValidator.FileNameValidator import com.owncloud.android.AbstractOnServerIT import com.owncloud.android.R @@ -42,6 +44,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test + @SinceServer(ServerVersion.NEXTCLOUD_30) fun testInvalidCharacter() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -53,6 +56,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test + @SinceServer(ServerVersion.NEXTCLOUD_30) fun testReservedName() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -61,6 +65,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test + @SinceServer(ServerVersion.NEXTCLOUD_30) fun testForbiddenFilenameExtension() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -141,6 +146,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test + @SinceServer(ServerVersion.NEXTCLOUD_30) fun testFolderPathWithReservedName() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -152,6 +158,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test + @SinceServer(ServerVersion.NEXTCLOUD_30) fun testFilePathWithReservedName() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -163,6 +170,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test + @SinceServer(ServerVersion.NEXTCLOUD_30) fun testFolderPathWithInvalidCharacter() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -174,6 +182,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test + @SinceServer(ServerVersion.NEXTCLOUD_30) fun testFilePathWithInvalidCharacter() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -203,6 +212,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test + @SinceServer(ServerVersion.NEXTCLOUD_30) fun testFilePathWithNestedFolder() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -222,6 +232,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test + @SinceServer(ServerVersion.NEXTCLOUD_30) fun testOnlyFolderPathWithOneReservedName() { testOnlyOnServer(NextcloudVersion.nextcloud_30) diff --git a/app/src/androidTest/java/com/nextcloud/utils/UploadDateTests.kt b/app/src/androidTest/java/com/nextcloud/utils/UploadDateTests.kt index 795148f2b3e5..c8e384fb4b57 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/UploadDateTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/UploadDateTests.kt @@ -9,6 +9,7 @@ package com.nextcloud.utils import android.content.Context +import android.content.res.Configuration import android.text.format.DateUtils import androidx.test.platform.app.InstrumentationRegistry import com.nextcloud.client.database.entity.UploadEntity @@ -16,11 +17,14 @@ import com.nextcloud.client.database.entity.toOCUpload import com.nextcloud.client.database.entity.toUploadEntity import com.owncloud.android.R import com.owncloud.android.utils.DisplayUtils +import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Test +import java.text.DateFormat import java.util.Date +import java.util.Locale class UploadDateTests { @@ -30,17 +34,32 @@ class UploadDateTests { private const val ONE_HOUR = 60 * ONE_MINUTE private const val ONE_DAY = 24 * ONE_HOUR - private const val ONE_YEAR = 365L * ONE_DAY - private const val ONE_MONTH = 30L * ONE_DAY - private const val ONE_WEEK = 7L * ONE_DAY - private const val TWO_HOURS = 2L * ONE_HOUR + private const val ONE_AND_A_HALF_MINUTES = ONE_MINUTE + THIRTY_SECONDS + private const val TWO_AND_A_HALF_HOURS = 2 * ONE_HOUR + ONE_HOUR / 2 + private const val TWO_DAYS = 2 * ONE_DAY + private const val ONE_WEEK = 7 * ONE_DAY + private const val ONE_MONTH = 30 * ONE_DAY + private const val ONE_YEAR = 365 * ONE_DAY + + private const val DATE_AND_TIME_PARTS = 2 + private const val TIME_OF_DAY_SEPARATOR = ":" + private const val NARROW_NO_BREAK_SPACE = ' ' + private const val NO_BREAK_SPACE = ' ' } private lateinit var context: Context + private lateinit var systemLocale: Locale @Before fun setup() { - context = InstrumentationRegistry.getInstrumentation().targetContext + systemLocale = Locale.getDefault() + Locale.setDefault(Locale.US) + context = InstrumentationRegistry.getInstrumentation().targetContext.localized(Locale.US) + } + + @After + fun tearDown() { + Locale.setDefault(systemLocale) } @Test @@ -82,189 +101,139 @@ class UploadDateTests { @Test fun getRelativeDateTimeStringReturnsSecondsAgoForRecentPast() { - val result = DisplayUtils.getRelativeDateTimeString( - context, - System.currentTimeMillis() - THIRTY_SECONDS, - DateUtils.MINUTE_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0 + assertRelativeDateTimeString( + time = System.currentTimeMillis() - THIRTY_SECONDS, + expected = context.getString(R.string.file_list_seconds_ago) ) - assertEquals(context.getString(R.string.file_list_seconds_ago), result.toString()) } @Test fun getRelativeDateTimeStringReturnsFutureAsAbsoluteWhenShowFutureIsFalse() { - val time = System.currentTimeMillis() + ONE_MINUTE - val expected = java.text.DateFormat.getDateTimeInstance().format(Date(time)) + val time = System.currentTimeMillis() + ONE_AND_A_HALF_MINUTES - val result = DisplayUtils.getRelativeDateTimeString( - context, - time, - DateUtils.SECOND_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0, - false + assertRelativeDateTimeString( + time = time, + expected = DateFormat.getDateTimeInstance().format(Date(time)) ) - assertEquals(expected, result.toString()) } @Test fun getRelativeDateTimeStringReturnsFutureAsRelativeWhenShowFutureIsTrue() { - val expected = "In 1 minute" - val time = System.currentTimeMillis() + ONE_MINUTE - - assertRelativeDateTimeString(time, expected, DateUtils.MINUTE_IN_MILLIS, showFuture = true) + assertRelativeDateTimeString( + time = System.currentTimeMillis() + ONE_AND_A_HALF_MINUTES, + expected = "In 1 minute", + showFuture = true + ) } @Test fun getRelativeDateTimeStringReturnsRelativeStringForHoursAgo() { - val expected = "2 hours ago" - val time = System.currentTimeMillis() - TWO_HOURS - - assertRelativeDateTimeString(time, expected, DateUtils.SECOND_IN_MILLIS) + assertRelativeDateTimeString( + time = System.currentTimeMillis() - TWO_AND_A_HALF_HOURS, + expected = "2 hours ago", + minResolution = DateUtils.SECOND_IN_MILLIS + ) } @Test - fun getRelativeDateTimeStringReturnsAbbreviatedStringForOneWeekAgo() { - val time = System.currentTimeMillis() - ONE_WEEK - val expectedString = DateUtils.getRelativeDateTimeString( - context, - time, - DateUtils.MINUTE_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0 - ).toString() - val parts = expectedString.split(",") - val expected = if (parts.size == 2) { - if (parts[1].contains(":") && !parts[0].contains(":")) parts[0].trim() else parts[1].trim() - } else { - expectedString - } - - assertRelativeDateTimeString(time, expected) + fun getRelativeDateTimeStringReturnsTodayForNow() { + assertRelativeDateTimeString( + time = System.currentTimeMillis(), + expected = "Today", + minResolution = DateUtils.DAY_IN_MILLIS + ) } @Test - fun getRelativeDateTimeStringReturnsAbbreviatedStringForOneMonthAgo() { - val time = System.currentTimeMillis() - ONE_MONTH - val expectedString = DateUtils.getRelativeDateTimeString( - context, - time, - DateUtils.SECOND_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0 - ).toString() - val parts = expectedString.split(",") - val expected = if (parts.size == 2) { - if (parts[1].contains(":") && !parts[0].contains(":")) parts[0].trim() else parts[1].trim() - } else { - expectedString - } - - assertRelativeDateTimeString(time, expected, DateUtils.SECOND_IN_MILLIS) + fun getRelativeDateTimeStringReturnsYesterdayForOneDayAgo() { + assertRelativeDateTimeString( + time = System.currentTimeMillis() - ONE_DAY, + expected = "Yesterday", + minResolution = DateUtils.DAY_IN_MILLIS + ) } @Test - fun getRelativeDateTimeStringReturnsAbsoluteStringForOneYearAgo() { - val time = System.currentTimeMillis() - ONE_YEAR - val expectedString = DateUtils.getRelativeDateTimeString( - context, - time, - DateUtils.SECOND_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0 - ).toString() - val parts = expectedString.split(",") - val expected = if (parts.size == 2) { - if (parts[1].contains(":") && !parts[0].contains(":")) parts[0].trim() else parts[1].trim() - } else { - expectedString - } - - assertRelativeDateTimeString(time, expected, DateUtils.SECOND_IN_MILLIS) + fun getRelativeDateTimeStringReturnsDaysAgoForTwoDaysAgo() { + assertRelativeDateTimeString( + time = System.currentTimeMillis() - TWO_DAYS, + expected = "2 days ago", + minResolution = DateUtils.DAY_IN_MILLIS + ) } - @Suppress("MagicNumber") @Test - fun getRelativeDateTimeStringReturnsDaysForDayInMillis() { - var testTimestamp = System.currentTimeMillis() - var expected = "Today" - var result = DisplayUtils.getRelativeDateTimeString( - context, - testTimestamp, - DateUtils.DAY_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0, - false - ) - assertEquals(expected, result) + fun getRelativeDateTimeStringDropsTimeOfDayForOneWeekAgo() { + assertDateWithoutTimeOfDay(System.currentTimeMillis() - ONE_WEEK, DateUtils.MINUTE_IN_MILLIS) + } - testTimestamp = System.currentTimeMillis() - DateUtils.DAY_IN_MILLIS - expected = "Yesterday" - result = DisplayUtils.getRelativeDateTimeString( - context, - testTimestamp, - DateUtils.DAY_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0, - false - ) - assertEquals(expected, result) + @Test + fun getRelativeDateTimeStringDropsTimeOfDayForOneWeekAgoWithDayResolution() { + assertDateWithoutTimeOfDay(System.currentTimeMillis() - ONE_WEEK, DateUtils.DAY_IN_MILLIS) + } - testTimestamp = System.currentTimeMillis() - 2 * DateUtils.DAY_IN_MILLIS - expected = "2 days ago" - result = DisplayUtils.getRelativeDateTimeString( - context, - testTimestamp, - DateUtils.DAY_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0, - false - ) - assertEquals(expected, result) + @Test + fun getRelativeDateTimeStringDropsTimeOfDayForOneMonthAgo() { + assertDateWithoutTimeOfDay(System.currentTimeMillis() - ONE_MONTH, DateUtils.SECOND_IN_MILLIS) + } - testTimestamp = System.currentTimeMillis() - 7 * DateUtils.DAY_IN_MILLIS - val expectedString = DateUtils.getRelativeDateTimeString( - context, - testTimestamp, - DateUtils.DAY_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0 - ).toString() - val parts = expectedString.split(",") - expected = if (parts.size == 2) { - if (parts[1].contains(":") && !parts[0].contains(":")) parts[0].trim() else parts[1].trim() - } else { - expectedString - } - result = DisplayUtils.getRelativeDateTimeString( - context, - testTimestamp, - DateUtils.DAY_IN_MILLIS, - DateUtils.WEEK_IN_MILLIS, - 0, - false - ) - assertEquals(expected, result) + @Test + fun getRelativeDateTimeStringDropsTimeOfDayForOneYearAgo() { + assertDateWithoutTimeOfDay(System.currentTimeMillis() - ONE_YEAR, DateUtils.SECOND_IN_MILLIS) } private fun assertRelativeDateTimeString( time: Long, expected: String, minResolution: Long = DateUtils.MINUTE_IN_MILLIS, - transitionResolution: Long = DateUtils.WEEK_IN_MILLIS, showFuture: Boolean = false ) { val result = DisplayUtils.getRelativeDateTimeString( context, time, minResolution, - transitionResolution, + DateUtils.WEEK_IN_MILLIS, 0, showFuture ) - assertEquals(expected.normalizeResult(), result.toString().normalizeResult()) + + assertEquals(expected.normalizeSpaces(), result.toString().normalizeSpaces()) } - private fun String.normalizeResult(): String = replace('\u202F', ' ').replace('\u00A0', ' ') + private fun assertDateWithoutTimeOfDay(time: Long, minResolution: Long) = assertRelativeDateTimeString( + time = time, + expected = platformDateClause(time, minResolution), + minResolution = minResolution + ) + + private fun platformDateClause(time: Long, minResolution: Long): String { + val platformString = DateUtils.getRelativeDateTimeString( + context, + time, + minResolution, + DateUtils.WEEK_IN_MILLIS, + 0 + ).toString() + + val parts = platformString.split(",").map(String::trim) + if (parts.size != DATE_AND_TIME_PARTS) { + return platformString + } + + val (date, timeOfDay) = parts + return when { + timeOfDay.hasTimeOfDay() && !date.hasTimeOfDay() -> date + date.hasTimeOfDay() && !timeOfDay.hasTimeOfDay() -> timeOfDay + else -> platformString + } + } + + private fun Context.localized(locale: Locale): Context { + val configuration = Configuration(resources.configuration).apply { setLocale(locale) } + return createConfigurationContext(configuration) + } + + private fun String.hasTimeOfDay(): Boolean = contains(TIME_OF_DAY_SEPARATOR) + + private fun String.normalizeSpaces(): String = replace(NARROW_NO_BREAK_SPACE, ' ').replace(NO_BREAK_SPACE, ' ') } diff --git a/app/src/androidTest/java/com/owncloud/android/UploadIT.java b/app/src/androidTest/java/com/owncloud/android/UploadIT.java index 0dfdc09d2748..b2cda663e4b7 100644 --- a/app/src/androidTest/java/com/owncloud/android/UploadIT.java +++ b/app/src/androidTest/java/com/owncloud/android/UploadIT.java @@ -14,6 +14,8 @@ import com.nextcloud.client.jobs.upload.FileUploadWorker; import com.nextcloud.client.network.ConnectivityManagerFactory; import com.nextcloud.client.network.ConnectivityService; +import com.nextcloud.test.ServerVersion; +import com.nextcloud.test.SinceServer; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.UploadsStorageManager; import com.owncloud.android.db.OCUpload; @@ -321,6 +323,7 @@ public void testUploadOnWifiOnlyButMeteredWifi() { } @Test + @SinceServer(majorVersion = ServerVersion.NEXTCLOUD_27) public void testCreationAndUploadTimestamp() throws IOException, AccountUtils.AccountNotFoundException { testOnlyOnServer(NextcloudVersion.nextcloud_27); @@ -375,6 +378,7 @@ public void testCreationAndUploadTimestamp() throws IOException, AccountUtils.Ac } @Test + @SinceServer(majorVersion = ServerVersion.NEXTCLOUD_27) public void testMetadata() throws IOException, AccountUtils.AccountNotFoundException { testOnlyOnServer(NextcloudVersion.nextcloud_27); diff --git a/app/src/androidTest/java/com/owncloud/android/ui/LoginIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/LoginIT.kt index 554c1ae650ca..bc50e57361bc 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/LoginIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/LoginIT.kt @@ -20,6 +20,7 @@ import androidx.test.filters.SdkSuppress import androidx.test.platform.app.InstrumentationRegistry import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.account.UserAccountManagerImpl +import com.nextcloud.test.Flaky import com.nextcloud.test.GrantStoragePermissionRule import com.nextcloud.test.RetryTestRule import com.owncloud.android.AbstractIT @@ -28,7 +29,6 @@ import com.owncloud.android.authentication.AuthenticatorActivity import org.junit.AfterClass import org.junit.Assert import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test @@ -54,7 +54,7 @@ class LoginIT : AbstractIT() { @Throws(InterruptedException::class) @Suppress("MagicNumber", "SwallowedException") @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q) - @Ignore("Login no longer uses an in-app WebView, so espresso-web (Espresso.onWebView) cannot drive it. ") + @Flaky("Login no longer uses an in-app WebView, so espresso-web (Espresso.onWebView) cannot drive it. ") fun login() { val arguments = InstrumentationRegistry.getArguments() val baseUrl = arguments.getString("TEST_SERVER_URL")!! diff --git a/app/src/androidTest/java/com/owncloud/android/ui/preview/PreviewImageActivityIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/preview/PreviewImageActivityIT.kt index 163dd875f07c..b87398f46130 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/preview/PreviewImageActivityIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/preview/PreviewImageActivityIT.kt @@ -211,7 +211,7 @@ class PreviewImageActivityIT : AbstractOnServerIT() { } @Test - @Ignore( + @Flaky( "Offline deletion is following a different UX and it is also brittle: Deletion might happen 10 minutes later" ) fun deleteFromSlideshow_remote_offline() { diff --git a/scripts/runCombinedTest.sh b/scripts/runCombinedTest.sh index 93bd567e13f2..86ecf0cc6763 100755 --- a/scripts/runCombinedTest.sh +++ b/scripts/runCombinedTest.sh @@ -26,14 +26,23 @@ scripts/wait_for_emulator.sh || exit 1 ./gradlew installGplayDebugAndroidTest +gradle_arguments=( + -Pcoverage + -Pandroid.testInstrumentationRunnerArguments.notAnnotation=com.owncloud.android.utils.ScreenshotTest + -Pandroid.testInstrumentationRunnerArguments.filter=com.nextcloud.test.FlakyTestFilter,com.nextcloud.test.ServerVersionFilter +) + +if [[ "$BRANCH" =~ ^stable([0-9]+)$ ]]; then + gradle_arguments+=("-Pandroid.testInstrumentationRunnerArguments.TEST_SERVER_VERSION=${BASH_REMATCH[1]}") +fi + # clear logcat and start saving it to file adb logcat -c adb logcat > logcat.txt & LOGCAT_PID=$! + ./gradlew createGplayDebugCoverageReport \ --Pcoverage \ --Pandroid.testInstrumentationRunnerArguments.notAnnotation=com.owncloud.android.utils.ScreenshotTest \ --Pandroid.testInstrumentationRunnerArguments.filter=com.nextcloud.test.FlakyTestFilter \ +"${gradle_arguments[@]}" \ -Dorg.gradle.jvmargs="--add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/java.nio.channels=ALL-UNNAMED --add-exports java.base/sun.nio.ch=ALL-UNNAMED" stat=$? From 20088c58b965a9fe90cf6ae9ff2e4b8f41fd2b48 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 14 Sep 2026 14:32:20 +0200 Subject: [PATCH 2/2] cover server versions for garm Signed-off-by: alperozturk96 --- .../assistant/AssistantRepositoryTests.kt | 3 +-- .../java/com/nextcloud/test/ServerVersion.kt | 13 ------------- .../com/nextcloud/utils/AutoRenameTests.kt | 3 +-- .../nextcloud/utils/FileNameValidatorTests.kt | 19 +++++++++---------- .../java/com/owncloud/android/UploadIT.java | 5 ++--- 5 files changed, 13 insertions(+), 30 deletions(-) delete mode 100644 app/src/androidTest/java/com/nextcloud/test/ServerVersion.kt diff --git a/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt b/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt index 8ecd98763099..2effe006f166 100644 --- a/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt +++ b/app/src/androidTest/java/com/nextcloud/client/assistant/AssistantRepositoryTests.kt @@ -8,7 +8,6 @@ package com.nextcloud.client.assistant import com.nextcloud.client.assistant.repository.remote.AssistantRemoteRepositoryImpl -import com.nextcloud.test.ServerVersion import com.nextcloud.test.SinceServer import com.owncloud.android.AbstractOnServerIT import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData @@ -19,7 +18,7 @@ import org.junit.Before import org.junit.Test @Suppress("MagicNumber") -@SinceServer(ServerVersion.NEXTCLOUD_28) +@SinceServer(majorVersion = 28) class AssistantRepositoryTests : AbstractOnServerIT() { private var sut: AssistantRemoteRepositoryImpl? = null diff --git a/app/src/androidTest/java/com/nextcloud/test/ServerVersion.kt b/app/src/androidTest/java/com/nextcloud/test/ServerVersion.kt deleted file mode 100644 index 6e1e8f944430..000000000000 --- a/app/src/androidTest/java/com/nextcloud/test/ServerVersion.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ -package com.nextcloud.test - -object ServerVersion { - const val NEXTCLOUD_27 = 27 - const val NEXTCLOUD_28 = 28 - const val NEXTCLOUD_30 = 30 -} diff --git a/app/src/androidTest/java/com/nextcloud/utils/AutoRenameTests.kt b/app/src/androidTest/java/com/nextcloud/utils/AutoRenameTests.kt index 79a8657b3a4a..f495c4806633 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/AutoRenameTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/AutoRenameTests.kt @@ -8,7 +8,6 @@ package com.nextcloud.utils -import com.nextcloud.test.ServerVersion import com.nextcloud.test.SinceServer import com.nextcloud.utils.autoRename.AutoRename import com.owncloud.android.AbstractOnServerIT @@ -20,7 +19,7 @@ import org.junit.Before import org.junit.Test @Suppress("TooManyFunctions") -@SinceServer(ServerVersion.NEXTCLOUD_30) +@SinceServer(majorVersion = 30) class AutoRenameTests : AbstractOnServerIT() { private var capability: OCCapability = fileDataStorageManager.getCapability(account.name) diff --git a/app/src/androidTest/java/com/nextcloud/utils/FileNameValidatorTests.kt b/app/src/androidTest/java/com/nextcloud/utils/FileNameValidatorTests.kt index 46f7690647ba..13f2e4585281 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/FileNameValidatorTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/FileNameValidatorTests.kt @@ -7,7 +7,6 @@ package com.nextcloud.utils -import com.nextcloud.test.ServerVersion import com.nextcloud.test.SinceServer import com.nextcloud.utils.fileNameValidator.FileNameValidator import com.owncloud.android.AbstractOnServerIT @@ -44,7 +43,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test - @SinceServer(ServerVersion.NEXTCLOUD_30) + @SinceServer(majorVersion = 30) fun testInvalidCharacter() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -56,7 +55,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test - @SinceServer(ServerVersion.NEXTCLOUD_30) + @SinceServer(majorVersion = 30) fun testReservedName() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -65,7 +64,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test - @SinceServer(ServerVersion.NEXTCLOUD_30) + @SinceServer(majorVersion = 30) fun testForbiddenFilenameExtension() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -146,7 +145,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test - @SinceServer(ServerVersion.NEXTCLOUD_30) + @SinceServer(majorVersion = 30) fun testFolderPathWithReservedName() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -158,7 +157,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test - @SinceServer(ServerVersion.NEXTCLOUD_30) + @SinceServer(majorVersion = 30) fun testFilePathWithReservedName() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -170,7 +169,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test - @SinceServer(ServerVersion.NEXTCLOUD_30) + @SinceServer(majorVersion = 30) fun testFolderPathWithInvalidCharacter() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -182,7 +181,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test - @SinceServer(ServerVersion.NEXTCLOUD_30) + @SinceServer(majorVersion = 30) fun testFilePathWithInvalidCharacter() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -212,7 +211,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test - @SinceServer(ServerVersion.NEXTCLOUD_30) + @SinceServer(majorVersion = 30) fun testFilePathWithNestedFolder() { testOnlyOnServer(NextcloudVersion.nextcloud_30) @@ -232,7 +231,7 @@ class FileNameValidatorTests : AbstractOnServerIT() { } @Test - @SinceServer(ServerVersion.NEXTCLOUD_30) + @SinceServer(majorVersion = 30) fun testOnlyFolderPathWithOneReservedName() { testOnlyOnServer(NextcloudVersion.nextcloud_30) diff --git a/app/src/androidTest/java/com/owncloud/android/UploadIT.java b/app/src/androidTest/java/com/owncloud/android/UploadIT.java index b2cda663e4b7..54966c13320a 100644 --- a/app/src/androidTest/java/com/owncloud/android/UploadIT.java +++ b/app/src/androidTest/java/com/owncloud/android/UploadIT.java @@ -14,7 +14,6 @@ import com.nextcloud.client.jobs.upload.FileUploadWorker; import com.nextcloud.client.network.ConnectivityManagerFactory; import com.nextcloud.client.network.ConnectivityService; -import com.nextcloud.test.ServerVersion; import com.nextcloud.test.SinceServer; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.UploadsStorageManager; @@ -323,7 +322,7 @@ public void testUploadOnWifiOnlyButMeteredWifi() { } @Test - @SinceServer(majorVersion = ServerVersion.NEXTCLOUD_27) + @SinceServer(majorVersion = 27) public void testCreationAndUploadTimestamp() throws IOException, AccountUtils.AccountNotFoundException { testOnlyOnServer(NextcloudVersion.nextcloud_27); @@ -378,7 +377,7 @@ public void testCreationAndUploadTimestamp() throws IOException, AccountUtils.Ac } @Test - @SinceServer(majorVersion = ServerVersion.NEXTCLOUD_27) + @SinceServer(majorVersion = 27) public void testMetadata() throws IOException, AccountUtils.AccountNotFoundException { testOnlyOnServer(NextcloudVersion.nextcloud_27);