2
2
import inspect
3
3
import os
4
4
import subprocess
5
+ import sys
5
6
import textwrap
6
7
from pathlib import Path
7
8
from typing import AsyncIterator , Awaitable , Callable , Dict , List , Mapping , Optional , Protocol , Union
8
9
9
10
import pytest
11
+ from filelock import FileLock
10
12
11
13
from apify_client import ApifyClientAsync
12
14
from apify_client .clients .resource_clients import ActorClientAsync
16
18
17
19
TOKEN_ENV_VAR = 'APIFY_TEST_USER_API_TOKEN'
18
20
API_URL_ENV_VAR = 'APIFY_INTEGRATION_TESTS_API_URL'
21
+ SDK_ROOT_PATH = Path (__file__ ).parent .parent .parent .resolve ()
19
22
20
23
21
24
# This fixture can't be session-scoped,
@@ -34,8 +37,40 @@ def apify_client_async() -> ApifyClientAsync:
34
37
return ApifyClientAsync (api_token , api_url = api_url )
35
38
36
39
40
+ # Build the package wheel if it hasn't been built yet, and return the path to the wheel
37
41
@pytest .fixture (scope = 'session' )
38
- def actor_base_source_files () -> Dict [str , Union [str , bytes ]]:
42
+ def sdk_wheel_path (tmp_path_factory : pytest .TempPathFactory , testrun_uid : str ) -> Path :
43
+ # Make sure the wheel is not being built concurrently across all the pytest-xdist runners,
44
+ # through locking the building process with a temp file
45
+ with FileLock (tmp_path_factory .getbasetemp ().parent / 'sdk_wheel_build.lock' ):
46
+ # Make sure the wheel is built exactly once across across all the pytest-xdist runners,
47
+ # through an indicator file saying that the wheel was already built
48
+ was_wheel_built_this_test_run_file = tmp_path_factory .getbasetemp () / f'wheel_was_built_in_run_{ testrun_uid } '
49
+ if not was_wheel_built_this_test_run_file .exists ():
50
+ subprocess .run ('python setup.py bdist_wheel' , cwd = SDK_ROOT_PATH , shell = True , check = True , capture_output = True )
51
+ was_wheel_built_this_test_run_file .touch ()
52
+
53
+ # Read the current package version, necessary for getting the right wheel filename
54
+ version_file = (SDK_ROOT_PATH / 'src/apify/_version.py' ).read_text (encoding = 'utf-8' )
55
+ sdk_version = None
56
+ for line in version_file .splitlines ():
57
+ if line .startswith ('__version__' ):
58
+ delim = '"' if '"' in line else "'"
59
+ sdk_version = line .split (delim )[1 ]
60
+ break
61
+ else :
62
+ raise RuntimeError ('Unable to find version string.' )
63
+
64
+ wheel_path = SDK_ROOT_PATH / 'dist' / f'apify-{ sdk_version } -py3-none-any.whl'
65
+
66
+ # Just to be sure
67
+ assert wheel_path .exists ()
68
+
69
+ return wheel_path
70
+
71
+
72
+ @pytest .fixture (scope = 'session' )
73
+ def actor_base_source_files (sdk_wheel_path : Path ) -> Dict [str , Union [str , bytes ]]:
39
74
"""Create a dictionary of the base source files for a testing actor.
40
75
41
76
It takes the files from `tests/integration/actor_source_base`,
@@ -57,24 +92,14 @@ def actor_base_source_files() -> Dict[str, Union[str, bytes]]:
57
92
except ValueError :
58
93
source_files [relative_path ] = path .read_bytes ()
59
94
60
- # Then build the SDK and the wheel to the source files
61
- subprocess .run ('python setup.py bdist_wheel' , cwd = sdk_root_path , shell = True , check = True , capture_output = True )
62
-
63
- version_file = (sdk_root_path / 'src/apify/_version.py' ).read_text (encoding = 'utf-8' )
64
- sdk_version = None
65
- for line in version_file .splitlines ():
66
- if line .startswith ('__version__' ):
67
- delim = '"' if '"' in line else "'"
68
- sdk_version = line .split (delim )[1 ]
69
- break
70
- else :
71
- raise RuntimeError ('Unable to find version string.' )
95
+ sdk_wheel_file_name = sdk_wheel_path .name
96
+ source_files [sdk_wheel_file_name ] = sdk_wheel_path .read_bytes ()
72
97
73
- wheel_file_name = f'apify-{ sdk_version } -py3-none-any.whl'
74
- wheel_path = sdk_root_path / 'dist' / wheel_file_name
98
+ source_files ['requirements.txt' ] = str (source_files ['requirements.txt' ]).replace ('APIFY_SDK_WHEEL_PLACEHOLDER' , f'./{ sdk_wheel_file_name } ' )
75
99
76
- source_files [wheel_file_name ] = wheel_path .read_bytes ()
77
- source_files ['requirements.txt' ] = str (source_files ['requirements.txt' ]).replace ('APIFY_SDK_WHEEL_PLACEHOLDER' , f'./{ wheel_file_name } ' )
100
+ current_major_minor_python_version = '.' .join ([str (x ) for x in sys .version_info [:2 ]])
101
+ integration_tests_python_version = os .getenv ('INTEGRATION_TESTS_PYTHON_VERSION' ) or current_major_minor_python_version
102
+ source_files ['Dockerfile' ] = str (source_files ['Dockerfile' ]).replace ('BASE_IMAGE_VERSION_PLACEHOLDER' , integration_tests_python_version )
78
103
79
104
return source_files
80
105
0 commit comments