Skip to content

Commit e544a2c

Browse files
committed
Add more e2e tests
1 parent 2a4ad4d commit e544a2c

File tree

13 files changed

+334
-38
lines changed

13 files changed

+334
-38
lines changed

.dockerignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@
1212
**/.venv/
1313
**/venv/
1414

15+
**/test_report/
16+

test-services/exclusions.yaml

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,19 @@
11
exclusions:
22
"alwaysSuspending":
33
- "dev.restate.sdktesting.tests.AwaitTimeout"
4-
- "dev.restate.sdktesting.tests.NonDeterminismErrors"
5-
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication"
6-
- "dev.restate.sdktesting.tests.SideEffect"
7-
- "dev.restate.sdktesting.tests.Sleep"
8-
- "dev.restate.sdktesting.tests.SleepWithFailures"
94
- "dev.restate.sdktesting.tests.State"
105
- "dev.restate.sdktesting.tests.UserErrors"
116
"default":
127
- "dev.restate.sdktesting.tests.AwaitTimeout"
13-
- "dev.restate.sdktesting.tests.CallOrdering"
148
- "dev.restate.sdktesting.tests.CancelInvocation"
15-
- "dev.restate.sdktesting.tests.Ingress"
16-
- "dev.restate.sdktesting.tests.KillInvocation"
17-
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication"
18-
- "dev.restate.sdktesting.tests.Sleep"
19-
- "dev.restate.sdktesting.tests.SleepWithFailures"
9+
- "dev.restate.sdktesting.tests.KafkaIngress"
2010
- "dev.restate.sdktesting.tests.State"
2111
- "dev.restate.sdktesting.tests.UserErrors"
2212
"lazyState":
2313
- "dev.restate.sdktesting.tests.State"
24-
"persistedTimers":
25-
- "dev.restate.sdktesting.tests.Sleep"
2614
"singleThreadSinglePartition":
2715
- "dev.restate.sdktesting.tests.AwaitTimeout"
28-
- "dev.restate.sdktesting.tests.CallOrdering"
2916
- "dev.restate.sdktesting.tests.CancelInvocation"
30-
- "dev.restate.sdktesting.tests.Ingress"
3117
- "dev.restate.sdktesting.tests.KafkaIngress"
32-
- "dev.restate.sdktesting.tests.KillInvocation"
33-
- "dev.restate.sdktesting.tests.KillRuntime"
34-
- "dev.restate.sdktesting.tests.ProxyRequestSigning"
35-
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication"
36-
- "dev.restate.sdktesting.tests.Sleep"
37-
- "dev.restate.sdktesting.tests.SleepWithFailures"
3818
- "dev.restate.sdktesting.tests.State"
39-
- "dev.restate.sdktesting.tests.StopRuntime"
4019
- "dev.restate.sdktesting.tests.UserErrors"
41-
- "dev.restate.sdktesting.tests.WorkflowAPI"

test-services/services/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,17 @@
1111
from typing import Dict, Union
1212
from restate import Service, VirtualObject, Workflow
1313

14-
from .counter import counter
14+
from .counter import counter_object
1515
from .proxy import proxy
1616
from .awakable_holder import awakeable_holder
1717
from. block_and_wait_workflow import workflow
1818
from .cancel_test import runner, blocking_service
19+
from .failing import failing
20+
from .kill_test import kill_runner, kill_singleton
21+
from .list_object import list_object
22+
from .map_object import map_object
23+
from .non_determinism import non_deterministic
24+
from .test_utils import test_utils
1925

2026
def list_services(bindings):
2127
"""List all services in this module"""

test-services/services/block_and_wait_workflow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# pylint: disable=W0613
1414
# pylint: disable=W0622
1515

16-
from restate import Workflow, WorkflowContext, WorkflowSharedContext
16+
from restate import Workflow, WorkflowContext, WorkflowSharedContext
1717
from restate.exceptions import TerminalError
1818

1919
workflow = Workflow("BlockAndWaitWorkflow")

test-services/services/cancel_test.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,14 @@ async def start_test(ctx: ObjectContext, op: BlockingOperation):
3535
raise t
3636

