From 1bce2913870a537b453ce63ff1876be3d95418ad Mon Sep 17 00:00:00 2001 From: Josef Prochazka Date: Tue, 25 Nov 2025 13:49:19 +0100 Subject: [PATCH 1/3] Update integration tests to create storages of second user on the fly --- tests/integration/conftest.py | 95 ++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index ad5759db..51b30436 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -1,6 +1,10 @@ +import json import os +import secrets +from collections.abc import Generator import pytest +from apify_shared.utils import create_hmac_signature, create_storage_content_signature from .integration_test_utils import TestDataset, TestKvs from apify_client import ApifyClient, ApifyClientAsync @@ -9,7 +13,13 @@ API_URL_ENV_VAR = 'APIFY_INTEGRATION_TESTS_API_URL' -@pytest.fixture +def crypto_random_object_id(length: int = 17) -> str: + """Generate a random object ID.""" + chars = 'abcdefghijklmnopqrstuvwxyzABCEDFGHIJKLMNOPQRSTUVWXYZ0123456789' + return ''.join(secrets.choice(chars) for _ in range(length)) + + +@pytest.fixture(scope='session') def api_token() -> str: token = os.getenv(TOKEN_ENV_VAR) if not token: @@ -17,10 +27,19 @@ def api_token() -> str: return token +@pytest.fixture(scope='session') +def api_token_2() -> str: + """API token for the second test user for storage permission tests.""" + second_user_env_var = 'APIFY_TEST_USER_PYTHON_SDK_API_TOKEN' + token = os.getenv(second_user_env_var) + if not token: + raise RuntimeError(f'{second_user_env_var} environment variable is missing, cannot run permission tests!') + return token + + @pytest.fixture def apify_client(api_token: str) -> ApifyClient: - api_url = os.getenv(API_URL_ENV_VAR) - return ApifyClient(api_token, api_url=api_url) + return ApifyClient(api_token, api_url=os.getenv(API_URL_ENV_VAR)) # This fixture can't be session-scoped, @@ -30,30 +49,60 @@ def apify_client(api_token: str) -> ApifyClient: # and uses a new one for the next test. @pytest.fixture def apify_client_async(api_token: str) -> ApifyClientAsync: - api_url = os.getenv(API_URL_ENV_VAR) - return ApifyClientAsync(api_token, api_url=api_url) + return ApifyClientAsync(api_token, api_url=os.getenv(API_URL_ENV_VAR)) -@pytest.fixture -def test_dataset_of_another_user() -> TestDataset: - """Pre-existing dataset of another test user with restricted access.""" - return TestDataset( - id='InrsNvJNGwJMFAR2l', - signature='MC4wLjFGbVN3UjB5T0xvMU1hU0lFQjZCMQ', +@pytest.fixture(scope='session') +def test_dataset_of_another_user(api_token_2: str) -> Generator[TestDataset]: + """Pre-existing named dataset of another test user with restricted access.""" + client = ApifyClient(api_token_2, api_url=os.getenv(API_URL_ENV_VAR)) + + dataset_name = f'API-test-permissions-{crypto_random_object_id()}' + dataset = client.datasets().get_or_create(name=dataset_name) + dataset_client = client.dataset(dataset_id=dataset['id']) + expected_content = [{'item1': 1, 'item2': 2, 'item3': 3}, {'item1': 4, 'item2': 5, 'item3': 6}] + + # Push data to dataset + dataset_client.push_items(json.dumps(expected_content)) + + # Generate signature for the test + signature = create_storage_content_signature( + resource_id=dataset['id'], url_signing_secret_key=dataset['urlSigningSecretKey'] + ) + + yield TestDataset( + id=dataset['id'], + signature=signature, expected_content=[{'item1': 1, 'item2': 2, 'item3': 3}, {'item1': 4, 'item2': 5, 'item3': 6}], ) + dataset_client.delete() -@pytest.fixture -def test_kvs_of_another_user() -> TestKvs: - """Pre-existing key value store of another test user with restricted access.""" - return TestKvs( - id='0SWREKM4yzKnpQRGA', - signature='MC4wLjVKVmlMSVpDNEhaazg1Z1VXTnBP', - expected_content={'key1': 1, 'key2': 2, 'key3': 3}, - keys_signature={ - 'key1': 'qrQL9pHpiok99v9kWhKx', - 'key2': '1BhGTfsLvpsF8aPiIgoBt', - 'key3': 'rPPqxmTNcxvvpvO0Bx5s', - }, + +@pytest.fixture(scope='session') +def test_kvs_of_another_user(api_token_2: str) -> Generator[TestKvs]: + """Pre-existing named key value store of another test user with restricted access.""" + client = ApifyClient(api_token_2, api_url=os.getenv(API_URL_ENV_VAR)) + + kvs_name = f'API-test-permissions-{crypto_random_object_id()}' + kvs = client.key_value_stores().get_or_create(name=kvs_name) + kvs_client = client.key_value_store(key_value_store_id=kvs['id']) + expected_content = {'key1': 1, 'key2': 2, 'key3': 3} + + # Push data to kvs + for key, value in expected_content.items(): + kvs_client.set_record(key, value) + + # Generate signature for the test + signature = create_storage_content_signature( + resource_id=kvs['id'], url_signing_secret_key=kvs['urlSigningSecretKey'] ) + + yield TestKvs( + id=kvs['id'], + signature=signature, + expected_content=expected_content, + keys_signature={key: create_hmac_signature(kvs['urlSigningSecretKey'], key) for key in expected_content}, + ) + + kvs_client.delete() From 1a6e4d2bb41a5bf7e5fd3e4a90ffdef219c83682 Mon Sep 17 00:00:00 2001 From: Josef Prochazka Date: Tue, 25 Nov 2025 14:08:05 +0100 Subject: [PATCH 2/3] Tmp print user id, to see which test user is being used in CI --- CONTRIBUTING.md | 3 +++ tests/integration/conftest.py | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0328ea1..8c57bbe8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -78,6 +78,9 @@ We have integration tests which build and run Actors using the Python SDK on the 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`. +For subset of integration tests another token is needed `APIFY_TEST_USER_2_API_TOKEN`. Such tests are testing +the storage restricted access and thus need two user accounts. + 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. diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 51b30436..aee7e34f 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -1,3 +1,4 @@ +# type:ignore #noqa:PGH003 import json import os import secrets @@ -10,6 +11,7 @@ from apify_client import ApifyClient, ApifyClientAsync TOKEN_ENV_VAR = 'APIFY_TEST_USER_API_TOKEN' +TOKEN_ENV_VAR_2 = 'APIFY_TEST_USER_2_API_TOKEN' API_URL_ENV_VAR = 'APIFY_INTEGRATION_TESTS_API_URL' @@ -30,15 +32,16 @@ def api_token() -> str: @pytest.fixture(scope='session') def api_token_2() -> str: """API token for the second test user for storage permission tests.""" - second_user_env_var = 'APIFY_TEST_USER_PYTHON_SDK_API_TOKEN' - token = os.getenv(second_user_env_var) + token = os.getenv(TOKEN_ENV_VAR_2) if not token: - raise RuntimeError(f'{second_user_env_var} environment variable is missing, cannot run permission tests!') + raise RuntimeError(f'{TOKEN_ENV_VAR_2} environment variable is missing, cannot run permission tests!') return token @pytest.fixture def apify_client(api_token: str) -> ApifyClient: + client = ApifyClient(api_token, api_url=os.getenv(API_URL_ENV_VAR)) + raise Exception(client.user().get()['id']) # noqa:TRY002 return ApifyClient(api_token, api_url=os.getenv(API_URL_ENV_VAR)) From 99d378ddfa041b5fde607408a2ca09848f75a4af Mon Sep 17 00:00:00 2001 From: Josef Prochazka Date: Tue, 25 Nov 2025 14:54:01 +0100 Subject: [PATCH 3/3] Finalize, wait for workflow update --- tests/integration/conftest.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index aee7e34f..5e1d4de1 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -1,4 +1,3 @@ -# type:ignore #noqa:PGH003 import json import os import secrets @@ -40,8 +39,6 @@ def api_token_2() -> str: @pytest.fixture def apify_client(api_token: str) -> ApifyClient: - client = ApifyClient(api_token, api_url=os.getenv(API_URL_ENV_VAR)) - raise Exception(client.user().get()['id']) # noqa:TRY002 return ApifyClient(api_token, api_url=os.getenv(API_URL_ENV_VAR))