Skip to content

Commit 0b6f2b7

Browse files
committed
done
1 parent 2de09d7 commit 0b6f2b7

11 files changed

+182
-364
lines changed

tests/integration/README.md

Lines changed: 38 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
1-
Integration tests
2-
=================
1+
# Integration tests
32

4-
We have integration tests which build and run Actors using the Python SDK on the Apify Platform.
5-
To run these tests, you need to set the `APIFY_TEST_USER_API_TOKEN` environment variable to the API token of the Apify user you want to use for the tests,
6-
and then start them with `make integration-tests`.
3+
We have integration tests which build and run Actors using the Python SDK on the Apify Platform. To run these tests, you need to set the `APIFY_TEST_USER_API_TOKEN` environment variable to the API token of the Apify user you want to use for the tests, and then start them with `make integration-tests`.
74

8-
If you want to run the integration tests on a different environment than the main Apify Platform,
9-
you need to set the `APIFY_INTEGRATION_TESTS_API_URL` environment variable to the right URL to the Apify API you want to use.
5+
If you want to run the integration tests on a different environment than the main Apify Platform, you need to set the `APIFY_INTEGRATION_TESTS_API_URL` environment variable to the right URL to the Apify API you want to use.
106

11-
How to write tests
12-
------------------
7+
## How to write tests
138

149
There are two fixtures which you can use to write tests:
1510

1611
### `apify_client_async`
1712

18-
This fixture just gives you an instance of `ApifyClientAsync` configured with the right token and API URL,
19-
so you don't have to do that yourself.
13+
This fixture just gives you an instance of `ApifyClientAsync` configured with the right token and API URL, so you don't have to do that yourself.
2014

2115
```python
2216
async def test_something(apify_client_async: ApifyClientAsync) -> None:
@@ -27,64 +21,62 @@ async def test_something(apify_client_async: ApifyClientAsync) -> None:
2721

2822
This fixture returns a factory function for creating Actors on the Apify Platform.
2923

30-
For the Actor source, the fixture takes the files from `tests/integration/actor_source_base`,
31-
builds the Apify SDK wheel from the current codebase,
32-
and adds the Actor source you passed to the fixture as an argument.
33-
You have to pass exactly one of the `main_func`, `main_py` and `source_files` arguments.
24+
For the Actor source, the fixture takes the files from `tests/integration/actor_source_base`, builds the Apify SDK wheel from the current codebase, and adds the Actor source you passed to the fixture as an argument. You have to pass exactly one of the `main_func`, `main_py` and `source_files` arguments.
3425

35-
The created Actor will be uploaded to the platform, built there, and after the test finishes, it will be automatically deleted.
36-
If the Actor build fails, it will not be deleted, so that you can check why the build failed.
26+
The created Actor will be uploaded to the platform, built there, and after the test finishes, it will be automatically deleted. If the Actor build fails, it will not be deleted, so that you can check why the build failed.
3727

3828
### Creating test Actor straight from a Python function
3929

40-
You can create Actors straight from a Python function.
41-
This is great because you can have the test Actor source code checked with the linter.
30+
You can create Actors straight from a Python function. This is great because you can have the test Actor source code checked with the linter.
4231

4332
```python
44-
async def test_something(self, make_actor: ActorFactory) -> None:
33+
async def test_something(
34+
make_actor: MakeActorFunction,
35+
run_actor: RunActorFunction,
36+
) -> None:
4537
async def main() -> None:
4638
async with Actor:
4739
print('Hello!')
4840

49-
actor = await make_actor('something', main_func=main)
41+
actor = await make_actor(label='something', main_func=main)
42+
run_result = await run_actor(actor)
5043

