Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BI-4885: add basic RLS tests #120

Merged
merged 1 commit into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions lib/dl_api_lib/dl_api_lib_tests/db/control_api/test_rls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import pytest

from dl_api_lib_testing.rls import (
RLS_CONFIG_CASES,
config_to_comparable,
load_rls_config,
)
from dl_api_lib_tests.db.base import DefaultApiTestBase


class TestDataset(DefaultApiTestBase):
@staticmethod
def add_rls_to_dataset(control_api, dataset, rls_config):
field_guid = dataset.result_schema[0].id
dataset.rls = {field_guid: rls_config}
resp = control_api.save_dataset(dataset, fail_ok=True)
return field_guid, resp

@pytest.mark.parametrize("case", RLS_CONFIG_CASES, ids=[c["name"] for c in RLS_CONFIG_CASES])
def test_create_and_update_rls(self, control_api, saved_dataset, case):
config = case["config"]
ds = saved_dataset
field_guid, rls_resp = self.add_rls_to_dataset(control_api, ds, config)
assert rls_resp.status_code == 200, rls_resp.json

resp = control_api.load_dataset(ds)
assert resp.status_code == 200, resp.json
ds = resp.dataset
assert config_to_comparable(ds.rls[field_guid]) == config_to_comparable(case["config_to_compare"])

config_updated = case.get("config_updated")
if config_updated is None:
return
field_guid, rls_resp = self.add_rls_to_dataset(control_api, ds, config_updated)
assert rls_resp.status_code == 200, rls_resp.json

resp = control_api.load_dataset(ds)
assert resp.status_code == 200, resp.json
assert config_to_comparable(resp.dataset.rls[field_guid]) == config_to_comparable(config_updated)

def test_create_rls_for_nonexistent_user(self, control_api, saved_dataset):
config = load_rls_config("bad_login")
ds = saved_dataset
field_guid, rls_resp = self.add_rls_to_dataset(control_api, ds, config)
assert rls_resp.status_code == 200, rls_resp.json

resp = control_api.load_dataset(ds)
assert resp.status_code == 200, resp.json
assert "!FAILED_robot-user2" in resp.dataset.rls[field_guid]

def test_create_rls_from_invalid_config(self, control_api, saved_dataset):
config = load_rls_config("bad")
_, rls_resp = self.add_rls_to_dataset(control_api, saved_dataset, config)

assert rls_resp.status_code == 400
assert rls_resp.bi_status_code == "ERR.DS_API.RLS.PARSE"
assert rls_resp.json["message"] == "RLS: Parsing failed at line 2"
assert rls_resp.json["details"] == {"description": "Wrong format"}
52 changes: 41 additions & 11 deletions lib/dl_api_lib_testing/dl_api_lib_testing/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
from dl_api_lib.app.control_api.app import EnvSetupResult as ControlApiEnvSetupResult
from dl_api_lib.app.data_api.app import DataApiAppFactory
from dl_api_lib.app.data_api.app import EnvSetupResult as DataApiEnvSetupResult
from dl_api_lib.app_common import (
SRFactoryBuilder,
StandaloneServiceRegistryFactory,
)
from dl_api_lib.app_common import SRFactoryBuilder
from dl_api_lib.app_common_settings import ConnOptionsMutatorsFactory
from dl_api_lib.app_settings import (
AppSettings,
Expand All @@ -27,26 +24,33 @@
from dl_api_lib.connector_availability.base import ConnectorAvailabilityConfig
from dl_api_lib_testing.configuration import ApiTestEnvironmentConfiguration
from dl_configs.connectors_settings import ConnectorSettingsBase
from dl_configs.enums import (
RedisMode,
RequiredService,
)
from dl_configs.enums import RequiredService
from dl_configs.rqe import (
RQEBaseURL,
RQEConfig,
)
from dl_configs.settings_submodels import RedisSettings
from dl_constants.enums import (
ConnectionType,
RLSSubjectType,
USAuthMode,
)
from dl_core.aio.middlewares.services_registry import services_registry_middleware
from dl_core.aio.middlewares.us_manager import service_us_manager_middleware
from dl_core.data_processing.cache.primitives import CacheTTLConfig
from dl_core.rls import (
RLS_FAILED_USER_NAME_PREFIX,
BaseSubjectResolver,
RLSSubject,
)
from dl_core.services_registry import ServicesRegistry
from dl_core.services_registry.entity_checker import EntityUsageChecker
from dl_core.services_registry.env_manager_factory_base import EnvManagerFactory
from dl_core.services_registry.inst_specific_sr import InstallationSpecificServiceRegistryFactory
from dl_core.services_registry.inst_specific_sr import (
InstallationSpecificServiceRegistry,
InstallationSpecificServiceRegistryFactory,
)
from dl_core.services_registry.rqe_caches import RQECachesSetting
from dl_core.utils import FutureRef
from dl_core_testing.app_test_workarounds import TestEnvManagerFactory
from dl_core_testing.fixture_server_runner import WSGIRunner

Expand Down Expand Up @@ -98,6 +102,32 @@ def rqe_config_subprocess_cm(self) -> Generator[RQEConfig, None, None]:
)


