Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,35 @@ import com.fasterxml.jackson.annotation.JsonProperty
data class PermissionsConfiguration(
@JsonProperty("grant") val grant: Set<Permission> = emptySet(),
@JsonProperty("lifecycle") val lifecycle: GrantLifecycle = GrantLifecycle.BEFORE_TEST_RUN,
@JsonProperty("applications") val applications: Map<String, ApplicationPermissionsConfiguration> = emptyMap(),
) {
fun resolve(applicationBundleId: String): List<ApplicationPermissionGrant> {
val applicationUnderTestGrant = grant.takeIf { it.isNotEmpty() }?.let {
ApplicationPermissionGrant(
bundleId = applicationBundleId,
permissions = it,
)
}
val explicitApplicationGrants = applications.mapNotNull { (bundleId, configuration) ->
configuration.grant.takeIf { it.isNotEmpty() }?.let {
ApplicationPermissionGrant(
bundleId = bundleId,
permissions = it,
)
}
}

return listOfNotNull(applicationUnderTestGrant) + explicitApplicationGrants
}
}

data class ApplicationPermissionsConfiguration(
@JsonProperty("grant") val grant: Set<Permission> = emptySet(),
)

data class ApplicationPermissionGrant(
val bundleId: String,
val permissions: Set<Permission>,
)

enum class GrantLifecycle {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class ConfigurationSerializationTest {
"ios/sample_1.yaml",
"ios/sample_2.yaml",
"ios/sample_3.yaml",
"ios/sample_8.yaml",
)
)
@ParameterizedTest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.malinskiy.marathon.config.serialization.yaml.SerializeModule
import com.malinskiy.marathon.config.vendor.apple.TimeoutConfiguration
import com.malinskiy.marathon.config.vendor.apple.TestType
import com.malinskiy.marathon.config.vendor.apple.ios.ApplicationPermissionsConfiguration
import com.malinskiy.marathon.config.vendor.apple.ios.GrantLifecycle
import com.malinskiy.marathon.config.vendor.apple.ios.Permission
import com.malinskiy.marathon.config.vendor.apple.ios.PullingPolicy
import com.malinskiy.marathon.config.vendor.apple.ios.XcresultConfiguration
import org.amshove.kluent.`should be`
Expand Down Expand Up @@ -166,4 +169,22 @@ class IosConfigurationFactoryTest {
xcresultConfiguration.pullingPolicy `should be equal to` PullingPolicy.NEVER
xcresultConfiguration.remoteClean `should be` false
}

@Test
fun `should parse permissions for multiple applications`() {
val file = File(ConfigurationFactoryTest::class.java.getResource("/fixture/config/ios/sample_8.yaml").file)
val configuration = parser.parse(file)

val permissions = (configuration.vendorConfiguration as VendorConfiguration.IOSConfiguration).permissions
permissions.grant shouldBeEqualTo setOf(Permission.Contacts)
permissions.lifecycle shouldBeEqualTo GrantLifecycle.BEFORE_TEST_RUN
permissions.applications shouldBeEqualTo mapOf(
"com.apple.Maps" to ApplicationPermissionsConfiguration(
grant = setOf(Permission.Location),
),
"com.example.companion" to ApplicationPermissionsConfiguration(
grant = setOf(Permission.Microphone),
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.malinskiy.marathon.config.vendor.ios

import com.malinskiy.marathon.config.vendor.apple.ios.ApplicationPermissionGrant
import com.malinskiy.marathon.config.vendor.apple.ios.ApplicationPermissionsConfiguration
import com.malinskiy.marathon.config.vendor.apple.ios.GrantLifecycle
import com.malinskiy.marathon.config.vendor.apple.ios.Permission
import com.malinskiy.marathon.config.vendor.apple.ios.PermissionsConfiguration
import org.amshove.kluent.shouldBeEqualTo
import org.junit.jupiter.api.Test

class PermissionsConfigurationTest {
@Test
fun `legacy grant targets application under test`() {
val configuration = PermissionsConfiguration(
grant = setOf(Permission.Contacts),
lifecycle = GrantLifecycle.BEFORE_EACH_BATCH,
)

configuration.resolve("com.example.app") shouldBeEqualTo listOf(
ApplicationPermissionGrant(
bundleId = "com.example.app",
permissions = setOf(Permission.Contacts),
)
)
}

@Test
fun `application grants support multiple bundle identifiers with shared lifecycle`() {
val configuration = PermissionsConfiguration(
lifecycle = GrantLifecycle.BEFORE_TEST_RUN,
applications = mapOf(
"com.apple.Maps" to ApplicationPermissionsConfiguration(
grant = setOf(Permission.Location),
),
"com.example.companion" to ApplicationPermissionsConfiguration(
grant = setOf(Permission.Microphone),
),
),
)

configuration.resolve("com.example.app").toSet() shouldBeEqualTo setOf(
ApplicationPermissionGrant(
bundleId = "com.apple.Maps",
permissions = setOf(Permission.Location),
),
ApplicationPermissionGrant(
bundleId = "com.example.companion",
permissions = setOf(Permission.Microphone),
),
)
}

@Test
fun `empty grants are ignored`() {
val configuration = PermissionsConfiguration(
applications = mapOf(
"com.apple.Maps" to ApplicationPermissionsConfiguration(),
),
)

configuration.resolve("com.example.app") shouldBeEqualTo emptyList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: "sample-app tests"
outputDir: "./marathon"
vendorConfiguration:
type: "iOS"
bundle:
derivedDataDir: "derivedDataDir"
permissions:
lifecycle: BEFORE_TEST_RUN
grant:
- contacts
applications:
com.apple.Maps:
grant:
- location
com.example.companion:
grant:
- microphone
17 changes: 17 additions & 0 deletions docs/runner/apple/configure/ios.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,23 @@ permissions:
</TabItem>
</Tabs>

Permissions can also be granted to multiple applications by bundle identifier. All configured grants use the top-level lifecycle.
The existing `grant` list continues to target the application under test.

```yaml
permissions:
lifecycle: BEFORE_TEST_RUN
grant:
- contacts
applications:
com.apple.Maps:
grant:
- location
com.example.companion:
grant:
- microphone
```

### Timeouts

All the timeouts for test run can be overridden, here is an example configuration with default values:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ class AppleSimulatorApplicationInstaller(override val vendorConfiguration: Vendo

private suspend fun grantPermissions(device: AppleSimulatorDevice, bundleId: String) {
if (vendorConfiguration.permissions.lifecycle == GrantLifecycle.BEFORE_TEST_RUN) {
for (permission in vendorConfiguration.permissions.grant) {
device.grant(permission, bundleId)
vendorConfiguration.permissions.resolve(bundleId).forEach { applicationGrant ->
for (permission in applicationGrant.permissions) {
device.grant(permission, applicationGrant.bundleId)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,10 @@ class AppleSimulatorDevice(
val (listener, lineListeners) = createExecutionListeners(devicePoolId, testBatch, deferred)
executionLineListeners = lineListeners.onEach { addLineListener(it) }
if (vendorConfiguration.permissions.lifecycle == GrantLifecycle.BEFORE_EACH_BATCH) {
for (permission in vendorConfiguration.permissions.grant) {
grant(permission, testBundle.appId)
vendorConfiguration.permissions.resolve(testBundle.appId).forEach { applicationGrant ->
for (permission in applicationGrant.permissions) {
grant(permission, applicationGrant.bundleId)
}
}
}
AppleDeviceTestRunner(this@AppleSimulatorDevice, testBundleIdentifier).execute(
Expand Down