Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[New arch] Modularization and mockk #2702

Merged
merged 22 commits into from
Nov 7, 2019

Conversation

davigonz
Copy link
Contributor

@davigonz davigonz commented Nov 5, 2019

1st PR for #2607 , changes are not final, coming PRs will bring more.

Implements:

Split the project in different modules: #2696
Switch from Mockito to Mockk: #2697
Create new use cases for sharing in domain module: #2698

@davigonz davigonz force-pushed the new_arch/modularization_and_mockk branch from 970397b to bef38d0 Compare November 5, 2019 15:51
@davigonz davigonz changed the title New arch/modularization and mockk [New arch] Modularization and mockk Nov 5, 2019
@davigonz davigonz force-pushed the new_arch/modularization_and_mockk branch from bef38d0 to d590027 Compare November 5, 2019 16:59
@davigonz davigonz requested a review from abelgardep November 5, 2019 17:05
build.gradle Outdated

// Testing
junitVersion = "4.12"
mockitoVersion = "2.24.0"

// Extensions
ktxVersion = "1.1.0"
ktxVersion = "1.0.2"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you downgrade it??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was during the rebase with master, fixing it

@@ -25,7 +28,7 @@ dependencies {
// Dependencies for unit tests
testImplementation "junit:junit:$junitVersion"
testImplementation "androidx.arch.core:core-testing:$archLifecycleVersion"
testImplementation "org.mockito:mockito-core:$mockitoVersion"
testImplementation "io.mockk:mockk:$mockkVersion"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏


private lateinit var file: OCFile

private val publicShares = arrayListOf(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you use arrayList?? It's always better to interfaces, in this case List ;-)

private lateinit var file: OCFile

private val publicShares = arrayListOf(
AppTestUtil.createPublicShare(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't you create a DUMMY_PUBLIC_SHARE and create new instances with copy function??

}

private fun loadCapabilitiesSuccessfully(
capability: OCCapabilityEntity = AppTestUtil.createCapability(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DUMMY_CAPABILITY instead?


private fun savePublicShare(newShare: OCShareEntity, resource: DataResult<Unit> = DataResult.success()) {

every {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in this function, you are mixing mocking with performing a click action.... Please, divide it

Comment on lines +105 to +124
private val account = Account("admin", "owncloud")

@BeforeClass
@JvmStatic
fun init() {
addAccount()
}

@AfterClass
@JvmStatic
fun cleanUp() {
AccountsManager.deleteAllAccounts(targetContext)
}

private fun addAccount() {
// obtaining an AccountManager instance
val accountManager = AccountManager.get(targetContext)

accountManager.addAccountExplicitly(account, "a", null)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't you create a class to be extended for instrumented tests with these functions?? I have seen this code repeated several times....

onView(withText(R.string.unshare_link_file_error)).check(matches(isDisplayed()))
}

private fun getOCFileForTesting(name: String = "default"): OCFile {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function is also repeated several times. Can you create a DUMMY_FILE?

}

private fun loadCapabilitiesSuccessfully(
capability: OCCapabilityEntity = AppTestUtil.createCapability(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same as before

AppTestUtil.createPublicShare( // With permission Download/View/Upload
path = "/Photos/",
expirationDate = 0L,
permissions = 15,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

permissions 15?? Use constants please.

Apply for all files

every { ocShareViewModel.getPublicShares(file.remotePath) } returns sharesLiveData
every { ocShareViewModel.getPrivateShares(file.remotePath) } returns MutableLiveData()

stopKoin()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should call stopKoin in @after method

OCShareViewModel(androidContext(), account)
val viewModelModule = module {
viewModel { (filePath: String, account: Account) ->
OCShareViewModel(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need context??

Copy link
Contributor Author

@davigonz davigonz Nov 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a pretty old and strong dependency I need to create ownCloud Clients and execute network operations. I already fixed it using dependency injection in coming PRs.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Comment on lines 1395 to 1406
if (getContentResolver() != null) {
getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);

} else {
try {
getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where,
whereArgs);
} catch (RemoteException e) {
Log_OC.e(TAG, "Exception in resetShareFlagsInFolder " + e.getMessage());
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these lines have been repeated several times differing with just one aegument. Can you simplify it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean resetShareFlagsInAllFiles, resetShareFlagsInFolder, resetShareFlagInAFile and cleanShares methods? They have more than one different argument when calling getContentResolver() or getContentProviderClient(). Anyway, I removed those 4 methods since are no longer used.

}

fun isLoading(): Boolean = (status == Status.LOADING)
fun isSuccess(): Boolean = (status == Status.SUCCESS)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why don't you create a function isError??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -146,96 +143,96 @@ class UsersAndGroupsSearchProvider : ContentProvider() {
userQuery,
REQUESTED_PAGE,
RESULTS_PER_PAGE
)
).also { uiResult ->
if (!uiResult.isSuccess() && !uiResult.isLoading()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you'd need it here

val names = uiResult.data

// convert the responses from the OC server to the expected format
if (names?.size!! > 0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use !names.isNullOrEmpty() instead


val manager = FileDataStorageManager(
context,
account, context!!.contentResolver

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you are formatting file, do it well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this, I can not trust in the AS reformat code option anymore. The whole file was properly formatted except this line. 😄

.isTrue

try {
while (namesIt.hasNext()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this file has been translated by Android Studio.

Why don't you use something like a for (name in names)

}

public override fun onStop() {
super.onStop()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can remove this function, can't you?

Copy link
Contributor Author

@davigonz davigonz Nov 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure though AS doesn't complain about it

when (uiResult?.status) {
Status.SUCCESS -> {
if (publicShareFragment != null) {
publicShareFragment?.updateCapabilities(uiResult.data)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why don't you a shared view model instead of keeping references to fragments?? That's the best way to do it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fix this in coming PRs

}
}
else -> {
Log.d(TAG, "Unknown status when loading capabilities in account ${account?.name}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

never entering here, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not needed

file.isSharedWithMe -> return RemoteShare.READ_PERMISSION_FLAG // minimum permissions
isFederated -> {
val serverVersion = com.owncloud.android.authentication.AccountUtils.getServerVersion(account)
return if (serverVersion != null && serverVersion.isNotReshareableFederatedSupported) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use when better

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even with two conditions? I rather use if else for those cases.

Status.LOADING -> {
showLoadingDialog(R.string.common_loading)
}
else -> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing to do with success case??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'm observing the database shares from observeShares() function of ShareFileFragment so if everything was fine, they are automatically updated from there.

}

override fun showEditPrivateShare(share: OCShareEntity) {
val ft = supportFragmentManager.beginTransaction()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've managed to use it when using replace() but not show() as we have to do in this function

@@ -101,7 +107,7 @@ class ShareFileFragment : Fragment(), ShareUserListAdapter.ShareUserAdapterListe
/**
* List of public links bound to the file
*/
private var publicLinks: ArrayList<OCShare>? = null
private var publicLinks: ArrayList<OCShareEntity>? = null

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as I said before, thinking in ArrayList instead of List is not best, use interfaces instead

}

init {
capabilitiesLiveData?.observeForever(capabilitiesObserver)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really??? observing forever??

Why don't use a _capabilities as MediatorLiveData, adding source capabilitiesLiveData ???

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MediatorLiveData is meant to merge emissions of changes from different LiveDatas in one object. Here we have just one LiveData to observe.

If _capabilities is a MediatorLiveData and we add capabilitiesLiveData as unique source, we are doing basically the same as I wrote, since MediatorLiveData uses observeForever and removeObserver under the hood, as you can see below.

Screenshot 2019-11-06 at 11 27 36

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, it's better to use MediatorLiveData because you don't need to override onCleared to remove the observer. It's automatically done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I changed it and is cleaner but let's see if I do not need to use removeSource() to make it work in the future. 😄

@davigonz davigonz force-pushed the new_arch/modularization_and_mockk branch from 03850e5 to fe18043 Compare November 7, 2019 11:12
@davigonz davigonz self-assigned this Nov 7, 2019
@davigonz
Copy link
Contributor Author

davigonz commented Nov 7, 2019

@jesmrec code approved, ready to QA. Please take into account that the tests are not going to pass here, they will be fixed in coming PRs. It was the only way to start merging the modularization without having just one and very huge PR.

@davigonz davigonz changed the title [New arch] Modularization and mockk [New arch] Modularization Nov 7, 2019
@davigonz davigonz changed the base branch from master to new_arch/modularization November 7, 2019 12:13
@jesmrec
Copy link
Collaborator

jesmrec commented Nov 7, 2019

App build and correctly installed. Approved.

@jesmrec jesmrec self-requested a review November 7, 2019 12:22
@davigonz davigonz changed the title [New arch] Modularization [New arch] Modularization and mockk Nov 7, 2019
@davigonz davigonz merged commit f2f2115 into new_arch/modularization Nov 7, 2019
@delete-merged-branch delete-merged-branch bot deleted the new_arch/modularization_and_mockk branch November 7, 2019 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants