Skip to content

Commit 76e1e21

Browse files
feat: Separating the RBAC and Remote related integration tests. (feast-dev#4905)
* Separating the tests related to remote and rbac functionality. * Added a new test marker to separate the tests related to rbac and remote functionality. * Added a new github action to perform tests related to rbac and remote functionality. * Filtered the rbac integration tests in the current github job. and added new make target to run the new tests. Signed-off-by: lrangine <19699092+lokeshrangineni@users.noreply.github.com>
1 parent 07958f7 commit 76e1e21

File tree

10 files changed

+128
-2
lines changed

10 files changed

+128
-2
lines changed

.github/workflows/operator-e2e-integration-tests.yml

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ on:
1010
- opened
1111
- synchronize
1212
- labeled
13+
paths-ignore:
14+
- 'community/**'
15+
- 'docs/**'
16+
- 'examples/**'
1317

1418
jobs:
1519
operator-e2e-tests:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: pr-remote-rbac-integration-tests
2+
# This runs the integration tests related to rbac functionality and remote registry and online features.
3+
4+
on:
5+
pull_request:
6+
types:
7+
- opened
8+
- synchronize
9+
- labeled
10+
paths-ignore:
11+
- 'community/**'
12+
- 'docs/**'
13+
- 'examples/**'
14+
15+
jobs:
16+
remote-rbac-integration-tests-python:
17+
if:
18+
((github.event.action == 'labeled' && (github.event.label.name == 'approved' || github.event.label.name == 'lgtm' || github.event.label.name == 'ok-to-test')) ||
19+
(github.event.action != 'labeled' && (contains(github.event.pull_request.labels.*.name, 'ok-to-test') || contains(github.event.pull_request.labels.*.name, 'approved') || contains(github.event.pull_request.labels.*.name, 'lgtm')))) &&
20+
github.event.pull_request.base.repo.full_name == 'feast-dev/feast'
21+
runs-on: ${{ matrix.os }}
22+
strategy:
23+
fail-fast: false
24+
matrix:
25+
python-version: [ "3.11" ]
26+
os: [ ubuntu-latest ]
27+
env:
28+
OS: ${{ matrix.os }}
29+
PYTHON: ${{ matrix.python-version }}
30+
steps:
31+
- uses: actions/checkout@v4
32+
with:
33+
repository: ${{ github.event.repository.full_name }} # Uses the full repository name
34+
ref: ${{ github.ref }} # Uses the ref from the event
35+
token: ${{ secrets.GITHUB_TOKEN }} # Automatically provided token
36+
submodules: recursive
37+
- name: Setup Python
38+
uses: actions/setup-python@v5
39+
id: setup-python
40+
with:
41+
python-version: ${{ matrix.python-version }}
42+
architecture: x64
43+
- name: Install uv
44+
run: curl -LsSf https://astral.sh/uv/install.sh | sh
45+
- name: Get uv cache dir
46+
id: uv-cache
47+
run: |
48+
echo "dir=$(uv cache dir)" >> $GITHUB_OUTPUT
49+
- name: uv cache
50+
uses: actions/cache@v4
51+
with:
52+
path: ${{ steps.uv-cache.outputs.dir }}
53+
key: ${{ runner.os }}-${{ matrix.python-version }}-uv-${{ hashFiles(format('**/py{0}-ci-requirements.txt', matrix.python-version)) }}
54+
- name: Install dependencies
55+
run: make install-python-dependencies-ci
56+
- name: Test rbac and remote feature integration tests
57+
if: ${{ always() }} # this will guarantee that step won't be canceled and resources won't leak
58+
run: make test-python-integration-rbac-remote

Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,26 @@ test-python-unit:
107107
test-python-integration:
108108
python -m pytest --tb=short -v -n 8 --integration --color=yes --durations=10 --timeout=1200 --timeout_method=thread --dist loadgroup \
109109
-k "(not snowflake or not test_historical_features_main)" \
110+
-m "not rbac_remote_integration_test" \
111+
--log-cli-level=INFO -s \
110112
sdk/python/tests
111113

112114
test-python-integration-local:
113115
FEAST_IS_LOCAL_TEST=True \
114116
FEAST_LOCAL_ONLINE_CONTAINER=True \
115117
python -m pytest --tb=short -v -n 8 --color=yes --integration --durations=10 --timeout=1200 --timeout_method=thread --dist loadgroup \
116118
-k "not test_lambda_materialization and not test_snowflake_materialization" \
119+
-m "not rbac_remote_integration_test" \
120+
--log-cli-level=INFO -s \
121+
sdk/python/tests
122+
123+
test-python-integration-rbac-remote:
124+
FEAST_IS_LOCAL_TEST=True \
125+
FEAST_LOCAL_ONLINE_CONTAINER=True \
126+
python -m pytest --tb=short -v -n 8 --color=yes --integration --durations=10 --timeout=1200 --timeout_method=thread --dist loadgroup \
127+
-k "not test_lambda_materialization and not test_snowflake_materialization" \
128+
-m "rbac_remote_integration_test" \
129+
--log-cli-level=INFO -s \
117130
sdk/python/tests
118131

119132
test-python-integration-container:

sdk/python/pytest.ini

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ asyncio_mode = auto
44
markers =
55
universal_offline_stores: mark a test as using all offline stores.
66
universal_online_stores: mark a test as using all online stores.
7+
rbac_remote_integration_test: mark a integration test related to rbac and remote functionality.
78

89
env =
910
IS_TEST=True

sdk/python/tests/conftest.py

+4
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,10 @@ def pytest_generate_tests(metafunc: pytest.Metafunc):
310310
pytest.mark.xdist_group(name=m)
311311
for m in c.offline_store_creator.xdist_groups()
312312
]
313+
# Check if there are any test markers associated with the creator and add them.
314+
if c.offline_store_creator.test_markers():
315+
marks.extend(c.offline_store_creator.test_markers())
316+
313317
_config_cache[c] = pytest.param(c, marks=marks)
314318

