Skip to content

Commit

Permalink
feat(test): add performance tests to check it doesn't timeout in edge…
Browse files Browse the repository at this point in the history
… cases
  • Loading branch information
sassanh committed May 4, 2024
1 parent debf12d commit 4499656
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- feat(core): add `view` method to `Store` to allow computing a derived value from
the state only when it is accessed and caching the result until the relevant parts
of the state change
- feat(test): add performance tests to check it doesn't timeout in edge cases

## Version 0.15.0

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "python-redux"
version = "0.15.0"
version = "0.15.1"
description = "Redux implementation for Python"
authors = ["Sassan Haradji <[email protected]>"]
license = "Apache-2.0"
Expand Down
88 changes: 88 additions & 0 deletions tests/test_performance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# ruff: noqa: D100, D101, D102, D103, D104, D107

from __future__ import annotations

from dataclasses import replace
from typing import Generator

import pytest
from immutable import Immutable

from redux.basic_types import (
BaseAction,
CompleteReducerResult,
CreateStoreOptions,
FinishAction,
FinishEvent,
InitAction,
InitializationActionError,
)
from redux.main import Store


class StateType(Immutable):
value: int


class IncrementAction(BaseAction): ...


Action = IncrementAction | InitAction | FinishAction


def reducer(
state: StateType | None,
action: Action,
) -> StateType | CompleteReducerResult[StateType, Action, FinishEvent]:
if state is None:
if isinstance(action, InitAction):
return StateType(value=0)
raise InitializationActionError(action)

if isinstance(action, IncrementAction):
return replace(state, value=state.value + 1)

return state


class StoreType(Store[StateType, Action, FinishEvent]):
@property
def state(self: StoreType) -> StateType | None:
return self._state


@pytest.fixture()
def store() -> Generator[StoreType, None, None]:
store = StoreType(reducer, options=CreateStoreOptions(auto_init=True))
yield store

store.dispatch(FinishAction())


# These tests will timeout if they take a long time to run, indicating a performance
# issue.


def test_simple_dispatch(store: StoreType) -> None:
count = 100000
for _ in range(count):
store.dispatch(IncrementAction())

assert store.state is not None
assert store.state.value == count


def test_dispatch_with_subscriptions(store: StoreType) -> None:
for _ in range(1000):

def callback(_: StateType | None) -> None:
pass

store.subscribe(callback)

count = 500
for _ in range(count):
store.dispatch(IncrementAction())

assert store.state is not None
assert store.state.value == count

0 comments on commit 4499656

Please sign in to comment.