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

Refactoring + adding new tests to increase code coverage. #351

Merged
merged 6 commits into from
Mar 15, 2024

Conversation

Laimiux
Copy link
Collaborator

@Laimiux Laimiux commented Mar 15, 2024

What

Miscellaneous non-behavior changes to increase coverage.

@carrotkite
Copy link

carrotkite commented Mar 15, 2024

JaCoCo Code Coverage 83.63% ✅

Class Covered Meta Status
com/instacart/formula/coroutines/FlowRuntime 100% 0%
com/instacart/formula/internal/Listeners 95% 0%
com/instacart/formula/internal/SnapshotImpl 87% 0%
com/instacart/formula/internal/FormulaManagerImpl 87% 0%
com/instacart/formula/internal/ChildrenManager 75% 0%
com/instacart/formula/internal/SingleRequestHolder 0% 0%
com/instacart/formula/rxjava3/RxJavaRuntime 100% 0%
com/instacart/formula/FormulaRuntime 94% 0%
com/instacart/formula/ActionBuilder 100% 0%

Generated by 🚫 Danger

@Laimiux Laimiux force-pushed the laimonas/increase-coverage branch from 673c99d to a8669da Compare March 15, 2024 18:45
@Laimiux Laimiux requested a review from jasonostrander March 15, 2024 18:45
@@ -3,16 +3,6 @@ package com.instacart.formula
/**
* Used within [Action] to receive a cancel event and perform clean up.
*/
interface Cancelable {
companion object {
inline operator fun invoke(crossinline cancel: () -> Unit): Cancelable {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not needed with fun interface

@@ -5,13 +5,13 @@ package com.instacart.formula
*/
class DeferredAction<Event>(
val key: Any,
val action: Action<Event>,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Make it private to reduce coverage requirements

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Simplify this as add tests

}

override fun hashCode(): Int {
return initial.hashCode()
}

fun keyAsString(): String {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not used

@@ -123,12 +123,12 @@ abstract class FormulaContext<out Input, State> internal constructor(
internal abstract fun <Event> eventListener(
key: Any,
useIndex: Boolean = true,
executionType: Transition.ExecutionType? = null,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Default parameter not needed

transition: Transition<Input, State, Event>
): Listener<Event>

// Internal key scope management
@PublishedApi internal abstract fun enterScope(key: Any)
@PublishedApi internal abstract fun endScope()
@PublishedApi internal abstract fun createScopedKey(type: KClass<*>, key: Any? = null): Any
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Default parameter not needed

@@ -17,14 +17,14 @@ class FormulaRuntime<Input : Any, Output : Any>(
private val formula: IFormula<Input, Output>,
private val onOutput: (Output) -> Unit,
private val onError: (Throwable) -> Unit,
config: RuntimeConfig?,
config: RuntimeConfig,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Instead of having default values here as well, lets just use non-null config

} else {
pendingEvaluation = pendingEvaluation || evaluate
}
pendingEvaluation = pendingEvaluation || evaluate
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added runIfNeeded that checks effects and pending evaluation (shared with executeBatch)

@Laimiux Laimiux force-pushed the laimonas/increase-coverage branch from a8669da to a76f428 Compare March 15, 2024 18:50
@@ -255,9 +253,10 @@ class FormulaRuntime<Input : Any, Output : Any>(
} catch (e: Throwable) {
isRunning = false

manager?.markAsTerminated()
val manager = requireManager()
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not possible to enter this block with null manager

@Laimiux Laimiux force-pushed the laimonas/increase-coverage branch 4 times, most recently from 8ecdc4a to 63c552c Compare March 15, 2024 19:41
@@ -91,15 +86,6 @@ internal class SnapshotImpl<out Input, State> internal constructor(
}

fun <Event> dispatch(transition: Transition<Input, State, Event>, event: Event) {
if (!running) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We don't need this check as transitions are controlled with a queue mechanism (lives in FormulaManager).

throw IllegalStateException("Transitions are not allowed during evaluation")
}

if (!delegate.isTerminated() && delegate.isEvaluationNeeded(associatedEvaluationId)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We don't need this check as transitions are controlled with a queue mechanism (lives in FormulaManager).

@Volatile internal var manager: FormulaManagerImpl<Input, State, *>? = null
@Volatile internal var snapshotImpl: SnapshotImpl<Input, State>? = null
@Volatile internal var executionType: Transition.ExecutionType? = null
@Volatile private var manager: FormulaManagerImpl<Input, State, *>? = null
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Making private since getters are not needed

@@ -11,11 +9,10 @@ import com.instacart.formula.Transition
*/
class DeferredTransition<Input, State, EventT> internal constructor(
private val listener: ListenerImpl<Input, State, EventT>,
private val transition: Transition<Input, State, EventT>,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is more of a potential bug fix: we should use mutable transition that lives in ListenerImpl instead relying on fixed value. With dispatching, this value could be out of date by the time we call execute

@@ -41,7 +41,7 @@ internal class ActionBuilderImpl<out Input, State> internal constructor(

private fun <Event> toBoundStream(
stream: Action<Event>,
executionType: Transition.ExecutionType? = null,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No need for default value


if (evaluate) {
var shouldRun = true
while (shouldRun) {
val localInputId = inputId
if (!manager.isTerminated()) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's not possible to hit this case because evaluate will be false if the manager is terminated

// Terminated manager with input change indicates that formula
// key changed and we are resetting formula state. We need to
// start a new formula manager.
if (localInputId != inputId) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No need to check if localInputId != inputId

@Laimiux Laimiux force-pushed the laimonas/increase-coverage branch from 63c552c to a901953 Compare March 15, 2024 20:04
@Laimiux Laimiux changed the base branch from master to laimonas/increase-coverage-pt1 March 15, 2024 20:04
Base automatically changed from laimonas/increase-coverage-pt1 to master March 15, 2024 20:32
@Laimiux Laimiux force-pushed the laimonas/increase-coverage branch from a901953 to 9b7fb8c Compare March 15, 2024 20:32
Copy link

@jasonostrander jasonostrander left a comment

Choose a reason for hiding this comment

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

Looks good! A few questions I have, but no issues.

observer.output { assertThat(this).isEqualTo(1) }

// Check that termination was called
assertThat(terminationCallback.values()).containsExactly(0).inOrder()

Choose a reason for hiding this comment

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

This is interesting behavior. Took me a few read-throughs to understand why this happens. I wonder if we should alert devs somehow when this occurs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Could you elaborate on the interesting part?

Choose a reason for hiding this comment

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

Triggering onTerminate was surprising to me. I thought it would just discard the current evaluation and re-evaluate.

Also I've seen a lot of people trigger side-effects in an onEvent block like this and I'm thinking if that side-effect triggers a new input this would similarly surprise people.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It terminates because I have key defined for the formula

 override fun key(input: Int): Any {
      return input
  }

Choose a reason for hiding this comment

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

Ah, I see now, that makes more sense.

}

observer = runtime.test(root)
observer.input(0)

Choose a reason for hiding this comment

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

Should we assert the output value here? Should be 0, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There should be no output given formula exited before producing one.

Choose a reason for hiding this comment

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

Hmm, I thought there would be a single evaluation, with the transition running afterward?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There was, but since formula was terminated during transition, we don't emit an output.

}

observer = runtime.test(root)
observer.input(0)

Choose a reason for hiding this comment

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

This wouldn't have a valid output after terminating, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point, will validate

@Laimiux Laimiux force-pushed the laimonas/increase-coverage branch from 9b7fb8c to 0040fff Compare March 15, 2024 20:52
@Laimiux Laimiux force-pushed the laimonas/increase-coverage branch from 0040fff to 0e9595a Compare March 15, 2024 21:01
@Laimiux Laimiux merged commit fe5cce8 into master Mar 15, 2024
3 checks passed
@Laimiux Laimiux deleted the laimonas/increase-coverage branch March 15, 2024 22:10
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

Successfully merging this pull request may close these issues.

3 participants