315319
configs.append(_config_cache[c])

sdk/python/tests/integration/conftest.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import logging
2+
import random
3+
import time
4+
from multiprocessing import Manager
25

36
import pytest
47
from testcontainers.keycloak import KeycloakContainer
@@ -9,14 +12,30 @@
912
from tests.utils.auth_permissions_util import setup_permissions_on_keycloak
1013

1114
logger = logging.getLogger(__name__)
15+
logger.setLevel(logging.INFO)
16+
17+
shared_state = Manager().dict()
1218

1319

1420
@pytest.fixture(scope="session")
1521
def start_keycloak_server():
22+
# Add random sleep between 0 and 2 before checking the state to avoid concurrency issues.
23+
random_sleep_time = random.uniform(0, 2)
24+
time.sleep(random_sleep_time)
25+
26+
# If the Keycloak instance is already started (in any worker), reuse it
27+
if shared_state.get("keycloak_started", False):
28+
return shared_state["keycloak_url"]
1629
logger.info("Starting keycloak instance")
1730
with KeycloakContainer("quay.io/keycloak/keycloak:24.0.1") as keycloak_container:
1831
setup_permissions_on_keycloak(keycloak_container.get_client())
19-
yield keycloak_container.get_url()
32+
shared_state["keycloak_started"] = True
33+
shared_state["keycloak_url"] = keycloak_container.get_url()
34+
yield shared_state["keycloak_url"]
35+
36+
# After the fixture is done, cleanup the shared state
37+
del shared_state["keycloak_started"]
38+
del shared_state["keycloak_url"]
2039

2140

2241
@pytest.fixture(scope="session")

sdk/python/tests/integration/feature_repos/universal/data_source_creator.py

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import Dict, Optional
33

44
import pandas as pd
5+
from _pytest.mark import MarkDecorator
56

67
from feast.data_source import DataSource
78
from feast.feature_logging import LoggingDestination
@@ -64,3 +65,11 @@ def teardown(self):
6465
@staticmethod
6566
def xdist_groups() -> list[str]:
6667
return []
68+
69+
@staticmethod
70+
def test_markers() -> list[MarkDecorator]:
71+
"""
72+
return the array of test markers to add dynamically to the tests created by this creator method. override this method in your implementations. By default, it will not add any markers.
73+
:return:
74+
"""
75+
return []

sdk/python/tests/integration/feature_repos/universal/data_sources/file.py

+14
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
import pandas as pd
1212
import pyarrow as pa
1313
import pyarrow.parquet as pq
14+
import pytest
1415
import yaml
16+
from _pytest.mark import MarkDecorator
1517
from minio import Minio
1618
from testcontainers.core.generic import DockerContainer
1719
from testcontainers.core.waiting_utils import wait_for_logs
@@ -372,6 +374,10 @@ def __init__(self, project_name: str, *args, **kwargs):
372374
self.server_port: int = 0
373375
self.proc: Optional[Popen[bytes]] = None
374376

377+
@staticmethod
378+
def test_markers() -> list[MarkDecorator]:
379+
return [pytest.mark.rbac_remote_integration_test]
380+
375381
def setup(self, registry: RegistryConfig):
376382
parent_offline_config = super().create_offline_store_config()
377383
config = RepoConfig(
@@ -418,6 +424,10 @@ def __init__(self, project_name: str, *args, **kwargs):
418424
self.server_port: int = 0
419425
self.proc: Optional[Popen[bytes]] = None
420426

427+
@staticmethod
428+
def test_markers() -> list[MarkDecorator]:
429+
return [pytest.mark.rbac_remote_integration_test]
430+
421431
def setup(self, registry: RegistryConfig):
422432
parent_offline_config = super().create_offline_store_config()
423433
config = RepoConfig(
@@ -515,6 +525,10 @@ def __init__(self, project_name: str, *args, **kwargs):
515525
def xdist_groups() -> list[str]:
516526
return ["keycloak"]
517527

528+
@staticmethod
529+
def test_markers() -> list[MarkDecorator]:
530+
return [pytest.mark.rbac_remote_integration_test]
531+
518532
def setup(self, registry: RegistryConfig):
519533
parent_offline_config = super().create_offline_store_config()
520534
config = RepoConfig(

sdk/python/tests/integration/online_store/test_remote_online_store.py

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323

2424
@pytest.mark.integration
25+
@pytest.mark.rbac_remote_integration_test
2526
@pytest.mark.parametrize(
2627
"tls_mode", [("True", "True"), ("True", "False"), ("False", "")], indirect=True
2728
)

sdk/python/tests/integration/registration/test_universal_registry.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,10 @@ def mock_remote_registry():
344344
marks=pytest.mark.xdist_group(name="mysql_registry"),
345345
),
346346
lazy_fixture("sqlite_registry"),
347-
lazy_fixture("mock_remote_registry"),
347+
pytest.param(
348+
lazy_fixture("mock_remote_registry"),
349+
marks=pytest.mark.rbac_remote_integration_test,
350+
),
348351
]
349352

350353
sql_fixtures = [

0 commit comments

Comments
 (0)