3737
@runner.handler(name="verifyTest")
38-
async def verify_test(ctx: ObjectContext):
38+
async def verify_test(ctx: ObjectContext) -> bool:
3939
state = await ctx.get("state")
4040
if state is None:
4141
return False
4242
return state
4343

4444

45-
blocking_service = VirtualObject("BlockingService")
46-
45+
blocking_service = VirtualObject("CancelTestBlockingService")
4746

4847
@blocking_service.handler()
4948
async def block(ctx: ObjectContext, op: BlockingOperation):

test-services/services/counter.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@
1616
from restate import VirtualObject, ObjectContext
1717
from restate.exceptions import TerminalError
1818

19-
counter = VirtualObject("Counter")
19+
counter_object = VirtualObject("Counter")
2020

2121
COUNTER_KEY = "counter"
2222

2323

24-
@counter.handler()
24+
@counter_object.handler()
2525
async def reset(ctx: ObjectContext):
2626
ctx.clear(COUNTER_KEY)
2727

2828

29-
@counter.handler()
29+
@counter_object.handler()
3030
async def get(ctx: ObjectContext) -> int:
3131
c: int | None = await ctx.get(COUNTER_KEY)
3232
if c is None:
@@ -39,7 +39,7 @@ class CounterUpdateResponse(TypedDict):
3939
newValue: int
4040

4141

42-
@counter.handler()
42+
@counter_object.handler()
4343
async def add(ctx: ObjectContext, addend: int) -> CounterUpdateResponse:
4444
old_value: int | None = await ctx.get(COUNTER_KEY)
4545
if old_value is None:
@@ -49,8 +49,8 @@ async def add(ctx: ObjectContext, addend: int) -> CounterUpdateResponse:
4949
return CounterUpdateResponse(oldValue=old_value, newValue=new_value)
5050

5151

52-
@counter.handler()
53-
async def addThenFail(ctx: ObjectContext, addend: int):
52+
@counter_object.handler(name="addThenFail")
53+
async def add_then_fail(ctx: ObjectContext, addend: int):
5454
old_value: int | None = await ctx.get(COUNTER_KEY)
5555
if old_value is None:
5656
old_value = 0

