Skip to content

Commit 1843f48

Browse files
authored
feat: add a few integration tests (#48)
1 parent 64d4363 commit 1843f48

File tree

3 files changed

+217
-19
lines changed

3 files changed

+217
-19
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import asyncio
2+
3+
from apify import Actor
4+
from apify.consts import ActorEventType
5+
6+
from .conftest import ActorFactory
7+
8+
9+
class TestActorEvents:
10+
11+
async def test_interval_events(self, make_actor: ActorFactory) -> None:
12+
async def main() -> None:
13+
import os
14+
15+
from apify.consts import ActorEventType, ApifyEnvVars
16+
17+
os.environ[ApifyEnvVars.PERSIST_STATE_INTERVAL_MILLIS] = '900'
18+
19+
def on_event(event_type): # type: ignore
20+
async def log_event(data): # type: ignore
21+
await Actor.push_data({'event_type': event_type, 'data': data})
22+
return log_event
23+
24+
async with Actor:
25+
Actor.on(ActorEventType.SYSTEM_INFO, on_event(ActorEventType.SYSTEM_INFO)) # type: ignore
26+
Actor.on(ActorEventType.PERSIST_STATE, on_event(ActorEventType.PERSIST_STATE)) # type: ignore
27+
await asyncio.sleep(3)
28+
29+
actor = await make_actor('actor-interval-events', main_func=main)
30+
31+
run_result = await actor.call()
32+
33+
assert run_result is not None
34+
assert run_result['status'] == 'SUCCEEDED'
35+
dataset_items_page = await actor.last_run().dataset().list_items()
36+
persist_state_events = [item for item in dataset_items_page.items if item['event_type'] == ActorEventType.PERSIST_STATE]
37+
system_info_events = [item for item in dataset_items_page.items if item['event_type'] == ActorEventType.SYSTEM_INFO]
38+
assert len(persist_state_events) > 2
39+
assert len(system_info_events) > 0
40+
41+
async def test_off_event(self, make_actor: ActorFactory) -> None:
42+
async def main() -> None:
43+
import os
44+
45+
from apify.consts import ActorEventType, ApifyEnvVars
46+
47+
os.environ[ApifyEnvVars.PERSIST_STATE_INTERVAL_MILLIS] = '100'
48+
49+
counter = 0
50+
51+
def count_event(data): # type: ignore
52+
nonlocal counter
53+
print(data)
54+
counter += 1
55+
56+
async with Actor:
57+
Actor.on(ActorEventType.PERSIST_STATE, count_event)
58+
await asyncio.sleep(0.5)
59+
assert counter > 1
60+
last_count = counter
61+
Actor.off(ActorEventType.PERSIST_STATE, count_event)
62+
await asyncio.sleep(0.5)
63+
assert counter == last_count
64+
65+
actor = await make_actor('actor-off-event', main_func=main)
66+
67+
run = await actor.call()
68+
69+
assert run is not None
70+
assert run['status'] == 'SUCCEEDED'
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
from apify import Actor
2+
3+
from .conftest import ActorFactory
4+
5+
6+
class TestActorInit:
7+
8+
async def test_actor_init(self, make_actor: ActorFactory) -> None:
9+
async def main() -> None:
10+
my_actor = Actor()
11+
await my_actor.init()
12+
assert my_actor._is_initialized is True
13+
double_init = False
14+
try:
15+
await my_actor.init()
16+
double_init = True
17+
except RuntimeError as err:
18+
assert str(err) == 'The actor was already initialized!'
19+
except Exception as err:
20+
raise err
21+
try:
22+
await Actor.init()
23+
double_init = True
24+
except RuntimeError as err:
25+
assert str(err) == 'The actor was already initialized!'
26+
except Exception as err:
27+
raise err
28+
await my_actor.exit()
29+
assert double_init is False
30+
assert my_actor._is_initialized is False
31+
32+
actor = await make_actor('actor-init', main_func=main)
33+
34+
run_result = await actor.call()
35+
36+
assert run_result is not None
37+
assert run_result['status'] == 'SUCCEEDED'
38+
39+
async def test_async_with_actor_properly_initialize(self, make_actor: ActorFactory) -> None:
40+
async def main() -> None:
41+
async with Actor:
42+
assert Actor._get_default_instance()._is_initialized
43+
assert Actor._get_default_instance()._is_initialized is False
44+
45+
actor = await make_actor('with-actor-init', main_func=main)
46+
47+
run_result = await actor.call()
48+
49+
assert run_result is not None
50+
assert run_result['status'] == 'SUCCEEDED'
51+
52+
53+
class TestActorExit:
54+
55+
async def test_actor_exit_code(self, make_actor: ActorFactory) -> None:
56+
async def main() -> None:
57+
async with Actor:
58+
input = await Actor.get_input()
59+
await Actor.exit(**input)
60+
61+
actor = await make_actor('actor-exit', main_func=main)
62+
63+
for exit_code in [0, 1, 101]:
64+
run_result = await actor.call(run_input={'exit_code': exit_code})
65+
assert run_result is not None
66+
assert run_result['exitCode'] == exit_code
67+
assert run_result['status'] == 'FAILED' if exit_code > 0 else 'SUCCEEDED'
68+
69+
70+
class TestActorFail:
71+
72+
async def test_fail_exit_code(self, make_actor: ActorFactory) -> None:
73+
async def main() -> None:
74+
async with Actor:
75+
input = await Actor.get_input()
76+
await Actor.fail(**input) if input else await Actor.fail()
77+
78+
actor = await make_actor('actor-fail', main_func=main)
79+
80+
run_result = await actor.call()
81+
assert run_result is not None
82+
assert run_result['exitCode'] == 1
83+
assert run_result['status'] == 'FAILED'
84+
85+
for exit_code in [1, 10, 100]:
86+
run_result = await actor.call(run_input={'exit_code': exit_code})
87+
assert run_result is not None
88+
assert run_result['exitCode'] == exit_code
89+
assert run_result['status'] == 'FAILED'
90+
91+
async def test_with_actor_fail_correctly(self, make_actor: ActorFactory) -> None:
92+
async def main() -> None:
93+
async with Actor:
94+
raise Exception('This is a test exception')
95+
96+
actor = await make_actor('with-actor-fail', main_func=main)
97+
run_result = await actor.call()
98+
assert run_result is not None
99+
assert run_result['exitCode'] == 91
100+
assert run_result['status'] == 'FAILED'
101+
102+
103+
class TestActorMain:
104+
105+
async def test_actor_main(self, make_actor: ActorFactory) -> None:
106+
async def main() -> None:
107+
async def actor_function() -> None:
108+
input = await Actor.get_input()
109+
if input.get('raise_exception'):
110+
raise Exception(input.get('raise_exception'))
111+
elif input.get('exit_code'):
112+
await Actor.exit(exit_code=input.get('exit_code'))
113+
elif input.get('fail'):
114+
await Actor.fail()
115+
elif input.get('set_output'):
116+
await Actor.set_value('OUTPUT', input.get('set_output'))
117+
print('Main function called')
118+
119+
await Actor.main(actor_function)
120+
121+
actor = await make_actor('actor-main', main_func=main)
122+
123+
exception_run = await actor.call(run_input={'raise_exception': 'This is a test exception'})
124+
assert exception_run is not None
125+
assert exception_run['status'] == 'FAILED'
126+
assert exception_run['exitCode'] == 91
127+
128+
exit_code = 10
129+
exited_run = await actor.call(run_input={'exit_code': exit_code})
130+
assert exited_run is not None
131+
assert exited_run['status'] == 'FAILED'
132+
assert exited_run['exitCode'] == exit_code
133+
134+
failed_run = await actor.call(run_input={'fail': True})
135+
assert failed_run is not None
136+
assert failed_run['status'] == 'FAILED'
137+
assert failed_run['exitCode'] == 1
138+
139+
test_output = {'test': 'output'}
140+
run_with_output = await actor.call(run_input={'set_output': test_output})
141+
assert run_with_output is not None
142+
assert run_with_output['status'] == 'SUCCEEDED'
143+
output = await actor.last_run().key_value_store().get_record('OUTPUT')
144+
assert output is not None
145+
assert output['value'] == test_output

tests/unit/actor/test_actor_lifecycle.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from apify import Actor
88
from apify.consts import ActorEventType, ApifyEnvVars
9-
from apify_client import ApifyClientAsync
109

1110

1211
class TestActorInit:
@@ -64,7 +63,7 @@ def on_event(event_type: ActorEventType) -> Callable:
6463
on_system_info_count = len(on_system_info)
6564
assert on_persist_count != 0
6665
assert on_system_info_count != 0
67-
# Check if envents stopped emitting.
66+
# Check if events stopped emitting.
6867
await asyncio.sleep(0.2)
6968
assert on_persist_count == len(on_persist)
7069
assert on_system_info_count == len(on_system_info)
@@ -91,7 +90,7 @@ async def test_with_actor_failed(self) -> None:
9190
pass
9291
assert my_actor._is_initialized is False
9392

94-
async def test_raise_on_fail_witout_init(self) -> None:
93+
async def test_raise_on_fail_without_init(self) -> None:
9594
with pytest.raises(RuntimeError):
9695
await Actor.fail()
9796

@@ -140,19 +139,3 @@ async def actor_function() -> str:
140139

141140
returned_value = await my_actor.main(actor_function)
142141
assert returned_value == expected_string
143-
144-
class TestActorNewClient:
145-
146-
async def test_actor_new_client_config(self, monkeypatch: pytest.MonkeyPatch) -> None:
147-
token = 'my-token'
148-
monkeypatch.setenv(ApifyEnvVars.TOKEN, token)
149-
my_actor = Actor()
150-
await my_actor.init()
151-
client = my_actor.new_client()
152-
assert type(client) == ApifyClientAsync
153-
assert client.token == token
154-
passed_token = 'my-passed-token'
155-
client_with_token = my_actor.new_client(token=passed_token)
156-
assert type(client_with_token) == ApifyClientAsync
157-
assert client_with_token.token == passed_token
158-
await my_actor.exit()

0 commit comments

Comments
 (0)