51-
run_result = await actor.call()
52-
53-
assert run_result is not None
54-
assert run_result['status'] == 'SUCCEEDED'
44+
assert run_result.status == 'SUCCEEDED'
5545
```
5646

57-
These Actors will have the `src/main.py` file set to the `main` function definition,
58-
prepended with `import asyncio` and `from apify import Actor`, for your convenience.
47+
These Actors will have the `src/main.py` file set to the `main` function definition, prepended with `import asyncio` and `from apify import Actor`, for your convenience.
5948

6049
You can also pass extra imports directly to the main function:
6150

6251
```python
63-
async def test_something(self, make_actor: ActorFactory) -> None:
52+
async def test_something(
53+
make_actor: MakeActorFunction,
54+
run_actor: RunActorFunction,
55+
) -> None:
6456
async def main():
6557
import os
6658
from apify_shared.consts import ActorEventTypes, ActorEnvVars
6759
async with Actor:
6860
print('The Actor is running with ' + os.getenv(ActorEnvVars.MEMORY_MBYTES) + 'MB of memory')
6961
await Actor.on(ActorEventTypes.SYSTEM_INFO, lambda event_data: print(event_data))
7062

71-
actor = await make_actor('something', main_func=main)
72-
73-
run_result = await actor.call()
63+
actor = await make_actor(label='something', main_func=main)
64+
run_result = await run_actor(actor)
7465

75-
assert run_result is not None
76-
assert run_result['status'] == 'SUCCEEDED'
66+
assert run_result.status == 'SUCCEEDED'
7767
```
7868

7969
### Creating Actor from source files
8070

81-
You can also pass the source files directly if you need something more complex
82-
(e.g. pass some fixed value to the Actor source code or use multiple source files).
71+
You can also pass the source files directly if you need something more complex (e.g. pass some fixed value to the Actor source code or use multiple source files).
8372

8473
To pass the source code of the `src/main.py` file directly, use the `main_py` argument to `make_actor`:
8574

8675
```python
87-
async def test_something(self, make_actor: ActorFactory) -> None:
76+
async def test_something(
77+
make_actor: MakeActorFunction,
78+
run_actor: RunActorFunction,
79+
) -> None:
8880
expected_output = f'ACTOR_OUTPUT_{crypto_random_object_id(5)}'
8981
main_py_source = f"""
9082
import asyncio
@@ -96,21 +88,22 @@ async def test_something(self, make_actor: ActorFactory) -> None:
9688
await Actor.set_value('OUTPUT', '{expected_output}')
9789
"""
9890

99-
actor = await make_actor('something', main_py=main_py_source)
100-
101-
await actor.call()
91+
actor = await make_actor(label='something', main_py=main_py_source)
92+
await run_actor(actor)
10293

10394
output_record = await actor.last_run().key_value_store().get_record('OUTPUT')
10495
assert output_record is not None
10596
assert output_record['value'] == expected_output
10697

10798
```
10899

109-
Or you can pass multiple source files with the `source_files` argument,
110-
if you need something really complex:
100+
Or you can pass multiple source files with the `source_files` argument, if you need something really complex:
111101

112102
```python
113-
async def test_something(self, make_actor: ActorFactory) -> None:
103+
async def test_something(
104+
make_actor: MakeActorFunction,
105+
run_actor: RunActorFunction,
106+
) -> None:
114107
actor_source_files = {
115108
'src/utils.py': """
116109
from datetime import datetime, timezone
@@ -129,9 +122,8 @@ async def test_something(self, make_actor: ActorFactory) -> None:
129122
print('Hello! It is ' + current_datetime.time())
130123
""",
131124
}
132-
actor = await make_actor('something', source_files=actor_source_files)
125+
actor = await make_actor(label='something', source_files=actor_source_files)
126+
actor_run = await run_actor(actor)
133127

