Skip to content

Commit 2480d7e

Browse files
Lorenzo CurcioLorenzo Curcio
Lorenzo Curcio
authored and
Lorenzo Curcio
committed
fixed and added more unit tests. Added example
Signed-off-by: Lorenzo Curcio <[email protected]>
1 parent 1a82754 commit 2480d7e

File tree

5 files changed

+209
-2
lines changed

5 files changed

+209
-2
lines changed

dapr/actor/runtime/mock_state_manager.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ async def get_or_add_state(self, state_name: str, value: T) -> Optional[T]:
151151
if self.is_state_marked_for_remove(state_name)
152152
else StateChangeKind.add
153153
)
154+
self._mock_state[state_name] = value
154155
self._default_state_change_tracker[state_name] = StateMetadata(value, change_kind)
155156
return value
156157

@@ -173,7 +174,7 @@ async def add_or_update_state(
173174
if state_metadata.change_kind == StateChangeKind.none:
174175
state_metadata.change_kind = StateChangeKind.update
175176
self._default_state_change_tracker[state_name] = state_metadata
176-
self._mock_state[state_name] = value
177+
self._mock_state[state_name] = new_value
177178
return new_value
178179

179180
has_value = state_name in self._mock_state

examples/demo_actor/README.md

+45
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This document describes how to create an Actor(DemoActor) and invoke its methods
66
- **The actor service(demo_actor_service.py).** This implements FastAPI service that is going to host the actor. It contains the implementation of the actor, `demo_actor.py`. An actor implementation is a class that derives from the base type `Actor` and implements the interfaces defined in `demo_actor_interface.py`.
77
- **The actor service for flask(demo_actor_flask.py).** This implements Flask web service that is going to host the actor.
88
- **The actor client(demo_actor_client.py)** This contains the implementation of the actor client which calls DemoActor's method defined in Actor Interfaces.
9+
- **Actor tests(test_demo_actor.py)** This contains actor unit tests using mock actor testing functionality.
910

1011
## Pre-requisites
1112

@@ -183,3 +184,47 @@ expected_stdout_lines:
183184
kubectl logs -l app="demoactor-client" -c demoactor-client
184185
```
185186

187+
## Run DemoActor mock actor tests
188+
189+
<!-- STEP
190+
name: Actor Tests
191+
background: true
192+
sleep: 5
193+
expected_stdout_lines:
194+
- '----------------------------------------------------------------------'
195+
- 'OK'
196+
timeout_seconds: 60
197+
-->
198+
199+
1. Run Tests
200+
201+
```bash
202+
cd demo_actor
203+
unittest test_demo_actor.py
204+
```
205+
206+
Expected output (note that the unit test print outputs might not necessarily be in this order - what really matters is that all tests pass anyway):
207+
208+
```
209+
has_value: False
210+
set_my_data: {'state': 5}
211+
has_value: True
212+
clear_my_data
213+
has_value: False
214+
..has_value: False
215+
.set reminder to True
216+
set reminder is done
217+
set reminder to False
218+
set reminder is done
219+
.has_value: False
220+
set_my_data: {'state': 5}
221+
has_value: True
222+
.
223+
----------------------------------------------------------------------
224+
Ran 5 tests in 0.052s
225+
226+
OK
227+
```
228+
229+
<!-- END_STEP -->
230+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import unittest
2+
3+
from demo_actor import DemoActor
4+
5+
from dapr.actor.runtime.mock_actor import create_mock_actor
6+
7+
8+
class DemoActorTests(unittest.IsolatedAsyncioTestCase):
9+
def test_create_actor(self):
10+
mockactor = create_mock_actor(DemoActor, '1')
11+
self.assertEqual(mockactor.id.id, '1')
12+
13+
async def test_get_data(self):
14+
mockactor = create_mock_actor(DemoActor, '1')
15+
self.assertFalse(mockactor._state_manager._mock_state)
16+
val = await mockactor.get_my_data()
17+
self.assertIsNone(val)
18+
19+
async def test_set_data(self):
20+
mockactor = create_mock_actor(DemoActor, '1')
21+
self.assertFalse(mockactor._state_manager._mock_state)
22+
val = await mockactor.get_my_data()
23+
self.assertIsNone(val)
24+
await mockactor.set_my_data({'state': 5})
25+
val = await mockactor.get_my_data()
26+
self.assertIs(val['state'], 5) # type: ignore
27+
28+
async def test_clear_data(self):
29+
mockactor = create_mock_actor(DemoActor, '1')
30+
self.assertFalse(mockactor._state_manager._mock_state)
31+
val = await mockactor.get_my_data()
32+
self.assertIsNone(val)
33+
await mockactor.set_my_data({'state': 5})
34+
val = await mockactor.get_my_data()
35+
self.assertIs(val['state'], 5) # type: ignore
36+
await mockactor.clear_my_data()
37+
val = await mockactor.get_my_data()
38+
self.assertIsNone(val)
39+
40+
async def test_reminder(self):
41+
mockactor = create_mock_actor(DemoActor, '1')
42+
self.assertFalse(mockactor._state_manager._mock_reminders)
43+
await mockactor.set_reminder(True)
44+
self.assertTrue('demo_reminder' in mockactor._state_manager._mock_reminders)
45+
await mockactor.set_reminder(False)
46+
self.assertFalse(mockactor._state_manager._mock_reminders)

tests/actor/test_mock_actor.py

-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,6 @@ async def test_test_data(self):
246246

247247
async def test_add_state(self):
248248
mockactor = create_mock_actor(MockTestActor, '1')
249-
print(mockactor._state_manager._mock_state)
250249
self.assertFalse(mockactor._state_manager._mock_state)
251250
await mockactor.add_state('test', 5)
252251
self.assertTrue('test' in mockactor._state_manager._mock_state)
+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import unittest
2+
3+
from dapr.actor import Actor, ActorInterface
4+
from dapr.actor.runtime.mock_actor import create_mock_actor
5+
from dapr.actor.runtime.mock_state_manager import MockStateManager
6+
7+
8+
def double(_: str, x: int) -> int:
9+
return 2 * x
10+
11+
12+
class MockTestActorInterface(ActorInterface):
13+
pass
14+
15+
16+
class MockTestActor(Actor, MockTestActorInterface):
17+
def __init__(self, ctx, actor_id):
18+
super().__init__(ctx, actor_id)
19+
20+
21+
class ActorMockActorTests(unittest.IsolatedAsyncioTestCase):
22+
def test_init_state(self):
23+
mock_actor = create_mock_actor(MockTestActor, 'test')
24+
state_manager = mock_actor._state_manager
25+
self.assertIsInstance(state_manager, MockStateManager)
26+
self.assertFalse(state_manager._mock_state)
27+
self.assertFalse(state_manager._mock_reminders)
28+
self.assertFalse(state_manager._mock_timers)
29+
30+
async def test_add_state(self):
31+
mock_actor = create_mock_actor(MockTestActor, 'test')
32+
state_manager = mock_actor._state_manager
33+
await state_manager.add_state('state', 5)
34+
self.assertIs(state_manager._mock_state['state'], 5)
35+
await state_manager.add_state('state2', 5)
36+
self.assertIs(state_manager._mock_state['state2'], 5)
37+
with self.assertRaises(ValueError):
38+
await state_manager.add_state('state', 5)
39+
40+
async def test_get_state(self):
41+
mock_actor = create_mock_actor(MockTestActor, 'test')
42+
state_manager = mock_actor._state_manager
43+
with self.assertRaises(KeyError):
44+
await state_manager.get_state('state')
45+
await state_manager.add_state('state', 5)
46+
value = await state_manager.get_state('state')
47+
self.assertIs(value, 5)
48+
49+
async def test_set_state(self):
50+
mock_actor = create_mock_actor(MockTestActor, 'test')
51+
state_manager = mock_actor._state_manager
52+
await state_manager.set_state('state', 5)
53+
self.assertIs(state_manager._mock_state['state'], 5)
54+
await state_manager.set_state('state', 10)
55+
self.assertIs(state_manager._mock_state['state'], 10)
56+
57+
async def test_remove_state(self):
58+
mock_actor = create_mock_actor(MockTestActor, 'test')
59+
state_manager = mock_actor._state_manager
60+
await state_manager.set_state('state', 5)
61+
self.assertIs(state_manager._mock_state['state'], 5)
62+
await state_manager.remove_state('state')
63+
self.assertFalse(state_manager._mock_state)
64+
with self.assertRaises(KeyError):
65+
await state_manager.remove_state('state')
66+
67+
async def test_contains_state(self):
68+
mock_actor = create_mock_actor(MockTestActor, 'test')
69+
state_manager = mock_actor._state_manager
70+
self.assertFalse(await state_manager.contains_state('state'))
71+
await state_manager.set_state('state', 5)
72+
self.assertTrue(await state_manager.contains_state('state'))
73+
await state_manager.remove_state('state')
74+
self.assertFalse(await state_manager.contains_state('state'))
75+
76+
async def test_get_or_add_state(self):
77+
mock_actor = create_mock_actor(MockTestActor, 'test')
78+
state_manager = mock_actor._state_manager
79+
out = await state_manager.get_or_add_state('state', 5)
80+
self.assertIs(out, 5)
81+
self.assertIs(state_manager._mock_state['state'], 5)
82+
out = await state_manager.get_or_add_state('state', 10)
83+
self.assertIs(out, 5)
84+
self.assertIs(state_manager._mock_state['state'], 5)
85+
86+
async def test_add_or_update_state(self):
87+
mock_actor = create_mock_actor(MockTestActor, 'test')
88+
state_manager = mock_actor._state_manager
89+
await state_manager.add_or_update_state('state', 5, double)
90+
self.assertIs(state_manager._mock_state['state'], 5)
91+
await state_manager.add_or_update_state('state', 1000, double)
92+
self.assertIs(state_manager._mock_state['state'], 10)
93+
94+
async def test_get_state_names(self):
95+
mock_actor = create_mock_actor(MockTestActor, 'test')
96+
state_manager = mock_actor._state_manager
97+
names = await state_manager.get_state_names()
98+
self.assertFalse(names)
99+
await state_manager.set_state('state1', 5)
100+
names = await state_manager.get_state_names()
101+
self.assertCountEqual(names, ['state1'])
102+
await state_manager.set_state('state2', 5)
103+
names = await state_manager.get_state_names()
104+
self.assertCountEqual(names, ['state1', 'state2'])
105+
await state_manager.save_state()
106+
names = await state_manager.get_state_names()
107+
self.assertFalse(names)
108+
109+
async def test_clear_cache(self):
110+
mock_actor = create_mock_actor(MockTestActor, 'test')
111+
state_manager = mock_actor._state_manager
112+
self.assertFalse(state_manager._default_state_change_tracker)
113+
await state_manager.set_state('state1', 5)
114+
self.assertTrue('state1', state_manager._default_state_change_tracker)
115+
await state_manager.clear_cache()
116+
self.assertFalse(state_manager._default_state_change_tracker)

0 commit comments

Comments
 (0)