@attr.s
class TestingSubjectResolver(BaseSubjectResolver):
def get_subjects_by_names(self, names: list[str]) -> list[RLSSubject]:
"""Mock resolver. Considers a user real if his name starts with 'user'"""
return [
RLSSubject(
subject_id="",
subject_type=RLSSubjectType.user if name.startswith("user") else RLSSubjectType.notfound,
subject_name=name if name.startswith("user") else RLS_FAILED_USER_NAME_PREFIX + name,
)
for name in names
]


@attr.s
class TestingServiceRegistry(InstallationSpecificServiceRegistry):
async def get_subject_resolver(self) -> BaseSubjectResolver:
return TestingSubjectResolver()


@attr.s
class TestingServiceRegistryFactory(InstallationSpecificServiceRegistryFactory):
def get_inst_specific_sr(self, sr_ref: FutureRef[ServicesRegistry]) -> TestingServiceRegistry:
return TestingServiceRegistry(service_registry_ref=sr_ref)


class TestingSRFactoryBuilder(SRFactoryBuilder[AppSettings]):
def _get_required_services(self, settings: AppSettings) -> set[RequiredService]:
return {RequiredService.RQE_INT_SYNC, RequiredService.RQE_EXT_SYNC}
Expand All @@ -109,7 +139,7 @@ def _get_inst_specific_sr_factory(
self,
settings: AppSettings,
) -> Optional[InstallationSpecificServiceRegistryFactory]:
return StandaloneServiceRegistryFactory()
return TestingServiceRegistryFactory()

def _get_entity_usage_checker(self, settings: AppSettings) -> Optional[EntityUsageChecker]:
return None
Expand Down
4 changes: 4 additions & 0 deletions lib/dl_api_lib_testing/dl_api_lib_testing/rls.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ def load_rls(name: str) -> list[RLSEntry]:
MAIN_TEST_CASE = RLS_CONFIG_CASES[0]


def config_to_comparable(conf: str):
return set((line.split(": ")[0], ",".join(sorted(line.split(": ")[1]))) for line in conf.strip().split("\n"))


def check_text_config_to_rls_entries(case: dict, subject_resolver: BaseSubjectResolver) -> None:
field_guid, config, expected_rls_entries = case["field_guid"], case["config"], case["rls_entries"]
entries = FieldRLSSerializer.from_text_config(config, field_guid, subject_resolver=subject_resolver)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
'Москва': user2, user1
'Самара': user3, !FAILED_someuser, user1
'Омск': user5, pg
'Омск': user5, user7
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"subject": {
"subject_id": "1120000000000251",
"subject_type": "user",
"subject_name": "pg"
"subject_name": "user7"
}
}
]
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
'Москва': user2
'Самара': user1, user3
'Омск': user5, pg
'Омск': user5, user7
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"subject": {
"subject_id": "1120000000000251",
"subject_type": "user",
"subject_name": "pg"
"subject_name": "user7"
}
}
]
Loading