134-
actor_run = await actor.call()
135-
assert actor_run is not None
136-
assert actor_run['status'] == 'SUCCEEDED'
128+
assert actor_run.status == 'SUCCEEDED'
137129
```

tests/integration/conftest.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424

2525
from apify_client.clients.resource_clients import ActorClientAsync
2626

27-
TOKEN_ENV_VAR = 'APIFY_TEST_USER_API_TOKEN'
28-
API_URL_ENV_VAR = 'APIFY_INTEGRATION_TESTS_API_URL'
29-
SDK_ROOT_PATH = Path(__file__).parent.parent.parent.resolve()
27+
_TOKEN_ENV_VAR = 'APIFY_TEST_USER_API_TOKEN'
28+
_API_URL_ENV_VAR = 'APIFY_INTEGRATION_TESTS_API_URL'
29+
_SDK_ROOT_PATH = Path(__file__).parent.parent.parent.resolve()
3030

3131

3232
@pytest.fixture(autouse=True)
@@ -52,11 +52,11 @@ def apify_client_async() -> ApifyClientAsync:
5252
because `httpx.AsyncClient` in `ApifyClientAsync` tries to reuse the same event loop across requests,
5353
but `pytest-asyncio` closes the event loop after each test, and uses a new one for the next test.
5454
"""
55-
api_token = os.getenv(TOKEN_ENV_VAR)
56-
api_url = os.getenv(API_URL_ENV_VAR)
55+
api_token = os.getenv(_TOKEN_ENV_VAR)
56+
api_url = os.getenv(_API_URL_ENV_VAR)
5757

5858
if not api_token:
59-
raise RuntimeError(f'{TOKEN_ENV_VAR} environment variable is missing, cannot run tests!')
59+
raise RuntimeError(f'{_TOKEN_ENV_VAR} environment variable is missing, cannot run tests!')
6060

6161
return ApifyClientAsync(api_token, api_url=api_url)
6262

@@ -73,15 +73,15 @@ def sdk_wheel_path(tmp_path_factory: pytest.TempPathFactory, testrun_uid: str) -
7373
if not was_wheel_built_this_test_run_file.exists():
7474
subprocess.run(
7575
args='python -m build',
76-
cwd=SDK_ROOT_PATH,
76+
cwd=_SDK_ROOT_PATH,
7777
shell=True,
7878
check=True,
7979
capture_output=True,
8080
)
8181
was_wheel_built_this_test_run_file.touch()
8282

8383
# Read the current package version, necessary for getting the right wheel filename.
84-
pyproject_toml_file = (SDK_ROOT_PATH / 'pyproject.toml').read_text(encoding='utf-8')
84+
pyproject_toml_file = (_SDK_ROOT_PATH / 'pyproject.toml').read_text(encoding='utf-8')
8585
for line in pyproject_toml_file.splitlines():
8686
if line.startswith('version = '):
8787
delim = '"' if '"' in line else "'"
@@ -90,7 +90,7 @@ def sdk_wheel_path(tmp_path_factory: pytest.TempPathFactory, testrun_uid: str) -
9090
else:
9191
raise RuntimeError('Unable to find version string.')
9292

93-
wheel_path = SDK_ROOT_PATH / 'dist' / f'apify-{sdk_version}-py3-none-any.whl'
93+
wheel_path = _SDK_ROOT_PATH / 'dist' / f'apify-{sdk_version}-py3-none-any.whl'
9494

9595
# Just to be sure.
9696
assert wheel_path.exists()

tests/integration/test_actor_create_proxy_configuration.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ async def main() -> None:
2828
assert proxy_configuration._country_code == country_code
2929

3030
actor = await make_actor(label='proxy-configuration', main_func=main)
31-
run_result = await run_actor(actor=actor)
31+
run_result = await run_actor(actor)
3232

3333
assert run_result.status == 'SUCCEEDED'
3434

@@ -65,6 +65,6 @@ async def main() -> None:
6565
await Actor.exit()
6666

6767
actor = await make_actor(label='proxy-configuration', main_func=main)
68-
run_result = await run_actor(actor=actor)
68+
run_result = await run_actor(actor)
6969

7070
assert run_result.status == 'SUCCEEDED'

tests/integration/test_actor_dataset.py

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212

1313
from apify_client import ApifyClientAsync
1414

15-
from .conftest import MakeActorFunction
15+
from .conftest import MakeActorFunction, RunActorFunction
1616

1717

1818
async def test_push_and_verify_data_in_default_dataset(
19-
apify_client_async: ApifyClientAsync,
2019
make_actor: MakeActorFunction,
20+
run_actor: RunActorFunction,
2121
) -> None:
2222
desired_item_count = 100 # Also change inside main() if you're changing this
2323

@@ -26,16 +26,10 @@ async def main() -> None:
2626
async with Actor:
2727
await Actor.push_data([{'id': i} for i in range(desired_item_count)])
2828

29-
actor = await make_actor('push-data', main_func=main)
30-
31-
call_result = await actor.call()
32-
assert call_result is not None
33-
34-
run_client = apify_client_async.run(call_result['id'])
35-
run_result = await run_client.wait_for_finish(wait_secs=600)
29+
actor = await make_actor(label='push-data', main_func=main)
30+
run_result = await run_actor(actor)
3631

37-
assert run_result is not None
38-
assert run_result['status'] == 'SUCCEEDED'
32+
assert run_result.status == 'SUCCEEDED'
3933

4034
list_page = await actor.last_run().dataset().list_items()
4135
assert list_page.items[0]['id'] == 0
@@ -44,53 +38,41 @@ async def main() -> None:
4438

4539

4640
async def test_push_large_data_chunks_over_9mb(
47-
apify_client_async: ApifyClientAsync,
4841
make_actor: MakeActorFunction,
42+
run_actor: RunActorFunction,
4943
) -> None:
5044
async def main() -> None:
5145
async with Actor:
5246
await Actor.push_data([{'str': 'x' * 10000} for _ in range(5000)]) # ~50MB
5347

54-
actor = await make_actor('push-data-over-9mb', main_func=main)
55-
56-
call_result = await actor.call()
57-
assert call_result is not None
58-
59-
run_client = apify_client_async.run(call_result['id'])
60-
run_result = await run_client.wait_for_finish(wait_secs=600)
48+
actor = await make_actor(label='push-data-over-9mb', main_func=main)
49+
run_result = await run_actor(actor)
6150

62-
assert run_result is not None
63-
assert run_result['status'] == 'SUCCEEDED'
51+
assert run_result.status == 'SUCCEEDED'
6452

6553
async for item in actor.last_run().dataset().iterate_items():
6654
assert item['str'] == 'x' * 10000
6755

6856

6957
async def test_same_references_in_default_dataset(
70-
apify_client_async: ApifyClientAsync,
7158
make_actor: MakeActorFunction,
59+
run_actor: RunActorFunction,
7260
) -> None:
7361
async def main() -> None:
7462
async with Actor:
7563
dataset1 = await Actor.open_dataset()
7664
dataset2 = await Actor.open_dataset()
7765
assert dataset1 is dataset2
7866

79-
actor = await make_actor('dataset-same-ref-default', main_func=main)
80-
81-
call_result = await actor.call()
82-
assert call_result is not None
83-
84-
run_client = apify_client_async.run(call_result['id'])
85-
run_result = await run_client.wait_for_finish(wait_secs=600)
67+
actor = await make_actor(label='dataset-same-ref-default', main_func=main)
68+
run_result = await run_actor(actor)
8669

87-
assert run_result is not None
88-
assert run_result['status'] == 'SUCCEEDED'
70+
assert run_result.status == 'SUCCEEDED'
8971

9072

9173
async def test_same_references_in_named_dataset(
92-
apify_client_async: ApifyClientAsync,
9374
make_actor: MakeActorFunction,
75+
run_actor: RunActorFunction,
9476
) -> None:
9577
dataset_name = generate_unique_resource_name('dataset')
9678

@@ -109,16 +91,10 @@ async def main() -> None:
10991

11092
await dataset_by_name_1.drop()
11193

112-
actor = await make_actor('dataset-same-ref-named', main_func=main)
113-
114-
call_result = await actor.call(run_input={'datasetName': dataset_name})
115-
assert call_result is not None
116-
117-
run_client = apify_client_async.run(call_result['id'])
118-
run_result = await run_client.wait_for_finish(wait_secs=600)
94+
actor = await make_actor(label='dataset-same-ref-named', main_func=main)
95+
run_result = await run_actor(actor, run_input={'datasetName': dataset_name})
11996

120-
assert run_result is not None
121-
assert run_result['status'] == 'SUCCEEDED'
97+
assert run_result.status == 'SUCCEEDED'
12298

12399

124100
async def test_force_cloud(

0 commit comments

Comments
 (0)