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

[DO_NOT_MERGE] Make RibEvents' MutableSharedFlows buffers configurable. #642

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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 @@ -20,20 +20,52 @@ import io.reactivex.Observable
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.rx2.asObservable

public object RibEvents {
private var extraBufferCapacity: Int = Channel.UNLIMITED

private val mutableRouterEvents =
MutableSharedFlow<RibRouterEvent>(0, Channel.UNLIMITED, BufferOverflow.DROP_OLDEST)
private val mutableRibDurationEvents =
MutableSharedFlow<RibActionInfo>(0, Channel.UNLIMITED, BufferOverflow.DROP_OLDEST)
/**
* Sets the extra buffer capacity for [routerEventsFlow] and [ribActionEventsFlow].
*
* This function must be called on the main thread, and before any usage of:
Copy link
Member

Choose a reason for hiding this comment

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

What will happen if this isn't true? How can we guarantee it's called before?

Copy link
Contributor Author

@psteiger psteiger Oct 14, 2024

Choose a reason for hiding this comment

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

@tyvsmith

What will happen if this isn't true?

Then, the original value (UNLIMITED) will be used at the moment someone calls one of the RibEvents flow / observable.

How can we guarantee it's called before?

I propose we just do it on our Application.

Copy link
Member

Choose a reason for hiding this comment

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

What's the earliest we can safely fetch a param? Do we ever call this prior?

Copy link
Contributor Author

@psteiger psteiger Oct 14, 2024

Choose a reason for hiding this comment

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

@tyvsmith

What's the earliest we can safely fetch a param?

It seems we'll just have to bite that first session with some default value, and have the new configuration for the next app starts.

Do we ever call this prior?

No, I don't think there's any access to RibEvents flow before Application.onCreate. AFAIK only ContentProvider can run before, and we don't have any touching RibEvents.

* 1. [routerEventsFlow]
* 2. [routerEvents]
* 3. [ribActionEventsFlow]
* 4. [ribActionEvents]
*/
@JvmStatic
public fun setExtraBufferCapacity(capacity: Int) {
extraBufferCapacity = capacity
}

private val mutableRouterEvents by lazy {
MutableSharedFlow<RibRouterEvent>(0, extraBufferCapacity, BufferOverflow.DROP_OLDEST)
}

private val mutableRibDurationEvents by lazy {
MutableSharedFlow<RibActionInfo>(0, extraBufferCapacity, BufferOverflow.DROP_OLDEST)
}

@JvmStatic
public val routerEventsFlow: SharedFlow<RibRouterEvent> by lazy {
mutableRouterEvents.asSharedFlow()
}

@JvmStatic
public val routerEvents: Observable<RibRouterEvent> = mutableRouterEvents.asObservable()
public val routerEvents: Observable<RibRouterEvent> by lazy { mutableRouterEvents.asObservable() }

@JvmStatic
public val ribActionEvents: Observable<RibActionInfo> = mutableRibDurationEvents.asObservable()
public val ribActionEventsFlow: SharedFlow<RibActionInfo> by lazy {
mutableRibDurationEvents.asSharedFlow()
}

@JvmStatic
public val ribActionEvents: Observable<RibActionInfo> by lazy {
mutableRibDurationEvents.asObservable()
}

/** Indicates if [ribActionEvents] will be emitting. */
public var areRibActionEmissionsAllowed: Boolean = false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2024. Uber Technologies
*
* 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 com.uber.rib.core

import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.mockito.kotlin.mock

@OptIn(ExperimentalCoroutinesApi::class)
@Ignore(
"""
Test only passes when running in isolation: RibEvents flows might've been accessed
when running full suite.
""",
)
class RibEventsTest {
private val extraBufferCapacity = 16

@Before
fun setUp() {
RibEvents.setExtraBufferCapacity(extraBufferCapacity)
}

@After
fun tearDown() {
RibEvents.setExtraBufferCapacity(Channel.UNLIMITED)
}

@Test
fun setExtraBufferCapacityTest() = runTest {
val results = mutableListOf<RibRouterEvent>()
backgroundScope.launch { RibEvents.routerEventsFlow.collect(results::add) }
runCurrent()
repeat(32) { RibEvents.emitRouterEvent(RibEventType.ATTACHED, mock(), mock()) }
runCurrent()
assertThat(results.size).isEqualTo(16)
}
}
Loading