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

Alternative method for GrantPermissionRule #251

Closed
Moriarty16 opened this issue Jul 14, 2021 · 10 comments
Closed

Alternative method for GrantPermissionRule #251

Moriarty16 opened this issue Jul 14, 2021 · 10 comments

Comments

@Moriarty16
Copy link

The GrantPermissionRule works on JUnit4, but seems not working on JUnit5.
Is there an alternative method for this?

Code:

@Rule
public GrantPermissionRule rule = GrantPermissionRule.grant(
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.WRITE_EXTERNAL_STORAGE
);

I'm running this test code on Android R physical device.
Any help will be appreciated, thanks.

@mannodermaus
Copy link
Owner

mannodermaus commented Jul 15, 2021

The direct replacement for JUnit 4's TestRule is the JUnit 5 Extension Model. In essence, you'd need to translate the behavior of the GrantPermissionRule into an extension, which you could then attach to your test with the @RegisterExtension annotation. Skimming over the rule's code, it looks like the extension for permissions would only need to implement BeforeAllCallback, but I'd need to investigate further to have a better guess here.

As an example of how to write an extension based on an existing rule, you could check out the ActivityScenarioExtension, which is the direct translation of AndroidX's ActivityScenarioRule.

@mannodermaus
Copy link
Owner

mannodermaus commented Jul 27, 2021

Below is a first version of the JUnit5 implementation for the rule. I'll have to conduct some more tests with it, but it'll be likely shipped in the 1.3.0 release of the android-test-core library.

package de.mannodermaus.junit5

import android.Manifest
import android.os.Build
import androidx.test.internal.platform.ServiceLoaderWrapper.loadSingleService
import androidx.test.internal.platform.content.PermissionGranter
import androidx.test.runner.permission.PermissionRequester
import org.junit.jupiter.api.extension.BeforeEachCallback
import org.junit.jupiter.api.extension.ExtensionContext

/**
 * The {@code GrantPermissionExtension} allows granting of runtime permissions on Android M (API 23)
 * and above. Use this extension when a test requires a runtime permission to do its work.
 *
 * <p>When applied to a test class it attempts to grant all requested runtime permissions.
 * The requested permissions will then be granted on the device and will take immediate effect.
 * Permissions can only be requested on Android M (API 23) or above and will be ignored on all other
 * API levels. Once a permission is granted it will apply for all tests running in the current
 * Instrumentation. There is no way of revoking a permission after it was granted. Attempting to do
 * so will crash the Instrumentation process.
 */
public class GrantPermissionExtension
private constructor(
    permissions: Set<String>,
    private val granter: PermissionGranter = loadSingleService(PermissionGranter::class.java, ::PermissionRequester)
) : BeforeEachCallback {

    public companion object {
        @JvmStatic
        public fun grant(vararg permissions: String): GrantPermissionExtension {
            val permissionSet = satisfyPermissionDependencies(*permissions)
            return GrantPermissionExtension(permissionSet)
        }

        private fun satisfyPermissionDependencies(vararg permissions: String): Set<String> {
            val set = permissions.toMutableSet()

            // Grant READ_EXTERNAL_STORAGE implicitly if its counterpart is present
            if (Build.VERSION.SDK_INT >= 16 && Manifest.permission.WRITE_EXTERNAL_STORAGE in set) {
                set.add(Manifest.permission.READ_EXTERNAL_STORAGE)
            }

            return set
        }
    }

    init {
        granter.addPermissions(*permissions.toTypedArray())
    }

    override fun beforeEach(context: ExtensionContext?) {
        granter.requestPermissions()
    }
}

Usage:

@RegisterExtension
public GrantPermissionExtension extension = GrantPermissionExtension.grant(
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.WRITE_EXTERNAL_STORAGE
);

From an initial check, it didn't seem necessary to apply this extension however - the permissions were automatically granted to my emulator regardless of whether I used it or not. Is there some special configuration to disable the automatic granting of permissions that you can provide me with?

@mannodermaus mannodermaus added this to the instrumentation-1.3.0 milestone Jul 27, 2021
@Moriarty16
Copy link
Author

Seems in JUnit4, also if the rule GrantPermissionRule is initialized, related permissions will be granted directly.

@Moriarty16
Copy link
Author

Any progress on this recently?

@Moriarty16
Copy link
Author

No offense, but currently we're facing an android permission handling issue, this blocks a lot of our Java related test suites.
However, if I write the test suite in Python, I never have to deal with the annoying permission handling 'cause we can run our test in su.
With all these trouble, guess eventually I have to write and run my tests with Python3.

@jama5262
Copy link

jama5262 commented Nov 2, 2023

@mannodermaus Any updates on this feature?

@mannodermaus
Copy link
Owner

I posted an exemplary implementation above and haven't heard any feedback to the contrary that it works. Are you facing any problems with that snippet, or does it work for you and you're mainly asking when it would be available in a released version of the library?

@jama5262
Copy link

jama5262 commented Nov 3, 2023

Thank you for your response, @mannodermaus.

It works exceptionally well for me. I'm curious about the possibility of adding this to the library. Managing it ourselves might lead to neglect over time.

Including it in the library would empower the community to maintain and update it as necessary, making it easier for consumers to stay up-to-date.

I believe this is a vital feature to incorporate, given the frequent need for permissions in Android development. Do you think it aligns with the library's scope?

Personally, I believe it does. What's your perspective?

@mannodermaus
Copy link
Owner

Thanks for confirming that it works for you! I'll see what I can do in regards to pushing this into the next version of the instrumentation core shortly.

@mannodermaus
Copy link
Owner

mannodermaus commented Nov 4, 2023

This is now available as part of the new android-test-extensions artifact:

dependencies {
  androidTestImplementation("de.mannodermaus.junit5:android-test-extensions:1.4.0")
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants