Initial QSfera import
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package eu.qsfera.android.data
|
||||
|
||||
import android.accounts.AccountManager
|
||||
import android.content.Context
|
||||
import eu.qsfera.android.data.providers.SharedPreferencesProvider
|
||||
import eu.qsfera.android.lib.common.ConnectionValidator
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class ClientManagerTest {
|
||||
|
||||
private val accountManager: AccountManager = mockk()
|
||||
private val preferencesProvider: SharedPreferencesProvider = mockk()
|
||||
private val context: Context = mockk(relaxed = true)
|
||||
private val connectionValidator: ConnectionValidator = mockk()
|
||||
private lateinit var clientManager: ClientManager
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockkStatic(android.net.Uri::class)
|
||||
val uriMock = mockk<android.net.Uri>()
|
||||
io.mockk.every { android.net.Uri.parse(any()) } returns uriMock
|
||||
io.mockk.every { uriMock.toString() } returns "https://demo.qsfera.eu"
|
||||
|
||||
clientManager = ClientManager(
|
||||
accountManager,
|
||||
preferencesProvider,
|
||||
context,
|
||||
"eu.qsfera.android.account",
|
||||
connectionValidator
|
||||
)
|
||||
}
|
||||
|
||||
@org.junit.After
|
||||
fun tearDown() {
|
||||
io.mockk.unmockkStatic(android.net.Uri::class)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getClientForAnonymousCredentials reuses client and resets credentials`() {
|
||||
val url = "https://demo.qsfera.eu"
|
||||
val mockClient = mockk<eu.qsfera.android.lib.common.QSferaClient>(relaxed = true)
|
||||
val uriMock = android.net.Uri.parse(url)
|
||||
|
||||
io.mockk.every { mockClient.baseUri } returns uriMock
|
||||
|
||||
// Inject mock client into clientManager
|
||||
val field = ClientManager::class.java.getDeclaredField("qsferaClient")
|
||||
field.isAccessible = true
|
||||
field.set(clientManager, mockClient)
|
||||
|
||||
// Call method - should reuse mockClient
|
||||
val resultClient = clientManager.getClientForAnonymousCredentials(url, false)
|
||||
|
||||
assertEquals("Client should be reused", mockClient, resultClient)
|
||||
|
||||
// Verify credentials were set
|
||||
io.mockk.verify { mockClient.credentials = any() }
|
||||
}
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Aitor Ballesteros Pavón
|
||||
* @author Juan Carlos Garrote Gascón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.appregistry.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.appregistry.db.AppRegistryDao
|
||||
import eu.qsfera.android.domain.appregistry.model.AppRegistry
|
||||
import eu.qsfera.android.domain.appregistry.model.AppRegistryMimeType
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_APP_REGISTRY_ENTITY
|
||||
import eu.qsfera.android.testutil.OC_APP_REGISTRY_MIMETYPE
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
class OCLocalAppRegistryDataSourceTest {
|
||||
private lateinit var ocLocalAppRegistryDataSource: OCLocalAppRegistryDataSource
|
||||
private val appRegistryDao = mockk<AppRegistryDao>(relaxUnitFun = true)
|
||||
|
||||
private val mimeTypeDir = "DIR"
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
|
||||
ocLocalAppRegistryDataSource = OCLocalAppRegistryDataSource(appRegistryDao)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAppRegistryForMimeTypeAsStream returns a Flow with an AppRegistryMimeType`() = runTest {
|
||||
|
||||
every { appRegistryDao.getAppRegistryForMimeType(OC_ACCOUNT_NAME, mimeTypeDir) } returns flowOf(OC_APP_REGISTRY_ENTITY)
|
||||
|
||||
val appRegistry = ocLocalAppRegistryDataSource.getAppRegistryForMimeTypeAsStream(OC_ACCOUNT_NAME, mimeTypeDir)
|
||||
|
||||
val result = appRegistry.first()
|
||||
assertEquals(OC_APP_REGISTRY_MIMETYPE, result)
|
||||
|
||||
verify(exactly = 1) { appRegistryDao.getAppRegistryForMimeType(OC_ACCOUNT_NAME, mimeTypeDir) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAppRegistryForMimeTypeAsStream returns a Flow with null when there are no app registries for that mime type`() = runTest {
|
||||
|
||||
every { appRegistryDao.getAppRegistryForMimeType(OC_ACCOUNT_NAME, mimeTypeDir) } returns flowOf(null)
|
||||
|
||||
val appRegistry = ocLocalAppRegistryDataSource.getAppRegistryForMimeTypeAsStream(OC_ACCOUNT_NAME, mimeTypeDir)
|
||||
|
||||
val result = appRegistry.first()
|
||||
assertNull(result)
|
||||
|
||||
verify(exactly = 1) { appRegistryDao.getAppRegistryForMimeType(OC_ACCOUNT_NAME, mimeTypeDir) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAppRegistryWhichAllowCreation returns a Flow with a list of AppRegistryMimeType`() = runTest {
|
||||
|
||||
every { appRegistryDao.getAppRegistryWhichAllowCreation(OC_ACCOUNT_NAME) } returns flowOf(listOf(OC_APP_REGISTRY_ENTITY))
|
||||
|
||||
val appRegistry = ocLocalAppRegistryDataSource.getAppRegistryWhichAllowCreation(OC_ACCOUNT_NAME)
|
||||
|
||||
val result = appRegistry.first()
|
||||
assertEquals(listOf(OC_APP_REGISTRY_MIMETYPE), result)
|
||||
|
||||
verify(exactly = 1) { appRegistryDao.getAppRegistryWhichAllowCreation(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAppRegistryWhichAllowCreation returns an empty list when there are no app registries that allow creation`() = runTest {
|
||||
|
||||
every { appRegistryDao.getAppRegistryWhichAllowCreation(OC_ACCOUNT_NAME) } returns flowOf(emptyList())
|
||||
|
||||
val appRegistry = ocLocalAppRegistryDataSource.getAppRegistryWhichAllowCreation(OC_ACCOUNT_NAME)
|
||||
|
||||
val result = appRegistry.first()
|
||||
assertEquals(emptyList<AppRegistryMimeType>(), result)
|
||||
|
||||
verify(exactly = 1) { appRegistryDao.getAppRegistryWhichAllowCreation(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveAppRegistryForAccount saves an AppRegistry correctly`() {
|
||||
val appRegistryOtherName = "appRegistryMimeTypes.name2"
|
||||
val appRegistry = AppRegistry(
|
||||
OC_ACCOUNT_NAME, mutableListOf(
|
||||
OC_APP_REGISTRY_MIMETYPE,
|
||||
OC_APP_REGISTRY_MIMETYPE.copy(name = appRegistryOtherName)
|
||||
)
|
||||
)
|
||||
|
||||
ocLocalAppRegistryDataSource.saveAppRegistryForAccount(appRegistry)
|
||||
|
||||
verify(exactly = 1) {
|
||||
appRegistryDao.deleteAppRegistryForAccount(appRegistry.accountName)
|
||||
appRegistryDao.upsertAppRegistries(listOf(OC_APP_REGISTRY_ENTITY, OC_APP_REGISTRY_ENTITY.copy(name = appRegistryOtherName)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteAppRegistryForAccount removes the app registries for an account correctly`() {
|
||||
|
||||
ocLocalAppRegistryDataSource.deleteAppRegistryForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) { appRegistryDao.deleteAppRegistryForAccount(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Aitor Ballesteros Pavón
|
||||
* @author Juan Carlos Garrote Gascón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.appregistry.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.ClientManager
|
||||
import eu.qsfera.android.lib.resources.appregistry.services.OCAppRegistryService
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_APP_REGISTRY
|
||||
import eu.qsfera.android.testutil.OC_APP_REGISTRY_RESPONSE
|
||||
import eu.qsfera.android.testutil.OC_FILE
|
||||
import eu.qsfera.android.utils.createRemoteOperationResultMock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteAppRegistryDataSourceTest {
|
||||
|
||||
private lateinit var ocRemoteAppRegistryDataSource: OCRemoteAppRegistryDataSource
|
||||
|
||||
private val clientManager: ClientManager = mockk(relaxed = true)
|
||||
private val ocAppRegistryService: OCAppRegistryService = mockk()
|
||||
|
||||
private val appUrl = "app/list"
|
||||
private val testEndpoint = "app/open-with-web"
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
every { clientManager.getAppRegistryService(OC_ACCOUNT_NAME) } returns ocAppRegistryService
|
||||
|
||||
ocRemoteAppRegistryDataSource = OCRemoteAppRegistryDataSource(clientManager)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAppRegistryForAccount returns an AppRegistry`() {
|
||||
val getAppRegistryForAccountResult = createRemoteOperationResultMock(
|
||||
data = OC_APP_REGISTRY_RESPONSE, isSuccess = true
|
||||
)
|
||||
|
||||
every { ocAppRegistryService.getAppRegistry(appUrl) } returns getAppRegistryForAccountResult
|
||||
|
||||
val result = ocRemoteAppRegistryDataSource.getAppRegistryForAccount(OC_ACCOUNT_NAME, appUrl)
|
||||
|
||||
assertEquals(OC_APP_REGISTRY, result)
|
||||
|
||||
verify(exactly = 1) { ocAppRegistryService.getAppRegistry(appUrl) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUrlToOpenInWeb returns a URL String`() {
|
||||
val expectedUrl = "https://example.com/file123"
|
||||
val appName = "TestApp"
|
||||
|
||||
val getUrlToOpenInWebResult = createRemoteOperationResultMock(
|
||||
data = expectedUrl, isSuccess = true
|
||||
)
|
||||
|
||||
every {
|
||||
ocAppRegistryService.getUrlToOpenInWeb(
|
||||
openWebEndpoint = testEndpoint,
|
||||
fileId = OC_FILE.remoteId.toString(),
|
||||
appName = appName,
|
||||
)
|
||||
} returns getUrlToOpenInWebResult
|
||||
|
||||
val result = ocRemoteAppRegistryDataSource.getUrlToOpenInWeb(
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
openWebEndpoint = testEndpoint,
|
||||
fileId = OC_FILE.remoteId.toString(),
|
||||
appName = appName,
|
||||
)
|
||||
|
||||
assertEquals(expectedUrl, result)
|
||||
|
||||
verify {
|
||||
ocAppRegistryService.getUrlToOpenInWeb(
|
||||
openWebEndpoint = testEndpoint,
|
||||
fileId = OC_FILE.remoteId.toString(),
|
||||
appName = appName,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `createFileWithAppProvider returns a URL String to open the file in web`() {
|
||||
val expectedFileUrl = "https://example.com/files/testFile.txt"
|
||||
|
||||
val createFileWithAppProviderResult = createRemoteOperationResultMock(
|
||||
data = expectedFileUrl, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocAppRegistryService.createFileWithAppProvider(
|
||||
createFileWithAppProviderEndpoint = testEndpoint,
|
||||
parentContainerId = OC_FILE.remoteId.toString(),
|
||||
filename = OC_FILE.fileName,
|
||||
)
|
||||
} returns createFileWithAppProviderResult
|
||||
|
||||
val result = ocRemoteAppRegistryDataSource.createFileWithAppProvider(
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
createFileWithAppProviderEndpoint = testEndpoint,
|
||||
parentContainerId = OC_FILE.remoteId.toString(),
|
||||
filename = OC_FILE.fileName,
|
||||
)
|
||||
|
||||
assertEquals(expectedFileUrl, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocAppRegistryService.createFileWithAppProvider(
|
||||
createFileWithAppProviderEndpoint = testEndpoint,
|
||||
parentContainerId = OC_FILE.remoteId.toString(),
|
||||
filename = OC_FILE.fileName,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2024 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.appregistry.repository
|
||||
|
||||
import eu.qsfera.android.data.appregistry.datasources.LocalAppRegistryDataSource
|
||||
import eu.qsfera.android.data.appregistry.datasources.RemoteAppRegistryDataSource
|
||||
import eu.qsfera.android.data.capabilities.datasources.LocalCapabilitiesDataSource
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_APP_REGISTRY
|
||||
import eu.qsfera.android.testutil.OC_APP_REGISTRY_MIMETYPE
|
||||
import eu.qsfera.android.testutil.OC_CAPABILITY_WITH_FILES_APP_PROVIDERS
|
||||
import eu.qsfera.android.testutil.OC_FILE
|
||||
import eu.qsfera.android.testutil.OC_FOLDER
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
class OCAppRegistryRepositoryTest {
|
||||
|
||||
private val localAppRegistryDataSource = mockk<LocalAppRegistryDataSource>(relaxUnitFun = true)
|
||||
private val remoteAppRegistryDataSource = mockk<RemoteAppRegistryDataSource>()
|
||||
private val localCapabilitiesDataSource = mockk<LocalCapabilitiesDataSource>(relaxUnitFun = true)
|
||||
private val ocAppRegistryRepository = OCAppRegistryRepository(
|
||||
localAppRegistryDataSource,
|
||||
remoteAppRegistryDataSource,
|
||||
localCapabilitiesDataSource,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `refreshAppRegistryForAccount fetches the AppRegistry of an account and saves it`() {
|
||||
|
||||
every { localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME) } returns OC_CAPABILITY_WITH_FILES_APP_PROVIDERS
|
||||
every {
|
||||
remoteAppRegistryDataSource.getAppRegistryForAccount(
|
||||
OC_ACCOUNT_NAME,
|
||||
OC_CAPABILITY_WITH_FILES_APP_PROVIDERS.filesAppProviders?.appsUrl?.substring(1)
|
||||
)
|
||||
} returns OC_APP_REGISTRY
|
||||
|
||||
ocAppRegistryRepository.refreshAppRegistryForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteAppRegistryDataSource.getAppRegistryForAccount(
|
||||
OC_ACCOUNT_NAME,
|
||||
OC_CAPABILITY_WITH_FILES_APP_PROVIDERS.filesAppProviders?.appsUrl?.substring(1)
|
||||
)
|
||||
localAppRegistryDataSource.saveAppRegistryForAccount(OC_APP_REGISTRY)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAppRegistryForMimeTypeAsStream returns a Flow of AppRegistryMimeType`() = runTest {
|
||||
val mimeType = "DIR"
|
||||
every {
|
||||
localAppRegistryDataSource.getAppRegistryForMimeTypeAsStream(
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
mimeType = mimeType
|
||||
)
|
||||
} returns flowOf(
|
||||
OC_APP_REGISTRY_MIMETYPE
|
||||
)
|
||||
val resultActual =
|
||||
ocAppRegistryRepository.getAppRegistryForMimeTypeAsStream(accountName = OC_ACCOUNT_NAME, mimeType = mimeType).first()
|
||||
|
||||
assertEquals(OC_APP_REGISTRY_MIMETYPE, resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localAppRegistryDataSource.getAppRegistryForMimeTypeAsStream(
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
mimeType = mimeType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAppRegistryWhichAllowCreation returns a Flow of List of AppRegistryMimeType`() = runTest {
|
||||
|
||||
every { localAppRegistryDataSource.getAppRegistryWhichAllowCreation(OC_ACCOUNT_NAME) } returns
|
||||
flowOf(listOf(OC_APP_REGISTRY_MIMETYPE))
|
||||
val resultActual = ocAppRegistryRepository.getAppRegistryWhichAllowCreation(OC_ACCOUNT_NAME).first()
|
||||
|
||||
assertEquals(listOf(OC_APP_REGISTRY_MIMETYPE), resultActual)
|
||||
|
||||
verify(exactly = 1) { localAppRegistryDataSource.getAppRegistryWhichAllowCreation(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUrlToOpenInWeb returns a URL String`() {
|
||||
val expectedUrl = "https://example.com/file123"
|
||||
val appName = "qsfera"
|
||||
every {
|
||||
remoteAppRegistryDataSource.getUrlToOpenInWeb(
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
openWebEndpoint = OC_CAPABILITY_WITH_FILES_APP_PROVIDERS.filesAppProviders?.openWebUrl!!,
|
||||
fileId = OC_FILE.remoteId!!,
|
||||
appName = appName
|
||||
)
|
||||
} returns expectedUrl
|
||||
|
||||
val resultActual = ocAppRegistryRepository.getUrlToOpenInWeb(
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
openWebEndpoint = OC_CAPABILITY_WITH_FILES_APP_PROVIDERS.filesAppProviders?.openWebUrl!!,
|
||||
fileId = OC_FILE.remoteId!!,
|
||||
appName = appName
|
||||
)
|
||||
|
||||
assertEquals(expectedUrl, resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteAppRegistryDataSource.getUrlToOpenInWeb(
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
openWebEndpoint = OC_CAPABILITY_WITH_FILES_APP_PROVIDERS.filesAppProviders?.openWebUrl!!,
|
||||
fileId = OC_FILE.remoteId!!,
|
||||
appName = appName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `createFileWithAppProvider returns a String with the new file ID`() {
|
||||
|
||||
every {
|
||||
remoteAppRegistryDataSource.createFileWithAppProvider(
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
createFileWithAppProviderEndpoint = OC_CAPABILITY_WITH_FILES_APP_PROVIDERS.filesAppProviders?.newUrl!!,
|
||||
parentContainerId = OC_FOLDER.remoteId!!,
|
||||
filename = OC_FILE.fileName,
|
||||
)
|
||||
} returns OC_FILE.remoteId!!
|
||||
|
||||
val resultActual = ocAppRegistryRepository.createFileWithAppProvider(
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
createFileWithAppProviderEndpoint = OC_CAPABILITY_WITH_FILES_APP_PROVIDERS.filesAppProviders?.newUrl!!,
|
||||
parentContainerId = OC_FOLDER.remoteId!!,
|
||||
filename = OC_FILE.fileName,
|
||||
)
|
||||
assertEquals(OC_FILE.remoteId!!, resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteAppRegistryDataSource.createFileWithAppProvider(
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
createFileWithAppProviderEndpoint = OC_CAPABILITY_WITH_FILES_APP_PROVIDERS.filesAppProviders?.newUrl!!,
|
||||
parentContainerId = OC_FOLDER.remoteId!!,
|
||||
filename = OC_FILE.fileName,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* @author David González Verdugo
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2024 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package eu.qsfera.android.data.authentication.repository
|
||||
|
||||
import eu.qsfera.android.data.authentication.datasources.LocalAuthenticationDataSource
|
||||
import eu.qsfera.android.data.authentication.datasources.RemoteAuthenticationDataSource
|
||||
import eu.qsfera.android.testutil.OC_ACCESS_TOKEN
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_AUTH_TOKEN_TYPE
|
||||
import eu.qsfera.android.testutil.OC_BASIC_PASSWORD
|
||||
import eu.qsfera.android.testutil.OC_BASIC_USERNAME
|
||||
import eu.qsfera.android.testutil.OC_REDIRECTION_PATH
|
||||
import eu.qsfera.android.testutil.OC_REFRESH_TOKEN
|
||||
import eu.qsfera.android.testutil.OC_SCOPE
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_BASIC_AUTH
|
||||
import eu.qsfera.android.testutil.OC_USER_INFO
|
||||
import eu.qsfera.android.testutil.oauth.OC_CLIENT_REGISTRATION
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class OCAuthenticationRepositoryTest {
|
||||
|
||||
private val localAuthenticationDataSource = mockk<LocalAuthenticationDataSource>()
|
||||
private val remoteAuthenticationDataSource = mockk<RemoteAuthenticationDataSource>()
|
||||
private val ocAuthenticationRepository: OCAuthenticationRepository =
|
||||
OCAuthenticationRepository(localAuthenticationDataSource, remoteAuthenticationDataSource)
|
||||
|
||||
@Test
|
||||
fun `loginBasic returns String with the account name`() {
|
||||
every {
|
||||
remoteAuthenticationDataSource.loginBasic(
|
||||
serverPath = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
username = OC_BASIC_USERNAME,
|
||||
password = OC_BASIC_PASSWORD
|
||||
)
|
||||
} returns Pair(
|
||||
OC_USER_INFO,
|
||||
OC_REDIRECTION_PATH.lastPermanentLocation
|
||||
)
|
||||
|
||||
every {
|
||||
localAuthenticationDataSource.addBasicAccount(
|
||||
userName = OC_BASIC_USERNAME,
|
||||
lastPermanentLocation = OC_REDIRECTION_PATH.lastPermanentLocation,
|
||||
password = OC_BASIC_PASSWORD,
|
||||
serverInfo = OC_SECURE_SERVER_INFO_BASIC_AUTH,
|
||||
userInfo = OC_USER_INFO,
|
||||
updateAccountWithUsername = null
|
||||
)
|
||||
} returns OC_ACCOUNT_NAME
|
||||
|
||||
val accountName = ocAuthenticationRepository.loginBasic(
|
||||
serverInfo = OC_SECURE_SERVER_INFO_BASIC_AUTH,
|
||||
username = OC_BASIC_USERNAME,
|
||||
password = OC_BASIC_PASSWORD,
|
||||
updateAccountWithUsername = null
|
||||
)
|
||||
|
||||
assertEquals(OC_ACCOUNT_NAME, accountName)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteAuthenticationDataSource.loginBasic(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, OC_BASIC_USERNAME, OC_BASIC_PASSWORD)
|
||||
localAuthenticationDataSource.addBasicAccount(
|
||||
userName = OC_BASIC_USERNAME,
|
||||
lastPermanentLocation = OC_REDIRECTION_PATH.lastPermanentLocation,
|
||||
password = OC_BASIC_PASSWORD,
|
||||
serverInfo = OC_SECURE_SERVER_INFO_BASIC_AUTH,
|
||||
userInfo = OC_USER_INFO,
|
||||
updateAccountWithUsername = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `loginOAuth returns String with the account name`() {
|
||||
every {
|
||||
remoteAuthenticationDataSource.loginOAuth(
|
||||
serverPath = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
username = OC_BASIC_USERNAME,
|
||||
accessToken = OC_ACCESS_TOKEN
|
||||
)
|
||||
} returns Pair(
|
||||
first = OC_USER_INFO,
|
||||
second = OC_REDIRECTION_PATH.lastPermanentLocation
|
||||
)
|
||||
|
||||
every {
|
||||
localAuthenticationDataSource.addOAuthAccount(
|
||||
userName = OC_BASIC_USERNAME,
|
||||
lastPermanentLocation = OC_REDIRECTION_PATH.lastPermanentLocation,
|
||||
authTokenType = OC_AUTH_TOKEN_TYPE,
|
||||
accessToken = OC_ACCESS_TOKEN,
|
||||
serverInfo = OC_SECURE_SERVER_INFO_BASIC_AUTH,
|
||||
userInfo = OC_USER_INFO,
|
||||
refreshToken = OC_REFRESH_TOKEN,
|
||||
scope = OC_SCOPE,
|
||||
updateAccountWithUsername = null,
|
||||
clientRegistrationInfo = OC_CLIENT_REGISTRATION
|
||||
)
|
||||
} returns OC_ACCOUNT_NAME
|
||||
|
||||
val accountName = ocAuthenticationRepository.loginOAuth(
|
||||
serverInfo = OC_SECURE_SERVER_INFO_BASIC_AUTH,
|
||||
username = OC_BASIC_USERNAME,
|
||||
authTokenType = OC_AUTH_TOKEN_TYPE,
|
||||
accessToken = OC_ACCESS_TOKEN,
|
||||
refreshToken = OC_REFRESH_TOKEN,
|
||||
scope = OC_SCOPE,
|
||||
updateAccountWithUsername = null,
|
||||
clientRegistrationInfo = OC_CLIENT_REGISTRATION
|
||||
)
|
||||
|
||||
assertEquals(OC_ACCOUNT_NAME, accountName)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteAuthenticationDataSource.loginOAuth(
|
||||
serverPath = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
username = OC_BASIC_USERNAME,
|
||||
accessToken = OC_ACCESS_TOKEN
|
||||
)
|
||||
localAuthenticationDataSource.addOAuthAccount(
|
||||
userName = OC_BASIC_USERNAME,
|
||||
lastPermanentLocation = OC_REDIRECTION_PATH.lastPermanentLocation,
|
||||
authTokenType = OC_AUTH_TOKEN_TYPE,
|
||||
accessToken = OC_ACCESS_TOKEN,
|
||||
serverInfo = OC_SECURE_SERVER_INFO_BASIC_AUTH,
|
||||
userInfo = OC_USER_INFO,
|
||||
refreshToken = OC_REFRESH_TOKEN,
|
||||
scope = OC_SCOPE,
|
||||
updateAccountWithUsername = null,
|
||||
clientRegistrationInfo = OC_CLIENT_REGISTRATION
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `supportsOAuth2UseCase returns Boolean`() {
|
||||
every {
|
||||
localAuthenticationDataSource.supportsOAuth2(OC_ACCOUNT_NAME)
|
||||
} returns true
|
||||
|
||||
val actualResult = ocAuthenticationRepository.supportsOAuth2UseCase(OC_ACCOUNT_NAME)
|
||||
|
||||
assertTrue(actualResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localAuthenticationDataSource.supportsOAuth2(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getBaseUrl returns a String with the base URL`() {
|
||||
every {
|
||||
localAuthenticationDataSource.getBaseUrl(OC_ACCOUNT_NAME)
|
||||
} returns OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl
|
||||
|
||||
val resultActual = ocAuthenticationRepository.getBaseUrl(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localAuthenticationDataSource.getBaseUrl(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author David González Verdugo
|
||||
* @author Abel García de Prada
|
||||
* @author Aitor Ballesteros Pavón
|
||||
* @author Juan Carlos Garrote Gascón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.capabilities.datasources.implementation
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import eu.qsfera.android.data.capabilities.datasources.implementation.OCLocalCapabilitiesDataSource.Companion.toEntity
|
||||
import eu.qsfera.android.data.capabilities.db.OCCapabilityDao
|
||||
import eu.qsfera.android.data.capabilities.db.OCCapabilityEntity
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_CAPABILITY
|
||||
import eu.qsfera.android.testutil.livedata.getLastEmittedValue
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
|
||||
class OCLocalCapabilitiesDataSourceTest {
|
||||
|
||||
private lateinit var ocLocalCapabilitiesDataSource: OCLocalCapabilitiesDataSource
|
||||
private val ocCapabilityDao = mockk<OCCapabilityDao>(relaxUnitFun = true)
|
||||
|
||||
private val ocCapability = OC_CAPABILITY.copy(id = 0)
|
||||
private val ocCapabilityEntity = ocCapability.toEntity()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule: TestRule = InstantTaskExecutorRule()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
ocLocalCapabilitiesDataSource =
|
||||
OCLocalCapabilitiesDataSource(
|
||||
ocCapabilityDao,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCapabilitiesForAccountAsLiveData returns a LiveData of OCCapability`() {
|
||||
val capabilitiesLiveData = MutableLiveData(ocCapabilityEntity)
|
||||
every { ocCapabilityDao.getCapabilitiesForAccountAsLiveData(OC_ACCOUNT_NAME) } returns capabilitiesLiveData
|
||||
|
||||
val result = ocLocalCapabilitiesDataSource.getCapabilitiesForAccountAsLiveData(OC_ACCOUNT_NAME).getLastEmittedValue()
|
||||
|
||||
assertEquals(ocCapability, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocCapabilityDao.getCapabilitiesForAccountAsLiveData(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCapabilitiesForAccountAsLiveData returns null when DAO returns a null capability`() {
|
||||
val capabilitiesLiveData = MutableLiveData<OCCapabilityEntity>(null)
|
||||
every { ocCapabilityDao.getCapabilitiesForAccountAsLiveData(OC_ACCOUNT_NAME) } returns capabilitiesLiveData
|
||||
|
||||
val result = ocLocalCapabilitiesDataSource.getCapabilitiesForAccountAsLiveData(OC_ACCOUNT_NAME).getLastEmittedValue()
|
||||
|
||||
assertNull(result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocCapabilityDao.getCapabilitiesForAccountAsLiveData(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCapabilitiesForAccount returns a OCCapability`() {
|
||||
every { ocCapabilityDao.getCapabilitiesForAccount(OC_ACCOUNT_NAME) } returns ocCapabilityEntity
|
||||
|
||||
val result = ocLocalCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(ocCapability, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocCapabilityDao.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCapabilitiesForAccount returns null when DAO returns a null capability`() {
|
||||
every { ocCapabilityDao.getCapabilitiesForAccount(OC_ACCOUNT_NAME) } returns null
|
||||
|
||||
val result = ocLocalCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertNull(result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocCapabilityDao.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `insertCapabilities saves a list of OCCapability correctly`() {
|
||||
ocLocalCapabilitiesDataSource.insertCapabilities(listOf(ocCapability))
|
||||
|
||||
verify(exactly = 1) { ocCapabilityDao.replace(listOf(ocCapabilityEntity)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteCapabilitiesForAccount removes capabilities correctly`() {
|
||||
ocLocalCapabilitiesDataSource.deleteCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) { ocCapabilityDao.deleteByAccountName(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author David González Verdugo
|
||||
* @author Jesús Recio
|
||||
* @author Aitor Ballesteros Pavón
|
||||
* @author Juan Carlos Garrote Gascón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.capabilities.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.ClientManager
|
||||
import eu.qsfera.android.data.capabilities.datasources.mapper.RemoteCapabilityMapper
|
||||
import eu.qsfera.android.lib.resources.status.services.implementation.OCCapabilityService
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_CAPABILITY
|
||||
import eu.qsfera.android.utils.createRemoteOperationResultMock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteCapabilitiesDataSourceTest {
|
||||
|
||||
private lateinit var ocRemoteCapabilitiesDataSource: OCRemoteCapabilitiesDataSource
|
||||
|
||||
private val ocCapabilityService: OCCapabilityService = mockk()
|
||||
private val clientManager: ClientManager = mockk(relaxed = true)
|
||||
private val remoteCapabilityMapper = RemoteCapabilityMapper()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
every { clientManager.getCapabilityService(OC_ACCOUNT_NAME) } returns ocCapabilityService
|
||||
|
||||
ocRemoteCapabilitiesDataSource =
|
||||
OCRemoteCapabilitiesDataSource(
|
||||
clientManager,
|
||||
remoteCapabilityMapper
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCapabilities returns a OCCapability`() {
|
||||
val remoteCapability = remoteCapabilityMapper.toRemote(OC_CAPABILITY)!!
|
||||
|
||||
val getRemoteCapabilitiesOperationResult = createRemoteOperationResultMock(remoteCapability, true)
|
||||
|
||||
every { ocCapabilityService.getCapabilities() } returns getRemoteCapabilitiesOperationResult
|
||||
|
||||
val result = ocRemoteCapabilitiesDataSource.getCapabilities(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(OC_CAPABILITY, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getCapabilityService(OC_ACCOUNT_NAME)
|
||||
ocCapabilityService.getCapabilities()
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.capabilities.datasources.mapper
|
||||
|
||||
import eu.qsfera.android.testutil.OC_CAPABILITY
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteCapabilityMapperTest {
|
||||
|
||||
private val ocRemoteCapabilityMapper = RemoteCapabilityMapper()
|
||||
|
||||
@Test
|
||||
fun checkToModelNull() {
|
||||
Assert.assertNull(ocRemoteCapabilityMapper.toModel(null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkToModelNotNull() {
|
||||
val remoteCapability = ocRemoteCapabilityMapper.toRemote(OC_CAPABILITY)
|
||||
Assert.assertNotNull(remoteCapability)
|
||||
|
||||
val capability = ocRemoteCapabilityMapper.toModel(remoteCapability)
|
||||
Assert.assertNotNull(capability)
|
||||
Assert.assertEquals(capability, OC_CAPABILITY)
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author David González Verdugo
|
||||
* @author Abel García de Prada
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2024 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.capabilities.repository
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import eu.qsfera.android.data.capabilities.datasources.LocalCapabilitiesDataSource
|
||||
import eu.qsfera.android.data.capabilities.datasources.RemoteCapabilitiesDataSource
|
||||
import eu.qsfera.android.domain.appregistry.AppRegistryRepository
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_CAPABILITY
|
||||
import eu.qsfera.android.testutil.OC_CAPABILITY_WITH_FILES_APP_PROVIDERS
|
||||
import eu.qsfera.android.testutil.livedata.getLastEmittedValue
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class OCCapabilityRepositoryTest {
|
||||
@Rule
|
||||
@JvmField
|
||||
val instantExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
private val localCapabilitiesDataSource = mockk<LocalCapabilitiesDataSource>(relaxUnitFun = true)
|
||||
private val remoteCapabilitiesDataSource = mockk<RemoteCapabilitiesDataSource>()
|
||||
private val appRegistryRepository = mockk<AppRegistryRepository>(relaxUnitFun = true)
|
||||
private val ocCapabilityRepository: OCCapabilityRepository =
|
||||
OCCapabilityRepository(localCapabilitiesDataSource, remoteCapabilitiesDataSource, appRegistryRepository)
|
||||
|
||||
@Test
|
||||
fun `getCapabilitiesAsLiveData returns a LiveData of OCCapability`() {
|
||||
val capabilitiesLiveData = MutableLiveData(OC_CAPABILITY)
|
||||
|
||||
every {
|
||||
localCapabilitiesDataSource.getCapabilitiesForAccountAsLiveData(OC_ACCOUNT_NAME)
|
||||
} returns capabilitiesLiveData
|
||||
|
||||
val capabilitiesToEmit = capabilitiesLiveData.getLastEmittedValue()
|
||||
|
||||
val capabilitiesEmitted = ocCapabilityRepository.getCapabilitiesAsLiveData(OC_ACCOUNT_NAME).getLastEmittedValue()
|
||||
|
||||
assertEquals(capabilitiesToEmit, capabilitiesEmitted)
|
||||
|
||||
verify(exactly = 1) { localCapabilitiesDataSource.getCapabilitiesForAccountAsLiveData(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getStoredCapabilities returns an OCCapability`() {
|
||||
|
||||
every {
|
||||
localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns OC_CAPABILITY
|
||||
|
||||
val actualResult = ocCapabilityRepository.getStoredCapabilities(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(OC_CAPABILITY, actualResult)
|
||||
|
||||
verify(exactly = 1) { localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refreshCapabilitiesForAccount updates capabilities correctly when files app providers is not null`() {
|
||||
|
||||
every { remoteCapabilitiesDataSource.getCapabilities(OC_ACCOUNT_NAME) } returns OC_CAPABILITY_WITH_FILES_APP_PROVIDERS
|
||||
|
||||
ocCapabilityRepository.refreshCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteCapabilitiesDataSource.getCapabilities(OC_ACCOUNT_NAME)
|
||||
localCapabilitiesDataSource.insertCapabilities(listOf(OC_CAPABILITY_WITH_FILES_APP_PROVIDERS))
|
||||
appRegistryRepository.refreshAppRegistryForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refreshCapabilitiesForAccount updates capabilities correctly but not refresh AppRegistry when filesAppProviders is null`() {
|
||||
|
||||
every { remoteCapabilitiesDataSource.getCapabilities(OC_ACCOUNT_NAME) } returns OC_CAPABILITY
|
||||
|
||||
ocCapabilityRepository.refreshCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteCapabilitiesDataSource.getCapabilities(OC_ACCOUNT_NAME)
|
||||
localCapabilitiesDataSource.insertCapabilities(listOf(OC_CAPABILITY))
|
||||
}
|
||||
}
|
||||
}
|
||||
+659
@@ -0,0 +1,659 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* @author Aitor Ballesteros Pavón
|
||||
* @author Juan Carlos Garrote Gascón
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2024 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.files.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.files.datasources.implementation.OCLocalFileDataSource.Companion.toEntity
|
||||
import eu.qsfera.android.data.files.db.FileDao
|
||||
import eu.qsfera.android.data.files.db.OCFileEntity
|
||||
import eu.qsfera.android.domain.availableoffline.model.AvailableOfflineStatus
|
||||
import eu.qsfera.android.domain.files.model.MIME_DIR
|
||||
import eu.qsfera.android.domain.files.model.MIME_PREFIX_IMAGE
|
||||
import eu.qsfera.android.domain.files.model.OCFile
|
||||
import eu.qsfera.android.domain.files.model.OCFile.Companion.ROOT_PARENT_ID
|
||||
import eu.qsfera.android.domain.files.model.OCFile.Companion.ROOT_PATH
|
||||
import eu.qsfera.android.domain.files.model.OCFileWithSyncInfo
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_FILE
|
||||
import eu.qsfera.android.testutil.OC_FILE_AND_FILE_SYNC
|
||||
import eu.qsfera.android.testutil.OC_FILE_AVAILABLE_OFFLINE
|
||||
import eu.qsfera.android.testutil.OC_FILE_AVAILABLE_OFFLINE_ENTITY
|
||||
import eu.qsfera.android.testutil.OC_FILE_ENTITY
|
||||
import eu.qsfera.android.testutil.OC_FILE_WITH_SYNC_INFO_AND_SPACE
|
||||
import eu.qsfera.android.testutil.OC_FOLDER
|
||||
import eu.qsfera.android.testutil.OC_FOLDER_ENTITY
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.util.UUID
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
class OCLocalFileDataSourceTest {
|
||||
|
||||
private lateinit var ocLocalFileDataSource: OCLocalFileDataSource
|
||||
private val fileDao = mockk<FileDao>(relaxUnitFun = true)
|
||||
|
||||
private val fileEntitySharedByLink = OC_FILE_ENTITY.copy(sharedByLink = true).apply { this.id = OC_FILE_ENTITY.id }
|
||||
private val fileSharedByLink = OC_FILE.copy(sharedByLink = true)
|
||||
private val timeInMilliseconds = 3600000L
|
||||
@Before
|
||||
fun setUp() {
|
||||
ocLocalFileDataSource = OCLocalFileDataSource(fileDao)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileById returns a OCFile`() {
|
||||
every { fileDao.getFileById(OC_FILE_ENTITY.id) } returns OC_FILE_ENTITY
|
||||
|
||||
val result = ocLocalFileDataSource.getFileById(OC_FILE_ENTITY.id)
|
||||
|
||||
assertEquals(OC_FILE, result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFileById(OC_FILE_ENTITY.id) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileById returns null when DAO returns a null file`() {
|
||||
every { fileDao.getFileById(OC_FILE_ENTITY.id) } returns null
|
||||
|
||||
val result = ocLocalFileDataSource.getFileById(OC_FILE_ENTITY.id)
|
||||
|
||||
assertNull(result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFileById(OC_FILE_ENTITY.id) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileByIdAsFlow returns a Flow with an OCFile`() = runTest {
|
||||
every { fileDao.getFileByIdAsFlow(OC_FILE_ENTITY.id) } returns flowOf(OC_FILE_ENTITY)
|
||||
|
||||
val result = ocLocalFileDataSource.getFileByIdAsFlow(OC_FILE_ENTITY.id).first()
|
||||
|
||||
assertEquals(OC_FILE, result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFileByIdAsFlow(OC_FILE_ENTITY.id) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileByIdAsFlow returns a Flow with null when DAO returns a Flow with null`() = runTest {
|
||||
every { fileDao.getFileByIdAsFlow(OC_FILE_ENTITY.id) } returns flowOf(null)
|
||||
|
||||
val result = ocLocalFileDataSource.getFileByIdAsFlow(OC_FILE_ENTITY.id).first()
|
||||
|
||||
assertNull(result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFileByIdAsFlow(OC_FILE_ENTITY.id) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDownloadedFilesForAccount returns a list of OCFile`() {
|
||||
every { fileDao.getDownloadedFilesForAccount(OC_ACCOUNT_NAME) } returns listOf(OC_FILE_ENTITY)
|
||||
|
||||
val result = ocLocalFileDataSource.getDownloadedFilesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(listOf(OC_FILE), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getDownloadedFilesForAccount(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDownloadedFilesForAccount returns an empty list when DAO returns an empty list`() {
|
||||
every { fileDao.getDownloadedFilesForAccount(OC_ACCOUNT_NAME) } returns emptyList()
|
||||
|
||||
val result = ocLocalFileDataSource.getDownloadedFilesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getDownloadedFilesForAccount(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileWithSyncInfoByIdAsFlow returns a Flow with an OCFileWithSyncInfo`() = runTest {
|
||||
every { fileDao.getFileWithSyncInfoByIdAsFlow(OC_FILE_ENTITY.id) } returns flowOf(OC_FILE_AND_FILE_SYNC)
|
||||
|
||||
val result = ocLocalFileDataSource.getFileWithSyncInfoByIdAsFlow(OC_FILE_ENTITY.id).first()
|
||||
|
||||
assertEquals(OC_FILE_WITH_SYNC_INFO_AND_SPACE, result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFileWithSyncInfoByIdAsFlow(OC_FILE_ENTITY.id) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileWithSyncInfoByIdAsFlow returns a Flow with null when DAO returns a Flow with null`() = runTest {
|
||||
every { fileDao.getFileWithSyncInfoByIdAsFlow(OC_FILE_ENTITY.id) } returns flowOf(null)
|
||||
|
||||
val result = ocLocalFileDataSource.getFileWithSyncInfoByIdAsFlow(OC_FILE_ENTITY.id).first()
|
||||
|
||||
assertNull(result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFileWithSyncInfoByIdAsFlow(OC_FILE_ENTITY.id) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileByRemotePath returns a OCFile`() {
|
||||
every { fileDao.getFileByOwnerAndRemotePath(OC_FILE.owner, OC_FILE.remotePath, OC_FILE.spaceId) } returns OC_FILE_ENTITY
|
||||
|
||||
val result = ocLocalFileDataSource.getFileByRemotePath(OC_FILE.remotePath, OC_FILE.owner, OC_FILE.spaceId)
|
||||
|
||||
assertEquals(OC_FILE, result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFileByOwnerAndRemotePath(OC_FILE.owner, OC_FILE.remotePath, OC_FILE.spaceId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileByRemotePath returns null when DAO returns a null file`() {
|
||||
every { fileDao.getFileByOwnerAndRemotePath(OC_FILE.owner, OC_FILE.remotePath, OC_FILE.spaceId) } returns null
|
||||
|
||||
val result = ocLocalFileDataSource.getFileByRemotePath(OC_FILE.remotePath, OC_FILE.owner, OC_FILE.spaceId)
|
||||
|
||||
assertNull(result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFileByOwnerAndRemotePath(OC_FILE.owner, OC_FILE.remotePath, OC_FILE.spaceId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileByRemotePath returns OCFile of root folder when creating it`() {
|
||||
val rootFolder = OCFile(
|
||||
id = 0,
|
||||
parentId = ROOT_PARENT_ID,
|
||||
owner = OC_ACCOUNT_NAME,
|
||||
remotePath = ROOT_PATH,
|
||||
length = 0,
|
||||
mimeType = MIME_DIR,
|
||||
modificationTimestamp = 0,
|
||||
spaceId = OC_FILE.spaceId,
|
||||
permissions = "CK",
|
||||
availableOfflineStatus = AvailableOfflineStatus.NOT_AVAILABLE_OFFLINE,
|
||||
)
|
||||
|
||||
val rootFolderEntity = OCFileEntity(
|
||||
parentId = ROOT_PARENT_ID,
|
||||
remotePath = ROOT_PATH,
|
||||
owner = OC_ACCOUNT_NAME,
|
||||
permissions = "CK",
|
||||
remoteId = null,
|
||||
creationTimestamp = 0,
|
||||
modificationTimestamp = 0,
|
||||
etag = "",
|
||||
remoteEtag = "",
|
||||
mimeType = MIME_DIR,
|
||||
length = 0,
|
||||
fileIsDownloading = false,
|
||||
modifiedAtLastSyncForData = 0,
|
||||
lastSyncDateForData = 0,
|
||||
treeEtag = "",
|
||||
privateLink = "",
|
||||
|
||||
)
|
||||
|
||||
every { fileDao.getFileByOwnerAndRemotePath(OC_FILE.owner, ROOT_PATH, OC_FILE.spaceId) } returns null
|
||||
every { fileDao.mergeRemoteAndLocalFile(rootFolder.toEntity()) } returns 0
|
||||
every { fileDao.getFileById(0) } returns rootFolderEntity
|
||||
|
||||
val result = ocLocalFileDataSource.getFileByRemotePath(ROOT_PATH, OC_FILE.owner, OC_FILE.spaceId)
|
||||
|
||||
assertEquals(rootFolder, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
fileDao.getFileByOwnerAndRemotePath(OC_FILE.owner, ROOT_PATH, OC_FILE.spaceId)
|
||||
fileDao.mergeRemoteAndLocalFile(rootFolder.toEntity())
|
||||
fileDao.getFileById(0)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileByRemoteId returns a OCFile`() {
|
||||
every { fileDao.getFileByRemoteId(OC_FILE_ENTITY.remoteId!!) } returns OC_FILE_ENTITY
|
||||
|
||||
val result = ocLocalFileDataSource.getFileByRemoteId(OC_FILE_ENTITY.remoteId!!)
|
||||
|
||||
assertEquals(OC_FILE, result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFileByRemoteId(OC_FILE_ENTITY.remoteId!!) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFileByRemoteId returns null when DAO returns a null file`() {
|
||||
every { fileDao.getFileByRemoteId(OC_FILE_ENTITY.remoteId!!) } returns null
|
||||
|
||||
val result = ocLocalFileDataSource.getFileByRemoteId(OC_FILE_ENTITY.remoteId!!)
|
||||
|
||||
assertNull(result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFileByRemoteId(OC_FILE_ENTITY.remoteId!!) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFolderContent returns a list of OCFile`() {
|
||||
every { fileDao.getFolderContent(OC_FILE_ENTITY.parentId!!) } returns listOf(OC_FILE_ENTITY)
|
||||
|
||||
val result = ocLocalFileDataSource.getFolderContent(OC_FILE_ENTITY.parentId!!)
|
||||
|
||||
assertEquals(listOf(OC_FILE), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFolderContent(OC_FILE_ENTITY.parentId!!) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFolderContent returns an empty list when DAO returns an empty list`() {
|
||||
every { fileDao.getFolderContent(OC_FILE_ENTITY.parentId!!) } returns emptyList()
|
||||
|
||||
val result = ocLocalFileDataSource.getFolderContent(OC_FILE_ENTITY.parentId!!)
|
||||
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFolderContent(OC_FILE_ENTITY.parentId!!) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSearchFolderContent returns a list of OCFile`() {
|
||||
every { fileDao.getSearchFolderContent(OC_FILE_ENTITY.parentId!!, "test") } returns listOf(OC_FILE_ENTITY)
|
||||
|
||||
val result = ocLocalFileDataSource.getSearchFolderContent(OC_FILE_ENTITY.parentId!!, "test")
|
||||
|
||||
assertEquals(listOf(OC_FILE), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getSearchFolderContent(OC_FILE_ENTITY.parentId!!, "test") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSearchFolderContent returns an empty list when DAO returns an empty list`() {
|
||||
every { fileDao.getSearchFolderContent(OC_FILE_ENTITY.parentId!!, "test") } returns emptyList()
|
||||
|
||||
val result = ocLocalFileDataSource.getSearchFolderContent(OC_FILE_ENTITY.parentId!!, "test")
|
||||
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getSearchFolderContent(OC_FILE_ENTITY.parentId!!, "test") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSearchAvailableOfflineFolderContent returns a list of OCFile`() {
|
||||
every {
|
||||
fileDao.getSearchAvailableOfflineFolderContent(OC_FILE_AVAILABLE_OFFLINE_ENTITY.parentId!!, "test")
|
||||
} returns listOf(OC_FILE_AVAILABLE_OFFLINE_ENTITY)
|
||||
|
||||
val result = ocLocalFileDataSource.getSearchAvailableOfflineFolderContent(OC_FILE_AVAILABLE_OFFLINE_ENTITY.parentId!!, "test")
|
||||
|
||||
assertEquals(listOf(OC_FILE_AVAILABLE_OFFLINE), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getSearchAvailableOfflineFolderContent(OC_FILE_AVAILABLE_OFFLINE_ENTITY.parentId!!, "test") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSearchAvailableOfflineFolderContent returns an empty list when DAO returns an empty list`() {
|
||||
every { fileDao.getSearchAvailableOfflineFolderContent(OC_FILE_ENTITY.parentId!!, "test") } returns emptyList()
|
||||
|
||||
val result = ocLocalFileDataSource.getSearchAvailableOfflineFolderContent(OC_FILE_ENTITY.parentId!!, "test")
|
||||
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getSearchAvailableOfflineFolderContent(OC_FILE_ENTITY.parentId!!, "test") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSearchSharedByLinkFolderContent returns a list of OCFile`() {
|
||||
every { fileDao.getSearchSharedByLinkFolderContent(fileEntitySharedByLink.parentId!!, "test") } returns listOf(fileEntitySharedByLink)
|
||||
|
||||
val result = ocLocalFileDataSource.getSearchSharedByLinkFolderContent(fileEntitySharedByLink.parentId!!, "test")
|
||||
|
||||
assertEquals(listOf(fileSharedByLink), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getSearchSharedByLinkFolderContent(fileEntitySharedByLink.parentId!!, "test") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSearchSharedByLinkFolderContent returns an empty list when DAO returns an empty list`() {
|
||||
every { fileDao.getSearchSharedByLinkFolderContent(OC_FILE_ENTITY.parentId!!, "test") } returns emptyList()
|
||||
|
||||
val result = ocLocalFileDataSource.getSearchSharedByLinkFolderContent(OC_FILE_ENTITY.parentId!!, "test")
|
||||
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getSearchSharedByLinkFolderContent(OC_FILE_ENTITY.parentId!!, "test") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFolderContentWithSyncInfoAsFlow returns a Flow with a list of OCFileWithSyncInfo`() = runTest {
|
||||
every { fileDao.getFolderContentWithSyncInfoAsFlow(OC_FILE_ENTITY.parentId!!) } returns flowOf(listOf(OC_FILE_AND_FILE_SYNC))
|
||||
|
||||
val result = ocLocalFileDataSource.getFolderContentWithSyncInfoAsFlow(OC_FILE_ENTITY.parentId!!).first()
|
||||
|
||||
assertEquals(listOf(OC_FILE_WITH_SYNC_INFO_AND_SPACE), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFolderContentWithSyncInfoAsFlow(OC_FILE_ENTITY.parentId!!) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFolderContentWithSyncInfoAsFlow returns a Flow with an empty list when DAO returns a Flow with an empty list`() = runTest {
|
||||
every { fileDao.getFolderContentWithSyncInfoAsFlow(OC_FILE_ENTITY.parentId!!) } returns flowOf(emptyList())
|
||||
|
||||
val result = ocLocalFileDataSource.getFolderContentWithSyncInfoAsFlow(OC_FILE_ENTITY.parentId!!).first()
|
||||
|
||||
assertEquals(emptyList<OCFileWithSyncInfo>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFolderContentWithSyncInfoAsFlow(OC_FILE_ENTITY.parentId!!) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFolderImages returns a list of OCFile`() {
|
||||
every { fileDao.getFolderByMimeType(OC_FILE_ENTITY.parentId!!, MIME_PREFIX_IMAGE) } returns listOf(OC_FILE_ENTITY)
|
||||
|
||||
val result = ocLocalFileDataSource.getFolderImages(OC_FILE_ENTITY.parentId!!)
|
||||
|
||||
assertEquals(listOf(OC_FILE), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFolderByMimeType(OC_FILE_ENTITY.parentId!!, MIME_PREFIX_IMAGE) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFolderImages returns an empty list when DAO returns an empty list`() {
|
||||
every { fileDao.getFolderByMimeType(OC_FILE_ENTITY.parentId!!, MIME_PREFIX_IMAGE) } returns emptyList()
|
||||
|
||||
val result = ocLocalFileDataSource.getFolderImages(OC_FILE_ENTITY.parentId!!)
|
||||
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFolderByMimeType(OC_FILE_ENTITY.parentId!!, MIME_PREFIX_IMAGE) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharedByLinkWithSyncInfoForAccountAsFlow returns a Flow with a list of OCFileWithSyncInfo`() = runTest {
|
||||
val fileAndFileSyncEntitySharedByLink = OC_FILE_AND_FILE_SYNC.copy(file = OC_FILE_ENTITY.copy(sharedByLink = true).apply {
|
||||
this.id = OC_FILE_ENTITY.id
|
||||
})
|
||||
|
||||
val fileWithSyncInfoSharedByLink = OC_FILE_WITH_SYNC_INFO_AND_SPACE.copy(file = OC_FILE.copy(sharedByLink = true))
|
||||
|
||||
every { fileDao.getFilesWithSyncInfoSharedByLinkAsFlow(OC_ACCOUNT_NAME) } returns flowOf(listOf(fileAndFileSyncEntitySharedByLink))
|
||||
|
||||
val result = ocLocalFileDataSource.getSharedByLinkWithSyncInfoForAccountAsFlow(OC_ACCOUNT_NAME).first()
|
||||
|
||||
assertEquals(listOf(fileWithSyncInfoSharedByLink), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFilesWithSyncInfoSharedByLinkAsFlow(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharedByLinkWithSyncInfoForAccountAsFlow returns a Flow with an empty list when DAO returns a Flow with an empty list`() = runTest {
|
||||
every { fileDao.getFilesWithSyncInfoSharedByLinkAsFlow(OC_ACCOUNT_NAME) } returns flowOf(emptyList())
|
||||
|
||||
val result = ocLocalFileDataSource.getSharedByLinkWithSyncInfoForAccountAsFlow(OC_ACCOUNT_NAME).first()
|
||||
|
||||
assertEquals(emptyList<OCFileWithSyncInfo>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFilesWithSyncInfoSharedByLinkAsFlow(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFilesWithSyncInfoAvailableOfflineFromAccountAsFlow returns a Flow with a list of OCFileWithSyncInfo`() = runTest {
|
||||
val fileAndFileSyncEntityAvailableOffline = OC_FILE_AND_FILE_SYNC.copy(
|
||||
file = OC_FILE_ENTITY.copy(availableOfflineStatus = AvailableOfflineStatus.AVAILABLE_OFFLINE.ordinal).apply {
|
||||
this.id = OC_FILE_ENTITY.id
|
||||
}
|
||||
)
|
||||
|
||||
val fileWithSyncInfoAvailableOffline = OC_FILE_WITH_SYNC_INFO_AND_SPACE.copy(
|
||||
file = OC_FILE.copy(availableOfflineStatus = AvailableOfflineStatus.AVAILABLE_OFFLINE)
|
||||
)
|
||||
|
||||
every {
|
||||
fileDao.getFilesWithSyncInfoAvailableOfflineFromAccountAsFlow(OC_ACCOUNT_NAME)
|
||||
} returns flowOf(listOf(fileAndFileSyncEntityAvailableOffline))
|
||||
|
||||
val result = ocLocalFileDataSource.getFilesWithSyncInfoAvailableOfflineFromAccountAsFlow(OC_ACCOUNT_NAME).first()
|
||||
|
||||
assertEquals(listOf(fileWithSyncInfoAvailableOffline), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFilesWithSyncInfoAvailableOfflineFromAccountAsFlow(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFilesWithSyncInfoAvailableOfflineFromAccountAsFlow returns a Flow with an empty list when DAO returns a Flow with an empty list`() =
|
||||
runTest {
|
||||
every { fileDao.getFilesWithSyncInfoAvailableOfflineFromAccountAsFlow(OC_ACCOUNT_NAME) } returns flowOf(emptyList())
|
||||
|
||||
val result = ocLocalFileDataSource.getFilesWithSyncInfoAvailableOfflineFromAccountAsFlow(OC_ACCOUNT_NAME).first()
|
||||
|
||||
assertEquals(emptyList<OCFileWithSyncInfo>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFilesWithSyncInfoAvailableOfflineFromAccountAsFlow(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFilesAvailableOfflineFromAccount returns a list of OCFile`() {
|
||||
every { fileDao.getFilesAvailableOfflineFromAccount(OC_ACCOUNT_NAME) } returns listOf(OC_FILE_AVAILABLE_OFFLINE_ENTITY)
|
||||
|
||||
val result = ocLocalFileDataSource.getFilesAvailableOfflineFromAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(listOf(OC_FILE_AVAILABLE_OFFLINE), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFilesAvailableOfflineFromAccount(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFilesAvailableOfflineFromAccount returns an empty list when DAO returns an empty list`() {
|
||||
every { fileDao.getFilesAvailableOfflineFromAccount(OC_ACCOUNT_NAME) } returns emptyList()
|
||||
|
||||
val result = ocLocalFileDataSource.getFilesAvailableOfflineFromAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFilesAvailableOfflineFromAccount(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFilesAvailableOfflineFromEveryAccount returns a list of OCFile`() {
|
||||
every { fileDao.getFilesAvailableOfflineFromEveryAccount() } returns listOf(OC_FILE_AVAILABLE_OFFLINE_ENTITY)
|
||||
|
||||
val result = ocLocalFileDataSource.getFilesAvailableOfflineFromEveryAccount()
|
||||
|
||||
assertEquals(listOf(OC_FILE_AVAILABLE_OFFLINE), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFilesAvailableOfflineFromEveryAccount() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFilesAvailableOfflineFromEveryAccount returns an empty list when DAO returns an empty list`() {
|
||||
every { fileDao.getFilesAvailableOfflineFromEveryAccount() } returns emptyList()
|
||||
|
||||
val result = ocLocalFileDataSource.getFilesAvailableOfflineFromEveryAccount()
|
||||
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFilesAvailableOfflineFromEveryAccount() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFilesLastUsageIsOlderThanGivenTime returns a list of OCFile`() {
|
||||
every { fileDao.getFilesWithLastUsageOlderThanGivenTime(timeInMilliseconds) } returns listOf(OC_FILE_ENTITY)
|
||||
|
||||
val result = ocLocalFileDataSource.getFilesWithLastUsageOlderThanGivenTime(timeInMilliseconds)
|
||||
|
||||
assertEquals(listOf(OC_FILE), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFilesWithLastUsageOlderThanGivenTime(timeInMilliseconds) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFilesLastUsageIsOlderThanGivenTime returns an empty list when DAO returns an empty list`() {
|
||||
every { fileDao.getFilesWithLastUsageOlderThanGivenTime(timeInMilliseconds) } returns emptyList()
|
||||
|
||||
val result = ocLocalFileDataSource.getFilesWithLastUsageOlderThanGivenTime(timeInMilliseconds)
|
||||
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.getFilesWithLastUsageOlderThanGivenTime(timeInMilliseconds) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `moveFile moves a file correctly`() {
|
||||
val finalRemotePath = "/final/remote/path"
|
||||
val finalStoragePath = "/final/storage/path"
|
||||
|
||||
ocLocalFileDataSource.moveFile(OC_FILE, OC_FOLDER, finalRemotePath, finalStoragePath)
|
||||
|
||||
verify(exactly = 1) { fileDao.moveFile(OC_FILE_ENTITY, OC_FOLDER_ENTITY, finalRemotePath, finalStoragePath) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `copyFile copies a file correctly`() {
|
||||
val finalRemotePath = "/final/remote/path"
|
||||
val remoteId = "testRemoteId"
|
||||
|
||||
ocLocalFileDataSource.copyFile(OC_FILE, OC_FOLDER, finalRemotePath, remoteId, false)
|
||||
|
||||
verify(exactly = 1) { fileDao.copy(OC_FILE_ENTITY, OC_FOLDER_ENTITY, finalRemotePath, remoteId, false) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveFilesInFolderAndReturnTheFilesThatChanged saves a list of OCFile and returns only the changed files`() {
|
||||
every { fileDao.insertFilesInFolderAndReturnTheFilesThatChanged(OC_FOLDER_ENTITY, listOf(OC_FILE_ENTITY)) } returns listOf(OC_FILE_ENTITY)
|
||||
|
||||
val result = ocLocalFileDataSource.saveFilesInFolderAndReturnTheFilesThatChanged(listOf(OC_FILE), OC_FOLDER)
|
||||
|
||||
assertEquals(listOf(OC_FILE), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.insertFilesInFolderAndReturnTheFilesThatChanged(OC_FOLDER_ENTITY, listOf(OC_FILE_ENTITY)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveFilesInFolderAndReturnTheFilesThatChanged returns an empty list when DAO returns an empty list`() {
|
||||
every { fileDao.insertFilesInFolderAndReturnTheFilesThatChanged(OC_FOLDER_ENTITY, emptyList()) } returns emptyList()
|
||||
|
||||
val result = ocLocalFileDataSource.saveFilesInFolderAndReturnTheFilesThatChanged(emptyList(), OC_FOLDER)
|
||||
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) { fileDao.insertFilesInFolderAndReturnTheFilesThatChanged(OC_FOLDER_ENTITY, emptyList()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveFile saves a file correctly`() {
|
||||
ocLocalFileDataSource.saveFile(OC_FILE)
|
||||
|
||||
verify(exactly = 1) { fileDao.upsert(OC_FILE_ENTITY) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveConflict saves the etagInConflict related to a file correctly`() {
|
||||
val etagInConflict = "error"
|
||||
|
||||
ocLocalFileDataSource.saveConflict(OC_FILE_ENTITY.id, etagInConflict)
|
||||
|
||||
verify(exactly = 1) { fileDao.updateConflictStatusForFile(OC_FILE_ENTITY.id, etagInConflict) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `cleanConflict saves a null etagInConflict related to a file correctly`() {
|
||||
ocLocalFileDataSource.cleanConflict(OC_FILE_ENTITY.id)
|
||||
|
||||
verify(exactly = 1) { fileDao.updateConflictStatusForFile(OC_FILE_ENTITY.id, null) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteFile removes a file correctly`() {
|
||||
ocLocalFileDataSource.deleteFile(OC_FILE_ENTITY.id)
|
||||
|
||||
verify(exactly = 1) { fileDao.deleteFileById(OC_FILE_ENTITY.id) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteFilesForAccount removes files for an account correctly`() {
|
||||
ocLocalFileDataSource.deleteFilesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) { fileDao.deleteFilesForAccount(OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `renameFile performs a move in the file to change its name`() {
|
||||
every { fileDao.getFileById(OC_FILE.parentId!!) } returns OC_FOLDER_ENTITY
|
||||
|
||||
val finalRemotePath = "/final/remote/path"
|
||||
val finalStoragePath = "/final/storage/path"
|
||||
|
||||
ocLocalFileDataSource.renameFile(OC_FILE, finalRemotePath, finalStoragePath)
|
||||
|
||||
verify(exactly = 1) {
|
||||
fileDao.getFileById(OC_FILE.parentId!!)
|
||||
fileDao.moveFile(OC_FILE_ENTITY, OC_FOLDER_ENTITY, finalRemotePath, finalStoragePath)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `disableThumbnailsForFile disables thumbnails for a file correctly`() {
|
||||
ocLocalFileDataSource.disableThumbnailsForFile(OC_FILE_ENTITY.id)
|
||||
|
||||
verify(exactly = 1) { fileDao.disableThumbnailsForFile(OC_FILE_ENTITY.id) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateAvailableOfflineStatusForFile updates available offline status for a file correctly`() {
|
||||
ocLocalFileDataSource.updateAvailableOfflineStatusForFile(OC_FILE, AvailableOfflineStatus.AVAILABLE_OFFLINE)
|
||||
|
||||
verify(exactly = 1) { fileDao.updateAvailableOfflineStatusForFile(OC_FILE, AvailableOfflineStatus.AVAILABLE_OFFLINE.ordinal) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateDownloadedFilesStorageDirectoryInStoragePath updates storage path for downloaded files correctly`() {
|
||||
val oldDirectory = "/old/directory"
|
||||
val newDirectory = "/new/directory"
|
||||
|
||||
ocLocalFileDataSource.updateDownloadedFilesStorageDirectoryInStoragePath(oldDirectory, newDirectory)
|
||||
|
||||
verify(exactly = 1) { fileDao.updateDownloadedFilesStorageDirectoryInStoragePath(oldDirectory, newDirectory) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateFileWithLastUsage updates last usage for a file correctly`() {
|
||||
val lastUsage = 12345L
|
||||
|
||||
ocLocalFileDataSource.updateFileWithLastUsage(OC_FILE_ENTITY.id, lastUsage)
|
||||
|
||||
verify(exactly = 1) { fileDao.updateFileWithLastUsage(OC_FILE_ENTITY.id, lastUsage) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveDownloadWorkerUuid saves the worker UUID for a file correctly`() {
|
||||
val workerUuid = UUID.randomUUID()
|
||||
|
||||
ocLocalFileDataSource.saveDownloadWorkerUuid(OC_FILE_ENTITY.id, workerUuid)
|
||||
|
||||
verify(exactly = 1) { fileDao.updateSyncStatusForFile(OC_FILE_ENTITY.id, workerUuid) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `cleanWorkersUuid saves a null worker UUID for a file correctly`() {
|
||||
ocLocalFileDataSource.cleanWorkersUuid(OC_FILE_ENTITY.id)
|
||||
|
||||
verify(exactly = 1) { fileDao.updateSyncStatusForFile(OC_FILE_ENTITY.id, null) }
|
||||
}
|
||||
}
|
||||
+405
@@ -0,0 +1,405 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* @author Aitor Ballesteros Pavón
|
||||
* @author Juan Carlos Garrote Gascón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.files.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.ClientManager
|
||||
import eu.qsfera.android.data.files.datasources.implementation.OCRemoteFileDataSource.Companion.toModel
|
||||
import eu.qsfera.android.domain.files.model.OCFile
|
||||
import eu.qsfera.android.lib.resources.files.RemoteFile
|
||||
import eu.qsfera.android.lib.resources.files.services.implementation.OCFileService
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_FILE
|
||||
import eu.qsfera.android.testutil.OC_FOLDER
|
||||
import eu.qsfera.android.testutil.REMOTE_FILE
|
||||
import eu.qsfera.android.testutil.REMOTE_META_FILE
|
||||
import eu.qsfera.android.utils.createRemoteOperationResultMock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteFileDataSourceTest {
|
||||
|
||||
private lateinit var ocRemoteFileDataSource: OCRemoteFileDataSource
|
||||
|
||||
private val ocFileService: OCFileService = mockk()
|
||||
private val clientManager: ClientManager = mockk(relaxed = true)
|
||||
|
||||
private val sourceRemotePath = "/source/remote/path/file.txt"
|
||||
private val targetRemotePath = "/target/remote/path/file.txt"
|
||||
|
||||
private val remoteResult = createRemoteOperationResultMock(data = Unit, isSuccess = true)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
every { clientManager.getFileService(OC_ACCOUNT_NAME) } returns ocFileService
|
||||
|
||||
ocRemoteFileDataSource = OCRemoteFileDataSource(clientManager)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `checkPathExistence returns true when the path exists in remote`() {
|
||||
val checkPathExistenceRemoteResult = createRemoteOperationResultMock(data = true, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocFileService.checkPathExistence(sourceRemotePath, true)
|
||||
} returns checkPathExistenceRemoteResult
|
||||
|
||||
val checkPathExistence = ocRemoteFileDataSource.checkPathExistence(sourceRemotePath, true, OC_ACCOUNT_NAME, null)
|
||||
|
||||
assertTrue(checkPathExistence)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.checkPathExistence(sourceRemotePath, true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `checkPathExistence returns false when the path does not exist in remote`() {
|
||||
val checkPathExistenceRemoteResult = createRemoteOperationResultMock(data = false, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocFileService.checkPathExistence(sourceRemotePath, true)
|
||||
} returns checkPathExistenceRemoteResult
|
||||
|
||||
val checkPathExistence = ocRemoteFileDataSource.checkPathExistence(sourceRemotePath, true, OC_ACCOUNT_NAME, null)
|
||||
|
||||
assertFalse(checkPathExistence)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.checkPathExistence(sourceRemotePath, true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `copyFile copies a file and returns a fileRemoteId`() {
|
||||
val fileRemoteId = "fileRemoteId"
|
||||
|
||||
val remoteResult = createRemoteOperationResultMock(data = fileRemoteId as String?, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocFileService.copyFile(
|
||||
sourceRemotePath = sourceRemotePath,
|
||||
targetRemotePath = targetRemotePath,
|
||||
sourceSpaceWebDavUrl = null,
|
||||
targetSpaceWebDavUrl = null,
|
||||
replace = any(),
|
||||
)
|
||||
} returns remoteResult
|
||||
|
||||
val result = ocRemoteFileDataSource.copyFile(
|
||||
sourceRemotePath,
|
||||
targetRemotePath,
|
||||
OC_ACCOUNT_NAME,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
)
|
||||
|
||||
assertEquals(fileRemoteId, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.copyFile(
|
||||
sourceRemotePath = sourceRemotePath,
|
||||
targetRemotePath = targetRemotePath,
|
||||
sourceSpaceWebDavUrl = null,
|
||||
targetSpaceWebDavUrl = null,
|
||||
replace = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `createFolder creates folder in remote correctly`() {
|
||||
every {
|
||||
ocFileService.createFolder(remotePath = sourceRemotePath, createFullPath = false)
|
||||
} returns remoteResult
|
||||
|
||||
ocRemoteFileDataSource.createFolder(
|
||||
remotePath = sourceRemotePath,
|
||||
createFullPath = false,
|
||||
isChunksFolder = false,
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
spaceWebDavUrl = null
|
||||
)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.createFolder(sourceRemotePath, false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAvailableRemotePath returns same String path if file does not exist`() {
|
||||
val checkPathExistenceRemoteResult = createRemoteOperationResultMock(data = false, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocFileService.checkPathExistence(sourceRemotePath, true)
|
||||
} returns checkPathExistenceRemoteResult
|
||||
|
||||
val firstCopyName = ocRemoteFileDataSource.getAvailableRemotePath(
|
||||
remotePath = sourceRemotePath,
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
spaceWebDavUrl = null,
|
||||
isUserLogged = true,
|
||||
)
|
||||
|
||||
assertEquals(sourceRemotePath, firstCopyName)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.checkPathExistence(sourceRemotePath, true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAvailableRemotePath returns String path with (1) if file already exists`() {
|
||||
val checkPathExistenceRemoteResultFirst = createRemoteOperationResultMock(data = true, isSuccess = true)
|
||||
val checkPathExistenceRemoteResultSecond = createRemoteOperationResultMock(data = false, isSuccess = true)
|
||||
val finalRemotePath = "/source/remote/path/file (1).txt"
|
||||
|
||||
every {
|
||||
ocFileService.checkPathExistence(sourceRemotePath, true)
|
||||
} returns checkPathExistenceRemoteResultFirst
|
||||
every {
|
||||
ocFileService.checkPathExistence(finalRemotePath, true)
|
||||
} returns checkPathExistenceRemoteResultSecond
|
||||
|
||||
val firstCopyName = ocRemoteFileDataSource.getAvailableRemotePath(
|
||||
remotePath = sourceRemotePath,
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
spaceWebDavUrl = null,
|
||||
isUserLogged = true,
|
||||
)
|
||||
|
||||
assertEquals(finalRemotePath, firstCopyName)
|
||||
|
||||
verify(exactly = 2) { clientManager.getFileService(OC_ACCOUNT_NAME) }
|
||||
verify(exactly = 1) {
|
||||
ocFileService.checkPathExistence(sourceRemotePath, true)
|
||||
ocFileService.checkPathExistence(finalRemotePath, true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAvailableRemotePath returns String path with two (1) if file with (1) already exists`() {
|
||||
val checkPathExistenceRemoteResultFirst = createRemoteOperationResultMock(data = true, isSuccess = true)
|
||||
val checkPathExistenceRemoteResultSecond = createRemoteOperationResultMock(data = false, isSuccess = true)
|
||||
val remotePath = "/remote/path/file (1).txt"
|
||||
val finalRemotePath = "/remote/path/file (1) (1).txt"
|
||||
|
||||
every {
|
||||
ocFileService.checkPathExistence(remotePath, true)
|
||||
} returns checkPathExistenceRemoteResultFirst
|
||||
every {
|
||||
ocFileService.checkPathExistence(finalRemotePath, true)
|
||||
} returns checkPathExistenceRemoteResultSecond
|
||||
|
||||
val firstCopyName = ocRemoteFileDataSource.getAvailableRemotePath(
|
||||
remotePath = remotePath,
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
spaceWebDavUrl = null,
|
||||
isUserLogged = true,
|
||||
)
|
||||
|
||||
assertEquals(finalRemotePath, firstCopyName)
|
||||
|
||||
verify(exactly = 2) { clientManager.getFileService(OC_ACCOUNT_NAME) }
|
||||
verify(exactly = 1) {
|
||||
ocFileService.checkPathExistence(remotePath, true)
|
||||
ocFileService.checkPathExistence(finalRemotePath, true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `moveFile moves a file correctly`() {
|
||||
every {
|
||||
ocFileService.moveFile(
|
||||
sourceRemotePath = sourceRemotePath,
|
||||
targetRemotePath = targetRemotePath,
|
||||
spaceWebDavUrl = null,
|
||||
replace = any(),
|
||||
)
|
||||
} returns remoteResult
|
||||
|
||||
ocRemoteFileDataSource.moveFile(
|
||||
sourceRemotePath,
|
||||
targetRemotePath,
|
||||
OC_ACCOUNT_NAME,
|
||||
null,
|
||||
true,
|
||||
)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.moveFile(
|
||||
sourceRemotePath = sourceRemotePath,
|
||||
targetRemotePath = targetRemotePath,
|
||||
spaceWebDavUrl = null,
|
||||
replace = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `readFile returns a OCFile`() {
|
||||
val remoteResult = createRemoteOperationResultMock(data = REMOTE_FILE, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocFileService.readFile(
|
||||
remotePath = REMOTE_FILE.remotePath,
|
||||
spaceWebDavUrl = null
|
||||
)
|
||||
} returns remoteResult
|
||||
|
||||
val result = ocRemoteFileDataSource.readFile(
|
||||
REMOTE_FILE.remotePath,
|
||||
OC_ACCOUNT_NAME,
|
||||
null,
|
||||
)
|
||||
|
||||
assertEquals(REMOTE_FILE.toModel(), result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.readFile(
|
||||
REMOTE_FILE.remotePath,
|
||||
null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refreshFolder returns a list of OCFile`() {
|
||||
val remoteResult = createRemoteOperationResultMock(data = arrayListOf(REMOTE_FILE), isSuccess = true)
|
||||
|
||||
every {
|
||||
ocFileService.refreshFolder(OC_FOLDER.remotePath, null)
|
||||
} returns remoteResult
|
||||
|
||||
val result = ocRemoteFileDataSource.refreshFolder(
|
||||
OC_FOLDER.remotePath,
|
||||
OC_ACCOUNT_NAME,
|
||||
null,
|
||||
)
|
||||
assertEquals(arrayListOf(REMOTE_FILE.toModel()), result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.refreshFolder(OC_FOLDER.remotePath, null)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refreshFolder returns an empty list if service returns an empty list`() {
|
||||
val remoteResult = createRemoteOperationResultMock(data = arrayListOf<RemoteFile>(), isSuccess = true)
|
||||
|
||||
every {
|
||||
ocFileService.refreshFolder(OC_FOLDER.remotePath, null)
|
||||
} returns remoteResult
|
||||
|
||||
val result = ocRemoteFileDataSource.refreshFolder(
|
||||
OC_FOLDER.remotePath,
|
||||
OC_ACCOUNT_NAME,
|
||||
null,
|
||||
)
|
||||
assertEquals(emptyList<OCFile>(), result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.refreshFolder(OC_FOLDER.remotePath, null)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteFile deletes a file correctly`() {
|
||||
every {
|
||||
ocFileService.removeFile(OC_FILE.remotePath, null)
|
||||
} returns remoteResult
|
||||
|
||||
ocRemoteFileDataSource.deleteFile(
|
||||
OC_FILE.remotePath,
|
||||
OC_ACCOUNT_NAME,
|
||||
null,
|
||||
)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.removeFile(OC_FILE.remotePath, null)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `renameFile renames a file correctly`() {
|
||||
val oldName = "oldName"
|
||||
val oldRemotePath = "/old/remote/path"
|
||||
val newName = "newName"
|
||||
|
||||
every {
|
||||
ocFileService.renameFile(oldName, oldRemotePath, newName, false, null)
|
||||
} returns remoteResult
|
||||
|
||||
ocRemoteFileDataSource.renameFile(
|
||||
oldName,
|
||||
oldRemotePath,
|
||||
newName,
|
||||
false,
|
||||
OC_ACCOUNT_NAME,
|
||||
null)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.renameFile(oldName, oldRemotePath, newName, false, null)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getMetaFile returns a OCMetaFile`() {
|
||||
val remoteResult = createRemoteOperationResultMock(data = REMOTE_META_FILE, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocFileService.getMetaFileInfo(
|
||||
fileId = OC_FILE.remoteId!!,
|
||||
)
|
||||
} returns remoteResult
|
||||
|
||||
val result = ocRemoteFileDataSource.getMetaFile(
|
||||
OC_FILE.remoteId!!,
|
||||
OC_ACCOUNT_NAME,
|
||||
)
|
||||
|
||||
assertEquals(REMOTE_META_FILE.toModel(), result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getFileService(OC_ACCOUNT_NAME)
|
||||
ocFileService.getMetaFileInfo(OC_FILE.remoteId!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
+2071
File diff suppressed because it is too large
Load Diff
+113
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.folderbackup.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.folderbackup.datasources.implementation.OCLocalFolderBackupDataSource.Companion.toModel
|
||||
import eu.qsfera.android.data.folderbackup.db.FolderBackupDao
|
||||
import eu.qsfera.android.domain.automaticuploads.model.FolderBackUpConfiguration
|
||||
import eu.qsfera.android.testutil.OC_BACKUP
|
||||
import eu.qsfera.android.testutil.OC_BACKUP_ENTITY
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCLocalFolderBackupDataSourceTest {
|
||||
|
||||
private lateinit var ocLocalFolderBackupDataSource: OCLocalFolderBackupDataSource
|
||||
private val folderBackupDao = mockk<FolderBackupDao>(relaxed = true)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
ocLocalFolderBackupDataSource = OCLocalFolderBackupDataSource(folderBackupDao)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAutomaticUploadsConfiguration returns an AutomaticUploadsConfiguration when having valid configurations`() {
|
||||
every { folderBackupDao.getFolderBackUpConfigurationByName(FolderBackUpConfiguration.pictureUploadsName) } returns OC_BACKUP_ENTITY
|
||||
every { folderBackupDao.getFolderBackUpConfigurationByName(FolderBackUpConfiguration.videoUploadsName) } returns OC_BACKUP_ENTITY
|
||||
|
||||
val resultCurrent = ocLocalFolderBackupDataSource.getAutomaticUploadsConfiguration()
|
||||
|
||||
assertEquals(OC_BACKUP_ENTITY.toModel(), resultCurrent?.pictureUploadsConfiguration)
|
||||
assertEquals(OC_BACKUP_ENTITY.toModel(), resultCurrent?.videoUploadsConfiguration)
|
||||
|
||||
verify(exactly = 1) {
|
||||
folderBackupDao.getFolderBackUpConfigurationByName(FolderBackUpConfiguration.pictureUploadsName)
|
||||
folderBackupDao.getFolderBackUpConfigurationByName(FolderBackUpConfiguration.videoUploadsName)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAutomaticUploadsConfiguration returns null when there are not configurations`() {
|
||||
every { folderBackupDao.getFolderBackUpConfigurationByName(FolderBackUpConfiguration.pictureUploadsName) } returns null
|
||||
every { folderBackupDao.getFolderBackUpConfigurationByName(FolderBackUpConfiguration.videoUploadsName) } returns null
|
||||
|
||||
val resultCurrent = ocLocalFolderBackupDataSource.getAutomaticUploadsConfiguration()
|
||||
|
||||
assertNull(resultCurrent)
|
||||
|
||||
verify(exactly = 1) {
|
||||
folderBackupDao.getFolderBackUpConfigurationByName(FolderBackUpConfiguration.pictureUploadsName)
|
||||
folderBackupDao.getFolderBackUpConfigurationByName(FolderBackUpConfiguration.videoUploadsName)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFolderBackupConfigurationByNameAsFlow returns a Flow of AutomaticUploadsConfiguration when having valid configurations`() = runBlocking {
|
||||
every { folderBackupDao.getFolderBackUpConfigurationByNameAsFlow(FolderBackUpConfiguration.pictureUploadsName) } returns flowOf(
|
||||
OC_BACKUP_ENTITY
|
||||
)
|
||||
|
||||
val resultCurrent = ocLocalFolderBackupDataSource.getFolderBackupConfigurationByNameAsFlow(FolderBackUpConfiguration.pictureUploadsName)
|
||||
|
||||
val result = resultCurrent.first()
|
||||
assertEquals(OC_BACKUP_ENTITY.toModel(), result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
folderBackupDao.getFolderBackUpConfigurationByNameAsFlow(FolderBackUpConfiguration.pictureUploadsName)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveFolderBackupConfiguration saves valid configurations correctly`() {
|
||||
ocLocalFolderBackupDataSource.saveFolderBackupConfiguration(OC_BACKUP)
|
||||
|
||||
verify(exactly = 1) {
|
||||
folderBackupDao.update(OC_BACKUP_ENTITY)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `resetFolderBackupConfigurationByName removes current folder backup configuration correctly`() {
|
||||
ocLocalFolderBackupDataSource.resetFolderBackupConfigurationByName(FolderBackUpConfiguration.pictureUploadsName)
|
||||
|
||||
verify(exactly = 1) {
|
||||
folderBackupDao.delete(FolderBackUpConfiguration.pictureUploadsName)
|
||||
}
|
||||
}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Jorge Aguado Recio
|
||||
*
|
||||
* Copyright (C) 2024 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.folderbackup.repository
|
||||
|
||||
import eu.qsfera.android.data.folderbackup.datasources.LocalFolderBackupDataSource
|
||||
import eu.qsfera.android.testutil.OC_AUTOMATIC_UPLOADS_CONFIGURATION
|
||||
import eu.qsfera.android.testutil.OC_BACKUP
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Test
|
||||
|
||||
class OCFolderBackupRepositoryTest {
|
||||
|
||||
private val localFolderBackupDataSource = mockk<LocalFolderBackupDataSource>(relaxUnitFun = true)
|
||||
private val ocFolderBackupRepository = OCFolderBackupRepository(localFolderBackupDataSource)
|
||||
|
||||
@Test
|
||||
fun `getAutomaticUploadsConfiguration returns an AutomaticUploadsConfiguration`() {
|
||||
every {
|
||||
localFolderBackupDataSource.getAutomaticUploadsConfiguration()
|
||||
} returns OC_AUTOMATIC_UPLOADS_CONFIGURATION
|
||||
|
||||
val automaticUploadsConfiguration = ocFolderBackupRepository.getAutomaticUploadsConfiguration()
|
||||
assertEquals(OC_AUTOMATIC_UPLOADS_CONFIGURATION, automaticUploadsConfiguration)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localFolderBackupDataSource.getAutomaticUploadsConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAutomaticUploadsConfiguration returns null when local datasource returns a null configuration`() {
|
||||
every {
|
||||
localFolderBackupDataSource.getAutomaticUploadsConfiguration()
|
||||
} returns null
|
||||
|
||||
val automaticUploadsConfiguration = ocFolderBackupRepository.getAutomaticUploadsConfiguration()
|
||||
assertNull(automaticUploadsConfiguration)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localFolderBackupDataSource.getAutomaticUploadsConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFolderBackupConfigurationByNameAsFlow returns a Flow with a FolderBackUpConfiguration`() = runTest {
|
||||
every {
|
||||
localFolderBackupDataSource.getFolderBackupConfigurationByNameAsFlow(OC_BACKUP.name)
|
||||
} returns flowOf(OC_BACKUP)
|
||||
|
||||
val folderBackUpConfiguration = ocFolderBackupRepository.getFolderBackupConfigurationByNameAsFlow(OC_BACKUP.name).first()
|
||||
assertEquals(OC_BACKUP, folderBackUpConfiguration)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localFolderBackupDataSource.getFolderBackupConfigurationByNameAsFlow(OC_BACKUP.name)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFolderBackupConfigurationByNameAsFlow returns a Flow with null when local datasource returns a Flow with null `() = runTest {
|
||||
every {
|
||||
localFolderBackupDataSource.getFolderBackupConfigurationByNameAsFlow(OC_BACKUP.name)
|
||||
} returns flowOf(null)
|
||||
|
||||
val folderBackUpConfiguration = ocFolderBackupRepository.getFolderBackupConfigurationByNameAsFlow(OC_BACKUP.name).first()
|
||||
assertNull(folderBackUpConfiguration)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localFolderBackupDataSource.getFolderBackupConfigurationByNameAsFlow(OC_BACKUP.name)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveFolderBackupConfiguration saves a folder backup configuration correctly`() {
|
||||
ocFolderBackupRepository.saveFolderBackupConfiguration(OC_BACKUP)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localFolderBackupDataSource.saveFolderBackupConfiguration(OC_BACKUP)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `resetFolderBackupConfigurationByName resets a folder backup configuration by name correctly`() {
|
||||
ocFolderBackupRepository.resetFolderBackupConfigurationByName(OC_BACKUP.name)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localFolderBackupDataSource.resetFolderBackupConfigurationByName(OC_BACKUP.name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* Copyright (C) 2021 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package eu.qsfera.android.data.oauth
|
||||
|
||||
import eu.qsfera.android.lib.resources.oauth.params.ClientRegistrationParams
|
||||
import eu.qsfera.android.lib.resources.oauth.params.TokenRequestParams
|
||||
import eu.qsfera.android.lib.resources.oauth.responses.ClientRegistrationResponse
|
||||
import eu.qsfera.android.lib.resources.oauth.responses.OIDCDiscoveryResponse
|
||||
import eu.qsfera.android.lib.resources.oauth.responses.TokenResponse
|
||||
import eu.qsfera.android.testutil.oauth.OC_CLIENT_REGISTRATION
|
||||
import eu.qsfera.android.testutil.oauth.OC_CLIENT_REGISTRATION_REQUEST
|
||||
import eu.qsfera.android.testutil.oauth.OC_OIDC_SERVER_CONFIGURATION
|
||||
import eu.qsfera.android.testutil.oauth.OC_TOKEN_REQUEST_ACCESS
|
||||
import eu.qsfera.android.testutil.oauth.OC_TOKEN_REQUEST_REFRESH
|
||||
import eu.qsfera.android.testutil.oauth.OC_TOKEN_RESPONSE
|
||||
|
||||
val OC_REMOTE_OIDC_DISCOVERY_RESPONSE = OIDCDiscoveryResponse(
|
||||
authorizationEndpoint = OC_OIDC_SERVER_CONFIGURATION.authorizationEndpoint,
|
||||
checkSessionIframe = OC_OIDC_SERVER_CONFIGURATION.checkSessionIframe,
|
||||
endSessionEndpoint = OC_OIDC_SERVER_CONFIGURATION.endSessionEndpoint,
|
||||
issuer = OC_OIDC_SERVER_CONFIGURATION.issuer,
|
||||
registrationEndpoint = OC_OIDC_SERVER_CONFIGURATION.registrationEndpoint,
|
||||
responseTypesSupported = OC_OIDC_SERVER_CONFIGURATION.responseTypesSupported,
|
||||
scopesSupported = OC_OIDC_SERVER_CONFIGURATION.scopesSupported,
|
||||
tokenEndpoint = OC_OIDC_SERVER_CONFIGURATION.tokenEndpoint,
|
||||
tokenEndpointAuthMethodsSupported = OC_OIDC_SERVER_CONFIGURATION.tokenEndpointAuthMethodsSupported,
|
||||
userinfoEndpoint = OC_OIDC_SERVER_CONFIGURATION.userInfoEndpoint
|
||||
)
|
||||
|
||||
val OC_REMOTE_TOKEN_REQUEST_PARAMS_ACCESS = TokenRequestParams.Authorization(
|
||||
tokenEndpoint = OC_TOKEN_REQUEST_ACCESS.tokenEndpoint,
|
||||
clientAuth = OC_TOKEN_REQUEST_ACCESS.clientAuth,
|
||||
grantType = OC_TOKEN_REQUEST_ACCESS.grantType,
|
||||
scope = OC_TOKEN_REQUEST_ACCESS.scope,
|
||||
clientId = null,
|
||||
clientSecret = null,
|
||||
authorizationCode = OC_TOKEN_REQUEST_ACCESS.authorizationCode,
|
||||
redirectUri = OC_TOKEN_REQUEST_ACCESS.redirectUri,
|
||||
codeVerifier = OC_TOKEN_REQUEST_ACCESS.codeVerifier
|
||||
)
|
||||
|
||||
val OC_REMOTE_TOKEN_REQUEST_PARAMS_REFRESH = TokenRequestParams.RefreshToken(
|
||||
tokenEndpoint = OC_TOKEN_REQUEST_REFRESH.tokenEndpoint,
|
||||
clientAuth = OC_TOKEN_REQUEST_REFRESH.clientAuth,
|
||||
grantType = OC_TOKEN_REQUEST_REFRESH.grantType,
|
||||
scope = OC_TOKEN_REQUEST_REFRESH.scope,
|
||||
clientId = null,
|
||||
clientSecret = null,
|
||||
refreshToken = OC_TOKEN_REQUEST_REFRESH.refreshToken
|
||||
)
|
||||
|
||||
val OC_REMOTE_TOKEN_RESPONSE = TokenResponse(
|
||||
accessToken = OC_TOKEN_RESPONSE.accessToken,
|
||||
expiresIn = OC_TOKEN_RESPONSE.expiresIn,
|
||||
refreshToken = OC_TOKEN_RESPONSE.refreshToken,
|
||||
tokenType = OC_TOKEN_RESPONSE.tokenType,
|
||||
userId = OC_TOKEN_RESPONSE.userId,
|
||||
scope = OC_TOKEN_RESPONSE.scope,
|
||||
additionalParameters = OC_TOKEN_RESPONSE.additionalParameters
|
||||
)
|
||||
|
||||
val OC_REMOTE_CLIENT_REGISTRATION_PARAMS = ClientRegistrationParams(
|
||||
registrationEndpoint = OC_CLIENT_REGISTRATION_REQUEST.registrationEndpoint,
|
||||
clientName = OC_CLIENT_REGISTRATION_REQUEST.clientName,
|
||||
redirectUris = OC_CLIENT_REGISTRATION_REQUEST.redirectUris,
|
||||
tokenEndpointAuthMethod = OC_CLIENT_REGISTRATION_REQUEST.tokenEndpointAuthMethod,
|
||||
applicationType = OC_CLIENT_REGISTRATION_REQUEST.applicationType
|
||||
)
|
||||
|
||||
val OC_REMOTE_CLIENT_REGISTRATION_RESPONSE = ClientRegistrationResponse(
|
||||
clientId = OC_CLIENT_REGISTRATION.clientId,
|
||||
clientSecret = OC_CLIENT_REGISTRATION.clientSecret,
|
||||
clientIdIssuedAt = OC_CLIENT_REGISTRATION.clientIdIssuedAt,
|
||||
clientSecretExpiration = OC_CLIENT_REGISTRATION.clientSecretExpiration
|
||||
)
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* Copyright (C) 2021 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.oauth.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.ClientManager
|
||||
import eu.qsfera.android.data.oauth.OC_REMOTE_CLIENT_REGISTRATION_RESPONSE
|
||||
import eu.qsfera.android.data.oauth.OC_REMOTE_OIDC_DISCOVERY_RESPONSE
|
||||
import eu.qsfera.android.data.oauth.OC_REMOTE_TOKEN_RESPONSE
|
||||
import eu.qsfera.android.lib.common.QSferaClient
|
||||
import eu.qsfera.android.lib.common.operations.RemoteOperationResult
|
||||
import eu.qsfera.android.lib.resources.oauth.responses.ClientRegistrationResponse
|
||||
import eu.qsfera.android.lib.resources.oauth.responses.OIDCDiscoveryResponse
|
||||
import eu.qsfera.android.lib.resources.oauth.responses.TokenResponse
|
||||
import eu.qsfera.android.lib.resources.oauth.services.OIDCService
|
||||
import eu.qsfera.android.testutil.OC_SECURE_BASE_URL
|
||||
import eu.qsfera.android.testutil.oauth.OC_CLIENT_REGISTRATION
|
||||
import eu.qsfera.android.testutil.oauth.OC_CLIENT_REGISTRATION_REQUEST
|
||||
import eu.qsfera.android.testutil.oauth.OC_OIDC_SERVER_CONFIGURATION
|
||||
import eu.qsfera.android.testutil.oauth.OC_TOKEN_REQUEST_ACCESS
|
||||
import eu.qsfera.android.testutil.oauth.OC_TOKEN_REQUEST_ACCESS_PUBLIC_CLIENT
|
||||
import eu.qsfera.android.testutil.oauth.OC_TOKEN_RESPONSE
|
||||
import eu.qsfera.android.utils.createRemoteOperationResultMock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteOAuthDataSourceTest {
|
||||
private lateinit var remoteOAuthDataSource: OCRemoteOAuthDataSource
|
||||
|
||||
private val clientManager: ClientManager = mockk(relaxed = true)
|
||||
private val ocClientMocked: QSferaClient = mockk()
|
||||
|
||||
private val oidcService: OIDCService = mockk()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
every { clientManager.getClientForAnonymousCredentials(any(), any()) } returns ocClientMocked
|
||||
|
||||
remoteOAuthDataSource = OCRemoteOAuthDataSource(
|
||||
clientManager = clientManager,
|
||||
oidcService = oidcService,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `performOIDCDiscovery returns a OIDCServerConfiguration`() {
|
||||
val oidcDiscoveryResult: RemoteOperationResult<OIDCDiscoveryResponse> =
|
||||
createRemoteOperationResultMock(data = OC_REMOTE_OIDC_DISCOVERY_RESPONSE, isSuccess = true)
|
||||
|
||||
every {
|
||||
oidcService.getOIDCServerDiscovery(ocClientMocked)
|
||||
} returns oidcDiscoveryResult
|
||||
|
||||
val oidcDiscovery = remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_BASE_URL)
|
||||
|
||||
assertNotNull(oidcDiscovery)
|
||||
assertEquals(OC_OIDC_SERVER_CONFIGURATION, oidcDiscovery)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getClientForAnonymousCredentials(OC_SECURE_BASE_URL, false)
|
||||
oidcService.getOIDCServerDiscovery(ocClientMocked)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `performTokenRequest returns a TokenResponse`() {
|
||||
val tokenResponseResult: RemoteOperationResult<TokenResponse> =
|
||||
createRemoteOperationResultMock(data = OC_REMOTE_TOKEN_RESPONSE, isSuccess = true)
|
||||
|
||||
every {
|
||||
oidcService.performTokenRequest(ocClientMocked, any())
|
||||
} returns tokenResponseResult
|
||||
|
||||
val tokenResponse = remoteOAuthDataSource.performTokenRequest(OC_TOKEN_REQUEST_ACCESS)
|
||||
|
||||
assertNotNull(tokenResponse)
|
||||
assertEquals(OC_TOKEN_RESPONSE, tokenResponse)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getClientForAnonymousCredentials(OC_SECURE_BASE_URL, any())
|
||||
oidcService.performTokenRequest(ocClientMocked, any())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for public PKCE clients (RFC 7636).
|
||||
* Public clients MUST NOT send Authorization header during token exchange.
|
||||
* This test verifies that token requests work correctly with empty clientAuth.
|
||||
*/
|
||||
@Test
|
||||
fun `performTokenRequest with public PKCE client returns a TokenResponse`() {
|
||||
val tokenResponseResult: RemoteOperationResult<TokenResponse> =
|
||||
createRemoteOperationResultMock(data = OC_REMOTE_TOKEN_RESPONSE, isSuccess = true)
|
||||
|
||||
every {
|
||||
oidcService.performTokenRequest(ocClientMocked, any())
|
||||
} returns tokenResponseResult
|
||||
|
||||
// Verify the fixture has empty clientAuth for public clients
|
||||
assertTrue(
|
||||
"clientAuth should be empty for public clients",
|
||||
OC_TOKEN_REQUEST_ACCESS_PUBLIC_CLIENT.clientAuth.isEmpty()
|
||||
)
|
||||
|
||||
val tokenResponse = remoteOAuthDataSource.performTokenRequest(OC_TOKEN_REQUEST_ACCESS_PUBLIC_CLIENT)
|
||||
|
||||
assertNotNull(tokenResponse)
|
||||
assertEquals(OC_TOKEN_RESPONSE, tokenResponse)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getClientForAnonymousCredentials(OC_SECURE_BASE_URL, any())
|
||||
oidcService.performTokenRequest(ocClientMocked, any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `registerClient returns a ClientRegistrationInfo`() {
|
||||
val clientRegistrationResponse: RemoteOperationResult<ClientRegistrationResponse> =
|
||||
createRemoteOperationResultMock(data = OC_REMOTE_CLIENT_REGISTRATION_RESPONSE, isSuccess = true)
|
||||
|
||||
every {
|
||||
oidcService.registerClientWithRegistrationEndpoint(ocClientMocked, any())
|
||||
} returns clientRegistrationResponse
|
||||
|
||||
val clientRegistrationInfo = remoteOAuthDataSource.registerClient(OC_CLIENT_REGISTRATION_REQUEST)
|
||||
|
||||
assertNotNull(clientRegistrationInfo)
|
||||
assertEquals(OC_CLIENT_REGISTRATION, clientRegistrationInfo)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getClientForAnonymousCredentials(OC_CLIENT_REGISTRATION_REQUEST.registrationEndpoint, false)
|
||||
oidcService.registerClientWithRegistrationEndpoint(ocClientMocked, any())
|
||||
}
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* @author Juan Carlos Garrote Gascón
|
||||
* @author Jorge Aguado Recio
|
||||
*
|
||||
* Copyright (C) 2024 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.oauth.repository
|
||||
|
||||
import eu.qsfera.android.data.oauth.datasources.RemoteOAuthDataSource
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_OIDC_AUTH
|
||||
import eu.qsfera.android.testutil.oauth.OC_CLIENT_REGISTRATION
|
||||
import eu.qsfera.android.testutil.oauth.OC_CLIENT_REGISTRATION_REQUEST
|
||||
import eu.qsfera.android.testutil.oauth.OC_OIDC_SERVER_CONFIGURATION
|
||||
import eu.qsfera.android.testutil.oauth.OC_TOKEN_REQUEST_ACCESS
|
||||
import eu.qsfera.android.testutil.oauth.OC_TOKEN_RESPONSE
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class OCOAuthRepositoryTest {
|
||||
|
||||
private val remoteOAuthDataSource = mockk<RemoteOAuthDataSource>()
|
||||
private val oAuthRepository = OCOAuthRepository(remoteOAuthDataSource)
|
||||
|
||||
@Test
|
||||
fun `performOIDCDiscovery returns an OIDCServerConfiguration`() {
|
||||
every {
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl)
|
||||
} returns OC_OIDC_SERVER_CONFIGURATION
|
||||
|
||||
val oidcServerConfiguration = oAuthRepository.performOIDCDiscovery(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl)
|
||||
assertEquals(OC_OIDC_SERVER_CONFIGURATION, oidcServerConfiguration)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `performTokenRequest returns a TokenResponse`() {
|
||||
every {
|
||||
remoteOAuthDataSource.performTokenRequest(OC_TOKEN_REQUEST_ACCESS)
|
||||
} returns OC_TOKEN_RESPONSE
|
||||
|
||||
val tokenResponse = oAuthRepository.performTokenRequest(OC_TOKEN_REQUEST_ACCESS)
|
||||
assertEquals(OC_TOKEN_RESPONSE, tokenResponse)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteOAuthDataSource.performTokenRequest(OC_TOKEN_REQUEST_ACCESS)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `registerClient returns a ClientRegistrationInfo`() {
|
||||
every {
|
||||
remoteOAuthDataSource.registerClient(OC_CLIENT_REGISTRATION_REQUEST)
|
||||
} returns OC_CLIENT_REGISTRATION
|
||||
|
||||
val clientRegistrationInfo = oAuthRepository.registerClient(OC_CLIENT_REGISTRATION_REQUEST)
|
||||
assertEquals(OC_CLIENT_REGISTRATION, clientRegistrationInfo)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteOAuthDataSource.registerClient(OC_CLIENT_REGISTRATION_REQUEST)
|
||||
}
|
||||
}
|
||||
}
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
package eu.qsfera.android.data.providers
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import eu.qsfera.android.domain.transfers.model.OCTransfer
|
||||
import eu.qsfera.android.testutil.OC_FILE
|
||||
import eu.qsfera.android.testutil.OC_SPACE_PROJECT_WITH_IMAGE
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
class ScopedStorageProviderTest {
|
||||
private lateinit var scopedStorageProvider: ScopedStorageProvider
|
||||
|
||||
private lateinit var context: Context
|
||||
private lateinit var filesDir: File
|
||||
|
||||
private val spaceId = OC_SPACE_PROJECT_WITH_IMAGE.id
|
||||
private val accountName = "qsfera"
|
||||
private val newName = "qsferaNewName.txt"
|
||||
private val uriEncoded = "/path/to/remote/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B"
|
||||
private val rootFolderName = "root_folder"
|
||||
private val expectedSizeOfDirectoryValue: Long = 100
|
||||
private val separator = File.separator
|
||||
private val remotePath =
|
||||
listOf("storage", "emulated", "0", "qsfera", "remotepath").joinToString(separator, prefix = separator)
|
||||
private val rootFolderPath get() = filesDir.absolutePath + File.separator + rootFolderName
|
||||
private lateinit var directory: File
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
context = mockk()
|
||||
filesDir = Files.createTempDirectory("scoped-storage-provider").toFile().apply { deleteOnExit() }
|
||||
directory = File(filesDir, "dir").apply {
|
||||
mkdirs()
|
||||
File(this, "child.bin").writeBytes(ByteArray(expectedSizeOfDirectoryValue.toInt()))
|
||||
}
|
||||
|
||||
scopedStorageProvider = ScopedStorageProvider(rootFolderName, context)
|
||||
every { context.filesDir } returns filesDir
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPrimaryStorageDirectory returns filesDir`() {
|
||||
val result = scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
assertEquals(filesDir, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
context.filesDir
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getRootFolderPath returns the root folder path String`() {
|
||||
val rootFolderPath = filesDir.absolutePath + File.separator + rootFolderName
|
||||
val actualPath = scopedStorageProvider.getRootFolderPath()
|
||||
assertEquals(rootFolderPath, actualPath)
|
||||
|
||||
verify(exactly = 1) {
|
||||
scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDefaultSavePathFor returns the path with spaces when there is a space`() {
|
||||
mockkStatic(Uri::class)
|
||||
every { Uri.encode(accountName, "@") } returns uriEncoded
|
||||
|
||||
val accountDirectoryPath = filesDir.absolutePath + File.separator + rootFolderName + File.separator + uriEncoded
|
||||
val expectedPath = accountDirectoryPath + File.separator + spaceId + File.separator + remotePath
|
||||
val actualPath = scopedStorageProvider.getDefaultSavePathFor(accountName, remotePath, spaceId)
|
||||
|
||||
assertEquals(expectedPath, actualPath)
|
||||
|
||||
verify(exactly = 1) {
|
||||
scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDefaultSavePathFor returns the path without spaces when there is not space`() {
|
||||
val spaceId = null
|
||||
|
||||
mockkStatic(Uri::class)
|
||||
every { Uri.encode(accountName, "@") } returns uriEncoded
|
||||
|
||||
val accountDirectoryPath = filesDir.absolutePath + File.separator + rootFolderName + File.separator + uriEncoded
|
||||
val expectedPath = accountDirectoryPath + remotePath
|
||||
val actualPath = scopedStorageProvider.getDefaultSavePathFor(accountName, remotePath, spaceId)
|
||||
|
||||
assertEquals(expectedPath, actualPath)
|
||||
|
||||
verify(exactly = 1) {
|
||||
scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getExpectedRemotePath returns expected remote path with separator in the end when there is separator and is folder true`() {
|
||||
|
||||
val isFolder = true
|
||||
val expectedPath = expectedRemotePath(remotePath, newName, isFolder)
|
||||
val actualPath = scopedStorageProvider.getExpectedRemotePath(remotePath, newName, isFolder)
|
||||
|
||||
assertEquals(expectedPath, actualPath)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getExpectedRemotePath returns expected remote path with separator in the end when is separator and is folder false`() {
|
||||
|
||||
val isFolder = false
|
||||
val expectedPath = expectedRemotePath(remotePath, newName, isFolder)
|
||||
val actualPath = scopedStorageProvider.getExpectedRemotePath(remotePath, newName, isFolder)
|
||||
|
||||
assertEquals(expectedPath, actualPath)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getExpectedRemotePath returns expected remote path with separator in the end when is not separator and is folder true`() {
|
||||
|
||||
val isFolder = true
|
||||
val expectedPath = expectedRemotePath(remotePath, newName, isFolder)
|
||||
val actualPath = scopedStorageProvider.getExpectedRemotePath(remotePath, newName, isFolder)
|
||||
|
||||
assertEquals(expectedPath, actualPath)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getExpectedRemotePath returns expected remote path with separator in the end when is not separator and is folder false`() {
|
||||
val isFolder = false
|
||||
val expectedPath = expectedRemotePath(remotePath, newName, isFolder)
|
||||
val actualPath = scopedStorageProvider.getExpectedRemotePath(remotePath, newName, isFolder)
|
||||
|
||||
assertEquals(expectedPath, actualPath)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun `getExpectedRemotePath returns a IllegalArgumentException when there is not file`() {
|
||||
val isFolder = false
|
||||
val remotePath = ""
|
||||
|
||||
scopedStorageProvider.getExpectedRemotePath(remotePath, newName, isFolder)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getTemporalPath returns expected temporal path with separator and space when there is a space`() {
|
||||
mockkStatic(Uri::class)
|
||||
every { Uri.encode(accountName, "@") } returns uriEncoded
|
||||
|
||||
val temporalPathWithoutSpace = rootFolderPath + File.separator + "tmp" + File.separator + uriEncoded
|
||||
|
||||
val expectedValue = temporalPathWithoutSpace + File.separator + spaceId
|
||||
val actualValue = scopedStorageProvider.getTemporalPath(accountName, spaceId)
|
||||
assertEquals(expectedValue, actualValue)
|
||||
|
||||
verify(exactly = 1) {
|
||||
scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getTemporalPath returns expected temporal path neither with separator not space when there is not a space`() {
|
||||
val spaceId = null
|
||||
|
||||
mockkStatic(Uri::class)
|
||||
every { Uri.encode(accountName, "@") } returns uriEncoded
|
||||
|
||||
val expectedValue = rootFolderPath + File.separator + TEMPORAL_FOLDER_NAME + File.separator + uriEncoded
|
||||
val actualValue = scopedStorageProvider.getTemporalPath(accountName, spaceId)
|
||||
assertEquals(expectedValue, actualValue)
|
||||
|
||||
verify(exactly = 1) {
|
||||
scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLogsPath returns logs path`() {
|
||||
val expectedValue = rootFolderPath + File.separator + LOGS_FOLDER_NAME + File.separator
|
||||
val actualValue = scopedStorageProvider.getLogsPath()
|
||||
|
||||
assertEquals(expectedValue, actualValue)
|
||||
|
||||
verify(exactly = 1) {
|
||||
scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUsableSpace returns usable space from the storage directory`() {
|
||||
val actualUsableSpace = scopedStorageProvider.getUsableSpace()
|
||||
assertTrue(actualUsableSpace > 0)
|
||||
|
||||
verify(exactly = 1) {
|
||||
scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `sizeOfDirectory returns the sum the file size in bytes (Long) when isDirectory is true doing a recursive call if it's a directory`() {
|
||||
val actualValue = scopedStorageProvider.sizeOfDirectory(directory)
|
||||
|
||||
assertEquals(expectedSizeOfDirectoryValue, actualValue)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `sizeOfDirectory returns the sum the file size in bytes (Long) when isDirectory is false without doing a recursive call`() {
|
||||
val tmpDir = Files.createTempDirectory("scoped-storage-size").toFile().apply {
|
||||
deleteOnExit()
|
||||
File(this, "single.bin").writeBytes(ByteArray(expectedSizeOfDirectoryValue.toInt()))
|
||||
}
|
||||
|
||||
val actualValue = scopedStorageProvider.sizeOfDirectory(tmpDir)
|
||||
assertEquals(expectedSizeOfDirectoryValue, actualValue)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `sizeOfDirectory returns zero value when directory not exists`() {
|
||||
val expectedSizeOfDirectoryValue: Long = 0
|
||||
|
||||
val missingDir = File(filesDir, "does-not-exist")
|
||||
|
||||
val actualValue = scopedStorageProvider.sizeOfDirectory(missingDir)
|
||||
|
||||
assertEquals(expectedSizeOfDirectoryValue, actualValue)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteLocalFile calls getPrimaryStorageDirectory()`() {
|
||||
mockkStatic(Uri::class)
|
||||
every { Uri.encode(any(), any()) } returns uriEncoded
|
||||
scopedStorageProvider.deleteLocalFile(OC_FILE)
|
||||
|
||||
verify(exactly = 1) {
|
||||
scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `moveLocalFile calls getPrimaryStorageDirectory()`() {
|
||||
val finalStoragePath = "file.txt"
|
||||
mockkStatic(Uri::class)
|
||||
|
||||
every { Uri.encode(any(), any()) } returns uriEncoded
|
||||
scopedStorageProvider.moveLocalFile(OC_FILE, finalStoragePath)
|
||||
|
||||
verify(exactly = 1) {
|
||||
scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteCacheIfNeeded delete cache file when transfer local path start with cacheDir`() {
|
||||
val transfer: OCTransfer = mockk()
|
||||
val accountName = "testAccount"
|
||||
val localPath = "/file.txt"
|
||||
|
||||
mockkStatic(Uri::class)
|
||||
every { Uri.encode(any(), any()) } returns uriEncoded
|
||||
every { transfer.accountName } returns accountName
|
||||
every { transfer.localPath } returns localPath
|
||||
|
||||
scopedStorageProvider.deleteCacheIfNeeded(transfer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
scopedStorageProvider.getPrimaryStorageDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
private fun expectedRemotePath(current: String, newName: String, isFolder: Boolean): String {
|
||||
var parent = File(current).parent ?: throw IllegalArgumentException("Parent path is null")
|
||||
parent = if (parent.endsWith(File.separator)) parent else parent + File.separator
|
||||
var newRemotePath = parent + newName
|
||||
if (isFolder) {
|
||||
newRemotePath += File.separator
|
||||
}
|
||||
return newRemotePath
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val LOGS_FOLDER_NAME = "logs"
|
||||
private const val TEMPORAL_FOLDER_NAME = "tmp"
|
||||
}
|
||||
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
package eu.qsfera.android.data.providers.implementation
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.preference.PreferenceManager
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCSharedPreferencesProviderTest {
|
||||
|
||||
private lateinit var ocSharedPreferencesProvider: OCSharedPreferencesProvider
|
||||
private lateinit var context: Context
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
private lateinit var editor: SharedPreferences.Editor
|
||||
private val key = "test_key"
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
context = mockk(relaxed = true)
|
||||
sharedPreferences = mockk(relaxed = true)
|
||||
editor = mockk(relaxed = true)
|
||||
mockkStatic(PreferenceManager::class)
|
||||
every { PreferenceManager.getDefaultSharedPreferences(any()) } returns sharedPreferences
|
||||
every { sharedPreferences.edit() } returns editor
|
||||
|
||||
ocSharedPreferencesProvider = OCSharedPreferencesProvider(context)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `putString put a String in sharedPreferences`() {
|
||||
val value = "test_value"
|
||||
ocSharedPreferencesProvider.putString(key, value)
|
||||
|
||||
verify(exactly = 1) {
|
||||
editor.putString(key, value).apply()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getString returns a String from sharedPreferences`() {
|
||||
val defaultValue = "default_value"
|
||||
val savedValue = "saved_value"
|
||||
|
||||
every { sharedPreferences.getString(key, defaultValue) } returns savedValue
|
||||
|
||||
val result = ocSharedPreferencesProvider.getString(key, defaultValue)
|
||||
assertEquals(savedValue, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
sharedPreferences.getString(key, defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `putInt put a Int in sharedPreferences`() {
|
||||
val value = 12
|
||||
ocSharedPreferencesProvider.putInt(key, value)
|
||||
|
||||
verify(exactly = 1) {
|
||||
editor.putInt(key, value).apply()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getInt returns a Int from sharedPreferences`() {
|
||||
val defaultValue = 111
|
||||
val savedValue = 233
|
||||
|
||||
every { sharedPreferences.getInt(key, defaultValue) } returns savedValue
|
||||
|
||||
val result = ocSharedPreferencesProvider.getInt(key, defaultValue)
|
||||
assertEquals(savedValue, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
sharedPreferences.getInt(key, defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `putLong put a Long in sharedPreferences`() {
|
||||
val value = 12L
|
||||
ocSharedPreferencesProvider.putLong(key, value)
|
||||
|
||||
verify(exactly = 1) {
|
||||
editor.putLong(key, value).apply()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLong returns a Long from sharedPreferences`() {
|
||||
val defaultValue = 1411L
|
||||
val savedValue = 73L
|
||||
|
||||
every { sharedPreferences.getLong(key, defaultValue) } returns savedValue
|
||||
|
||||
val result = ocSharedPreferencesProvider.getLong(key, defaultValue)
|
||||
assertEquals(savedValue, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
sharedPreferences.getLong(key, defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `putBoolean put a Boolean in sharedPreferences`() {
|
||||
val value = true
|
||||
ocSharedPreferencesProvider.putBoolean(key, value)
|
||||
|
||||
verify(exactly = 1) {
|
||||
editor.putBoolean(key, value).apply()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getBoolean returns a Boolean from sharedPreferences`() {
|
||||
val defaultValue = false
|
||||
val savedValue = true
|
||||
|
||||
every { sharedPreferences.getBoolean(key, defaultValue) } returns savedValue
|
||||
|
||||
val result = ocSharedPreferencesProvider.getBoolean(key, defaultValue)
|
||||
assertTrue(result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
sharedPreferences.getBoolean(key, defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `containsPreference verify if the value with the key is contained in sharedPreferences`() {
|
||||
every { sharedPreferences.contains(key) } returns true
|
||||
|
||||
val result = ocSharedPreferencesProvider.containsPreference(key)
|
||||
assertTrue(result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
sharedPreferences.contains(key)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removePreferences remove a preference by key`() {
|
||||
ocSharedPreferencesProvider.removePreference(key)
|
||||
|
||||
verify(exactly = 1) {
|
||||
editor.remove(key).apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* @author Juan Carlos Garrote Gascón
|
||||
*
|
||||
* Copyright (C) 2024 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.server.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.ClientManager
|
||||
import eu.qsfera.android.domain.exceptions.NoConnectionWithServerException
|
||||
import eu.qsfera.android.domain.exceptions.QSferaVersionNotSupportedException
|
||||
import eu.qsfera.android.domain.exceptions.SpecificServiceUnavailableException
|
||||
import eu.qsfera.android.domain.server.model.AuthenticationMethod
|
||||
import eu.qsfera.android.lib.common.QSferaClient
|
||||
import eu.qsfera.android.lib.common.http.HttpConstants.HTTP_SERVICE_UNAVAILABLE
|
||||
import eu.qsfera.android.lib.common.http.HttpConstants.HTTP_UNAUTHORIZED
|
||||
import eu.qsfera.android.lib.common.operations.RemoteOperationResult
|
||||
import eu.qsfera.android.lib.common.operations.RemoteOperationResult.ResultCode.OK_NO_SSL
|
||||
import eu.qsfera.android.lib.common.operations.RemoteOperationResult.ResultCode.OK_SSL
|
||||
import eu.qsfera.android.lib.resources.status.QSferaVersion
|
||||
import eu.qsfera.android.lib.resources.status.RemoteServerInfo
|
||||
import eu.qsfera.android.lib.resources.status.services.implementation.OCServerInfoService
|
||||
import eu.qsfera.android.testutil.OC_INSECURE_SERVER_INFO_BASIC_AUTH
|
||||
import eu.qsfera.android.testutil.OC_INSECURE_SERVER_INFO_BEARER_AUTH
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_BASIC_AUTH
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_BEARER_AUTH
|
||||
import eu.qsfera.android.utils.createRemoteOperationResultMock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteServerInfoDataSourceTest {
|
||||
private lateinit var ocRemoteServerInfoDatasource: OCRemoteServerInfoDataSource
|
||||
|
||||
private val ocServerInfoService: OCServerInfoService = mockk()
|
||||
private val clientManager: ClientManager = mockk(relaxed = true)
|
||||
private val ocClientMocked: QSferaClient = mockk(relaxed = true)
|
||||
|
||||
private val remoteServerInfo = RemoteServerInfo(
|
||||
qsferaVersion = QSferaVersion(OC_SECURE_SERVER_INFO_BASIC_AUTH.qsferaVersion, "2.0.0"),
|
||||
baseUrl = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
isSecureConnection = OC_SECURE_SERVER_INFO_BASIC_AUTH.isSecureConnection
|
||||
)
|
||||
private val basicAuthHeader = "basic realm=\"qsfera\", charset=\"utf-8\""
|
||||
private val bearerHeader = "bearer realm=\"qsfera\""
|
||||
private val authHeadersBasic = listOf(basicAuthHeader)
|
||||
private val authHeaderBearer = listOf(basicAuthHeader, bearerHeader)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
ocRemoteServerInfoDatasource = OCRemoteServerInfoDataSource(ocServerInfoService, clientManager)
|
||||
every { clientManager.getClientForAnonymousCredentials(any(), any()) } returns ocClientMocked
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAuthenticationMethod returns basic authentication`() {
|
||||
val expectedValue = AuthenticationMethod.BASIC_HTTP_AUTH
|
||||
prepareAuthorizationMethodToBeRetrieved(expectedValue)
|
||||
|
||||
val currentValue = ocRemoteServerInfoDatasource.getAuthenticationMethod(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl)
|
||||
|
||||
assertNotNull(expectedValue)
|
||||
assertEquals(expectedValue, currentValue)
|
||||
|
||||
verify { ocServerInfoService.checkPathExistence(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, false, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAuthenticationMethod returns bearer authentication`() {
|
||||
val expectedValue = AuthenticationMethod.BEARER_TOKEN
|
||||
prepareAuthorizationMethodToBeRetrieved(expectedValue)
|
||||
|
||||
val currentValue = ocRemoteServerInfoDatasource.getAuthenticationMethod(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl)
|
||||
|
||||
assertNotNull(expectedValue)
|
||||
assertEquals(expectedValue, currentValue)
|
||||
|
||||
verify { ocServerInfoService.checkPathExistence(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, false, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAuthenticationMethod returns none method`() {
|
||||
val expectedValue = AuthenticationMethod.NONE
|
||||
prepareAuthorizationMethodToBeRetrieved(expectedValue)
|
||||
|
||||
val currentValue = ocRemoteServerInfoDatasource.getAuthenticationMethod(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl)
|
||||
|
||||
assertNotNull(expectedValue)
|
||||
assertEquals(expectedValue, currentValue)
|
||||
|
||||
verify { ocServerInfoService.checkPathExistence(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, false, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test(expected = SpecificServiceUnavailableException::class)
|
||||
fun `getAuthenticationMethod throws exception when server is not available`() {
|
||||
prepareAuthorizationMethodToBeRetrieved(
|
||||
expectedAuthenticationMethod = AuthenticationMethod.BASIC_HTTP_AUTH,
|
||||
isServerAvailable = false
|
||||
)
|
||||
ocRemoteServerInfoDatasource.getAuthenticationMethod(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getRemoteStatus returns RemoteServerInfo with secure connection`() {
|
||||
val expectedValue = remoteServerInfo.copy(isSecureConnection = true)
|
||||
prepareRemoteStatusToBeRetrieved(expectedValue)
|
||||
|
||||
val currentValue = ocRemoteServerInfoDatasource.getRemoteStatus(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl)
|
||||
|
||||
assertNotNull(currentValue)
|
||||
assertEquals(expectedValue, currentValue)
|
||||
|
||||
verify { ocServerInfoService.getRemoteStatus(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getRemoteStatus returns RemoteServerInfo with insecure connection`() {
|
||||
val expectedValue = remoteServerInfo.copy(isSecureConnection = false)
|
||||
prepareRemoteStatusToBeRetrieved(expectedValue)
|
||||
|
||||
val currentValue = ocRemoteServerInfoDatasource.getRemoteStatus(OC_INSECURE_SERVER_INFO_BASIC_AUTH.baseUrl)
|
||||
|
||||
assertNotNull(currentValue)
|
||||
assertEquals(expectedValue, currentValue)
|
||||
|
||||
verify { ocServerInfoService.getRemoteStatus(OC_INSECURE_SERVER_INFO_BASIC_AUTH.baseUrl, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test(expected = QSferaVersionNotSupportedException::class)
|
||||
fun `getRemoteStatus throws exception when qsfera version is not supported`() {
|
||||
val expectedValue = remoteServerInfo.copy(qsferaVersion = QSferaVersion("0.0.2", ""))
|
||||
prepareRemoteStatusToBeRetrieved(expectedValue)
|
||||
|
||||
ocRemoteServerInfoDatasource.getRemoteStatus(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getRemoteStatus returns RemoteServerInfo with hidden qsfera version`() {
|
||||
val expectedValue = remoteServerInfo.copy(qsferaVersion = QSferaVersion("", ""))
|
||||
prepareRemoteStatusToBeRetrieved(expectedValue)
|
||||
|
||||
ocRemoteServerInfoDatasource.getRemoteStatus(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl)
|
||||
|
||||
val remoteStatus = ocRemoteServerInfoDatasource.getRemoteStatus(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl)
|
||||
|
||||
assertTrue(remoteStatus.qsferaVersion.isVersionHidden)
|
||||
verify { ocServerInfoService.getRemoteStatus(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns ServerInfo with basic and secure connection`() {
|
||||
val expectedValue = OC_SECURE_SERVER_INFO_BASIC_AUTH
|
||||
|
||||
prepareRemoteStatusToBeRetrieved(remoteServerInfo)
|
||||
prepareAuthorizationMethodToBeRetrieved(AuthenticationMethod.BASIC_HTTP_AUTH, true)
|
||||
|
||||
val currentValue = ocRemoteServerInfoDatasource.getServerInfo(expectedValue.baseUrl, false)
|
||||
assertEquals(expectedValue, currentValue)
|
||||
|
||||
verify(exactly = 1) { ocServerInfoService.getRemoteStatus(expectedValue.baseUrl, ocClientMocked) }
|
||||
verify(exactly = 1) { ocServerInfoService.checkPathExistence(expectedValue.baseUrl, false, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns ServerInfo with basic and insecure connection`() {
|
||||
val expectedValue = OC_INSECURE_SERVER_INFO_BASIC_AUTH
|
||||
|
||||
prepareRemoteStatusToBeRetrieved(remoteServerInfo.copy(baseUrl = expectedValue.baseUrl, isSecureConnection = false))
|
||||
prepareAuthorizationMethodToBeRetrieved(AuthenticationMethod.BASIC_HTTP_AUTH, true)
|
||||
|
||||
val currentValue = ocRemoteServerInfoDatasource.getServerInfo(expectedValue.baseUrl, false)
|
||||
assertEquals(expectedValue, currentValue)
|
||||
|
||||
verify(exactly = 1) { ocServerInfoService.getRemoteStatus(expectedValue.baseUrl, ocClientMocked) }
|
||||
verify(exactly = 1) { ocServerInfoService.checkPathExistence(expectedValue.baseUrl, false, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns ServerInfo with bearer and secure connection`() {
|
||||
val expectedValue = OC_SECURE_SERVER_INFO_BEARER_AUTH
|
||||
|
||||
prepareRemoteStatusToBeRetrieved(remoteServerInfo.copy(isSecureConnection = true))
|
||||
prepareAuthorizationMethodToBeRetrieved(AuthenticationMethod.BEARER_TOKEN, true)
|
||||
|
||||
val currentValue = ocRemoteServerInfoDatasource.getServerInfo(expectedValue.baseUrl, false)
|
||||
assertEquals(expectedValue, currentValue)
|
||||
|
||||
verify(exactly = 1) { ocServerInfoService.getRemoteStatus(expectedValue.baseUrl, ocClientMocked) }
|
||||
verify(exactly = 1) { ocServerInfoService.checkPathExistence(expectedValue.baseUrl, false, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns ServerInfo with bearer and insecure connection`() {
|
||||
val expectedValue = OC_INSECURE_SERVER_INFO_BEARER_AUTH
|
||||
|
||||
prepareRemoteStatusToBeRetrieved(remoteServerInfo.copy(baseUrl = expectedValue.baseUrl, isSecureConnection = false))
|
||||
prepareAuthorizationMethodToBeRetrieved(AuthenticationMethod.BEARER_TOKEN, true)
|
||||
|
||||
val currentValue = ocRemoteServerInfoDatasource.getServerInfo(expectedValue.baseUrl, false)
|
||||
assertEquals(expectedValue, currentValue)
|
||||
|
||||
verify(exactly = 1) { ocServerInfoService.getRemoteStatus(expectedValue.baseUrl, ocClientMocked) }
|
||||
verify(exactly = 1) { ocServerInfoService.checkPathExistence(expectedValue.baseUrl, false, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns ServerInfo with bearer and secure connection when OIDC enforcement is enabled`() {
|
||||
val expectedValue = OC_SECURE_SERVER_INFO_BEARER_AUTH
|
||||
|
||||
prepareRemoteStatusToBeRetrieved(remoteServerInfo.copy(baseUrl = expectedValue.baseUrl, isSecureConnection = true))
|
||||
|
||||
val currentValue = ocRemoteServerInfoDatasource.getServerInfo(expectedValue.baseUrl, true)
|
||||
assertEquals(expectedValue, currentValue)
|
||||
|
||||
verify(exactly = 1) { ocServerInfoService.getRemoteStatus(expectedValue.baseUrl, ocClientMocked) }
|
||||
}
|
||||
|
||||
@Test(expected = NoConnectionWithServerException::class)
|
||||
fun `getServerInfo throws exception when there is no connection with the server`() {
|
||||
prepareRemoteStatusToBeRetrieved(remoteServerInfo, NoConnectionWithServerException())
|
||||
|
||||
ocRemoteServerInfoDatasource.getServerInfo(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, false)
|
||||
|
||||
verify(exactly = 1) { ocServerInfoService.getRemoteStatus(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, ocClientMocked) }
|
||||
verify(exactly = 0) { ocServerInfoService.checkPathExistence(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, false, ocClientMocked) }
|
||||
}
|
||||
|
||||
private fun prepareAuthorizationMethodToBeRetrieved(
|
||||
expectedAuthenticationMethod: AuthenticationMethod,
|
||||
isServerAvailable: Boolean = true
|
||||
) {
|
||||
val expectedAuthHeader = when (expectedAuthenticationMethod) {
|
||||
AuthenticationMethod.BEARER_TOKEN -> authHeaderBearer
|
||||
AuthenticationMethod.BASIC_HTTP_AUTH -> authHeadersBasic
|
||||
else -> listOf()
|
||||
}
|
||||
|
||||
val checkPathExistenceResultMocked: RemoteOperationResult<Boolean> =
|
||||
createRemoteOperationResultMock(
|
||||
data = true,
|
||||
isSuccess = true,
|
||||
resultCode = OK_SSL,
|
||||
authenticationHeader = expectedAuthHeader,
|
||||
httpCode = if (isServerAvailable) HTTP_UNAUTHORIZED else HTTP_SERVICE_UNAVAILABLE
|
||||
)
|
||||
|
||||
every {
|
||||
ocServerInfoService.checkPathExistence(any(), false, ocClientMocked)
|
||||
} returns checkPathExistenceResultMocked
|
||||
}
|
||||
|
||||
private fun prepareRemoteStatusToBeRetrieved(
|
||||
expectedConfig: RemoteServerInfo,
|
||||
exception: Exception? = null
|
||||
) {
|
||||
val expectedResultCode = when (expectedConfig.isSecureConnection) {
|
||||
true -> OK_SSL
|
||||
false -> OK_NO_SSL
|
||||
}
|
||||
|
||||
val remoteStatusResultMocked: RemoteOperationResult<RemoteServerInfo> =
|
||||
createRemoteOperationResultMock(
|
||||
data = expectedConfig,
|
||||
isSuccess = true,
|
||||
resultCode = expectedResultCode,
|
||||
exception = exception
|
||||
)
|
||||
|
||||
every {
|
||||
ocServerInfoService.getRemoteStatus(any(), ocClientMocked)
|
||||
} returns remoteStatusResultMocked
|
||||
}
|
||||
}
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* @author Juan Carlos Garrote Gascón
|
||||
* @author Jorge Aguado Recio
|
||||
*
|
||||
* Copyright (C) 2024 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.server.repository
|
||||
|
||||
import eu.qsfera.android.data.oauth.datasources.RemoteOAuthDataSource
|
||||
import eu.qsfera.android.data.server.datasources.RemoteServerInfoDataSource
|
||||
import eu.qsfera.android.data.webfinger.datasources.RemoteWebFingerDataSource
|
||||
import eu.qsfera.android.domain.server.model.ServerInfo
|
||||
import eu.qsfera.android.domain.webfinger.model.WebFingerOidcInfo
|
||||
import eu.qsfera.android.domain.webfinger.model.WebFingerRel
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_BASIC_AUTH
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_BEARER_AUTH
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_OIDC_AUTH
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE_WITH_CLIENT
|
||||
import eu.qsfera.android.testutil.OC_WEBFINGER_CLIENT_ID
|
||||
import eu.qsfera.android.testutil.OC_WEBFINGER_INSTANCE_URL
|
||||
import eu.qsfera.android.testutil.OC_WEBFINGER_SCOPES
|
||||
import eu.qsfera.android.testutil.oauth.OC_OIDC_SERVER_CONFIGURATION
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class OCServerInfoRepositoryTest {
|
||||
|
||||
private val remoteServerInfoDataSource = mockk<RemoteServerInfoDataSource>()
|
||||
private val remoteWebFingerDataSource = mockk<RemoteWebFingerDataSource>()
|
||||
private val remoteOAuthDataSource = mockk<RemoteOAuthDataSource>()
|
||||
private val ocServerInfoRepository = OCServerInfoRepository(remoteServerInfoDataSource, remoteWebFingerDataSource, remoteOAuthDataSource)
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns a BasicServer when creatingAccount parameter is false`() {
|
||||
every {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, false)
|
||||
} returns OC_SECURE_SERVER_INFO_BASIC_AUTH
|
||||
|
||||
val basicServer = ocServerInfoRepository.getServerInfo(
|
||||
path = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
creatingAccount = false,
|
||||
enforceOIDC = false
|
||||
)
|
||||
assertEquals(OC_SECURE_SERVER_INFO_BASIC_AUTH, basicServer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns a BasicServer when creatingAccount parameter is true and webfinger datasource throws an exception`() {
|
||||
every {
|
||||
remoteWebFingerDataSource.getOidcInfoFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl
|
||||
)
|
||||
} throws Exception()
|
||||
|
||||
every {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, false)
|
||||
} returns OC_SECURE_SERVER_INFO_BASIC_AUTH
|
||||
|
||||
val basicServer = ocServerInfoRepository.getServerInfo(
|
||||
path = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
creatingAccount = true,
|
||||
enforceOIDC = false
|
||||
)
|
||||
assertEquals(OC_SECURE_SERVER_INFO_BASIC_AUTH, basicServer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteWebFingerDataSource.getOidcInfoFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl
|
||||
)
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns an OAuth2Server when creatingAccount parameter is false`() {
|
||||
every {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl, false)
|
||||
} returns OC_SECURE_SERVER_INFO_BEARER_AUTH
|
||||
|
||||
every {
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl)
|
||||
} throws Exception()
|
||||
|
||||
val oAuthServer = ocServerInfoRepository.getServerInfo(
|
||||
path = OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl,
|
||||
creatingAccount = false,
|
||||
enforceOIDC = false
|
||||
)
|
||||
assertEquals(OC_SECURE_SERVER_INFO_BEARER_AUTH, oAuthServer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl, false)
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns an OAuth2Server when creatingAccount parameter is true and webfinger datasource throws an exception`() {
|
||||
every {
|
||||
remoteWebFingerDataSource.getOidcInfoFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl
|
||||
)
|
||||
} throws Exception()
|
||||
|
||||
every {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl, false)
|
||||
} returns OC_SECURE_SERVER_INFO_BEARER_AUTH
|
||||
|
||||
every {
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl)
|
||||
} throws Exception()
|
||||
|
||||
val oAuthServer = ocServerInfoRepository.getServerInfo(
|
||||
path = OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl,
|
||||
creatingAccount = true,
|
||||
enforceOIDC = false
|
||||
)
|
||||
assertEquals(OC_SECURE_SERVER_INFO_BEARER_AUTH, oAuthServer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteWebFingerDataSource.getOidcInfoFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl
|
||||
)
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl, false)
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_SERVER_INFO_BEARER_AUTH.baseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns an OIDCServer when creatingAccount parameter is false`() {
|
||||
every {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl, false)
|
||||
} returns OC_SECURE_SERVER_INFO_OIDC_AUTH
|
||||
|
||||
every {
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl)
|
||||
} returns OC_OIDC_SERVER_CONFIGURATION
|
||||
|
||||
val oIDCServer = ocServerInfoRepository.getServerInfo(
|
||||
path = OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl,
|
||||
creatingAccount = false,
|
||||
enforceOIDC = false
|
||||
)
|
||||
assertEquals(OC_SECURE_SERVER_INFO_OIDC_AUTH, oIDCServer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl, false)
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns an OIDCServer when creatingAccount parameter is true and webfinger datasource throws an exception`() {
|
||||
every {
|
||||
remoteWebFingerDataSource.getOidcInfoFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl
|
||||
)
|
||||
} throws Exception()
|
||||
|
||||
every {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl, false)
|
||||
} returns OC_SECURE_SERVER_INFO_OIDC_AUTH
|
||||
|
||||
every {
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl)
|
||||
} returns OC_OIDC_SERVER_CONFIGURATION
|
||||
|
||||
val oIDCServer = ocServerInfoRepository.getServerInfo(
|
||||
path = OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl,
|
||||
creatingAccount = true,
|
||||
enforceOIDC = false
|
||||
)
|
||||
assertEquals(OC_SECURE_SERVER_INFO_OIDC_AUTH, oIDCServer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteWebFingerDataSource.getOidcInfoFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl
|
||||
)
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl, false)
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_SECURE_SERVER_INFO_OIDC_AUTH.baseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns an OIDCServer when creatingAccount is true and webfinger datasource returns an OIDC issuer`() {
|
||||
every {
|
||||
remoteWebFingerDataSource.getOidcInfoFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE.baseUrl
|
||||
)
|
||||
} returns WebFingerOidcInfo(issuer = OC_WEBFINGER_INSTANCE_URL, clientId = null, scopes = null)
|
||||
|
||||
every {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE.baseUrl, false)
|
||||
} returns ServerInfo.OAuth2Server(baseUrl = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE.baseUrl, qsferaVersion = "10.12")
|
||||
|
||||
every {
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_WEBFINGER_INSTANCE_URL)
|
||||
} returns OC_OIDC_SERVER_CONFIGURATION
|
||||
|
||||
val oIDCServerWebfinger = ocServerInfoRepository.getServerInfo(
|
||||
path = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE.baseUrl,
|
||||
creatingAccount = true,
|
||||
enforceOIDC = false
|
||||
)
|
||||
assertEquals(OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE, oIDCServerWebfinger)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteWebFingerDataSource.getOidcInfoFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE.baseUrl
|
||||
)
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_WEBFINGER_INSTANCE_URL)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getServerInfo returns an OIDCServer with webfinger client id and scopes when webfinger provides them`() {
|
||||
every {
|
||||
remoteWebFingerDataSource.getOidcInfoFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE_WITH_CLIENT.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE_WITH_CLIENT.baseUrl
|
||||
)
|
||||
} returns WebFingerOidcInfo(issuer = OC_WEBFINGER_INSTANCE_URL, clientId = OC_WEBFINGER_CLIENT_ID, scopes = OC_WEBFINGER_SCOPES)
|
||||
|
||||
every {
|
||||
remoteServerInfoDataSource.getServerInfo(OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE_WITH_CLIENT.baseUrl, false)
|
||||
} returns ServerInfo.OAuth2Server(
|
||||
baseUrl = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE_WITH_CLIENT.baseUrl,
|
||||
qsferaVersion = "10.12",
|
||||
)
|
||||
|
||||
every {
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_WEBFINGER_INSTANCE_URL)
|
||||
} returns OC_OIDC_SERVER_CONFIGURATION
|
||||
|
||||
val result = ocServerInfoRepository.getServerInfo(
|
||||
path = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE_WITH_CLIENT.baseUrl,
|
||||
creatingAccount = true,
|
||||
enforceOIDC = false
|
||||
)
|
||||
assertEquals(OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE_WITH_CLIENT, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteWebFingerDataSource.getOidcInfoFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE_WITH_CLIENT.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_OIDC_AUTH_WEBFINGER_INSTANCE_WITH_CLIENT.baseUrl
|
||||
)
|
||||
remoteOAuthDataSource.performOIDCDiscovery(OC_WEBFINGER_INSTANCE_URL)
|
||||
}
|
||||
}
|
||||
}
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author David González Verdugo
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.sharing.sharees.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.ClientManager
|
||||
import eu.qsfera.android.data.sharing.sharees.datasources.mapper.RemoteShareeMapper
|
||||
import eu.qsfera.android.domain.sharing.sharees.model.OCSharee
|
||||
import eu.qsfera.android.domain.sharing.shares.model.ShareType
|
||||
import eu.qsfera.android.lib.resources.shares.responses.ExactSharees
|
||||
import eu.qsfera.android.lib.resources.shares.responses.ShareeItem
|
||||
import eu.qsfera.android.lib.resources.shares.responses.ShareeOcsResponse
|
||||
import eu.qsfera.android.lib.resources.shares.responses.ShareeValue
|
||||
import eu.qsfera.android.lib.resources.shares.services.implementation.OCShareeService
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.utils.createRemoteOperationResultMock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteShareeDataSourceTest {
|
||||
private lateinit var ocRemoteShareesDataSource: OCRemoteShareeDataSource
|
||||
private val ocShareeService: OCShareeService = mockk()
|
||||
private val clientManager: ClientManager = mockk()
|
||||
private lateinit var sharees: List<OCSharee>
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
every { clientManager.getShareeService(OC_ACCOUNT_NAME) } returns ocShareeService
|
||||
ocRemoteShareesDataSource =
|
||||
OCRemoteShareeDataSource(clientManager, RemoteShareeMapper())
|
||||
|
||||
val getRemoteShareesOperationResult = createRemoteOperationResultMock(
|
||||
REMOTE_SHAREES,
|
||||
true
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareeService.getSharees(searchString = "user", page = 1, perPage = 30)
|
||||
} returns getRemoteShareesOperationResult
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharees returns a list of OCSharee entered as remote sharees`() {
|
||||
sharees = ocRemoteShareesDataSource.getSharees(
|
||||
"user",
|
||||
1,
|
||||
30,
|
||||
OC_ACCOUNT_NAME,
|
||||
)
|
||||
assertNotNull(sharees)
|
||||
assertEquals(5, sharees.size)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareeService(OC_ACCOUNT_NAME)
|
||||
ocShareeService.getSharees(searchString = "user", page = 1, perPage = 30)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharees returns a list of OCSharee when contains exact user match`() {
|
||||
sharees = ocRemoteShareesDataSource.getSharees(
|
||||
"user",
|
||||
1,
|
||||
30,
|
||||
OC_ACCOUNT_NAME,
|
||||
)
|
||||
|
||||
val sharee = sharees[0]
|
||||
assertEquals(sharee.label, "User")
|
||||
assertEquals(sharee.shareType, ShareType.USER)
|
||||
assertEquals(sharee.shareWith, "user")
|
||||
assertEquals(sharee.additionalInfo, "user@exact.com")
|
||||
assertTrue(sharee.isExactMatch)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareeService(OC_ACCOUNT_NAME)
|
||||
ocShareeService.getSharees(searchString = "user", page = 1, perPage = 30)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharees returns a list of OCSharee when contains one user not exactly matched`() {
|
||||
sharees = ocRemoteShareesDataSource.getSharees(
|
||||
"user",
|
||||
1,
|
||||
30,
|
||||
OC_ACCOUNT_NAME,
|
||||
)
|
||||
|
||||
val sharee = sharees[1]
|
||||
assertEquals("User 1", sharee.label)
|
||||
assertEquals(ShareType.USER, sharee.shareType)
|
||||
assertEquals("user1", sharee.shareWith)
|
||||
assertEquals("user1@mail.com", sharee.additionalInfo)
|
||||
assertFalse(sharee.isExactMatch)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareeService(OC_ACCOUNT_NAME)
|
||||
ocShareeService.getSharees(searchString = "user", page = 1, perPage = 30)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharees returns a list of OCSharee when contains one user without additional info`() {
|
||||
sharees = ocRemoteShareesDataSource.getSharees(
|
||||
"user",
|
||||
1,
|
||||
30,
|
||||
OC_ACCOUNT_NAME,
|
||||
)
|
||||
val sharee = sharees[2]
|
||||
assertEquals("User 2", sharee.label)
|
||||
assertEquals(ShareType.USER, sharee.shareType)
|
||||
assertEquals("user2", sharee.shareWith)
|
||||
assertEquals("", sharee.additionalInfo)
|
||||
assertFalse(sharee.isExactMatch)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareeService(OC_ACCOUNT_NAME)
|
||||
ocShareeService.getSharees(searchString = "user", page = 1, perPage = 30)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharees returns a list of OCSharee when contains one remote user`() {
|
||||
sharees = ocRemoteShareesDataSource.getSharees(
|
||||
"user",
|
||||
1,
|
||||
30,
|
||||
OC_ACCOUNT_NAME,
|
||||
)
|
||||
val sharee = sharees[3]
|
||||
assertEquals("Remoteuser 1", sharee.label)
|
||||
assertEquals(ShareType.FEDERATED, sharee.shareType)
|
||||
assertEquals("remoteuser1", sharee.shareWith)
|
||||
assertEquals("user1@remote.com", sharee.additionalInfo)
|
||||
assertFalse(sharee.isExactMatch)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareeService(OC_ACCOUNT_NAME)
|
||||
ocShareeService.getSharees(searchString = "user", page = 1, perPage = 30)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharees returns a list of OCSharee when contains one group`() {
|
||||
sharees = ocRemoteShareesDataSource.getSharees(
|
||||
"user",
|
||||
1,
|
||||
30,
|
||||
OC_ACCOUNT_NAME,
|
||||
)
|
||||
|
||||
val sharee = sharees[4]
|
||||
assertEquals("Group 1", sharee.label)
|
||||
assertEquals(ShareType.GROUP, sharee.shareType)
|
||||
assertEquals("group1", sharee.shareWith)
|
||||
assertEquals("group@group.com", sharee.additionalInfo)
|
||||
assertFalse(sharee.isExactMatch)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareeService(OC_ACCOUNT_NAME)
|
||||
ocShareeService.getSharees(searchString = "user", page = 1, perPage = 30)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharees returns a list of OCSharee when handle empty response`() {
|
||||
|
||||
val getRemoteShareesOperationResult = createRemoteOperationResultMock(
|
||||
EMPTY_REMOTE_SHAREES,
|
||||
true
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareeService.getSharees(searchString = "user2", page = 2, perPage = 32)
|
||||
} returns getRemoteShareesOperationResult
|
||||
|
||||
val emptySharees = ocRemoteShareesDataSource.getSharees(
|
||||
"user2",
|
||||
2,
|
||||
32,
|
||||
OC_ACCOUNT_NAME,
|
||||
)
|
||||
|
||||
assertTrue(emptySharees.isEmpty())
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareeService(OC_ACCOUNT_NAME)
|
||||
ocShareeService.getSharees(searchString = "user2", page = 2, perPage = 32)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val REMOTE_SHAREES = ShareeOcsResponse(
|
||||
ExactSharees(
|
||||
arrayListOf(), arrayListOf(), arrayListOf(
|
||||
ShareeItem("User", ShareeValue(0, "user", "user@exact.com"))
|
||||
)
|
||||
),
|
||||
arrayListOf(
|
||||
ShareeItem("Group 1", ShareeValue(1, "group1", "group@group.com"))
|
||||
),
|
||||
arrayListOf(
|
||||
ShareeItem("Remoteuser 1", ShareeValue(6, "remoteuser1", "user1@remote.com"))
|
||||
),
|
||||
arrayListOf(
|
||||
ShareeItem("User 1", ShareeValue(0, "user1", "user1@mail.com")),
|
||||
ShareeItem("User 2", ShareeValue(0, "user2", null))
|
||||
)
|
||||
)
|
||||
|
||||
val EMPTY_REMOTE_SHAREES = ShareeOcsResponse(
|
||||
ExactSharees(arrayListOf(), arrayListOf(), arrayListOf()),
|
||||
arrayListOf(), arrayListOf(), arrayListOf()
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author David González Verdugo
|
||||
* @author Jorge Aguado Recio
|
||||
*
|
||||
* Copyright (C) 2024 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.sharing.sharees.repository
|
||||
|
||||
import eu.qsfera.android.data.sharing.sharees.datasources.RemoteShareeDataSource
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_SHAREE
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class OCShareeRepositoryTest {
|
||||
|
||||
private val remoteShareeDataSource = mockk<RemoteShareeDataSource>()
|
||||
private val ocShareeRepository = OCShareeRepository(remoteShareeDataSource)
|
||||
|
||||
@Test
|
||||
fun `getSharees returns a list of OCSharees`() {
|
||||
val searchString = "user"
|
||||
val requestedPage = 1
|
||||
val resultsPerPage = 30
|
||||
|
||||
every {
|
||||
remoteShareeDataSource.getSharees(searchString, requestedPage, resultsPerPage, OC_ACCOUNT_NAME)
|
||||
} returns listOf(OC_SHAREE)
|
||||
|
||||
val listOfSharees = ocShareeRepository.getSharees(searchString, requestedPage, resultsPerPage, OC_ACCOUNT_NAME)
|
||||
assertEquals(listOf(OC_SHAREE), listOfSharees)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteShareeDataSource.getSharees(searchString, requestedPage, resultsPerPage, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
+331
@@ -0,0 +1,331 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author David González Verdugo
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.sharing.shares.datasources.implementation
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import eu.qsfera.android.data.sharing.shares.datasources.implementation.OCLocalShareDataSource.Companion.toEntity
|
||||
import eu.qsfera.android.data.sharing.shares.datasources.implementation.OCLocalShareDataSource.Companion.toModel
|
||||
import eu.qsfera.android.data.sharing.shares.db.OCShareDao
|
||||
import eu.qsfera.android.data.sharing.shares.db.OCShareEntity
|
||||
import eu.qsfera.android.domain.sharing.shares.model.ShareType
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_PRIVATE_SHARE
|
||||
import eu.qsfera.android.testutil.OC_PUBLIC_SHARE
|
||||
import eu.qsfera.android.testutil.OC_SHARE
|
||||
import eu.qsfera.android.testutil.livedata.getLastEmittedValue
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class OCLocalShareDataSourceTest {
|
||||
private lateinit var ocLocalSharesDataSource: OCLocalShareDataSource
|
||||
private val ocSharesDao = mockk<OCShareDao>(relaxUnitFun = true)
|
||||
|
||||
private val privateShares = listOf(
|
||||
OC_PRIVATE_SHARE.copy(
|
||||
path = "/Docs/doc1.doc",
|
||||
shareWith = "username",
|
||||
sharedWithDisplayName = "Sophie"
|
||||
).toEntity(),
|
||||
OC_PRIVATE_SHARE.copy(
|
||||
path = "/Docs/doc1.doc",
|
||||
shareWith = "user.name",
|
||||
sharedWithDisplayName = "Nicole"
|
||||
).toEntity()
|
||||
)
|
||||
|
||||
private val privateShareTypes = listOf(ShareType.USER, ShareType.GROUP, ShareType.FEDERATED)
|
||||
|
||||
private val publicShares = listOf(
|
||||
OC_PUBLIC_SHARE.copy(
|
||||
path = "/Photos/",
|
||||
isFolder = true,
|
||||
name = "Photos link",
|
||||
shareLink = "http://server:port/s/1"
|
||||
).toEntity(),
|
||||
OC_PUBLIC_SHARE.copy(
|
||||
path = "/Photos/",
|
||||
isFolder = true,
|
||||
name = "Photos link 2",
|
||||
shareLink = "http://server:port/s/2"
|
||||
).toEntity()
|
||||
)
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val instantExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
|
||||
ocLocalSharesDataSource =
|
||||
OCLocalShareDataSource(
|
||||
ocSharesDao,
|
||||
)
|
||||
}
|
||||
|
||||
/******************************************************************************************************
|
||||
******************************************* PRIVATE SHARES *******************************************
|
||||
******************************************************************************************************/
|
||||
|
||||
@Test
|
||||
fun `getSharesAsLiveData returns a LiveData of a list of OCShare when read local private shares`() {
|
||||
val privateSharesAsLiveData: MutableLiveData<List<OCShareEntity>> = MutableLiveData()
|
||||
privateSharesAsLiveData.value = privateShares
|
||||
|
||||
every {
|
||||
ocSharesDao.getSharesAsLiveData(
|
||||
"/Docs/doc1.doc",
|
||||
"admin@server",
|
||||
privateShareTypes.map { it.value })
|
||||
} returns privateSharesAsLiveData
|
||||
|
||||
val shares =
|
||||
ocLocalSharesDataSource.getSharesAsLiveData(
|
||||
"/Docs/doc1.doc", "admin@server", privateShareTypes
|
||||
).getLastEmittedValue()!!
|
||||
|
||||
assertEquals(2, shares.size)
|
||||
|
||||
assertEquals("/Docs/doc1.doc", shares.first().path)
|
||||
assertEquals(false, shares.first().isFolder)
|
||||
assertEquals("username", shares.first().shareWith)
|
||||
assertEquals("Sophie", shares.first().sharedWithDisplayName)
|
||||
|
||||
assertEquals("/Docs/doc1.doc", shares[1].path)
|
||||
assertEquals(false, shares[1].isFolder)
|
||||
assertEquals("user.name", shares[1].shareWith)
|
||||
assertEquals("Nicole", shares[1].sharedWithDisplayName)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocSharesDao.getSharesAsLiveData(
|
||||
"/Docs/doc1.doc",
|
||||
"admin@server",
|
||||
privateShareTypes.map { it.value })
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getShareAsLiveData read local private share returns a OCShare`() {
|
||||
val privateShareAsLiveData: MutableLiveData<OCShareEntity> = MutableLiveData()
|
||||
privateShareAsLiveData.value = privateShares.first()
|
||||
|
||||
every { ocSharesDao.getShareAsLiveData(OC_SHARE.remoteId) } returns privateShareAsLiveData
|
||||
|
||||
val share = ocLocalSharesDataSource.getShareAsLiveData(OC_SHARE.remoteId).getLastEmittedValue()!!
|
||||
|
||||
assertEquals("/Docs/doc1.doc", share.path)
|
||||
assertEquals(false, share.isFolder)
|
||||
assertEquals("username", share.shareWith)
|
||||
assertEquals("Sophie", share.sharedWithDisplayName)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.getShareAsLiveData(OC_SHARE.remoteId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `insert private OCShare saves it correctly`() {
|
||||
every { ocSharesDao.insertOrReplace(privateShares[0]) } returns 10
|
||||
|
||||
val insertedShareId = ocLocalSharesDataSource.insert(
|
||||
OC_PRIVATE_SHARE.copy(
|
||||
path = "/Docs/doc1.doc",
|
||||
shareWith = "username",
|
||||
sharedWithDisplayName = "Sophie"
|
||||
)
|
||||
)
|
||||
assertEquals(10, insertedShareId)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.insertOrReplace(privateShares[0]) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `insert list of private OCShares saves it correctly`() {
|
||||
|
||||
val expectedValues = listOf<Long>(1, 2)
|
||||
every { ocSharesDao.insertOrReplace(privateShares) } returns expectedValues
|
||||
|
||||
val insertedSharesid = ocLocalSharesDataSource.insert(
|
||||
privateShares.map { it.toModel() }
|
||||
)
|
||||
|
||||
assertEquals(expectedValues, insertedSharesid)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.insertOrReplace(privateShares) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update private OCShare changes it correctly`() {
|
||||
every { ocSharesDao.update(privateShares[1]) } returns 3
|
||||
|
||||
val updatedShareId = ocLocalSharesDataSource.update(
|
||||
OC_PRIVATE_SHARE.copy(
|
||||
path = "/Docs/doc1.doc",
|
||||
shareWith = "user.name",
|
||||
sharedWithDisplayName = "Nicole"
|
||||
)
|
||||
)
|
||||
assertEquals(3, updatedShareId)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.update(privateShares[1]) }
|
||||
}
|
||||
|
||||
/******************************************************************************************************
|
||||
******************************************* PUBLIC SHARES ********************************************
|
||||
******************************************************************************************************/
|
||||
|
||||
@Test
|
||||
fun `getSharesAsLiveData returns a LiveData of a list of OCShare when read local public shares`() {
|
||||
val publicSharesAsLiveData: MutableLiveData<List<OCShareEntity>> = MutableLiveData()
|
||||
publicSharesAsLiveData.value = publicShares
|
||||
|
||||
every {
|
||||
ocSharesDao.getSharesAsLiveData(
|
||||
"/Photos/",
|
||||
"admin@server",
|
||||
listOf(ShareType.PUBLIC_LINK.value)
|
||||
)
|
||||
} returns publicSharesAsLiveData
|
||||
|
||||
val shares = ocLocalSharesDataSource.getSharesAsLiveData(
|
||||
"/Photos/",
|
||||
"admin@server",
|
||||
listOf(ShareType.PUBLIC_LINK)
|
||||
).getLastEmittedValue()!!
|
||||
|
||||
assertEquals(2, shares.size)
|
||||
|
||||
assertEquals("/Photos/", shares.first().path)
|
||||
assertEquals(true, shares.first().isFolder)
|
||||
assertEquals("Photos link", shares.first().name)
|
||||
assertEquals("http://server:port/s/1", shares.first().shareLink)
|
||||
|
||||
assertEquals("/Photos/", shares[1].path)
|
||||
assertEquals(true, shares[1].isFolder)
|
||||
assertEquals("Photos link 2", shares[1].name)
|
||||
assertEquals("http://server:port/s/2", shares[1].shareLink)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocSharesDao.getSharesAsLiveData(
|
||||
"/Photos/",
|
||||
"admin@server",
|
||||
listOf(ShareType.PUBLIC_LINK.value))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `insert public OCShare saves it correctly`() {
|
||||
every { ocSharesDao.insertOrReplace(publicShares[0]) } returns 7
|
||||
|
||||
val insertedShareId = ocLocalSharesDataSource.insert(
|
||||
OC_PUBLIC_SHARE.copy(
|
||||
path = "/Photos/",
|
||||
isFolder = true,
|
||||
name = "Photos link",
|
||||
shareLink = "http://server:port/s/1"
|
||||
)
|
||||
)
|
||||
assertEquals(7, insertedShareId)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.insertOrReplace(publicShares[0]) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `insert list of public OCShares saves it correctly`() {
|
||||
val expectedValues = listOf<Long>(1, 2)
|
||||
every { ocSharesDao.insertOrReplace(publicShares) } returns expectedValues
|
||||
|
||||
val retrievedValues = ocLocalSharesDataSource.insert(
|
||||
publicShares.map { it.toModel() }
|
||||
)
|
||||
|
||||
assertEquals(expectedValues, retrievedValues)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.insertOrReplace(publicShares) }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
fun `update public OCShare changes it correctly`() {
|
||||
every { ocSharesDao.update(publicShares[1]) } returns 8
|
||||
|
||||
val updatedShareId = ocLocalSharesDataSource.update(
|
||||
OC_PUBLIC_SHARE.copy(
|
||||
path = "/Photos/",
|
||||
isFolder = true,
|
||||
name = "Photos link 2",
|
||||
shareLink = "http://server:port/s/2"
|
||||
)
|
||||
)
|
||||
assertEquals(8, updatedShareId)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.update(publicShares[1]) }
|
||||
}
|
||||
|
||||
/**************************************************************************************************************
|
||||
*************************************************** COMMON ***************************************************
|
||||
**************************************************************************************************************/
|
||||
|
||||
@Test
|
||||
fun `replaceShares updates a list of OCShare correctly`() {
|
||||
val expectedValues = listOf<Long>(1, 2)
|
||||
every { ocSharesDao.replaceShares(publicShares) } returns expectedValues
|
||||
|
||||
val retrievedValues = ocLocalSharesDataSource.replaceShares(
|
||||
publicShares.map { it.toModel() }
|
||||
)
|
||||
|
||||
assertEquals(expectedValues, retrievedValues)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.replaceShares(publicShares) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteSharesForFile removes shares related to a file`() {
|
||||
ocLocalSharesDataSource.deleteSharesForFile("file", OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.deleteSharesForFile("file", OC_ACCOUNT_NAME) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteShare removes a share correctly`() {
|
||||
every { ocSharesDao.deleteShare(OC_SHARE.remoteId) } returns 1
|
||||
|
||||
val deletedRows = ocLocalSharesDataSource.deleteShare(OC_SHARE.remoteId)
|
||||
|
||||
assertEquals(1, deletedRows)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.deleteShare(OC_SHARE.remoteId) }
|
||||
}
|
||||
@Test
|
||||
fun `deleteSharesForAccount removes shares related to an account`() {
|
||||
|
||||
ocLocalSharesDataSource.deleteSharesForAccount(OC_SHARE.accountOwner)
|
||||
|
||||
verify(exactly = 1) { ocSharesDao.deleteSharesForAccount(OC_SHARE.accountOwner) }
|
||||
}
|
||||
}
|
||||
+491
@@ -0,0 +1,491 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author David González Verdugo
|
||||
* @author Jesús Recio
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.sharing.shares.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.ClientManager
|
||||
import eu.qsfera.android.data.sharing.shares.datasources.mapper.RemoteShareMapper
|
||||
import eu.qsfera.android.domain.exceptions.ShareForbiddenException
|
||||
import eu.qsfera.android.domain.exceptions.ShareNotFoundException
|
||||
import eu.qsfera.android.domain.sharing.shares.model.ShareType
|
||||
import eu.qsfera.android.lib.common.operations.RemoteOperationResult
|
||||
import eu.qsfera.android.lib.resources.shares.ShareResponse
|
||||
import eu.qsfera.android.lib.resources.shares.services.implementation.OCShareService
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_SHARE
|
||||
import eu.qsfera.android.utils.createRemoteOperationResultMock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteShareDataSourceTest {
|
||||
private lateinit var ocRemoteShareDataSource: OCRemoteShareDataSource
|
||||
|
||||
private val ocShareService: OCShareService = mockk()
|
||||
private val remoteShareMapper = RemoteShareMapper()
|
||||
private val clientManager: ClientManager = mockk(relaxed = true)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
every { clientManager.getShareService(any()) } returns ocShareService
|
||||
|
||||
ocRemoteShareDataSource = OCRemoteShareDataSource(clientManager, remoteShareMapper)
|
||||
}
|
||||
|
||||
/******************************************************************************************************
|
||||
******************************************* PRIVATE SHARES *******************************************
|
||||
******************************************************************************************************/
|
||||
|
||||
@Test
|
||||
fun `insert private share returns OCShare`() {
|
||||
val createRemoteShareOperationResult = createRemoteOperationResultMock(
|
||||
ShareResponse(
|
||||
listOf(
|
||||
remoteShareMapper.toRemote(
|
||||
OC_SHARE.copy(
|
||||
shareType = ShareType.USER,
|
||||
path = "Photos/",
|
||||
isFolder = true,
|
||||
shareWith = "user",
|
||||
sharedWithDisplayName = "User"
|
||||
)
|
||||
)!!
|
||||
)
|
||||
),
|
||||
true
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareService.insertShare(
|
||||
remoteFilePath = "Photos/",
|
||||
shareType = eu.qsfera.android.lib.resources.shares.ShareType.fromValue(ShareType.USER.value)!!,
|
||||
shareWith = "user",
|
||||
permissions = 1,
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDate = 0,
|
||||
)
|
||||
} returns createRemoteShareOperationResult
|
||||
|
||||
val privateShareAdded = ocRemoteShareDataSource.insert(
|
||||
remoteFilePath = "Photos/",
|
||||
shareType = ShareType.USER,
|
||||
shareWith = "user",
|
||||
permissions = 1,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
|
||||
assertEquals("Photos/", privateShareAdded.path)
|
||||
assertEquals(true, privateShareAdded.isFolder)
|
||||
assertEquals("user", privateShareAdded.shareWith)
|
||||
assertEquals("User", privateShareAdded.sharedWithDisplayName)
|
||||
assertEquals(1, privateShareAdded.permissions)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareService(OC_ACCOUNT_NAME)
|
||||
ocShareService.insertShare(
|
||||
remoteFilePath = "Photos/",
|
||||
shareType = eu.qsfera.android.lib.resources.shares.ShareType.fromValue(ShareType.USER.value)!!,
|
||||
shareWith = "user",
|
||||
permissions = 1,
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDate = 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateShare for private share returns OCShare`() {
|
||||
val updateRemoteShareOperationResult = createRemoteOperationResultMock(
|
||||
ShareResponse(
|
||||
listOf(
|
||||
remoteShareMapper.toRemote(
|
||||
OC_SHARE.copy(
|
||||
shareType = ShareType.USER,
|
||||
path = "Images/image_1.mp4",
|
||||
shareWith = "user",
|
||||
sharedWithDisplayName = "User",
|
||||
permissions = 17,
|
||||
remoteId = "3"
|
||||
)
|
||||
)!!
|
||||
)
|
||||
),
|
||||
true
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareService.updateShare(
|
||||
remoteId = "3",
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDate = 0,
|
||||
permissions = 17,
|
||||
)
|
||||
} returns updateRemoteShareOperationResult
|
||||
|
||||
val privateShareUpdated = ocRemoteShareDataSource.updateShare(
|
||||
remoteId = "3",
|
||||
permissions = 17,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
|
||||
assertEquals("Images/image_1.mp4", privateShareUpdated.path)
|
||||
assertEquals("user", privateShareUpdated.shareWith)
|
||||
assertEquals("User", privateShareUpdated.sharedWithDisplayName)
|
||||
assertEquals(17, privateShareUpdated.permissions)
|
||||
assertEquals(false, privateShareUpdated.isFolder)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareService(OC_ACCOUNT_NAME)
|
||||
ocShareService.updateShare(
|
||||
remoteId = "3",
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDate = 0,
|
||||
permissions = 17,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************************************
|
||||
******************************************* PUBLIC SHARES ********************************************
|
||||
******************************************************************************************************/
|
||||
|
||||
@Test
|
||||
fun `insert public share returns OCShare`() {
|
||||
val createRemoteShareOperationResult = createRemoteOperationResultMock(
|
||||
ShareResponse(
|
||||
listOf(
|
||||
remoteShareMapper.toRemote(
|
||||
OC_SHARE.copy(
|
||||
shareType = ShareType.PUBLIC_LINK,
|
||||
path = "Photos/img1.png",
|
||||
name = "img1 link",
|
||||
shareLink = "http://server:port/s/112ejbhdasyd1"
|
||||
)
|
||||
)!!
|
||||
)
|
||||
),
|
||||
true
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareService.insertShare(
|
||||
remoteFilePath = "Photos/img1.png",
|
||||
shareType = eu.qsfera.android.lib.resources.shares.ShareType.fromValue(ShareType.PUBLIC_LINK.value)!!,
|
||||
shareWith = "",
|
||||
permissions = 1,
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDate = 0
|
||||
)
|
||||
} returns createRemoteShareOperationResult
|
||||
|
||||
val publicShareAdded = ocRemoteShareDataSource.insert(
|
||||
"Photos/img1.png",
|
||||
ShareType.PUBLIC_LINK,
|
||||
"",
|
||||
1,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
|
||||
assertEquals("", publicShareAdded.shareWith)
|
||||
assertEquals(1, publicShareAdded.permissions)
|
||||
assertEquals("img1 link", publicShareAdded.name)
|
||||
assertEquals("Photos/img1.png", publicShareAdded.path)
|
||||
assertEquals(false, publicShareAdded.isFolder)
|
||||
assertEquals("http://server:port/s/112ejbhdasyd1", publicShareAdded.shareLink)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareService(OC_ACCOUNT_NAME)
|
||||
ocShareService.insertShare(
|
||||
remoteFilePath = "Photos/img1.png",
|
||||
shareType = eu.qsfera.android.lib.resources.shares.ShareType.fromValue(ShareType.PUBLIC_LINK.value)!!,
|
||||
shareWith = "",
|
||||
permissions = 1,
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDate = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateShare for public share returns OCShare`() {
|
||||
val updateRemoteShareOperationResult = createRemoteOperationResultMock(
|
||||
ShareResponse(
|
||||
listOf(
|
||||
remoteShareMapper.toRemote(
|
||||
OC_SHARE.copy(
|
||||
shareType = ShareType.PUBLIC_LINK,
|
||||
path = "Videos/video1.mp4",
|
||||
expirationDate = 2000,
|
||||
remoteId = "3",
|
||||
name = "video1 link updated",
|
||||
shareLink = "http://server:port/s/1275farv"
|
||||
)
|
||||
)!!
|
||||
)
|
||||
),
|
||||
true
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareService.updateShare(
|
||||
remoteId = "3",
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDate = 0,
|
||||
permissions = 17,
|
||||
)
|
||||
} returns updateRemoteShareOperationResult
|
||||
|
||||
val publicShareUpdated = ocRemoteShareDataSource.updateShare(
|
||||
remoteId = "3",
|
||||
permissions = 17,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
|
||||
assertEquals("video1 link updated", publicShareUpdated.name)
|
||||
assertEquals("Videos/video1.mp4", publicShareUpdated.path)
|
||||
assertEquals(false, publicShareUpdated.isFolder)
|
||||
assertEquals(2000, publicShareUpdated.expirationDate)
|
||||
assertEquals(1, publicShareUpdated.permissions)
|
||||
assertEquals("http://server:port/s/1275farv", publicShareUpdated.shareLink)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareService(OC_ACCOUNT_NAME)
|
||||
ocShareService.updateShare(
|
||||
remoteId = "3",
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDate = 0,
|
||||
permissions = 17,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************************************
|
||||
*********************************************** COMMON ***********************************************
|
||||
******************************************************************************************************/
|
||||
|
||||
@Test
|
||||
fun `getShares returns a list of OCShare`() {
|
||||
val remoteShares = listOf(
|
||||
remoteShareMapper.toRemote(
|
||||
OC_SHARE.copy(
|
||||
shareType = ShareType.PUBLIC_LINK,
|
||||
path = "/Documents/doc",
|
||||
name = "Doc link",
|
||||
shareLink = "http://server:port/s/1"
|
||||
)
|
||||
)!!,
|
||||
remoteShareMapper.toRemote(
|
||||
OC_SHARE.copy(
|
||||
shareType = ShareType.PUBLIC_LINK,
|
||||
path = "/Documents/doc",
|
||||
name = "Doc link 2",
|
||||
shareLink = "http://server:port/s/2"
|
||||
)
|
||||
)!!,
|
||||
remoteShareMapper.toRemote(
|
||||
OC_SHARE.copy(
|
||||
shareType = ShareType.USER,
|
||||
path = "/Documents/doc",
|
||||
shareWith = "steve",
|
||||
sharedWithDisplayName = "Steve"
|
||||
)
|
||||
)!!,
|
||||
remoteShareMapper.toRemote(
|
||||
OC_SHARE.copy(
|
||||
shareType = ShareType.GROUP,
|
||||
path = "/Documents/doc",
|
||||
shareWith = "family",
|
||||
sharedWithDisplayName = "My family"
|
||||
)
|
||||
)!!
|
||||
)
|
||||
|
||||
val getRemoteSharesOperationResult = createRemoteOperationResultMock(
|
||||
ShareResponse(remoteShares),
|
||||
true
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareService.getShares(any(), any(), any())
|
||||
} returns getRemoteSharesOperationResult
|
||||
|
||||
val shares = ocRemoteShareDataSource.getShares(
|
||||
remoteFilePath = "/Documents/doc",
|
||||
reshares = true,
|
||||
subfiles = true,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
|
||||
assertEquals(4, shares.size)
|
||||
|
||||
val publicShare1 = shares[0]
|
||||
assertEquals(ShareType.PUBLIC_LINK, publicShare1.shareType)
|
||||
assertEquals("/Documents/doc", publicShare1.path)
|
||||
assertEquals(false, publicShare1.isFolder)
|
||||
assertEquals("Doc link", publicShare1.name)
|
||||
assertEquals("http://server:port/s/1", publicShare1.shareLink)
|
||||
|
||||
val publicShare2 = shares[1]
|
||||
assertEquals(ShareType.PUBLIC_LINK, publicShare2.shareType)
|
||||
assertEquals("/Documents/doc", publicShare2.path)
|
||||
assertEquals(false, publicShare2.isFolder)
|
||||
assertEquals("Doc link 2", publicShare2.name)
|
||||
assertEquals("http://server:port/s/2", publicShare2.shareLink)
|
||||
|
||||
val userShare = shares[2]
|
||||
assertEquals(ShareType.USER, userShare.shareType)
|
||||
assertEquals("/Documents/doc", userShare.path)
|
||||
assertEquals(false, userShare.isFolder)
|
||||
assertEquals("steve", userShare.shareWith)
|
||||
assertEquals("Steve", userShare.sharedWithDisplayName)
|
||||
|
||||
val groupShare = shares[3]
|
||||
assertEquals(ShareType.GROUP, groupShare.shareType)
|
||||
assertEquals("/Documents/doc", groupShare.path)
|
||||
assertEquals(false, groupShare.isFolder)
|
||||
assertEquals("family", groupShare.shareWith)
|
||||
assertEquals("My family", groupShare.sharedWithDisplayName)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getShareService(OC_ACCOUNT_NAME)
|
||||
ocShareService.getShares(
|
||||
remoteFilePath = "/Documents/doc",
|
||||
reshares = true,
|
||||
subfiles = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = ShareNotFoundException::class)
|
||||
fun `insert throws a ShareNotFoundException when share is not found`() {
|
||||
insertShareOperationWithError(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND)
|
||||
}
|
||||
|
||||
@Test(expected = ShareForbiddenException::class)
|
||||
fun `insert throws a ShareForbiddenException when share is forbidden`() {
|
||||
insertShareOperationWithError(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN)
|
||||
}
|
||||
|
||||
private fun insertShareOperationWithError(resultCode: RemoteOperationResult.ResultCode? = null) {
|
||||
val createRemoteSharesOperationResult = createRemoteOperationResultMock(
|
||||
ShareResponse(arrayListOf()),
|
||||
false,
|
||||
null,
|
||||
resultCode
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareService.insertShare(any(), any(), any(), any(), any(), any(), any())
|
||||
} returns createRemoteSharesOperationResult
|
||||
|
||||
ocRemoteShareDataSource.insert(
|
||||
"Photos/img2.png",
|
||||
ShareType.PUBLIC_LINK,
|
||||
"",
|
||||
1,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
}
|
||||
|
||||
@Test(expected = ShareNotFoundException::class)
|
||||
fun `updateShare throws a ShareNotFoundException when share is not found`() {
|
||||
updateShareOperationWithError(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND)
|
||||
}
|
||||
|
||||
@Test(expected = ShareForbiddenException::class)
|
||||
fun `updateShare throws a ShareForbiddenException when share is forbidden`() {
|
||||
updateShareOperationWithError(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN)
|
||||
}
|
||||
|
||||
private fun updateShareOperationWithError(resultCode: RemoteOperationResult.ResultCode? = null) {
|
||||
val updateRemoteShareOperationResult = createRemoteOperationResultMock(
|
||||
ShareResponse(arrayListOf()),
|
||||
false,
|
||||
null,
|
||||
resultCode
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareService.updateShare(any(), any(), any(), any(), any())
|
||||
} returns updateRemoteShareOperationResult
|
||||
|
||||
ocRemoteShareDataSource.updateShare(
|
||||
"3",
|
||||
permissions = 17,
|
||||
accountName = "user@server"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteShare removes a share correctly`() {
|
||||
val removeRemoteShareOperationResult = createRemoteOperationResultMock(
|
||||
Unit,
|
||||
isSuccess = true
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareService.deleteShare(any())
|
||||
} returns removeRemoteShareOperationResult
|
||||
|
||||
ocRemoteShareDataSource.deleteShare(remoteId = "3", accountName = "user@server")
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocShareService.deleteShare(any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = ShareNotFoundException::class)
|
||||
fun `deleteShare throws ShareNotFoundException when share is not found`() {
|
||||
deleteShareOperationWithError(RemoteOperationResult.ResultCode.SHARE_NOT_FOUND)
|
||||
}
|
||||
|
||||
@Test(expected = ShareForbiddenException::class)
|
||||
fun `deleteShare throws ShareForbiddenException when share is forbidden`() {
|
||||
deleteShareOperationWithError(RemoteOperationResult.ResultCode.SHARE_FORBIDDEN)
|
||||
}
|
||||
|
||||
private fun deleteShareOperationWithError(resultCode: RemoteOperationResult.ResultCode? = null) {
|
||||
val removeRemoteShareOperationResult = createRemoteOperationResultMock(
|
||||
Unit,
|
||||
false,
|
||||
null,
|
||||
resultCode
|
||||
)
|
||||
|
||||
every {
|
||||
ocShareService.deleteShare(any())
|
||||
} returns removeRemoteShareOperationResult
|
||||
|
||||
ocRemoteShareDataSource.deleteShare(remoteId = "1", accountName = "user@server")
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.sharing.shares.datasources.mapper
|
||||
|
||||
import eu.qsfera.android.testutil.OC_SHARE
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Test
|
||||
|
||||
class RemoteShareMapperTest {
|
||||
|
||||
private val ocRemoteShareMapper = RemoteShareMapper()
|
||||
|
||||
@Test
|
||||
fun checkToModelNull() {
|
||||
assertNull(ocRemoteShareMapper.toModel(null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkToModelNotNull() {
|
||||
val remoteShare = ocRemoteShareMapper.toRemote(OC_SHARE)
|
||||
assertNotNull(remoteShare)
|
||||
|
||||
val share = ocRemoteShareMapper.toModel(remoteShare)
|
||||
assertNotNull(share)
|
||||
assertEquals(OC_SHARE, share)
|
||||
}
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.sharing.shares.db
|
||||
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Test
|
||||
|
||||
class OCShareEntityTest {
|
||||
|
||||
@Test
|
||||
fun testEqualsNamedParams() {
|
||||
val item1 = OCShareEntity(
|
||||
shareType = 0,
|
||||
shareWith = "",
|
||||
path = "/Photos/image2.jpg",
|
||||
permissions = 1,
|
||||
sharedDate = 1542628397,
|
||||
expirationDate = 0,
|
||||
token = "pwdasd12dasdWZ",
|
||||
sharedWithDisplayName = "",
|
||||
sharedWithAdditionalInfo = "",
|
||||
isFolder = false,
|
||||
remoteId = "remoteId",
|
||||
accountOwner = "admin@server",
|
||||
name = "",
|
||||
shareLink = ""
|
||||
)
|
||||
|
||||
val item2 = OCShareEntity(
|
||||
0,
|
||||
"",
|
||||
"/Photos/image2.jpg",
|
||||
1,
|
||||
1542628397,
|
||||
0,
|
||||
"pwdasd12dasdWZ",
|
||||
"",
|
||||
"",
|
||||
false,
|
||||
"remoteId",
|
||||
"admin@server",
|
||||
"",
|
||||
""
|
||||
)
|
||||
|
||||
// Autogenerate Id should differ but it is not generated at this moment
|
||||
// Tested on DAO
|
||||
assertTrue(item1 == item2)
|
||||
assertFalse(item1 === item2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEqualsNamedParamsNullValues() {
|
||||
val item1 = OCShareEntity(
|
||||
shareType = 0,
|
||||
shareWith = null,
|
||||
path = "/Photos/image2.jpg",
|
||||
permissions = 1,
|
||||
sharedDate = 1542628397,
|
||||
expirationDate = 0,
|
||||
token = null,
|
||||
sharedWithDisplayName = null,
|
||||
sharedWithAdditionalInfo = null,
|
||||
isFolder = false,
|
||||
remoteId = "remoteId",
|
||||
accountOwner = "admin@server",
|
||||
name = null,
|
||||
shareLink = null
|
||||
)
|
||||
|
||||
val item2 = OCShareEntity(
|
||||
0,
|
||||
null,
|
||||
"/Photos/image2.jpg",
|
||||
1,
|
||||
1542628397,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
"remoteId",
|
||||
"admin@server",
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
// Autogenerate Id should differ but it is not generated at this moment
|
||||
assertTrue(item1 == item2)
|
||||
assertFalse(item1 === item2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNotEqualsNamedParams() {
|
||||
val item1 = OCShareEntity(
|
||||
shareType = 0,
|
||||
shareWith = "",
|
||||
path = "/Photos/image2.jpg",
|
||||
permissions = 1,
|
||||
sharedDate = 1542628397,
|
||||
expirationDate = 0,
|
||||
token = "pwdasd12dasdWZ",
|
||||
sharedWithDisplayName = "",
|
||||
sharedWithAdditionalInfo = "",
|
||||
isFolder = false,
|
||||
remoteId = "remoteId",
|
||||
accountOwner = "admin@server",
|
||||
name = "",
|
||||
shareLink = ""
|
||||
)
|
||||
|
||||
val item2 = OCShareEntity(
|
||||
0,
|
||||
"",
|
||||
"/Photos/image2.jpg",
|
||||
1,
|
||||
1542628397,
|
||||
0,
|
||||
"pwdasd12dasdWZ",
|
||||
"",
|
||||
"",
|
||||
false,
|
||||
"remoteId",
|
||||
"AnyServer",
|
||||
"",
|
||||
""
|
||||
)
|
||||
|
||||
assertFalse(item1 == item2)
|
||||
assertFalse(item1 === item2)
|
||||
}
|
||||
}
|
||||
+313
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author David González Verdugo
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.sharing.shares.repository
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import eu.qsfera.android.data.sharing.shares.datasources.LocalShareDataSource
|
||||
import eu.qsfera.android.data.sharing.shares.datasources.RemoteShareDataSource
|
||||
import eu.qsfera.android.domain.sharing.shares.model.OCShare
|
||||
import eu.qsfera.android.domain.sharing.shares.model.ShareType
|
||||
import eu.qsfera.android.lib.resources.shares.RemoteShare
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_PRIVATE_SHARE
|
||||
import eu.qsfera.android.testutil.OC_PUBLIC_SHARE
|
||||
import eu.qsfera.android.testutil.OC_SHARE
|
||||
import eu.qsfera.android.testutil.OC_SHAREE
|
||||
import eu.qsfera.android.testutil.livedata.getLastEmittedValue
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class OCShareRepositoryTest {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val instantExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
private val localShareDataSource = mockk<LocalShareDataSource>(relaxUnitFun = true)
|
||||
private val remoteShareDataSource = mockk<RemoteShareDataSource>(relaxUnitFun = true)
|
||||
private val ocShareRepository = OCShareRepository(localShareDataSource, remoteShareDataSource)
|
||||
|
||||
private val listOfShares = listOf(OC_PRIVATE_SHARE, OC_PUBLIC_SHARE)
|
||||
private val filePath = OC_SHARE.path
|
||||
private val password = "password"
|
||||
private val permissions = OC_SHARE.permissions
|
||||
private val expiration = RemoteShare.INIT_EXPIRATION_DATE_IN_MILLIS
|
||||
|
||||
@Test
|
||||
fun `insertPrivateShare inserts a private OCShare correctly`() {
|
||||
every {
|
||||
remoteShareDataSource.insert(
|
||||
remoteFilePath = filePath,
|
||||
shareType = OC_PRIVATE_SHARE.shareType,
|
||||
shareWith = OC_SHAREE.shareWith,
|
||||
permissions = permissions,
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDate = expiration,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
} returns OC_PRIVATE_SHARE
|
||||
|
||||
// The result of this method is not used, so it can be anything
|
||||
every {
|
||||
localShareDataSource.insert(OC_PRIVATE_SHARE)
|
||||
} returns 1
|
||||
|
||||
ocShareRepository.insertPrivateShare(filePath, OC_PRIVATE_SHARE.shareType, OC_SHAREE.shareWith, permissions, OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteShareDataSource.insert(
|
||||
remoteFilePath = filePath,
|
||||
shareType = OC_PRIVATE_SHARE.shareType,
|
||||
shareWith = OC_SHAREE.shareWith,
|
||||
permissions = permissions,
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDate = expiration,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
localShareDataSource.insert(OC_PRIVATE_SHARE)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updatePrivateShare updates a private OCShare correctly`() {
|
||||
every {
|
||||
remoteShareDataSource.updateShare(
|
||||
remoteId = OC_PRIVATE_SHARE.remoteId,
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDateInMillis = expiration,
|
||||
permissions = permissions,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
} returns OC_PRIVATE_SHARE
|
||||
|
||||
// The result of this method is not used, so it can be anything
|
||||
every {
|
||||
localShareDataSource.update(OC_PRIVATE_SHARE)
|
||||
} returns 1
|
||||
|
||||
ocShareRepository.updatePrivateShare(OC_PRIVATE_SHARE.remoteId, permissions, OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteShareDataSource.updateShare(
|
||||
remoteId = OC_PRIVATE_SHARE.remoteId,
|
||||
name = "",
|
||||
password = "",
|
||||
expirationDateInMillis = expiration,
|
||||
permissions = permissions,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
localShareDataSource.update(OC_PRIVATE_SHARE)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `insertPublicShare inserts a public OCShare correctly`() {
|
||||
every {
|
||||
remoteShareDataSource.insert(
|
||||
remoteFilePath = filePath,
|
||||
shareType = OC_PUBLIC_SHARE.shareType,
|
||||
shareWith = "",
|
||||
permissions = permissions,
|
||||
name = OC_PUBLIC_SHARE.name!!,
|
||||
password = password,
|
||||
expirationDate = expiration,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
} returns OC_PUBLIC_SHARE
|
||||
|
||||
// The result of this method is not used, so it can be anything
|
||||
every {
|
||||
localShareDataSource.insert(OC_PUBLIC_SHARE)
|
||||
} returns 1
|
||||
|
||||
ocShareRepository.insertPublicShare(filePath, permissions, OC_PUBLIC_SHARE.name!!, password, expiration, OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteShareDataSource.insert(
|
||||
remoteFilePath = filePath,
|
||||
shareType = OC_PUBLIC_SHARE.shareType,
|
||||
shareWith = "",
|
||||
permissions = permissions,
|
||||
name = OC_PUBLIC_SHARE.name!!,
|
||||
password = password,
|
||||
expirationDate = expiration,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
localShareDataSource.insert(OC_PUBLIC_SHARE)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updatePublicShare updates a public OCShare correctly`() {
|
||||
every {
|
||||
remoteShareDataSource.updateShare(
|
||||
remoteId = OC_PUBLIC_SHARE.remoteId,
|
||||
name = OC_PUBLIC_SHARE.name!!,
|
||||
password = password,
|
||||
expirationDateInMillis = expiration,
|
||||
permissions = permissions,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
} returns OC_PUBLIC_SHARE
|
||||
|
||||
// The result of this method is not used, so it can be anything
|
||||
every {
|
||||
localShareDataSource.update(OC_PUBLIC_SHARE)
|
||||
} returns 1
|
||||
|
||||
ocShareRepository.updatePublicShare(OC_PUBLIC_SHARE.remoteId, OC_PUBLIC_SHARE.name!!, password, expiration, permissions, OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteShareDataSource.updateShare(
|
||||
remoteId = OC_PUBLIC_SHARE.remoteId,
|
||||
name = OC_PUBLIC_SHARE.name!!,
|
||||
password = password,
|
||||
expirationDateInMillis = expiration,
|
||||
permissions = permissions,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
localShareDataSource.update(OC_PUBLIC_SHARE)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharesAsLiveData returns a LiveData with a list of OCShares`() {
|
||||
val sharesLiveDataList: LiveData<List<OCShare>> = MutableLiveData(listOf(OC_SHARE))
|
||||
|
||||
every {
|
||||
localShareDataSource.getSharesAsLiveData(
|
||||
filePath = filePath,
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
shareTypes = listOf(ShareType.PUBLIC_LINK, ShareType.USER, ShareType.GROUP, ShareType.FEDERATED)
|
||||
)
|
||||
} returns sharesLiveDataList
|
||||
|
||||
val sharesResult = ocShareRepository.getSharesAsLiveData(filePath, OC_ACCOUNT_NAME).getLastEmittedValue()!!
|
||||
assertEquals(1, sharesResult.size)
|
||||
assertEquals(OC_SHARE, sharesResult.first())
|
||||
|
||||
verify(exactly = 1) {
|
||||
localShareDataSource.getSharesAsLiveData(
|
||||
filePath = filePath,
|
||||
accountName = OC_ACCOUNT_NAME,
|
||||
shareTypes = listOf(ShareType.PUBLIC_LINK, ShareType.USER, ShareType.GROUP, ShareType.FEDERATED)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getShareAsLiveData returns a LiveData with an OCShare`() {
|
||||
val shareAsLiveData: LiveData<OCShare> = MutableLiveData(OC_SHARE)
|
||||
|
||||
every {
|
||||
localShareDataSource.getShareAsLiveData(OC_SHARE.remoteId)
|
||||
} returns shareAsLiveData
|
||||
|
||||
val shareResult = ocShareRepository.getShareAsLiveData(OC_SHARE.remoteId).getLastEmittedValue()!!
|
||||
assertEquals(OC_SHARE, shareResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localShareDataSource.getShareAsLiveData(OC_SHARE.remoteId)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refreshSharesFromNetwork refreshes shares correctly when the list of shares received is not empty`() {
|
||||
every {
|
||||
remoteShareDataSource.getShares(
|
||||
remoteFilePath = filePath,
|
||||
reshares = true,
|
||||
subfiles = false,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
} returns listOfShares
|
||||
|
||||
// The result of this method is not used, so it can be anything
|
||||
every {
|
||||
localShareDataSource.replaceShares(listOfShares)
|
||||
} returns listOf(1, 1)
|
||||
|
||||
ocShareRepository.refreshSharesFromNetwork(filePath, OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteShareDataSource.getShares(
|
||||
remoteFilePath = filePath,
|
||||
reshares = true,
|
||||
subfiles = false,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
localShareDataSource.replaceShares(listOfShares)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refreshSharesFromNetwork deletes local shares and refreshes shares correctly when the list of shares received is empty`() {
|
||||
every {
|
||||
remoteShareDataSource.getShares(
|
||||
remoteFilePath = filePath,
|
||||
reshares = true,
|
||||
subfiles = false,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
} returns emptyList()
|
||||
|
||||
every {
|
||||
localShareDataSource.replaceShares(emptyList())
|
||||
} returns emptyList()
|
||||
|
||||
ocShareRepository.refreshSharesFromNetwork(filePath, OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteShareDataSource.getShares(
|
||||
remoteFilePath = filePath,
|
||||
reshares = true,
|
||||
subfiles = false,
|
||||
accountName = OC_ACCOUNT_NAME
|
||||
)
|
||||
localShareDataSource.deleteSharesForFile(filePath, OC_ACCOUNT_NAME)
|
||||
localShareDataSource.replaceShares(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteShare deletes a share correctly`() {
|
||||
// The result of this method is not used, so it can be anything
|
||||
every {
|
||||
localShareDataSource.deleteShare(OC_SHARE.remoteId)
|
||||
} returns 1
|
||||
|
||||
ocShareRepository.deleteShare(OC_SHARE.remoteId, OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteShareDataSource.deleteShare(OC_SHARE.remoteId, OC_ACCOUNT_NAME)
|
||||
localShareDataSource.deleteShare(OC_SHARE.remoteId)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.spaces.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.spaces.datasources.implementation.OCLocalSpacesDataSource.Companion.toEntity
|
||||
import eu.qsfera.android.data.spaces.datasources.implementation.OCLocalSpacesDataSource.Companion.toModel
|
||||
import eu.qsfera.android.data.spaces.db.SpaceSpecialEntity
|
||||
import eu.qsfera.android.data.spaces.db.SpacesDao
|
||||
import eu.qsfera.android.data.spaces.db.SpacesEntity
|
||||
import eu.qsfera.android.domain.spaces.model.OCSpace
|
||||
import eu.qsfera.android.domain.spaces.model.OCSpace.Companion.SPACE_ID_SHARES
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_SPACE_PERSONAL
|
||||
import eu.qsfera.android.testutil.OC_SPACE_PROJECT_WITH_IMAGE
|
||||
import eu.qsfera.android.testutil.SPACE_ENTITY_SHARE
|
||||
import eu.qsfera.android.testutil.SPACE_ENTITY_WITH_SPECIALS
|
||||
import eu.qsfera.android.testutil.WEB_DAV_URL
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCLocalSpacesDataSourceTest {
|
||||
|
||||
private lateinit var ocLocalSpacesDataSource: OCLocalSpacesDataSource
|
||||
private val spacesDao = mockk<SpacesDao>()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
ocLocalSpacesDataSource = OCLocalSpacesDataSource(spacesDao)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveSpacesForAccount inserts spaces and special spaces correctly`() {
|
||||
val spaceEntities = mutableListOf<SpacesEntity>()
|
||||
val spaceSpecialEntities = mutableListOf<SpaceSpecialEntity>()
|
||||
|
||||
listOf(OC_SPACE_PROJECT_WITH_IMAGE).forEach { spaceModel ->
|
||||
spaceEntities.add(spaceModel.toEntity())
|
||||
spaceModel.special?.let { listOfSpacesSpecials ->
|
||||
spaceSpecialEntities.addAll(listOfSpacesSpecials.map { it.toEntity(spaceModel.accountName, spaceModel.id) })
|
||||
}
|
||||
}
|
||||
|
||||
every {
|
||||
spacesDao.insertOrDeleteSpaces(any(), any())
|
||||
} just Runs
|
||||
|
||||
ocLocalSpacesDataSource.saveSpacesForAccount(listOf(OC_SPACE_PROJECT_WITH_IMAGE))
|
||||
|
||||
verify(exactly = 1) {
|
||||
spacesDao.insertOrDeleteSpaces(spaceEntities, spaceSpecialEntities)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPersonalSpaceForAccount by drive type returns a OCSpace`() {
|
||||
every {
|
||||
spacesDao.getSpacesByDriveTypeForAccount(any(), any())
|
||||
} returns listOf(OC_SPACE_PERSONAL.toEntity())
|
||||
|
||||
val resultActual = ocLocalSpacesDataSource.getPersonalSpaceForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(OC_SPACE_PERSONAL, resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
spacesDao.getSpacesByDriveTypeForAccount(OC_ACCOUNT_NAME, setOf(OCSpace.DRIVE_TYPE_PERSONAL))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSharesSpaceForAccount returns a OCSpace`() {
|
||||
every {
|
||||
spacesDao.getSpaceByIdForAccount(SPACE_ID_SHARES, OC_ACCOUNT_NAME)
|
||||
} returns SPACE_ENTITY_SHARE.space
|
||||
|
||||
val resultActual = ocLocalSpacesDataSource.getSharesSpaceForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(SPACE_ENTITY_SHARE.space.toModel(), resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
spacesDao.getSpaceByIdForAccount(SPACE_ID_SHARES, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSpacesFromEveryAccountAsStream returns a Flow with a list of OCSpace`() = runBlocking {
|
||||
|
||||
every {
|
||||
spacesDao.getSpacesByDriveTypeFromEveryAccountAsStream(
|
||||
setOf(
|
||||
OCSpace.DRIVE_TYPE_PERSONAL,
|
||||
OCSpace.DRIVE_TYPE_PROJECT
|
||||
)
|
||||
)
|
||||
} returns flowOf(listOf(OC_SPACE_PERSONAL.toEntity()))
|
||||
|
||||
val resultActual = ocLocalSpacesDataSource.getSpacesFromEveryAccountAsStream().first()
|
||||
|
||||
assertEquals(listOf(OC_SPACE_PERSONAL), resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
spacesDao.getSpacesByDriveTypeFromEveryAccountAsStream(
|
||||
setOf(
|
||||
OCSpace.DRIVE_TYPE_PERSONAL,
|
||||
OCSpace.DRIVE_TYPE_PROJECT
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSpacesByDriveTypeWithSpecialsForAccountAsFlow returns a Flow with a list of OCSpace`() = runBlocking {
|
||||
|
||||
every {
|
||||
spacesDao.getSpacesByDriveTypeWithSpecialsForAccountAsFlow(
|
||||
OC_ACCOUNT_NAME,
|
||||
setOf(
|
||||
OCSpace.DRIVE_TYPE_PERSONAL,
|
||||
OCSpace.DRIVE_TYPE_PROJECT
|
||||
)
|
||||
)
|
||||
} returns flowOf(listOf(SPACE_ENTITY_WITH_SPECIALS))
|
||||
|
||||
val resultActual = ocLocalSpacesDataSource.getSpacesByDriveTypeWithSpecialsForAccountAsFlow(
|
||||
OC_ACCOUNT_NAME, setOf(
|
||||
OCSpace.DRIVE_TYPE_PERSONAL,
|
||||
OCSpace.DRIVE_TYPE_PROJECT
|
||||
)
|
||||
)
|
||||
|
||||
val result = resultActual.first()
|
||||
assertEquals(listOf(SPACE_ENTITY_WITH_SPECIALS.toModel()), result)
|
||||
|
||||
|
||||
verify(exactly = 1) {
|
||||
spacesDao.getSpacesByDriveTypeWithSpecialsForAccountAsFlow(
|
||||
OC_ACCOUNT_NAME,
|
||||
setOf(
|
||||
OCSpace.DRIVE_TYPE_PERSONAL,
|
||||
OCSpace.DRIVE_TYPE_PROJECT
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPersonalAndProjectSpacesForAccount returns a list of OCSpace`() {
|
||||
|
||||
every {
|
||||
spacesDao.getSpacesByDriveTypeForAccount(
|
||||
OC_ACCOUNT_NAME,
|
||||
setOf(
|
||||
OCSpace.DRIVE_TYPE_PERSONAL,
|
||||
OCSpace.DRIVE_TYPE_PROJECT
|
||||
)
|
||||
)
|
||||
} returns listOf(OC_SPACE_PERSONAL.toEntity())
|
||||
|
||||
val resultActual = ocLocalSpacesDataSource.getPersonalAndProjectSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(listOf(OC_SPACE_PERSONAL), resultActual)
|
||||
|
||||
|
||||
verify(exactly = 1) {
|
||||
spacesDao.getSpacesByDriveTypeForAccount(
|
||||
OC_ACCOUNT_NAME,
|
||||
setOf(
|
||||
OCSpace.DRIVE_TYPE_PERSONAL,
|
||||
OCSpace.DRIVE_TYPE_PROJECT
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSpaceWithSpecialsByIdForAccount returns a OCSpace`() {
|
||||
|
||||
every {
|
||||
spacesDao.getSpaceWithSpecialsByIdForAccount(OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME)
|
||||
} returns SPACE_ENTITY_WITH_SPECIALS
|
||||
|
||||
val resultActual = ocLocalSpacesDataSource.getSpaceWithSpecialsByIdForAccount(OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(SPACE_ENTITY_WITH_SPECIALS.toModel(), resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
spacesDao.getSpaceWithSpecialsByIdForAccount(
|
||||
OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSpaceByIdForAccount returns a OCSpace`() {
|
||||
|
||||
every {
|
||||
spacesDao.getSpaceByIdForAccount(OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME)
|
||||
} returns OC_SPACE_PERSONAL.toEntity()
|
||||
|
||||
val result = ocLocalSpacesDataSource.getSpaceByIdForAccount(OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(OC_SPACE_PERSONAL, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
spacesDao.getSpaceByIdForAccount(OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getWebDavUrlForSpace returns a String of webDavUrl`() {
|
||||
|
||||
every {
|
||||
spacesDao.getWebDavUrlForSpace(OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME)
|
||||
} returns WEB_DAV_URL
|
||||
|
||||
val resultActual = ocLocalSpacesDataSource.getWebDavUrlForSpace(OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(WEB_DAV_URL, resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
spacesDao.getWebDavUrlForSpace(
|
||||
OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteSpacesForAccount removes the spaces for an account correctly`() {
|
||||
|
||||
every {
|
||||
spacesDao.deleteSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns Unit
|
||||
|
||||
ocLocalSpacesDataSource.deleteSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
spacesDao.deleteSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Aitor Ballesteros Pavón
|
||||
* @author Juan Carlos Garrote Gascón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.spaces.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.ClientManager
|
||||
import eu.qsfera.android.data.spaces.datasources.implementation.OCRemoteSpacesDataSource.Companion.toModel
|
||||
import eu.qsfera.android.lib.resources.spaces.services.OCSpacesService
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.SPACE_RESPONSE
|
||||
import eu.qsfera.android.utils.createRemoteOperationResultMock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteSpacesDataSourceTest {
|
||||
|
||||
private lateinit var ocRemoteSpacesDataSource: OCRemoteSpacesDataSource
|
||||
|
||||
private val ocSpaceService: OCSpacesService = mockk()
|
||||
private val clientManager: ClientManager = mockk(relaxed = true)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
ocRemoteSpacesDataSource = OCRemoteSpacesDataSource(clientManager)
|
||||
every { clientManager.getSpacesService(OC_ACCOUNT_NAME) } returns ocSpaceService
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refreshSpacesForAccount returns a list of OCSpace`() {
|
||||
val getRemoteSpacesOperationResult = createRemoteOperationResultMock(
|
||||
listOf(SPACE_RESPONSE), isSuccess = true
|
||||
)
|
||||
|
||||
every { ocSpaceService.getSpaces() } returns getRemoteSpacesOperationResult
|
||||
|
||||
val resultActual = ocRemoteSpacesDataSource.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(listOf(SPACE_RESPONSE.toModel(OC_ACCOUNT_NAME)), resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getSpacesService(OC_ACCOUNT_NAME)
|
||||
ocSpaceService.getSpaces()
|
||||
}
|
||||
}
|
||||
}
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Jorge Aguado Recio
|
||||
*
|
||||
* Copyright (C) 2025 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.spaces.repository
|
||||
|
||||
import eu.qsfera.android.data.capabilities.datasources.LocalCapabilitiesDataSource
|
||||
import eu.qsfera.android.data.spaces.datasources.LocalSpacesDataSource
|
||||
import eu.qsfera.android.data.spaces.datasources.RemoteSpacesDataSource
|
||||
import eu.qsfera.android.data.user.datasources.LocalUserDataSource
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_CAPABILITY
|
||||
import eu.qsfera.android.testutil.OC_CAPABILITY_WITH_MULTIPERSONAL_ENABLED
|
||||
import eu.qsfera.android.testutil.OC_SPACE_PERSONAL
|
||||
import eu.qsfera.android.testutil.OC_SPACE_PERSONAL_WITH_LIMITED_QUOTA
|
||||
import eu.qsfera.android.testutil.OC_SPACE_PERSONAL_WITH_UNLIMITED_QUOTA
|
||||
import eu.qsfera.android.testutil.OC_SPACE_PROJECT_WITH_IMAGE
|
||||
import eu.qsfera.android.testutil.OC_USER_QUOTA_LIMITED
|
||||
import eu.qsfera.android.testutil.OC_USER_QUOTA_UNLIMITED
|
||||
import eu.qsfera.android.testutil.OC_USER_QUOTA_WITHOUT_PERSONAL
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class OCSpacesRepositoryTest {
|
||||
|
||||
private val localSpacesDataSource = mockk<LocalSpacesDataSource>(relaxUnitFun = true)
|
||||
private val localUserDataSource = mockk<LocalUserDataSource>(relaxUnitFun = true)
|
||||
private val remoteSpacesDataSource = mockk<RemoteSpacesDataSource>()
|
||||
private val localCapabilitiesDataSource = mockk<LocalCapabilitiesDataSource>(relaxUnitFun = true)
|
||||
private val ocSpacesRepository = OCSpacesRepository(localSpacesDataSource, localUserDataSource, remoteSpacesDataSource,
|
||||
localCapabilitiesDataSource)
|
||||
|
||||
@Test
|
||||
fun `refreshSpacesForAccount refreshes spaces for account correctly when multipersonal is enabled`() {
|
||||
every {
|
||||
remoteSpacesDataSource.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns listOf(OC_SPACE_PERSONAL)
|
||||
|
||||
every {
|
||||
localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns OC_CAPABILITY_WITH_MULTIPERSONAL_ENABLED
|
||||
|
||||
ocSpacesRepository.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteSpacesDataSource.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
localSpacesDataSource.saveSpacesForAccount(listOf(OC_SPACE_PERSONAL))
|
||||
localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
localUserDataSource.saveQuotaForAccount(OC_ACCOUNT_NAME, OC_USER_QUOTA_WITHOUT_PERSONAL)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refreshSpacesForAccount refreshes spaces for account correctly when quota is unlimited`() {
|
||||
every {
|
||||
remoteSpacesDataSource.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns listOf(OC_SPACE_PERSONAL_WITH_UNLIMITED_QUOTA)
|
||||
|
||||
every {
|
||||
localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns OC_CAPABILITY
|
||||
|
||||
ocSpacesRepository.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteSpacesDataSource.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
localSpacesDataSource.saveSpacesForAccount(listOf(OC_SPACE_PERSONAL_WITH_UNLIMITED_QUOTA))
|
||||
localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
localUserDataSource.saveQuotaForAccount(OC_ACCOUNT_NAME, OC_USER_QUOTA_UNLIMITED)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refreshSpacesForAccount refreshes spaces for account correctly when quota is limited`() {
|
||||
every {
|
||||
remoteSpacesDataSource.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns listOf(OC_SPACE_PERSONAL_WITH_LIMITED_QUOTA)
|
||||
|
||||
every {
|
||||
localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns OC_CAPABILITY
|
||||
|
||||
ocSpacesRepository.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteSpacesDataSource.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
localSpacesDataSource.saveSpacesForAccount(listOf(OC_SPACE_PERSONAL_WITH_LIMITED_QUOTA))
|
||||
localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
localUserDataSource.saveQuotaForAccount(OC_ACCOUNT_NAME, OC_USER_QUOTA_LIMITED)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refreshSpacesForAccount refreshes spaces for account correctly when personal space does not exist`() {
|
||||
every {
|
||||
remoteSpacesDataSource.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns listOf(OC_SPACE_PROJECT_WITH_IMAGE)
|
||||
|
||||
every {
|
||||
localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns OC_CAPABILITY
|
||||
|
||||
ocSpacesRepository.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteSpacesDataSource.refreshSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
localSpacesDataSource.saveSpacesForAccount(listOf(OC_SPACE_PROJECT_WITH_IMAGE))
|
||||
localCapabilitiesDataSource.getCapabilitiesForAccount(OC_ACCOUNT_NAME)
|
||||
localUserDataSource.saveQuotaForAccount(OC_ACCOUNT_NAME, OC_USER_QUOTA_WITHOUT_PERSONAL)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSpacesFromEveryAccountAsStream returns a Flow with a list of OCSpace`() = runTest {
|
||||
every {
|
||||
localSpacesDataSource.getSpacesFromEveryAccountAsStream()
|
||||
} returns flowOf(listOf(OC_SPACE_PROJECT_WITH_IMAGE))
|
||||
|
||||
val listOfSpaces = ocSpacesRepository.getSpacesFromEveryAccountAsStream().first()
|
||||
assertEquals(listOf(OC_SPACE_PROJECT_WITH_IMAGE), listOfSpaces)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localSpacesDataSource.getSpacesFromEveryAccountAsStream()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSpacesByDriveTypeWithSpecialsForAccountAsFlow returns a Flow with a list of OCSpace`() = runTest {
|
||||
every {
|
||||
localSpacesDataSource.getSpacesByDriveTypeWithSpecialsForAccountAsFlow(OC_ACCOUNT_NAME, setOf(OC_SPACE_PROJECT_WITH_IMAGE.driveType))
|
||||
} returns flowOf(listOf(OC_SPACE_PROJECT_WITH_IMAGE))
|
||||
|
||||
val listOfSpaces = ocSpacesRepository.getSpacesByDriveTypeWithSpecialsForAccountAsFlow(OC_ACCOUNT_NAME,
|
||||
setOf(OC_SPACE_PROJECT_WITH_IMAGE.driveType)).first()
|
||||
assertEquals(listOf(OC_SPACE_PROJECT_WITH_IMAGE), listOfSpaces)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localSpacesDataSource.getSpacesByDriveTypeWithSpecialsForAccountAsFlow(OC_ACCOUNT_NAME, setOf(OC_SPACE_PROJECT_WITH_IMAGE.driveType))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPersonalSpaceForAccount returns an OCSpace`() {
|
||||
every {
|
||||
localSpacesDataSource.getPersonalSpaceForAccount(OC_ACCOUNT_NAME)
|
||||
} returns OC_SPACE_PERSONAL
|
||||
|
||||
val personalSpace = ocSpacesRepository.getPersonalSpaceForAccount(OC_ACCOUNT_NAME)
|
||||
assertEquals(OC_SPACE_PERSONAL, personalSpace)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localSpacesDataSource.getPersonalSpaceForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPersonalSpaceForAccount returns null when local datasource returns a null personal space`() {
|
||||
every {
|
||||
localSpacesDataSource.getPersonalSpaceForAccount(OC_ACCOUNT_NAME)
|
||||
} returns null
|
||||
|
||||
val personalSpace = ocSpacesRepository.getPersonalSpaceForAccount(OC_ACCOUNT_NAME)
|
||||
assertNull(personalSpace)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localSpacesDataSource.getPersonalSpaceForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getPersonalAndProjectSpacesForAccount returns a list of OCSpace`() {
|
||||
every {
|
||||
localSpacesDataSource.getPersonalAndProjectSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
} returns listOf(OC_SPACE_PERSONAL, OC_SPACE_PROJECT_WITH_IMAGE)
|
||||
|
||||
val listOfSpaces = ocSpacesRepository.getPersonalAndProjectSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
assertEquals(listOf(OC_SPACE_PERSONAL, OC_SPACE_PROJECT_WITH_IMAGE), listOfSpaces)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localSpacesDataSource.getPersonalAndProjectSpacesForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSpaceWithSpecialsByIdForAccount returns an OCSpace`() {
|
||||
every {
|
||||
localSpacesDataSource.getSpaceWithSpecialsByIdForAccount(OC_SPACE_PROJECT_WITH_IMAGE.id, OC_ACCOUNT_NAME)
|
||||
} returns OC_SPACE_PROJECT_WITH_IMAGE
|
||||
|
||||
val spaceWithSpecials = ocSpacesRepository.getSpaceWithSpecialsByIdForAccount(OC_SPACE_PROJECT_WITH_IMAGE.id, OC_ACCOUNT_NAME)
|
||||
assertEquals(OC_SPACE_PROJECT_WITH_IMAGE, spaceWithSpecials)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localSpacesDataSource.getSpaceWithSpecialsByIdForAccount(OC_SPACE_PROJECT_WITH_IMAGE.id, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSpaceByIdForAccount returns an OCSpace`() {
|
||||
every {
|
||||
localSpacesDataSource.getSpaceByIdForAccount(OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME)
|
||||
} returns OC_SPACE_PERSONAL
|
||||
|
||||
val space = ocSpacesRepository.getSpaceByIdForAccount(OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME)
|
||||
assertEquals(OC_SPACE_PERSONAL, space)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localSpacesDataSource.getSpaceByIdForAccount(OC_SPACE_PERSONAL.id, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getSpaceByIdForAccount returns null when local datasource returns a null space`() {
|
||||
every {
|
||||
localSpacesDataSource.getSpaceByIdForAccount(OC_SPACE_PROJECT_WITH_IMAGE.id, OC_ACCOUNT_NAME)
|
||||
} returns null
|
||||
|
||||
val space = ocSpacesRepository.getSpaceByIdForAccount(OC_SPACE_PROJECT_WITH_IMAGE.id, OC_ACCOUNT_NAME)
|
||||
assertNull(space)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localSpacesDataSource.getSpaceByIdForAccount(OC_SPACE_PROJECT_WITH_IMAGE.id, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getWebDavUrlForSpace returns a String of webdav url`() {
|
||||
every {
|
||||
localSpacesDataSource.getWebDavUrlForSpace(OC_SPACE_PROJECT_WITH_IMAGE.id, OC_ACCOUNT_NAME)
|
||||
} returns OC_SPACE_PROJECT_WITH_IMAGE.webUrl
|
||||
|
||||
val webDavUrl = ocSpacesRepository.getWebDavUrlForSpace(OC_ACCOUNT_NAME, OC_SPACE_PROJECT_WITH_IMAGE.id)
|
||||
assertEquals(OC_SPACE_PROJECT_WITH_IMAGE.webUrl, webDavUrl)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localSpacesDataSource.getWebDavUrlForSpace(OC_SPACE_PROJECT_WITH_IMAGE.id, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getWebDavUrlForSpace returns null when local datasource returns null`() {
|
||||
every {
|
||||
localSpacesDataSource.getWebDavUrlForSpace(OC_SPACE_PROJECT_WITH_IMAGE.id, OC_ACCOUNT_NAME)
|
||||
} returns null
|
||||
|
||||
val webDavUrl = ocSpacesRepository.getWebDavUrlForSpace(OC_ACCOUNT_NAME, OC_SPACE_PROJECT_WITH_IMAGE.id)
|
||||
assertNull(webDavUrl)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localSpacesDataSource.getWebDavUrlForSpace(OC_SPACE_PROJECT_WITH_IMAGE.id, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.transfers.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.transfers.datasources.implementation.OCLocalTransferDataSource.Companion.toEntity
|
||||
import eu.qsfera.android.data.transfers.datasources.implementation.OCLocalTransferDataSource.Companion.toModel
|
||||
import eu.qsfera.android.data.transfers.db.OCTransferEntity
|
||||
import eu.qsfera.android.data.transfers.db.TransferDao
|
||||
import eu.qsfera.android.domain.transfers.model.TransferResult
|
||||
import eu.qsfera.android.domain.transfers.model.TransferStatus
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_TRANSFER
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCLocalTransferDataSourceTest {
|
||||
private lateinit var ocLocalTransferDataSource: OCLocalTransferDataSource
|
||||
private val transferDao = mockk<TransferDao>(relaxUnitFun = true)
|
||||
|
||||
private var transferEntity: OCTransferEntity = OC_TRANSFER.toEntity()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
ocLocalTransferDataSource = OCLocalTransferDataSource(transferDao)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveTransfer inserts a transfer correctly`() {
|
||||
val resultExpected = 1L
|
||||
every {
|
||||
transferDao.insertOrReplace(any())
|
||||
} returns resultExpected
|
||||
|
||||
val resultActual = ocLocalTransferDataSource.saveTransfer(OC_TRANSFER)
|
||||
|
||||
assertEquals(resultExpected, resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.insertOrReplace(OC_TRANSFER.toEntity())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransfer updates the transfer correctly`() {
|
||||
val resultExpected = 1L
|
||||
every {
|
||||
transferDao.insertOrReplace(any())
|
||||
} returns resultExpected
|
||||
|
||||
ocLocalTransferDataSource.updateTransfer(OC_TRANSFER)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.insertOrReplace(OC_TRANSFER.toEntity())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferStatusToInProgressById changes transfer status correctly`() {
|
||||
val resultExpected = 10L
|
||||
|
||||
ocLocalTransferDataSource.updateTransferStatusToInProgressById(resultExpected)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.updateTransferStatusWithId(resultExpected, TransferStatus.TRANSFER_IN_PROGRESS.value)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferStatusToEnqueuedById changes transfer status correctly`() {
|
||||
val resultExpected = 10L
|
||||
|
||||
ocLocalTransferDataSource.updateTransferStatusToEnqueuedById(resultExpected)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.updateTransferStatusWithId(resultExpected, TransferStatus.TRANSFER_QUEUED.value)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferWhenFinished changes transfer status correctly`() {
|
||||
val timestamp = System.currentTimeMillis()
|
||||
|
||||
ocLocalTransferDataSource.updateTransferWhenFinished(OC_TRANSFER.id!!, TransferStatus.TRANSFER_SUCCEEDED, timestamp, TransferResult.UPLOADED)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.updateTransferWhenFinished(
|
||||
OC_TRANSFER.id!!,
|
||||
TransferStatus.TRANSFER_SUCCEEDED.value,
|
||||
timestamp,
|
||||
TransferResult.UPLOADED.value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferLocalPath changes transfer local path correctly`() {
|
||||
|
||||
ocLocalTransferDataSource.updateTransferLocalPath(OC_TRANSFER.id!!, OC_TRANSFER.localPath)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.updateTransferLocalPath(OC_TRANSFER.id!!, OC_TRANSFER.localPath)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferSourcePath changes transfer source path correctly`() {
|
||||
|
||||
ocLocalTransferDataSource.updateTransferSourcePath(OC_TRANSFER.id!!, OC_TRANSFER.sourcePath!!)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.updateTransferSourcePath(OC_TRANSFER.id!!, OC_TRANSFER.sourcePath!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferStorageDirectoryInLocalPath changes directory correctly`() {
|
||||
val oldDirectory = "oldDirectory"
|
||||
val newDirectory = "newDirectory"
|
||||
|
||||
ocLocalTransferDataSource.updateTransferStorageDirectoryInLocalPath(OC_TRANSFER.id!!, oldDirectory, newDirectory)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.updateTransferStorageDirectoryInLocalPath(OC_TRANSFER.id!!, oldDirectory, newDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteTransferById removes a transfer correctly`() {
|
||||
|
||||
ocLocalTransferDataSource.deleteTransferById(OC_TRANSFER.id!!)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.deleteTransferWithId(OC_TRANSFER.id!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteAllTransfersFromAccount removes all transfers for an account correctly`() {
|
||||
|
||||
ocLocalTransferDataSource.deleteAllTransfersFromAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.deleteTransfersWithAccountName(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getTransferById returns a OCTransfer`() {
|
||||
every {
|
||||
transferDao.getTransferWithId(any())
|
||||
} returns OC_TRANSFER.toEntity()
|
||||
|
||||
val actualResult = ocLocalTransferDataSource.getTransferById(OC_TRANSFER.id!!)
|
||||
|
||||
assertEquals(OC_TRANSFER, actualResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.getTransferWithId(OC_TRANSFER.id!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAllTransfers returns a list of OCTransfer`() {
|
||||
|
||||
every {
|
||||
transferDao.getAllTransfers()
|
||||
} returns listOf(transferEntity)
|
||||
|
||||
val actualResult = ocLocalTransferDataSource.getAllTransfers()
|
||||
|
||||
assertEquals(listOf(transferEntity.toModel()), actualResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.getAllTransfers()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAllTransfersAsStream returns a Flow with a list of OCTransfer ordered by status`() = runBlocking {
|
||||
|
||||
val transferEntityInProgress: OCTransferEntity = OC_TRANSFER.copy(status = TransferStatus.TRANSFER_IN_PROGRESS).toEntity()
|
||||
|
||||
val transferEntityQueue: OCTransferEntity = OC_TRANSFER.copy(status = TransferStatus.TRANSFER_QUEUED).toEntity()
|
||||
|
||||
val transferEntityFailed: OCTransferEntity = OC_TRANSFER.copy(status = TransferStatus.TRANSFER_FAILED).toEntity()
|
||||
|
||||
val transferEntitySucceeded: OCTransferEntity = OC_TRANSFER.copy(status = TransferStatus.TRANSFER_SUCCEEDED).toEntity()
|
||||
|
||||
val transferListRandom = listOf(transferEntityQueue, transferEntityFailed, transferEntityInProgress, transferEntitySucceeded)
|
||||
|
||||
val transferQueue = OC_TRANSFER.copy()
|
||||
transferQueue.status = TransferStatus.TRANSFER_QUEUED
|
||||
|
||||
val transferFailed = OC_TRANSFER.copy()
|
||||
transferFailed.status = TransferStatus.TRANSFER_FAILED
|
||||
|
||||
val transferSucceeded = OC_TRANSFER.copy()
|
||||
transferSucceeded.status = TransferStatus.TRANSFER_SUCCEEDED
|
||||
|
||||
val transferListOrdered = listOf(OC_TRANSFER, transferQueue, transferFailed, transferSucceeded)
|
||||
|
||||
every {
|
||||
transferDao.getAllTransfersAsStream()
|
||||
} returns flowOf(transferListRandom)
|
||||
|
||||
val actualResult = ocLocalTransferDataSource.getAllTransfersAsStream().first()
|
||||
|
||||
assertEquals(transferListOrdered, actualResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.getAllTransfersAsStream()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLastTransferFor returns a OCTransfer`() {
|
||||
|
||||
every {
|
||||
transferDao.getLastTransferWithRemotePathAndAccountName(OC_TRANSFER.remotePath, OC_ACCOUNT_NAME)
|
||||
} returns transferEntity
|
||||
|
||||
val actualResult = ocLocalTransferDataSource.getLastTransferFor(OC_TRANSFER.remotePath, OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(transferEntity.toModel(), actualResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.getLastTransferWithRemotePathAndAccountName(OC_TRANSFER.remotePath, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCurrentAndPendingTransfers returns a list of OCTransfer`() {
|
||||
|
||||
every {
|
||||
transferDao.getTransfersWithStatus(listOf(TransferStatus.TRANSFER_IN_PROGRESS.value, TransferStatus.TRANSFER_QUEUED.value))
|
||||
} returns listOf(transferEntity)
|
||||
|
||||
val actualResult = ocLocalTransferDataSource.getCurrentAndPendingTransfers()
|
||||
|
||||
assertEquals(listOf(transferEntity.toModel()), actualResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.getTransfersWithStatus(listOf(TransferStatus.TRANSFER_IN_PROGRESS.value, TransferStatus.TRANSFER_QUEUED.value))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFailedTransfers returns a list of OCTransfer`() {
|
||||
|
||||
every {
|
||||
transferDao.getTransfersWithStatus(listOf(TransferStatus.TRANSFER_FAILED.value))
|
||||
} returns listOf(transferEntity)
|
||||
|
||||
val actualResult = ocLocalTransferDataSource.getFailedTransfers()
|
||||
|
||||
assertEquals(listOf(transferEntity.toModel()), actualResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.getTransfersWithStatus(listOf(TransferStatus.TRANSFER_FAILED.value))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFinishedTransfers returns a list of OCTransfer`() {
|
||||
|
||||
every {
|
||||
transferDao.getTransfersWithStatus(listOf(TransferStatus.TRANSFER_SUCCEEDED.value))
|
||||
} returns listOf(transferEntity)
|
||||
|
||||
val actualResult = ocLocalTransferDataSource.getFinishedTransfers()
|
||||
|
||||
assertEquals(listOf(transferEntity.toModel()), actualResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.getTransfersWithStatus(listOf(TransferStatus.TRANSFER_SUCCEEDED.value))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clearFailedTransfers removes failed transfers correctly`() {
|
||||
|
||||
ocLocalTransferDataSource.clearFailedTransfers()
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.deleteTransfersWithStatus(TransferStatus.TRANSFER_FAILED.value)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clearSuccessfulTransfers removes successful transfers correctly`() {
|
||||
|
||||
ocLocalTransferDataSource.clearSuccessfulTransfers()
|
||||
|
||||
verify(exactly = 1) {
|
||||
transferDao.deleteTransfersWithStatus(TransferStatus.TRANSFER_SUCCEEDED.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
+288
@@ -0,0 +1,288 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Jorge Aguado Recio
|
||||
*
|
||||
* Copyright (C) 2025 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.transfers.repository
|
||||
|
||||
import eu.qsfera.android.data.transfers.datasources.LocalTransferDataSource
|
||||
import eu.qsfera.android.domain.transfers.model.TransferResult
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_FAILED_TRANSFER
|
||||
import eu.qsfera.android.testutil.OC_FINISHED_TRANSFER
|
||||
import eu.qsfera.android.testutil.OC_PENDING_TRANSFER
|
||||
import eu.qsfera.android.testutil.OC_TRANSFER
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class OCTransferRepositoryTest {
|
||||
|
||||
private val localTransferDataSource = mockk<LocalTransferDataSource>(relaxUnitFun = true)
|
||||
private val ocTransferRepository = OCTransferRepository(localTransferDataSource)
|
||||
|
||||
@Test
|
||||
fun `saveTransfer inserts a transfer correctly`() {
|
||||
// The result of this method is not used, so it can be anything
|
||||
every {
|
||||
localTransferDataSource.saveTransfer(OC_TRANSFER)
|
||||
} returns 1L
|
||||
|
||||
val result = ocTransferRepository.saveTransfer(OC_TRANSFER)
|
||||
assertEquals(1L, result)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.saveTransfer(OC_TRANSFER)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransfer updates a transfer correctly`() {
|
||||
ocTransferRepository.updateTransfer(OC_TRANSFER)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.updateTransfer(OC_TRANSFER)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferStatusToInProgressById changes transfer status correctly`() {
|
||||
ocTransferRepository.updateTransferStatusToInProgressById(OC_TRANSFER.id!!)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.updateTransferStatusToInProgressById(OC_TRANSFER.id!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferStatusToEnqueuedById changes transfer status correctly`() {
|
||||
ocTransferRepository.updateTransferStatusToEnqueuedById(OC_TRANSFER.id!!)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.updateTransferStatusToEnqueuedById(OC_TRANSFER.id!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferLocalPath updates transfer local path correctly`() {
|
||||
ocTransferRepository.updateTransferLocalPath(OC_TRANSFER.id!!, OC_TRANSFER.localPath)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.updateTransferLocalPath(OC_TRANSFER.id!!, OC_TRANSFER.localPath)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferSourcePath updates transfer source path correctly`() {
|
||||
ocTransferRepository.updateTransferSourcePath(OC_TRANSFER.id!!, OC_TRANSFER.sourcePath!!)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.updateTransferSourcePath(OC_TRANSFER.id!!, OC_TRANSFER.sourcePath!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferWhenFinished changes transfer status correctly`() {
|
||||
ocTransferRepository.updateTransferWhenFinished(OC_TRANSFER.id!!, OC_FINISHED_TRANSFER.status, 1_000, TransferResult.UPLOADED)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.updateTransferWhenFinished(OC_TRANSFER.id!!, OC_FINISHED_TRANSFER.status, 1_000, TransferResult.UPLOADED)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateTransferStorageDirectoryInLocalPath updates transfer storage directory correctly`() {
|
||||
val oldDirectory = "/oldDirectory/path"
|
||||
val newDirectory = "/newDirectory/path"
|
||||
|
||||
ocTransferRepository.updateTransferStorageDirectoryInLocalPath(OC_TRANSFER.id!!, oldDirectory, newDirectory)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.updateTransferStorageDirectoryInLocalPath(OC_TRANSFER.id!!, oldDirectory, newDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteTransferById removes a transfer correctly`() {
|
||||
ocTransferRepository.deleteTransferById(OC_TRANSFER.id!!)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.deleteTransferById(OC_TRANSFER.id!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteAllTransfersFromAccount removes all transfers correctly`() {
|
||||
ocTransferRepository.deleteAllTransfersFromAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.deleteAllTransfersFromAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getTransferById returns a OCTransfer`() {
|
||||
every {
|
||||
localTransferDataSource.getTransferById(OC_TRANSFER.id!!)
|
||||
} returns OC_TRANSFER
|
||||
|
||||
val transfer = ocTransferRepository.getTransferById(OC_TRANSFER.id!!)
|
||||
assertEquals(OC_TRANSFER, transfer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.getTransferById(OC_TRANSFER.id!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getTransferById returns null when local datasource returns null`() {
|
||||
every {
|
||||
localTransferDataSource.getTransferById(OC_TRANSFER.id!!)
|
||||
} returns null
|
||||
|
||||
val transfer = ocTransferRepository.getTransferById(OC_TRANSFER.id!!)
|
||||
assertNull(transfer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.getTransferById(OC_TRANSFER.id!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAllTransfers returns a list of OCTransfer`() {
|
||||
every {
|
||||
localTransferDataSource.getAllTransfers()
|
||||
} returns listOf(OC_TRANSFER)
|
||||
|
||||
val listOfTransfers = ocTransferRepository.getAllTransfers()
|
||||
assertEquals(listOf(OC_TRANSFER), listOfTransfers)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.getAllTransfers()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAllTransfersAsStream returns a Flow with a list of OCTransfer`() = runTest {
|
||||
every {
|
||||
localTransferDataSource.getAllTransfersAsStream()
|
||||
} returns flowOf(listOf(OC_TRANSFER))
|
||||
|
||||
val listOfTransfers = ocTransferRepository.getAllTransfersAsStream().first()
|
||||
assertEquals(listOf(OC_TRANSFER), listOfTransfers)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.getAllTransfersAsStream()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLastTransferFor returns a OCTransfer`() {
|
||||
every {
|
||||
localTransferDataSource.getLastTransferFor(OC_TRANSFER.remotePath, OC_ACCOUNT_NAME)
|
||||
} returns OC_TRANSFER
|
||||
|
||||
val lastTransfer = ocTransferRepository.getLastTransferFor(OC_TRANSFER.remotePath, OC_ACCOUNT_NAME)
|
||||
assertEquals(OC_TRANSFER, lastTransfer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.getLastTransferFor(OC_TRANSFER.remotePath, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLastTransferFor returns null when local datasource returns null`() {
|
||||
every {
|
||||
localTransferDataSource.getLastTransferFor(OC_TRANSFER.remotePath, OC_ACCOUNT_NAME)
|
||||
} returns null
|
||||
|
||||
val lastTransfer = ocTransferRepository.getLastTransferFor(OC_TRANSFER.remotePath, OC_ACCOUNT_NAME)
|
||||
assertNull(lastTransfer)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.getLastTransferFor(OC_TRANSFER.remotePath, OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCurrentAndPendingTransfers returns a list of OCTransfer`() {
|
||||
every {
|
||||
localTransferDataSource.getCurrentAndPendingTransfers()
|
||||
} returns listOf(OC_TRANSFER, OC_PENDING_TRANSFER)
|
||||
|
||||
val listOfCurrentAndPendingTransfers = ocTransferRepository.getCurrentAndPendingTransfers()
|
||||
assertEquals(listOf(OC_TRANSFER, OC_PENDING_TRANSFER), listOfCurrentAndPendingTransfers)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.getCurrentAndPendingTransfers()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFailedTransfers returns a list of OCTransfer`() {
|
||||
every {
|
||||
localTransferDataSource.getFailedTransfers()
|
||||
} returns listOf(OC_FAILED_TRANSFER)
|
||||
|
||||
val listOfFailedTransfers = ocTransferRepository.getFailedTransfers()
|
||||
assertEquals(listOf(OC_FAILED_TRANSFER), listOfFailedTransfers)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.getFailedTransfers()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getFinishedTransfers returns a list of OCTransfer`() {
|
||||
every {
|
||||
localTransferDataSource.getFinishedTransfers()
|
||||
} returns listOf(OC_FINISHED_TRANSFER)
|
||||
|
||||
val listOfFinishedTransfers = ocTransferRepository.getFinishedTransfers()
|
||||
assertEquals(listOf(OC_FINISHED_TRANSFER), listOfFinishedTransfers)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.getFinishedTransfers()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clearFailedTransfers removes failed transfers correctly`() {
|
||||
ocTransferRepository.clearFailedTransfers()
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.clearFailedTransfers()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clearSuccessfulTransfers removes successful transfers correctly`() {
|
||||
ocTransferRepository.clearSuccessfulTransfers()
|
||||
|
||||
verify(exactly = 1) {
|
||||
localTransferDataSource.clearSuccessfulTransfers()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* @author Aitor Ballesteros Pavón
|
||||
* @author Jorge Aguado Recio
|
||||
*
|
||||
* Copyright (C) 2024 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.user.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.user.datasources.implementation.OCLocalUserDataSource.Companion.toEntity
|
||||
import eu.qsfera.android.data.user.db.UserDao
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_USER_QUOTA
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCLocalUserDataSourceTest {
|
||||
private lateinit var ocLocalUserDataSource: OCLocalUserDataSource
|
||||
private val ocUserQuotaDao = mockk<UserDao>(relaxUnitFun = true)
|
||||
|
||||
private val userQuotaEntity = OC_USER_QUOTA.toEntity()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
ocLocalUserDataSource = OCLocalUserDataSource(ocUserQuotaDao)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveQuotaForAccount saves user quota correctly`() {
|
||||
|
||||
ocLocalUserDataSource.saveQuotaForAccount(OC_ACCOUNT_NAME, OC_USER_QUOTA)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocUserQuotaDao.insertOrReplace(userQuotaEntity)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getQuotaForAccount returns a UserQuota`() {
|
||||
every { ocUserQuotaDao.getQuotaForAccount(any()) } returns userQuotaEntity
|
||||
|
||||
val userQuota = ocLocalUserDataSource.getQuotaForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertEquals(OC_USER_QUOTA, userQuota)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocUserQuotaDao.getQuotaForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getQuotaForAccount returns null when DAO returns a null quota`() {
|
||||
every { ocUserQuotaDao.getQuotaForAccount(any()) } returns null
|
||||
|
||||
val quotaEntity = ocLocalUserDataSource.getQuotaForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
assertNull(quotaEntity)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocUserQuotaDao.getQuotaForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getQuotaForAccountAsFlow returns a Flow with an UserQuota`() = runTest {
|
||||
every {
|
||||
ocUserQuotaDao.getQuotaForAccountAsFlow(OC_ACCOUNT_NAME)
|
||||
} returns flowOf(userQuotaEntity)
|
||||
|
||||
val userQuota = ocLocalUserDataSource.getQuotaForAccountAsFlow(OC_ACCOUNT_NAME).first()
|
||||
assertEquals(OC_USER_QUOTA, userQuota)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocUserQuotaDao.getQuotaForAccountAsFlow(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAllUserQuotas returns a list of UserQuota`() {
|
||||
|
||||
every { ocUserQuotaDao.getAllUserQuotas() } returns listOf(userQuotaEntity)
|
||||
|
||||
val resultActual = ocLocalUserDataSource.getAllUserQuotas()
|
||||
|
||||
assertEquals(listOf(OC_USER_QUOTA), resultActual)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocUserQuotaDao.getAllUserQuotas()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAllUserQuotasAsFlow returns a Flow with a list of UserQuota`() = runTest {
|
||||
every {
|
||||
ocUserQuotaDao.getAllUserQuotasAsFlow()
|
||||
} returns flowOf(listOf(userQuotaEntity))
|
||||
|
||||
val listOfUserQuotas = ocLocalUserDataSource.getAllUserQuotasAsFlow().first()
|
||||
assertEquals(listOf(OC_USER_QUOTA), listOfUserQuotas)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocUserQuotaDao.getAllUserQuotasAsFlow()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleteQuotaForAccount removes user quota correctly`() {
|
||||
|
||||
ocLocalUserDataSource.deleteQuotaForAccount(OC_ACCOUNT_NAME)
|
||||
|
||||
verify(exactly = 1) {
|
||||
ocUserQuotaDao.deleteQuotaForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.user.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.ClientManager
|
||||
import eu.qsfera.android.lib.common.operations.RemoteOperationResult
|
||||
import eu.qsfera.android.lib.resources.users.GetRemoteUserQuotaOperation
|
||||
import eu.qsfera.android.lib.resources.users.RemoteAvatarData
|
||||
import eu.qsfera.android.lib.resources.users.RemoteUserInfo
|
||||
import eu.qsfera.android.lib.resources.users.services.implementation.OCUserService
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_USER_AVATAR
|
||||
import eu.qsfera.android.testutil.OC_USER_INFO
|
||||
import eu.qsfera.android.testutil.OC_USER_QUOTA
|
||||
import eu.qsfera.android.utils.createRemoteOperationResultMock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteUserDataSourceTest {
|
||||
private lateinit var ocRemoteUserDataSource: OCRemoteUserDataSource
|
||||
|
||||
private val clientManager: ClientManager = mockk(relaxed = true)
|
||||
private val ocUserService: OCUserService = mockk()
|
||||
|
||||
private val avatarDimension = 128
|
||||
|
||||
private val remoteUserInfo = RemoteUserInfo(
|
||||
id = OC_USER_INFO.id,
|
||||
displayName = OC_USER_INFO.displayName,
|
||||
email = OC_USER_INFO.email
|
||||
)
|
||||
private val remoteQuota = GetRemoteUserQuotaOperation.RemoteQuota(
|
||||
used = OC_USER_QUOTA.used,
|
||||
free = OC_USER_QUOTA.available,
|
||||
relative = OC_USER_QUOTA.getRelative(),
|
||||
total = OC_USER_QUOTA.getTotal()
|
||||
)
|
||||
private val remoteAvatar = RemoteAvatarData(
|
||||
avatarData = OC_USER_AVATAR.avatarData,
|
||||
eTag = OC_USER_AVATAR.eTag,
|
||||
mimeType = OC_USER_AVATAR.mimeType
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
every { clientManager.getUserService(any()) } returns ocUserService
|
||||
|
||||
ocRemoteUserDataSource = OCRemoteUserDataSource(
|
||||
clientManager,
|
||||
avatarDimension
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUserInfo returns UserInfo`() {
|
||||
val getUserInfoResult: RemoteOperationResult<RemoteUserInfo> =
|
||||
createRemoteOperationResultMock(data = remoteUserInfo, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocUserService.getUserInfo()
|
||||
} returns getUserInfoResult
|
||||
|
||||
val userInfo = ocRemoteUserDataSource.getUserInfo(OC_ACCOUNT_NAME)
|
||||
|
||||
assertNotNull(userInfo)
|
||||
assertEquals(OC_USER_INFO, userInfo)
|
||||
|
||||
verify(exactly = 1) { ocUserService.getUserInfo() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUserQuota returns UserQuota`() {
|
||||
val getUserQuotaResult: RemoteOperationResult<GetRemoteUserQuotaOperation.RemoteQuota> =
|
||||
createRemoteOperationResultMock(data = remoteQuota, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocUserService.getUserQuota()
|
||||
} returns getUserQuotaResult
|
||||
|
||||
val userQuota = ocRemoteUserDataSource.getUserQuota(OC_ACCOUNT_NAME)
|
||||
|
||||
assertNotNull(userQuota)
|
||||
assertEquals(OC_USER_QUOTA, userQuota)
|
||||
|
||||
verify(exactly = 1) { ocUserService.getUserQuota() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUserAvatar returns UserAvatar`() {
|
||||
val getUserAvatarResult: RemoteOperationResult<RemoteAvatarData> =
|
||||
createRemoteOperationResultMock(data = remoteAvatar, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocUserService.getUserAvatar(avatarDimension)
|
||||
} returns getUserAvatarResult
|
||||
|
||||
val userAvatar = ocRemoteUserDataSource.getUserAvatar(OC_ACCOUNT_NAME)
|
||||
|
||||
assertNotNull(userAvatar)
|
||||
assertEquals(OC_USER_AVATAR, userAvatar)
|
||||
|
||||
verify(exactly = 1) { ocUserService.getUserAvatar(avatarDimension) }
|
||||
}
|
||||
}
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.user.db
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class UserQuotaEntityTest {
|
||||
@Test
|
||||
fun testConstructor() {
|
||||
val item = UserQuotaEntity(
|
||||
"accountName",
|
||||
200,
|
||||
800
|
||||
)
|
||||
|
||||
assertEquals("accountName", item.accountName)
|
||||
assertEquals(800, item.available)
|
||||
assertEquals(200, item.used)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEqualsOk() {
|
||||
val item1 = UserQuotaEntity(
|
||||
accountName = "accountName",
|
||||
available = 200,
|
||||
used = 800
|
||||
)
|
||||
|
||||
val item2 = UserQuotaEntity(
|
||||
"accountName",
|
||||
800,
|
||||
200
|
||||
)
|
||||
|
||||
assertTrue(item1 == item2)
|
||||
assertFalse(item1 === item2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEqualsKo() {
|
||||
val item1 = UserQuotaEntity(
|
||||
accountName = "accountName",
|
||||
available = 800,
|
||||
used = 200
|
||||
)
|
||||
|
||||
val item2 = UserQuotaEntity(
|
||||
"accountName2",
|
||||
200,
|
||||
800
|
||||
)
|
||||
|
||||
assertFalse(item1 == item2)
|
||||
assertFalse(item1 === item2)
|
||||
}
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Abel García de Prada
|
||||
* @author Jorge Aguado Recio
|
||||
*
|
||||
* Copyright (C) 2025 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.user.repository
|
||||
|
||||
import eu.qsfera.android.data.user.datasources.LocalUserDataSource
|
||||
import eu.qsfera.android.data.user.datasources.RemoteUserDataSource
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_NAME
|
||||
import eu.qsfera.android.testutil.OC_USER_AVATAR
|
||||
import eu.qsfera.android.testutil.OC_USER_INFO
|
||||
import eu.qsfera.android.testutil.OC_USER_QUOTA
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import junit.framework.TestCase.assertNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class OCUserRepositoryTest {
|
||||
private val remoteUserDataSource = mockk<RemoteUserDataSource>()
|
||||
private val localUserDataSource = mockk<LocalUserDataSource>(relaxUnitFun = true)
|
||||
private val ocUserRepository = OCUserRepository(localUserDataSource, remoteUserDataSource)
|
||||
|
||||
@Test
|
||||
fun `getUserInfo returns an UserInfo`() {
|
||||
every {
|
||||
remoteUserDataSource.getUserInfo(OC_ACCOUNT_NAME)
|
||||
} returns OC_USER_INFO
|
||||
|
||||
val userInfo = ocUserRepository.getUserInfo(OC_ACCOUNT_NAME)
|
||||
assertEquals(OC_USER_INFO, userInfo)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteUserDataSource.getUserInfo(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUserQuota returns an UserQuota`() {
|
||||
every {
|
||||
remoteUserDataSource.getUserQuota(OC_ACCOUNT_NAME)
|
||||
} returns OC_USER_QUOTA
|
||||
|
||||
val userQuota = ocUserRepository.getUserQuota(OC_ACCOUNT_NAME)
|
||||
assertEquals(OC_USER_QUOTA, userQuota)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteUserDataSource.getUserQuota(OC_ACCOUNT_NAME)
|
||||
localUserDataSource.saveQuotaForAccount(OC_ACCOUNT_NAME, OC_USER_QUOTA)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getStoredUserQuota returns an UserQuota`() {
|
||||
every {
|
||||
localUserDataSource.getQuotaForAccount(OC_ACCOUNT_NAME)
|
||||
} returns OC_USER_QUOTA
|
||||
|
||||
val storedQuota = ocUserRepository.getStoredUserQuota(OC_ACCOUNT_NAME)
|
||||
assertEquals(OC_USER_QUOTA, storedQuota)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localUserDataSource.getQuotaForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getStoredUserQuota returns null when local datasource returns null`() {
|
||||
every {
|
||||
localUserDataSource.getQuotaForAccount(OC_ACCOUNT_NAME)
|
||||
} returns null
|
||||
|
||||
val storedQuota = ocUserRepository.getStoredUserQuota(OC_ACCOUNT_NAME)
|
||||
assertNull(storedQuota)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localUserDataSource.getQuotaForAccount(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getStoredUserQuotaAsFlow returns a Flow with an UserQuota`() = runTest {
|
||||
every {
|
||||
localUserDataSource.getQuotaForAccountAsFlow(OC_ACCOUNT_NAME)
|
||||
} returns flowOf(OC_USER_QUOTA)
|
||||
|
||||
val userQuota = ocUserRepository.getStoredUserQuotaAsFlow(OC_ACCOUNT_NAME).first()
|
||||
assertEquals(OC_USER_QUOTA, userQuota)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localUserDataSource.getQuotaForAccountAsFlow(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAllUserQuotas returns a list of UserQuota`() {
|
||||
every {
|
||||
localUserDataSource.getAllUserQuotas()
|
||||
} returns listOf(OC_USER_QUOTA)
|
||||
|
||||
val listOfUserQuotas = ocUserRepository.getAllUserQuotas()
|
||||
assertEquals(listOf(OC_USER_QUOTA), listOfUserQuotas)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localUserDataSource.getAllUserQuotas()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getAllUserQuotasAsFlow returns a Flow with a list of UserQuota`() = runTest {
|
||||
every {
|
||||
localUserDataSource.getAllUserQuotasAsFlow()
|
||||
} returns flowOf(listOf(OC_USER_QUOTA))
|
||||
|
||||
val listOfUserQuotas = ocUserRepository.getAllUserQuotasAsFlow().first()
|
||||
assertEquals(listOf(OC_USER_QUOTA), listOfUserQuotas)
|
||||
|
||||
verify(exactly = 1) {
|
||||
localUserDataSource.getAllUserQuotasAsFlow()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUserAvatar returns an UserAvatar`() {
|
||||
every {
|
||||
remoteUserDataSource.getUserAvatar(OC_ACCOUNT_NAME)
|
||||
} returns OC_USER_AVATAR
|
||||
|
||||
val userAvatar = ocUserRepository.getUserAvatar(OC_ACCOUNT_NAME)
|
||||
assertEquals(OC_USER_AVATAR, userAvatar)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteUserDataSource.getUserAvatar(OC_ACCOUNT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Aitor Ballesteros Pavón
|
||||
*
|
||||
* Copyright (C) 2023 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.webfinger.datasources.implementation
|
||||
|
||||
import eu.qsfera.android.data.ClientManager
|
||||
import eu.qsfera.android.domain.webfinger.model.WebFingerRel
|
||||
import eu.qsfera.android.lib.common.QSferaClient
|
||||
import eu.qsfera.android.lib.common.operations.RemoteOperationResult
|
||||
import eu.qsfera.android.lib.resources.webfinger.services.implementation.OCWebFingerService
|
||||
import eu.qsfera.android.testutil.OC_ACCESS_TOKEN
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_ID
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_BASIC_AUTH
|
||||
import eu.qsfera.android.utils.createRemoteOperationResultMock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class OCRemoteWebFingerDataSourceTest {
|
||||
|
||||
private lateinit var ocRemoteWebFingerDatasource: OCRemoteWebFingerDataSource
|
||||
|
||||
private val clientManager: ClientManager = mockk(relaxed = true)
|
||||
private val qsferaClient: QSferaClient = mockk(relaxed = true)
|
||||
private val ocWebFingerService: OCWebFingerService = mockk()
|
||||
private val urls: List<String> = listOf(
|
||||
"http://webfinger.qsfera/tests/server-instance1",
|
||||
"http://webfinger.qsfera/tests/server-instance2",
|
||||
"http://webfinger.qsfera/tests/server-instance3",
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
ocRemoteWebFingerDatasource = OCRemoteWebFingerDataSource(
|
||||
ocWebFingerService,
|
||||
clientManager,
|
||||
)
|
||||
|
||||
every { clientManager.getClientForAnonymousCredentials(OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl, false) } returns qsferaClient
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getInstancesFromWebFinger returns a list of String of web finger urls`() {
|
||||
|
||||
val getInstancesFromWebFingerResult: RemoteOperationResult<List<String>> =
|
||||
createRemoteOperationResultMock(data = urls, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocWebFingerService.getInstancesFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
resource = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY.uri,
|
||||
qsferaClient,
|
||||
)
|
||||
} returns getInstancesFromWebFingerResult
|
||||
|
||||
val actualResult = ocRemoteWebFingerDatasource.getInstancesFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
)
|
||||
|
||||
assertEquals(getInstancesFromWebFingerResult.data, actualResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clientManager.getClientForAnonymousCredentials(any(), false)
|
||||
ocWebFingerService.getInstancesFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
resource = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY.uri,
|
||||
qsferaClient,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getInstancesFromAuthenticatedWebFinger returns a list of String of web finger urls`() {
|
||||
|
||||
val getInstancesFromAuthenticatedWebFingerResult: RemoteOperationResult<List<String>> =
|
||||
createRemoteOperationResultMock(data = urls, isSuccess = true)
|
||||
|
||||
every {
|
||||
ocWebFingerService.getInstancesFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
resource = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY.uri,
|
||||
qsferaClient,
|
||||
)
|
||||
} returns getInstancesFromAuthenticatedWebFingerResult
|
||||
|
||||
val actualResult = ocRemoteWebFingerDatasource.getInstancesFromAuthenticatedWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
resource = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
username = OC_ACCOUNT_ID,
|
||||
accessToken = OC_ACCESS_TOKEN
|
||||
)
|
||||
|
||||
assertEquals(getInstancesFromAuthenticatedWebFingerResult.data, actualResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
qsferaClient.credentials = any()
|
||||
clientManager.getClientForAnonymousCredentials(any(), false)
|
||||
ocWebFingerService.getInstancesFromWebFinger(
|
||||
lookupServer = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
resource = OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
rel = WebFingerRel.OIDC_ISSUER_DISCOVERY.uri,
|
||||
any(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author Jorge Aguado Recio
|
||||
*
|
||||
* Copyright (C) 2025 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package eu.qsfera.android.data.webfinger.repository
|
||||
|
||||
import eu.qsfera.android.data.webfinger.datasources.RemoteWebFingerDataSource
|
||||
import eu.qsfera.android.domain.webfinger.model.WebFingerRel
|
||||
import eu.qsfera.android.testutil.OC_ACCESS_TOKEN
|
||||
import eu.qsfera.android.testutil.OC_ACCOUNT_ID
|
||||
import eu.qsfera.android.testutil.OC_SECURE_SERVER_INFO_BASIC_AUTH
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class OCWebFingerRepositoryTest {
|
||||
|
||||
private val remoteWebFingerDatasource = mockk<RemoteWebFingerDataSource>()
|
||||
private val ocWebFingerRepository = OCWebFingerRepository(remoteWebFingerDatasource)
|
||||
|
||||
private val webFingerInstance = "http://webfinger.qsfera/tests/server-instance1"
|
||||
|
||||
@Test
|
||||
fun `getInstancesFromWebFinger returns a list of String of webfinger url`() {
|
||||
val webFingerResource = "admin"
|
||||
|
||||
every {
|
||||
remoteWebFingerDatasource.getInstancesFromWebFinger(
|
||||
OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
webFingerResource
|
||||
)
|
||||
} returns listOf(webFingerInstance)
|
||||
|
||||
val webFingerResult = ocWebFingerRepository.getInstancesFromWebFinger(
|
||||
OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
webFingerResource
|
||||
)
|
||||
assertEquals(listOf(webFingerInstance), webFingerResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteWebFingerDatasource.getInstancesFromWebFinger(
|
||||
OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
webFingerResource
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getInstancesFromAuthenticatedWebFinger returns a list of String of webfinger url`() {
|
||||
val webFingerAuthenticatedResource = "acct:me@demo.qsfera.eu"
|
||||
|
||||
every {
|
||||
remoteWebFingerDatasource.getInstancesFromAuthenticatedWebFinger(
|
||||
OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
webFingerAuthenticatedResource,
|
||||
OC_ACCOUNT_ID,
|
||||
OC_ACCESS_TOKEN
|
||||
)
|
||||
} returns listOf(webFingerInstance)
|
||||
|
||||
val webFingerResult = ocWebFingerRepository.getInstancesFromAuthenticatedWebFinger(
|
||||
OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
webFingerAuthenticatedResource,
|
||||
OC_ACCOUNT_ID,
|
||||
OC_ACCESS_TOKEN
|
||||
)
|
||||
assertEquals(listOf(webFingerInstance), webFingerResult)
|
||||
|
||||
verify(exactly = 1) {
|
||||
remoteWebFingerDatasource.getInstancesFromAuthenticatedWebFinger(
|
||||
OC_SECURE_SERVER_INFO_BASIC_AUTH.baseUrl,
|
||||
WebFingerRel.OIDC_ISSUER_DISCOVERY,
|
||||
webFingerAuthenticatedResource,
|
||||
OC_ACCOUNT_ID,
|
||||
OC_ACCESS_TOKEN
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* qsfera Android client application
|
||||
*
|
||||
* @author David González Verdugo
|
||||
* @author Abel García de Prada
|
||||
* Copyright (C) 2020 ownCloud GmbH.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package eu.qsfera.android.utils
|
||||
|
||||
import eu.qsfera.android.lib.common.operations.RemoteOperationResult
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
||||
fun <T> createRemoteOperationResultMock(
|
||||
data: T,
|
||||
isSuccess: Boolean,
|
||||
httpPhrase: String? = null,
|
||||
resultCode: RemoteOperationResult.ResultCode? = null,
|
||||
exception: Exception? = null,
|
||||
authenticationHeader: List<String> = listOf(),
|
||||
httpCode: Int? = null,
|
||||
redirectedLocation: String? = null
|
||||
): RemoteOperationResult<T> {
|
||||
val remoteOperationResult = mockk<RemoteOperationResult<T>>(relaxed = true)
|
||||
|
||||
every { remoteOperationResult.data } returns data
|
||||
|
||||
every { remoteOperationResult.isSuccess } returns isSuccess
|
||||
|
||||
if (httpPhrase != null) {
|
||||
every { remoteOperationResult.httpPhrase } returns httpPhrase
|
||||
}
|
||||
|
||||
if (resultCode != null) {
|
||||
every { remoteOperationResult.code } returns resultCode
|
||||
}
|
||||
|
||||
if (exception != null) {
|
||||
throw exception
|
||||
}
|
||||
|
||||
if (authenticationHeader.isNotEmpty()) {
|
||||
every { remoteOperationResult.authenticateHeaders } returns authenticationHeader
|
||||
}
|
||||
|
||||
if (httpCode != null) {
|
||||
every { remoteOperationResult.httpCode } returns httpCode
|
||||
}
|
||||
|
||||
if (redirectedLocation != null) {
|
||||
every { remoteOperationResult.redirectedLocation } returns redirectedLocation
|
||||
}
|
||||
|
||||
return remoteOperationResult
|
||||
}
|
||||
Reference in New Issue
Block a user