blob: f081fb6711d22ef3d5b524503726a6db7a4952e1 [file] [log] [blame]
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.datastore.core.multiprocess
import android.os.Parcelable
import androidx.datastore.core.twoWayIpc.CompositeServiceSubjectModel
import androidx.datastore.core.twoWayIpc.IpcAction
import androidx.datastore.core.twoWayIpc.TwoWayIpcSubject
import com.google.common.truth.Truth.assertThat
import kotlinx.parcelize.Parcelize
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
class TwoWayIpcTest {
@get:Rule
val multiProcessRule = MultiProcessTestRule()
@Parcelize
internal class MultiplyBy3Action(
var input: Int
) : IpcAction<MultiplyBy3Action.Output>() {
@Parcelize
data class Output(val value: Int) : Parcelable
override suspend fun invokeInRemoteProcess(
subject: TwoWayIpcSubject
): Output {
return Output(input * 3)
}
}
@Test
fun sample() = multiProcessRule.runTest {
val connection = multiProcessRule.createConnection()
val subject = connection.createSubject(this)
assertThat(
subject.invokeInRemoteProcess(MultiplyBy3Action(3))
).isEqualTo(MultiplyBy3Action.Output(9))
}
@Parcelize
internal class ThrowingAction : IpcAction<ThrowingAction>() {
override suspend fun invokeInRemoteProcess(
subject: TwoWayIpcSubject
): ThrowingAction {
error("some error i got")
}
}
@Test
fun exceptionThrown() = multiProcessRule.runTest {
val connection = multiProcessRule.createConnection()
val subject = connection.createSubject(this)
val result = runCatching {
subject.invokeInRemoteProcess(ThrowingAction())
}
assertThat(result.exceptionOrNull()).hasMessageThat().contains(
"some error i got"
)
}
@Parcelize
internal data class ValueInRemoteAction(
val id: String,
val value: String,
val set: Boolean
) : IpcAction<ValueInRemoteAction.Output>() {
@Parcelize
data class Output(val value: String) : Parcelable
override suspend fun invokeInRemoteProcess(
subject: TwoWayIpcSubject
): Output {
if (set) {
subject.data[StringKey(id)] = value
}
return Output(subject.data[StringKey(id)])
}
data class StringKey(val id: String) : CompositeServiceSubjectModel.Key<String>()
}
@Test
fun multipleSubjects() = multiProcessRule.runTest {
val connection = multiProcessRule.createConnection()
val subject1 = connection.createSubject(this)
val subject2 = connection.createSubject(this)
val action = ValueInRemoteAction(
id = "a", value = "b", set = true
)
assertThat(
subject1.invokeInRemoteProcess(action).value
).isEqualTo("b")
assertThat(
subject2.invokeInRemoteProcess(action).value
).isEqualTo("b")
assertThat(
subject1.invokeInRemoteProcess(action.copy(value = "c")).value
).isEqualTo("c")
assertThat(
// don't set
subject1.invokeInRemoteProcess(action.copy(value = "d", set = false)).value
).isEqualTo("c")
assertThat(
// don't set
subject2.invokeInRemoteProcess(action.copy(value = "d", set = false)).value
).isEqualTo("b")
}
@Parcelize
internal class SendFromRemoteProcess(
val value: String
) : IpcAction<SendFromRemoteProcess>() {
@Parcelize
internal class ActionInMainProcess(
val value: String
) : IpcAction<ActionInMainProcess>() {
override suspend fun invokeInRemoteProcess(
subject: TwoWayIpcSubject
): ActionInMainProcess {
subject.data[VALUE_KEY] = value
return this
}
}
override suspend fun invokeInRemoteProcess(
subject: TwoWayIpcSubject
): SendFromRemoteProcess {
subject.invokeInRemoteProcess(
ActionInMainProcess(
"$value-$value"
)
)
return this
}
companion object {
val VALUE_KEY = CompositeServiceSubjectModel.Key<String>()
}
}
@Test
fun getMessageFromRemoteProcess() = multiProcessRule.runTest {
val connection = multiProcessRule.createConnection()
val hostSubject = connection.createSubject(this)
hostSubject.invokeInRemoteProcess(SendFromRemoteProcess("hello"))
assertThat(
hostSubject.data[SendFromRemoteProcess.VALUE_KEY]
).isEqualTo("hello-hello")
}
}