test-services/services/failing.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#
2+
# Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
3+
#
4+
# This file is part of the Restate SDK for Python,
5+
# which is released under the MIT license.
6+
#
7+
# You can find a copy of the license in file LICENSE in the root
8+
# directory of this repository or package, or at
9+
# https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
10+
#
11+
"""example.py"""
12+
# pylint: disable=C0116
13+
# pylint: disable=W0613
14+
# pylint: disable=W0622
15+
16+
from restate import VirtualObject, ObjectContext
17+
from restate.exceptions import TerminalError
18+
19+
failing = VirtualObject("Failing")
20+
21+
@failing.handler(name="terminallyFailingCall")
22+
async def terminally_failing_call(ctx: ObjectContext, msg: str):
23+
raise TerminalError(message=msg)
24+
25+
@failing.handler(name="callTerminallyFailingCall")
26+
async def call_terminally_failing_call(ctx: ObjectContext, msg: str) -> str:
27+
await ctx.object_call(terminally_failing_call, key="random-583e1bf2", arg=msg)
28+
29+
raise Exception("Should not reach here")
30+
31+
failures = 0
32+
33+
@failing.handler(name="failingCallWithEventualSuccess")
34+
async def failing_call_with_eventual_success(ctx: ObjectContext) -> int:
35+
global failures
36+
failures += 1
37+
if failures >= 4:
38+
failures = 0
39+
return 4
40+
raise ValueError(f"Failed at attempt: {failures}")
41+
42+
43+
side_effect_failures = 0
44+
45+
@failing.handler(name="failingSideEffectWithEventualSuccess")
46+
async def failing_side_effect_with_eventual_success(ctx: ObjectContext) -> int:
47+
48+
def side_effect():
49+
global side_effect_failures
50+
side_effect_failures += 1
51+
if side_effect_failures >= 4:
52+
side_effect_failures = 0
53+
return 4
54+
raise ValueError(f"Failed at attempt: {side_effect_failures}")
55+
56+
return await ctx.run("sideEffect", side_effect) # type: ignore
57+
58+
59+
@failing.handler(name="terminallyFailingSideEffect")
60+
async def terminally_failing_side_effect(ctx: ObjectContext):
61+
62+
def side_effect():
63+
raise TerminalError(message="Terminally failing side effect")
64+
65+
await ctx.run("sideEffect", side_effect)
66+
raise ValueError("Should not reach here")
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#
2+
# Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
3+
#
4+
# This file is part of the Restate SDK for Python,
5+
# which is released under the MIT license.
6+
#
7+
# You can find a copy of the license in file LICENSE in the root
8+
# directory of this repository or package, or at
9+
# https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
10+
#
11+
"""example.py"""
12+
# pylint: disable=C0116
13+
# pylint: disable=W0613
14+
15+
from restate import Service, Context, VirtualObject, ObjectContext
16+
17+
from . import awakable_holder
18+
19+
kill_runner = Service("KillTestRunner")
20+
21+
@kill_runner.handler(name="startCallTree")
22+
async def start_call_tree(ctx: Context):
23+
await ctx.object_call(recursive_call, key="", arg=None)
24+
25+
kill_singleton = VirtualObject("KillTestSingleton")
26+
27+
@kill_singleton.handler(name="recursiveCall")
28+
async def recursive_call(ctx: ObjectContext):
29+
name, promise = ctx.awakeable()
30+
ctx.object_send(awakable_holder.hold, key="kill", arg=name)
31+
await promise
32+
33+
await ctx.object_call(recursive_call, key="", arg=None)
34+
35+
@kill_singleton.handler(name="isUnlocked")
36+
async def is_unlocked(ctx: ObjectContext):
37+
return None
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#
2+
# Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
3+
#
4+
# This file is part of the Restate SDK for Python,
5+
# which is released under the MIT license.
6+
#
7+
# You can find a copy of the license in file LICENSE in the root
8+
# directory of this repository or package, or at
9+
# https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
10+
#
11+
"""example.py"""
12+
# pylint: disable=C0116
13+
# pylint: disable=W0613
14+
15+
from restate import VirtualObject, ObjectContext
16+
17+
list_object = VirtualObject("ListObject")
18+
19+
@list_object.handler()
20+
async def append(ctx: ObjectContext, value: str):
21+
list = await ctx.get("list") or []
22+
ctx.set("list", list + [value])
23+
24+
@list_object.handler()
25+
async def get(ctx: ObjectContext) -> list[str]:
26+
return await ctx.get("list") or []
27+
28+
@list_object.handler()
29+
async def clear(ctx: ObjectContext) -> list[str]:
30+
result = await ctx.get("list") or []
31+
ctx.clear("list")
32+
return result
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#
2+
# Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
3+
#
4+
# This file is part of the Restate SDK for Python,
5+
# which is released under the MIT license.
6+
#
7+
# You can find a copy of the license in file LICENSE in the root
8+
# directory of this repository or package, or at
9+
# https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
10+
#
11+
"""example.py"""
12+
# pylint: disable=C0116
13+
# pylint: disable=W0613
14+
15+
from typing import TypedDict
16+
from restate import VirtualObject, ObjectContext
17+
18+
map_object = VirtualObject("MapObject")
19+
20+
21+
class Entry(TypedDict):
22+
key: str
23+
value: str
24+
25+
@map_object.handler(name="set")
26+
async def map_set(ctx: ObjectContext, entry: Entry):
27+
ctx.set(entry["key"], entry["value"])
28+
29+
@map_object.handler(name="get")
30+
async def map_get(ctx: ObjectContext, key: str) -> str:
31+
return await ctx.get(key) or ""
32+
33+
@map_object.handler(name="clearAll")
34+
async def map_clear_all(ctx: ObjectContext) -> list[Entry]:
35+
entries = []
36+
for key in await ctx.state_keys():
37+
value: str = await ctx.get(key) # type: ignore
38+
entry = Entry(key=key, value=value)
39+
entries.append(entry)
40+
ctx.clear(key)
41+
return entries

0 commit comments

Comments
 (0)