From ad5d744612f856775403910802f8576f8248141a Mon Sep 17 00:00:00 2001 From: deffer Date: Fri, 1 Dec 2023 11:37:38 +0500 Subject: [PATCH 01/23] add test for feature admin view --- .../admin/views/test_feature_admin_view.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/integration/admin/views/test_feature_admin_view.py diff --git a/tests/integration/admin/views/test_feature_admin_view.py b/tests/integration/admin/views/test_feature_admin_view.py new file mode 100644 index 00000000..7d666839 --- /dev/null +++ b/tests/integration/admin/views/test_feature_admin_view.py @@ -0,0 +1,21 @@ +from http import HTTPStatus + +import pytest +from flask.testing import FlaskClient + +from overhave import db +from overhave.storage import SystemUserModel +from tests.db_utils import create_test_session + + +@pytest.mark.usefixtures("database") +class TestFeatureAdminView: + """Tests for feature view.""" + + @pytest.mark.parametrize("test_user_role", [db.Role.admin], indirect=True) + def test_edit_redirects_to_feature_index_view_if_no_feature(self, test_client: FlaskClient, + test_authorized_user: SystemUserModel) -> None: + with create_test_session(): + response = test_client.get("/feature/edit/") + assert response.status_code == HTTPStatus.FOUND + assert response.location == '/feature/' \ No newline at end of file From 8712240d0d0636a715926b2c75a4d2335a026a1c Mon Sep 17 00:00:00 2001 From: deffer Date: Fri, 1 Dec 2023 11:40:29 +0500 Subject: [PATCH 02/23] refactoring --- tests/integration/admin/views/test_feature_admin_view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/admin/views/test_feature_admin_view.py b/tests/integration/admin/views/test_feature_admin_view.py index 7d666839..c740d2c9 100644 --- a/tests/integration/admin/views/test_feature_admin_view.py +++ b/tests/integration/admin/views/test_feature_admin_view.py @@ -18,4 +18,4 @@ def test_edit_redirects_to_feature_index_view_if_no_feature(self, test_client: F with create_test_session(): response = test_client.get("/feature/edit/") assert response.status_code == HTTPStatus.FOUND - assert response.location == '/feature/' \ No newline at end of file + assert response.location == '/feature/' From 991bf537114b84efb326ab55950820c519338175 Mon Sep 17 00:00:00 2001 From: deffer Date: Wed, 27 Dec 2023 21:17:14 +0500 Subject: [PATCH 03/23] add api client --- overhave/transport/http/api_client/client.py | 76 +++++++++++++++++++ .../transport/http/api_client/settings.py | 7 ++ .../transport/http/base_client/objects.py | 2 + 3 files changed, 85 insertions(+) create mode 100644 overhave/transport/http/api_client/client.py diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py new file mode 100644 index 00000000..51306500 --- /dev/null +++ b/overhave/transport/http/api_client/client.py @@ -0,0 +1,76 @@ +from typing import Any, Mapping + +import httpx + +from overhave.transport.http import BaseHttpClient, BearerAuth +from overhave.transport.http.api_client.settings import OverhaveApiClientSettings +from overhave.transport.http.base_client import HttpMethod + + +class OverhaveApiClient(BaseHttpClient[OverhaveApiClientSettings]): + def __init__(self, settings: OverhaveApiClientSettings): + super().__init__(settings=settings) + + def _get( + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + raise_for_status: bool = True, + ): + self._make_request( + method=HttpMethod.GET, + url=url, + params=params, + raise_for_status=raise_for_status, + auth=BearerAuth(self._settings.auth_token) + ) + + def _post( + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + json: dict[str, Any] | None = None, + data: str | bytes | Mapping[Any, Any] | None = None, + raise_for_status: bool = True, + ): + self._make_request( + method=HttpMethod.GET, + url=url, + params=params, + json=json, + data=data, + raise_for_status=raise_for_status, + auth=BearerAuth(self._settings.auth_token) + ) + + def _put( + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + json: dict[str, Any] | None = None, + data: str | bytes | Mapping[Any, Any] | None = None, + raise_for_status: bool = True, + ): + self._make_request( + method=HttpMethod.PUT, + url=url, + params=params, + json=json, + data=data, + raise_for_status=raise_for_status, + auth=BearerAuth(self._settings.auth_token) + ) + + def _delete( + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + raise_for_status: bool = True, + ): + self._make_request( + method=HttpMethod.DELETE, + url=url, + params=params, + raise_for_status=raise_for_status, + auth=BearerAuth(self._settings.auth_token) + ) diff --git a/overhave/transport/http/api_client/settings.py b/overhave/transport/http/api_client/settings.py index 61924568..46fac581 100644 --- a/overhave/transport/http/api_client/settings.py +++ b/overhave/transport/http/api_client/settings.py @@ -15,3 +15,10 @@ class Config: @property def get_auth_token_url(self) -> httpx.URL: return httpx.URL(f"{self.url}/{self.auth_token_path}") + + +class OverhaveApiClientSettings(BaseHttpClientSettings): + auth_token: str + + class Config: + env_prefix = "OVERHAVE_API_CLIENT" diff --git a/overhave/transport/http/base_client/objects.py b/overhave/transport/http/base_client/objects.py index 2900f5ea..955a18b0 100644 --- a/overhave/transport/http/base_client/objects.py +++ b/overhave/transport/http/base_client/objects.py @@ -6,3 +6,5 @@ class HttpMethod(enum.StrEnum): GET = "get" POST = "post" + PUT = "put" + DELETE = "delete" From 6ad9b8da4774c662a1274e04a3908a619cadee36 Mon Sep 17 00:00:00 2001 From: Matvey Ilichev Date: Wed, 27 Dec 2023 23:18:59 +0500 Subject: [PATCH 04/23] tmp --- overhave/transport/http/api_client/client.py | 91 +++++++++++++------ overhave/transport/http/api_client/models.py | 14 +++ .../transport/http/api_client/settings.py | 2 + .../admin/views/test_feature_admin_view.py | 7 +- 4 files changed, 83 insertions(+), 31 deletions(-) diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index 51306500..57f77c3c 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -1,55 +1,61 @@ -from typing import Any, Mapping +import logging +from typing import Any, Mapping, cast import httpx from overhave.transport.http import BaseHttpClient, BearerAuth +from overhave.transport.http.api_client.models import ApiTagResponse from overhave.transport.http.api_client.settings import OverhaveApiClientSettings -from overhave.transport.http.base_client import HttpMethod +from overhave.transport.http.base_client import HttpClientValidationError, HttpMethod + +logger = logging.getLogger(__name__) class OverhaveApiClient(BaseHttpClient[OverhaveApiClientSettings]): + """api client.""" + def __init__(self, settings: OverhaveApiClientSettings): super().__init__(settings=settings) def _get( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - raise_for_status: bool = True, + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + raise_for_status: bool = True, ): - self._make_request( + return self._make_request( method=HttpMethod.GET, url=url, params=params, raise_for_status=raise_for_status, - auth=BearerAuth(self._settings.auth_token) + auth=BearerAuth(self._settings.auth_token), ) def _post( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - json: dict[str, Any] | None = None, - data: str | bytes | Mapping[Any, Any] | None = None, - raise_for_status: bool = True, + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + json: dict[str, Any] | None = None, + data: str | bytes | Mapping[Any, Any] | None = None, + raise_for_status: bool = True, ): - self._make_request( + return self._make_request( method=HttpMethod.GET, url=url, params=params, json=json, data=data, raise_for_status=raise_for_status, - auth=BearerAuth(self._settings.auth_token) + auth=BearerAuth(self._settings.auth_token), ) def _put( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - json: dict[str, Any] | None = None, - data: str | bytes | Mapping[Any, Any] | None = None, - raise_for_status: bool = True, + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + json: dict[str, Any] | None = None, + data: str | bytes | Mapping[Any, Any] | None = None, + raise_for_status: bool = True, ): self._make_request( method=HttpMethod.PUT, @@ -58,19 +64,48 @@ def _put( json=json, data=data, raise_for_status=raise_for_status, - auth=BearerAuth(self._settings.auth_token) + auth=BearerAuth(self._settings.auth_token), ) def _delete( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - raise_for_status: bool = True, + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + raise_for_status: bool = True, ): self._make_request( method=HttpMethod.DELETE, url=url, params=params, raise_for_status=raise_for_status, - auth=BearerAuth(self._settings.auth_token) + auth=BearerAuth(self._settings.auth_token), ) + + def get_feature_tags_item(self): + response = self._get(url=httpx.URL(f"{self._settings.url}/feature/tags/item")) + + try: + return cast(ApiTagResponse, self._parse_or_raise(response, ApiTagResponse)) + except HttpClientValidationError: + logger.debug("Could not convert response to '%s'!", ApiTagResponse, exc_info=True) + + return None + + def get_feature_tags_list(self): + response = self._get(url=httpx.URL(f"{self._settings.url}/feature/tags/list")) + + try: + return cast(ApiTagResponse, self._parse_or_raise(response, ApiTagResponse)) + except HttpClientValidationError: + logger.debug("Could not convert response to '%s'!", ApiTagResponse, exc_info=True) + + return None + + def get_emulation_run_list(self): + pass # response = self._get(url=httpx.URL(f"{self._settings.url}/emulation/run/list")) + + def get_test_run(self): + pass # response = self._get(url=httpx.URL(f"{self._settings.url}/test_run")) + + def create_test_run(self): + pass # response = self._post(url=httpx.URL(f"{self._settings.url}/test_run/create/")) diff --git a/overhave/transport/http/api_client/models.py b/overhave/transport/http/api_client/models.py index 05d29938..a5a65de2 100644 --- a/overhave/transport/http/api_client/models.py +++ b/overhave/transport/http/api_client/models.py @@ -9,3 +9,17 @@ class TokenRequestData(BaseModel): grant_type: Literal["password"] = "password" username: str password: str + + +class ApiTagResponse(BaseModel): + """resp.""" + + id: int + value: str + created_by: str + + +class ApiTagsResponse(BaseModel): + """resp.""" + + items: list[ApiTagResponse] diff --git a/overhave/transport/http/api_client/settings.py b/overhave/transport/http/api_client/settings.py index 46fac581..4534d198 100644 --- a/overhave/transport/http/api_client/settings.py +++ b/overhave/transport/http/api_client/settings.py @@ -18,6 +18,8 @@ def get_auth_token_url(self) -> httpx.URL: class OverhaveApiClientSettings(BaseHttpClientSettings): + """settings.""" + auth_token: str class Config: diff --git a/tests/integration/admin/views/test_feature_admin_view.py b/tests/integration/admin/views/test_feature_admin_view.py index c740d2c9..9119c21e 100644 --- a/tests/integration/admin/views/test_feature_admin_view.py +++ b/tests/integration/admin/views/test_feature_admin_view.py @@ -13,9 +13,10 @@ class TestFeatureAdminView: """Tests for feature view.""" @pytest.mark.parametrize("test_user_role", [db.Role.admin], indirect=True) - def test_edit_redirects_to_feature_index_view_if_no_feature(self, test_client: FlaskClient, - test_authorized_user: SystemUserModel) -> None: + def test_edit_redirects_to_feature_index_view_if_no_feature( + self, test_client: FlaskClient, test_authorized_user: SystemUserModel + ) -> None: with create_test_session(): response = test_client.get("/feature/edit/") assert response.status_code == HTTPStatus.FOUND - assert response.location == '/feature/' + assert response.location == "/feature/" From f02070f125503c78a95c9f5bd13673d698cffa6b Mon Sep 17 00:00:00 2001 From: deffer Date: Fri, 29 Dec 2023 03:59:33 +0500 Subject: [PATCH 05/23] add get feature types, get features, tests --- overhave/transport/http/api_client/client.py | 33 +++++++++++++---- overhave/transport/http/api_client/models.py | 25 +++++++++++++ test.py | 14 ++++++++ tests/integration/api/conftest.py | 33 +---------------- tests/integration/client/conftest.py | 35 +++++++++++++++++++ .../client/test_client_feature_types.py | 16 +++++++++ .../client/test_client_features.py | 33 +++++++++++++++++ tests/integration/conftest.py | 35 +++++++++++++++++-- 8 files changed, 183 insertions(+), 41 deletions(-) create mode 100644 test.py create mode 100644 tests/integration/client/conftest.py create mode 100644 tests/integration/client/test_client_feature_types.py create mode 100644 tests/integration/client/test_client_features.py diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index 57f77c3c..5bdc0780 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -4,7 +4,7 @@ import httpx from overhave.transport.http import BaseHttpClient, BearerAuth -from overhave.transport.http.api_client.models import ApiTagResponse +from overhave.transport.http.api_client.models import ApiFeatureResponse, ApiFeatureTypeResponse, ApiTagResponse from overhave.transport.http.api_client.settings import OverhaveApiClientSettings from overhave.transport.http.base_client import HttpClientValidationError, HttpMethod @@ -12,7 +12,7 @@ class OverhaveApiClient(BaseHttpClient[OverhaveApiClientSettings]): - """api client.""" + """Client for overhave api.""" def __init__(self, settings: OverhaveApiClientSettings): super().__init__(settings=settings) @@ -57,7 +57,7 @@ def _put( data: str | bytes | Mapping[Any, Any] | None = None, raise_for_status: bool = True, ): - self._make_request( + return self._make_request( method=HttpMethod.PUT, url=url, params=params, @@ -73,7 +73,7 @@ def _delete( params: dict[str, Any] | None = None, raise_for_status: bool = True, ): - self._make_request( + return self._make_request( method=HttpMethod.DELETE, url=url, params=params, @@ -101,11 +101,30 @@ def get_feature_tags_list(self): return None - def get_emulation_run_list(self): + def get_emulation_run_list(self) -> None: pass # response = self._get(url=httpx.URL(f"{self._settings.url}/emulation/run/list")) - def get_test_run(self): + def get_test_run(self) -> None: pass # response = self._get(url=httpx.URL(f"{self._settings.url}/test_run")) - def create_test_run(self): + def create_test_run(self) -> None: pass # response = self._post(url=httpx.URL(f"{self._settings.url}/test_run/create/")) + + def get_feature_types(self) -> list[ApiFeatureTypeResponse]: + response = self._get(url=httpx.URL(f"{self._settings.url}/feature/types/list")) + feature_types = [ApiFeatureTypeResponse.model_validate(data) for data in response.json()] + return feature_types + + def get_features_by_tag_id(self, tag_id: int) -> list[ApiFeatureResponse]: + response = self._get( + url=httpx.URL(f"{self._settings.url}/feature/"), + params={"tag_id": tag_id}, + ) + return [ApiFeatureResponse.model_validate(data) for data in response.json()] + + def get_features_by_tag_value(self, tag_value: str) -> list[ApiFeatureResponse]: + response = self._get( + url=httpx.URL(f"{self._settings.url}/feature/"), + params={"tag_value": tag_value}, + ) + return [ApiFeatureResponse.model_validate(data) for data in response.json()] diff --git a/overhave/transport/http/api_client/models.py b/overhave/transport/http/api_client/models.py index a5a65de2..8502cf9d 100644 --- a/overhave/transport/http/api_client/models.py +++ b/overhave/transport/http/api_client/models.py @@ -1,5 +1,8 @@ +from datetime import datetime from typing import Literal +import allure + from pydantic import BaseModel @@ -23,3 +26,25 @@ class ApiTagsResponse(BaseModel): """resp.""" items: list[ApiTagResponse] + + +class ApiFeatureTypeResponse(BaseModel): + id: int + name: str + + +class ApiFeatureResponse(BaseModel): + id: int + created_at: datetime + name: str + author: str + type_id: int + last_edited_by: str + last_edited_at: datetime + task: list[str] + file_path: str + released: bool + severity: allure.severity_level + + feature_type: ApiFeatureTypeResponse + feature_tags: list[ApiTagResponse] diff --git a/test.py b/test.py new file mode 100644 index 00000000..410c2f60 --- /dev/null +++ b/test.py @@ -0,0 +1,14 @@ +from pydantic import SecretStr + +from overhave import OverhaveApiAuthenticator, OverhaveApiAuthenticatorSettings +from overhave.storage import AuthStorage +from overhave.transport.http.api_client.client import * + + +if __name__ == '__main__': + auth = OverhaveApiAuthenticator(OverhaveApiAuthenticatorSettings(url='http://localhost:8000'), AuthStorage()) + token = auth.get_bearer_auth('admin', SecretStr('86f2551dd8cb4dc18308916a5a7edc6a')) + settings = OverhaveApiClientSettings(url='http://localhost:8000', auth_token=token.token) + client = OverhaveApiClient(settings=settings) + print(client.get_features_by_tag_id(3)) + print(client.get_features_by_tag_value('chatbot')) diff --git a/tests/integration/api/conftest.py b/tests/integration/api/conftest.py index 8bd41395..3e5809fc 100644 --- a/tests/integration/api/conftest.py +++ b/tests/integration/api/conftest.py @@ -1,16 +1,10 @@ -from typing import Iterator from unittest import mock import httpx import pytest from faker import Faker -from fastapi.testclient import TestClient -from overhave import overhave_api -from overhave.storage import AuthStorage, SystemUserModel, TestUserSpecification -from overhave.transport.http.api_client.authenticator import OverhaveApiAuthenticator -from overhave.transport.http.api_client.settings import OverhaveApiAuthenticatorSettings -from overhave.transport.http.base_client import BearerAuth +from overhave.storage import TestUserSpecification @pytest.fixture(scope="module") @@ -28,31 +22,6 @@ def mock_default_value() -> str: return "" -@pytest.fixture() -def test_api_client(database) -> TestClient: - return TestClient(overhave_api()) - - -@pytest.fixture() -def api_authenticator_settings(test_api_client: TestClient) -> OverhaveApiAuthenticatorSettings: - return OverhaveApiAuthenticatorSettings(url=test_api_client.base_url) - - -@pytest.fixture() -def api_authenticator( - mock_envs, test_api_client: TestClient, api_authenticator_settings: OverhaveApiAuthenticatorSettings -) -> Iterator[OverhaveApiAuthenticator]: - with mock.patch.object(httpx, "request", new_callable=lambda: test_api_client.request): - yield OverhaveApiAuthenticator(settings=api_authenticator_settings, auth_storage=AuthStorage()) - - -@pytest.fixture() -def test_api_bearer_auth( - service_system_user: SystemUserModel, api_authenticator: OverhaveApiAuthenticator -) -> BearerAuth: - return api_authenticator.get_bearer_auth(username=service_system_user.login, password=service_system_user.password) - - @pytest.fixture(scope="module") def test_new_specification() -> TestUserSpecification: return TestUserSpecification({"new_test": "new_value"}) diff --git a/tests/integration/client/conftest.py b/tests/integration/client/conftest.py new file mode 100644 index 00000000..13bef79f --- /dev/null +++ b/tests/integration/client/conftest.py @@ -0,0 +1,35 @@ +from typing import Iterator +from unittest import mock + +import httpx +import pytest +from fastapi.testclient import TestClient + +from overhave.transport.http.api_client.client import OverhaveApiClient +from overhave.transport.http.api_client.settings import OverhaveApiClientSettings +from overhave.transport.http.base_client import BearerAuth + + +@pytest.fixture(scope="module") +def envs_for_mock() -> dict[str, str | None]: + return { + "OVERHAVE_API_AUTH_SECRET_KEY": "123", + "OVERHAVE_FEATURES_DIR": "/features", + "OVERHAVE_FIXTURES_DIR": "/fixtures", + "OVERHAVE_STEPS_DIR": "/steps", + } + + +@pytest.fixture() +def overhave_api_client_settings( + test_api_client: TestClient, test_api_bearer_auth: BearerAuth +) -> OverhaveApiClientSettings: + return OverhaveApiClientSettings(url=test_api_client.base_url, auth_token=test_api_bearer_auth.token) + + +@pytest.fixture() +def api_client( + mock_envs, test_api_client: TestClient, overhave_api_client_settings: OverhaveApiClientSettings +) -> Iterator[OverhaveApiClient]: + with mock.patch.object(httpx, "request", new_callable=lambda: test_api_client.request): + yield OverhaveApiClient(settings=overhave_api_client_settings) diff --git a/tests/integration/client/test_client_feature_types.py b/tests/integration/client/test_client_feature_types.py new file mode 100644 index 00000000..3aef77bc --- /dev/null +++ b/tests/integration/client/test_client_feature_types.py @@ -0,0 +1,16 @@ +import pytest + +from overhave import db +from overhave.storage import FeatureTypeModel +from overhave.transport.http.api_client.client import OverhaveApiClient + + +@pytest.mark.parametrize("test_user_role", [db.Role.user], indirect=True) +class TestFeatureTypesApiClient: + """Integration tests for Overhave FeatureTypes API Client.""" + + # TODO: этот тест как-то влияет на другой. разобраться почему + def test_get_feature_types(self, api_client: OverhaveApiClient, test_feature_type: FeatureTypeModel) -> None: + feature_types = api_client.get_feature_types() + assert len(feature_types) == 1 + assert feature_types[0].model_dump() == test_feature_type.model_dump() diff --git a/tests/integration/client/test_client_features.py b/tests/integration/client/test_client_features.py new file mode 100644 index 00000000..727fc7ff --- /dev/null +++ b/tests/integration/client/test_client_features.py @@ -0,0 +1,33 @@ +import allure +import pytest + +from overhave import db +from overhave.storage import FeatureModel, TagModel +from overhave.transport.http.api_client.client import OverhaveApiClient + + +@pytest.mark.parametrize("test_user_role", [db.Role.user], indirect=True) +class TestFeatureApiClient: + """Integration tests for Overhave FeatureTypes API Client.""" + + @pytest.mark.parametrize("test_severity", [allure.severity_level.NORMAL], indirect=True) + def test_get_feature_by_tag_id( + self, + api_client: OverhaveApiClient, + test_tag: TagModel, + test_feature_with_tag: FeatureModel, + ) -> None: + features = api_client.get_features_by_tag_id(tag_id=test_tag.id) + assert len(features) == 1 + assert features[0].model_dump() == test_feature_with_tag.model_dump() + + @pytest.mark.parametrize("test_severity", [allure.severity_level.NORMAL], indirect=True) + def test_get_feature_by_tag_value( + self, + api_client: OverhaveApiClient, + test_tag: TagModel, + test_feature_with_tag: FeatureModel, + ) -> None: + features = api_client.get_features_by_tag_value(tag_value=test_tag.value) + assert len(features) == 1 + assert features[0].model_dump() == test_feature_with_tag.model_dump() diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 7ce2cb84..687190ba 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -1,15 +1,21 @@ from datetime import datetime -from typing import cast +from typing import cast, Iterator +from unittest import mock from uuid import uuid1 import allure import pytest +import httpx from _pytest.fixtures import FixtureRequest from faker import Faker +from fastapi.testclient import TestClient -from overhave import OverhaveEmulationSettings, db +from overhave import OverhaveEmulationSettings, db, OverhaveApiAuthenticator, OverhaveApiAuthenticatorSettings +from overhave import overhave_api from overhave.db import DraftStatus +from overhave.transport.http.base_client import BearerAuth from overhave.storage import ( + AuthStorage, DraftModel, DraftStorage, EmulationModel, @@ -324,3 +330,28 @@ def test_draft( session.add(draft) session.flush() return DraftModel.model_validate(draft) + + +@pytest.fixture() +def test_api_client(database) -> TestClient: + return TestClient(overhave_api()) + + +@pytest.fixture() +def api_authenticator_settings(test_api_client: TestClient) -> OverhaveApiAuthenticatorSettings: + return OverhaveApiAuthenticatorSettings(url=test_api_client.base_url) + + +@pytest.fixture() +def api_authenticator( + mock_envs, test_api_client: TestClient, api_authenticator_settings: OverhaveApiAuthenticatorSettings +) -> Iterator[OverhaveApiAuthenticator]: + with mock.patch.object(httpx, "request", new_callable=lambda: test_api_client.request): + yield OverhaveApiAuthenticator(settings=api_authenticator_settings, auth_storage=AuthStorage()) + + +@pytest.fixture() +def test_api_bearer_auth( + service_system_user: SystemUserModel, api_authenticator: OverhaveApiAuthenticator +) -> BearerAuth: + return api_authenticator.get_bearer_auth(username=service_system_user.login, password=service_system_user.password) From 442f53a54681caf82399ab908c89229a8b5d82be Mon Sep 17 00:00:00 2001 From: Matvey Ilichev Date: Sat, 30 Dec 2023 17:08:40 +0500 Subject: [PATCH 06/23] add test run methods --- overhave/api/views/testrun_views.py | 1 + overhave/transport/http/api_client/client.py | 122 ++++++++++-------- overhave/transport/http/api_client/models.py | 23 ++-- .../client/test_client_feature_tags.py | 45 +++++++ .../client/test_client_test_run.py | 41 ++++++ tests/integration/conftest.py | 28 +++- 6 files changed, 199 insertions(+), 61 deletions(-) create mode 100644 tests/integration/client/test_client_feature_tags.py create mode 100644 tests/integration/client/test_client_test_run.py diff --git a/overhave/api/views/testrun_views.py b/overhave/api/views/testrun_views.py index 570c4656..fc3755fd 100644 --- a/overhave/api/views/testrun_views.py +++ b/overhave/api/views/testrun_views.py @@ -34,6 +34,7 @@ def run_tests_by_tag_handler( test_run_storage: TestRunStorage = fastapi.Depends(get_test_run_storage), redis_producer: RedisProducer = fastapi.Depends(get_redis_producer), ) -> list[str]: + print('-----------------------') tag_model = tags_item_handler(value=tag_value, feature_tag_storage=tag_storage) features = feature_storage.get_features_by_tag(tag_id=tag_model.id) if not features: diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index 5bdc0780..c48b26e5 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -1,12 +1,13 @@ import logging -from typing import Any, Mapping, cast +from typing import Any, Mapping import httpx from overhave.transport.http import BaseHttpClient, BearerAuth -from overhave.transport.http.api_client.models import ApiFeatureResponse, ApiFeatureTypeResponse, ApiTagResponse +from overhave.transport.http.api_client.models import ApiFeatureResponse, ApiFeatureTypeResponse, ApiTagResponse, \ + ApiTestRunResponse from overhave.transport.http.api_client.settings import OverhaveApiClientSettings -from overhave.transport.http.base_client import HttpClientValidationError, HttpMethod +from overhave.transport.http.base_client import HttpMethod logger = logging.getLogger(__name__) @@ -18,10 +19,10 @@ def __init__(self, settings: OverhaveApiClientSettings): super().__init__(settings=settings) def _get( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - raise_for_status: bool = True, + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + raise_for_status: bool = True, ): return self._make_request( method=HttpMethod.GET, @@ -32,15 +33,15 @@ def _get( ) def _post( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - json: dict[str, Any] | None = None, - data: str | bytes | Mapping[Any, Any] | None = None, - raise_for_status: bool = True, + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + json: dict[str, Any] | None = None, + data: str | bytes | Mapping[Any, Any] | None = None, + raise_for_status: bool = True, ): return self._make_request( - method=HttpMethod.GET, + method=HttpMethod.POST, url=url, params=params, json=json, @@ -50,12 +51,12 @@ def _post( ) def _put( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - json: dict[str, Any] | None = None, - data: str | bytes | Mapping[Any, Any] | None = None, - raise_for_status: bool = True, + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + json: dict[str, Any] | None = None, + data: str | bytes | Mapping[Any, Any] | None = None, + raise_for_status: bool = True, ): return self._make_request( method=HttpMethod.PUT, @@ -68,10 +69,10 @@ def _put( ) def _delete( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - raise_for_status: bool = True, + self, + url: httpx.URL, + params: dict[str, Any] | None = None, + raise_for_status: bool = True, ): return self._make_request( method=HttpMethod.DELETE, @@ -81,50 +82,69 @@ def _delete( auth=BearerAuth(self._settings.auth_token), ) - def get_feature_tags_item(self): - response = self._get(url=httpx.URL(f"{self._settings.url}/feature/tags/item")) - - try: - return cast(ApiTagResponse, self._parse_or_raise(response, ApiTagResponse)) - except HttpClientValidationError: - logger.debug("Could not convert response to '%s'!", ApiTagResponse, exc_info=True) - - return None - - def get_feature_tags_list(self): - response = self._get(url=httpx.URL(f"{self._settings.url}/feature/tags/list")) - - try: - return cast(ApiTagResponse, self._parse_or_raise(response, ApiTagResponse)) - except HttpClientValidationError: - logger.debug("Could not convert response to '%s'!", ApiTagResponse, exc_info=True) - - return None + def get_feature_tags_item(self, value: str) -> ApiTagResponse: + logger.debug(f"Start get feature tags item with [value: {value}]") + response = self._get( + url=httpx.URL(f"{self._settings.url}/feature/tags/item"), + params={"value": value} + ) + logger.debug("Get tags item successfully") - def get_emulation_run_list(self) -> None: - pass # response = self._get(url=httpx.URL(f"{self._settings.url}/emulation/run/list")) + return ApiTagResponse.model_validate(response.json()) - def get_test_run(self) -> None: - pass # response = self._get(url=httpx.URL(f"{self._settings.url}/test_run")) + def get_feature_tags_list(self, value: str) -> list[ApiTagResponse]: + logger.debug(f"Start get feature tags list with [value: {value}]") + response = self._get( + url=httpx.URL(f"{self._settings.url}/feature/tags/list"), + params={"value": value} + ) + logger.debug("Get tags list successfully") - def create_test_run(self) -> None: - pass # response = self._post(url=httpx.URL(f"{self._settings.url}/test_run/create/")) + return [ApiTagResponse.model_validate(data) for data in response.json()] def get_feature_types(self) -> list[ApiFeatureTypeResponse]: + logger.debug(f"Start get feature types list") response = self._get(url=httpx.URL(f"{self._settings.url}/feature/types/list")) - feature_types = [ApiFeatureTypeResponse.model_validate(data) for data in response.json()] - return feature_types + logger.debug("Get feature types successfully") + + return [ApiFeatureTypeResponse.model_validate(data) for data in response.json()] def get_features_by_tag_id(self, tag_id: int) -> list[ApiFeatureResponse]: + logger.debug(f"Start get feature with [tag_id: {tag_id}]") response = self._get( url=httpx.URL(f"{self._settings.url}/feature/"), params={"tag_id": tag_id}, ) + logger.debug("Get feature successfully") + return [ApiFeatureResponse.model_validate(data) for data in response.json()] def get_features_by_tag_value(self, tag_value: str) -> list[ApiFeatureResponse]: + logger.debug(f"Start get feature with [tag_value: {tag_value}]") response = self._get( url=httpx.URL(f"{self._settings.url}/feature/"), params={"tag_value": tag_value}, ) + logger.debug("Get feature successfully") + return [ApiFeatureResponse.model_validate(data) for data in response.json()] + + def get_test_run(self, test_run_id: int) -> ApiTestRunResponse: + logger.debug(f"Start get test run with [test_run_id: {test_run_id}]") + response = self._get( + url=httpx.URL(f"{self._settings.url}/test_run"), + params={"test_run_id": test_run_id}, + ) + logger.debug("Get test run successfully") + + return ApiTestRunResponse.model_validate(response.json()) + + def create_test_run(self, tag_value: str) -> list[str]: + logger.debug(f"Start create test run with [tag_value: {tag_value}]") + response = self._post( + url=httpx.URL(f"{self._settings.url}/test_run/create/"), + params={"tag_value": tag_value}, + ) + logger.debug("Create test run successfully") + + return response.json() diff --git a/overhave/transport/http/api_client/models.py b/overhave/transport/http/api_client/models.py index 8502cf9d..4e4584d5 100644 --- a/overhave/transport/http/api_client/models.py +++ b/overhave/transport/http/api_client/models.py @@ -15,19 +15,12 @@ class TokenRequestData(BaseModel): class ApiTagResponse(BaseModel): - """resp.""" - + """Model for Tag response data.""" id: int value: str created_by: str -class ApiTagsResponse(BaseModel): - """resp.""" - - items: list[ApiTagResponse] - - class ApiFeatureTypeResponse(BaseModel): id: int name: str @@ -48,3 +41,17 @@ class ApiFeatureResponse(BaseModel): feature_type: ApiFeatureTypeResponse feature_tags: list[ApiTagResponse] + + +class ApiTestRunResponse(BaseModel): + id: int + created_at: datetime + name: str + executed_by: str + start: datetime | None + end: datetime | None + status: str + report_status: str + report: str | None + traceback: str | None + scenario_id: int diff --git a/tests/integration/client/test_client_feature_tags.py b/tests/integration/client/test_client_feature_tags.py new file mode 100644 index 00000000..e48b0085 --- /dev/null +++ b/tests/integration/client/test_client_feature_tags.py @@ -0,0 +1,45 @@ +import pytest +from faker import Faker +from httpx import HTTPStatusError + +from overhave import db +from overhave.storage import TagModel +from overhave.transport.http.api_client.client import OverhaveApiClient + + +@pytest.mark.parametrize("test_user_role", [db.Role.user], indirect=True) +class TestFeatureTagsApiClient: + """Integration tests for Overhave Tags API Client.""" + + def test_get_feature_tags_item( + self, + api_client: OverhaveApiClient, + test_tag: TagModel, + ) -> None: + item = api_client.get_feature_tags_item(value=test_tag.value) + assert item.model_dump() == test_tag.model_dump() + + def test_get_feature_tags_with_unknown_value( + self, + api_client: OverhaveApiClient, + faker: Faker, + ) -> None: + with pytest.raises(HTTPStatusError): + api_client.get_feature_tags_item(value=faker.word()) + + def test_get_feature_tags_list( + self, + api_client: OverhaveApiClient, + test_tag: TagModel, + ) -> None: + items = api_client.get_feature_tags_list(value=test_tag.value) + assert len(items) >= 1 + assert items[0].model_dump() == test_tag.model_dump() + + def test_get_feature_tags_list_with_unknown_value( + self, + api_client: OverhaveApiClient, + faker: Faker, + ) -> None: + items = api_client.get_feature_tags_list(value=faker.word()) + assert len(items) == 0 diff --git a/tests/integration/client/test_client_test_run.py b/tests/integration/client/test_client_test_run.py new file mode 100644 index 00000000..89515acd --- /dev/null +++ b/tests/integration/client/test_client_test_run.py @@ -0,0 +1,41 @@ +import allure +import pytest +from faker import Faker +from httpx import HTTPStatusError + +from overhave import db +from overhave.storage import TestRunModel, FeatureModel +from overhave.transport.http.api_client.client import OverhaveApiClient + + +@pytest.mark.parametrize("test_user_role", [db.Role.user], indirect=True) +class TestTestRunApiClient: + """Integration tests for Overhave Test Run API Client.""" + + @pytest.mark.parametrize("test_severity", [allure.severity_level.NORMAL], indirect=True) + def test_get_test_run( + self, + api_client: OverhaveApiClient, + test_test_run: TestRunModel, + ) -> None: + item = api_client.get_test_run(test_run_id=test_test_run.id) + assert item.model_dump() == test_test_run.model_dump() + + @pytest.mark.parametrize("test_severity", [allure.severity_level.NORMAL], indirect=True) + def test_get_test_run_with_unknown_id( + self, + api_client: OverhaveApiClient, + test_test_run: TestRunModel, + faker: Faker, + ) -> None: + with pytest.raises(HTTPStatusError): + api_client.get_test_run(test_run_id=faker.random_int()) + + @pytest.mark.parametrize("test_severity", [allure.severity_level.NORMAL], indirect=True) + def test_create_test_run( + self, + api_client: OverhaveApiClient, + test_feature_with_scenario: FeatureModel, + ) -> None: + values = api_client.create_test_run(tag_value=test_feature_with_scenario.feature_tags[0].value) + assert len(values) > 0 diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 687190ba..ef1e9533 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -12,7 +12,7 @@ from overhave import OverhaveEmulationSettings, db, OverhaveApiAuthenticator, OverhaveApiAuthenticatorSettings from overhave import overhave_api -from overhave.db import DraftStatus +from overhave.db import DraftStatus, TestRunStatus, TestReportStatus from overhave.transport.http.base_client import BearerAuth from overhave.storage import ( AuthStorage, @@ -33,7 +33,7 @@ TestRunStorage, TestUserModel, TestUserSpecification, - TestUserStorage, + TestUserStorage, TestRunModel, ) from overhave.utils import get_current_time from tests.db_utils import create_test_session @@ -219,6 +219,15 @@ def test_feature_with_tag(test_feature: FeatureModel, test_tag: TagModel) -> Fea return FeatureModel.model_validate(feature) +@pytest.fixture() +def test_feature_with_scenario(test_feature_with_tag: FeatureModel, faker: Faker) -> FeatureModel: + with create_test_session() as session: + db_scenario = db.Scenario(feature_id=test_feature_with_tag.id, text=faker.word()) + session.add(db_scenario) + session.flush() + return test_feature_with_tag + + @pytest.fixture() def test_features_with_tag(test_features: list[FeatureModel], test_tag: TagModel) -> list[FeatureModel]: features = [] @@ -296,6 +305,21 @@ def test_emulation_run(service_system_user: SystemUserModel, test_emulation: Emu return EmulationRunModel.model_validate(emulation_run) +@pytest.fixture() +def test_test_run(faker: Faker, service_system_user: SystemUserModel, test_scenario: ScenarioModel) -> TestRunModel: + with create_test_session() as session: + test_run = db.TestRun( + scenario_id=test_scenario.id, + name=cast(str, faker.word()), + status=TestRunStatus.STARTED, + report_status=TestReportStatus.EMPTY, + executed_by=service_system_user.login, + ) + session.add(test_run) + session.flush() + return TestRunModel.model_validate(test_run) + + @pytest.fixture(scope="module") def envs_for_mock() -> dict[str, str | None]: return { From 9cb518a9be2180524cc40ac01624d605040b03d8 Mon Sep 17 00:00:00 2001 From: deffer Date: Tue, 2 Jan 2024 04:09:34 +0500 Subject: [PATCH 07/23] test --- tests/integration/client/test_client_feature_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/client/test_client_feature_types.py b/tests/integration/client/test_client_feature_types.py index 3aef77bc..f2d7959a 100644 --- a/tests/integration/client/test_client_feature_types.py +++ b/tests/integration/client/test_client_feature_types.py @@ -9,7 +9,7 @@ class TestFeatureTypesApiClient: """Integration tests for Overhave FeatureTypes API Client.""" - # TODO: этот тест как-то влияет на другой. разобраться почему + # TODO: этот тест как-то влияет на другой. разобраться почему. def test_get_feature_types(self, api_client: OverhaveApiClient, test_feature_type: FeatureTypeModel) -> None: feature_types = api_client.get_feature_types() assert len(feature_types) == 1 From 8ed96c4f1587352c3cf5485f8cb0a702b34fb6a5 Mon Sep 17 00:00:00 2001 From: deffer Date: Tue, 2 Jan 2024 22:42:42 +0500 Subject: [PATCH 08/23] delete print and test file --- overhave/api/views/testrun_views.py | 1 - test.py | 14 -------------- 2 files changed, 15 deletions(-) delete mode 100644 test.py diff --git a/overhave/api/views/testrun_views.py b/overhave/api/views/testrun_views.py index fc3755fd..570c4656 100644 --- a/overhave/api/views/testrun_views.py +++ b/overhave/api/views/testrun_views.py @@ -34,7 +34,6 @@ def run_tests_by_tag_handler( test_run_storage: TestRunStorage = fastapi.Depends(get_test_run_storage), redis_producer: RedisProducer = fastapi.Depends(get_redis_producer), ) -> list[str]: - print('-----------------------') tag_model = tags_item_handler(value=tag_value, feature_tag_storage=tag_storage) features = feature_storage.get_features_by_tag(tag_id=tag_model.id) if not features: diff --git a/test.py b/test.py deleted file mode 100644 index 410c2f60..00000000 --- a/test.py +++ /dev/null @@ -1,14 +0,0 @@ -from pydantic import SecretStr - -from overhave import OverhaveApiAuthenticator, OverhaveApiAuthenticatorSettings -from overhave.storage import AuthStorage -from overhave.transport.http.api_client.client import * - - -if __name__ == '__main__': - auth = OverhaveApiAuthenticator(OverhaveApiAuthenticatorSettings(url='http://localhost:8000'), AuthStorage()) - token = auth.get_bearer_auth('admin', SecretStr('86f2551dd8cb4dc18308916a5a7edc6a')) - settings = OverhaveApiClientSettings(url='http://localhost:8000', auth_token=token.token) - client = OverhaveApiClient(settings=settings) - print(client.get_features_by_tag_id(3)) - print(client.get_features_by_tag_value('chatbot')) From 9663744018adba9b357f12624923f283cd1f88ed Mon Sep 17 00:00:00 2001 From: deffer Date: Tue, 2 Jan 2024 23:06:04 +0500 Subject: [PATCH 09/23] add get emulations run --- overhave/transport/http/api_client/client.py | 12 +++++- overhave/transport/http/api_client/models.py | 37 +++++++++++++++++++ .../client/test_client_emulations.py | 30 +++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tests/integration/client/test_client_emulations.py diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index c48b26e5..2288a1db 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -5,7 +5,7 @@ from overhave.transport.http import BaseHttpClient, BearerAuth from overhave.transport.http.api_client.models import ApiFeatureResponse, ApiFeatureTypeResponse, ApiTagResponse, \ - ApiTestRunResponse + ApiTestRunResponse, ApiEmulationRunResponse from overhave.transport.http.api_client.settings import OverhaveApiClientSettings from overhave.transport.http.base_client import HttpMethod @@ -148,3 +148,13 @@ def create_test_run(self, tag_value: str) -> list[str]: logger.debug("Create test run successfully") return response.json() + + def get_emulation_runs(self, test_user_id: int | None = None): + logger.debug("Stat get list of EmulationRun") + params = {'test_user_id': test_user_id} if test_user_id else {} + response = self._get( + url=httpx.URL(f"{self._settings.url}/emulation/run/list"), + params=params, + ) + logger.debug("Get list of EmulationRun successfully") + return [ApiEmulationRunResponse.model_validate(data) for data in response.json()] diff --git a/overhave/transport/http/api_client/models.py b/overhave/transport/http/api_client/models.py index 4e4584d5..bd63c7bc 100644 --- a/overhave/transport/http/api_client/models.py +++ b/overhave/transport/http/api_client/models.py @@ -1,3 +1,4 @@ +import enum from datetime import datetime from typing import Literal @@ -55,3 +56,39 @@ class ApiTestRunResponse(BaseModel): report: str | None traceback: str | None scenario_id: int + + +class EmulationStatus(enum.StrEnum): + CREATED = "CREATED" + REQUESTED = "REQUESTED" + READY = "READY" + ERROR = "ERROR" + + +class ApiTestUserResponse(BaseModel): + id: int + created_at: datetime + key: str + name: str + created_by: str + specification: dict[str, str | None] + feature_type_id: int + feature_type: ApiFeatureTypeResponse + allow_update: bool + changed_at: datetime + + +class ApiEmulationResponse(BaseModel): + id: int + command: str + test_user: ApiTestUserResponse + + +class ApiEmulationRunResponse(BaseModel): + id: int + emulation_id: int + changed_at: datetime + status: EmulationStatus + port: int | None + initiated_by: str + emulation: ApiEmulationResponse diff --git a/tests/integration/client/test_client_emulations.py b/tests/integration/client/test_client_emulations.py new file mode 100644 index 00000000..892fe96c --- /dev/null +++ b/tests/integration/client/test_client_emulations.py @@ -0,0 +1,30 @@ +import pytest +from faker import Faker +from httpx import HTTPStatusError + +from overhave import db +from overhave.storage import EmulationRunModel, TestUserModel +from overhave.transport.http.api_client.client import OverhaveApiClient + + +@pytest.mark.parametrize("test_user_role", [db.Role.user], indirect=True) +class TestEmulationsApiClient: + """Integration tests for Overhave Emulation API Client.""" + + def test_get_emulation_run_list_no_body(self, api_client: OverhaveApiClient) -> None: + with pytest.raises(HTTPStatusError): + api_client.get_emulation_runs() + + def test_get_emulation_run_list_by_test_user_id_empty(self, api_client: OverhaveApiClient, faker: Faker) -> None: + emulations = api_client.get_emulation_runs(test_user_id=faker.random_int()) + assert len(emulations) == 0 + + def test_get_emulation_run_list_by_test_user_id( + self, + api_client: OverhaveApiClient, + test_testuser: TestUserModel, + test_emulation_run: EmulationRunModel, + ) -> None: + emulations = api_client.get_emulation_runs(test_user_id=test_testuser.id) + assert len(emulations) == 1 + assert emulations[0].model_dump() == test_emulation_run.model_dump() From afedc03c17cdded99a5512b06641fbab86cd06eb Mon Sep 17 00:00:00 2001 From: deffer Date: Tue, 2 Jan 2024 23:43:04 +0500 Subject: [PATCH 10/23] add client for test user --- overhave/transport/http/api_client/client.py | 57 ++++++++- .../client/test_client_testusers.py | 121 ++++++++++++++++++ 2 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 tests/integration/client/test_client_testusers.py diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index 2288a1db..9cda12a6 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -5,7 +5,7 @@ from overhave.transport.http import BaseHttpClient, BearerAuth from overhave.transport.http.api_client.models import ApiFeatureResponse, ApiFeatureTypeResponse, ApiTagResponse, \ - ApiTestRunResponse, ApiEmulationRunResponse + ApiTestRunResponse, ApiEmulationRunResponse, ApiTestUserResponse from overhave.transport.http.api_client.settings import OverhaveApiClientSettings from overhave.transport.http.base_client import HttpMethod @@ -149,8 +149,8 @@ def create_test_run(self, tag_value: str) -> list[str]: return response.json() - def get_emulation_runs(self, test_user_id: int | None = None): - logger.debug("Stat get list of EmulationRun") + def get_emulation_runs(self, test_user_id: int | None = None) -> list[ApiEmulationRunResponse]: + logger.debug("Start get list of EmulationRun") params = {'test_user_id': test_user_id} if test_user_id else {} response = self._get( url=httpx.URL(f"{self._settings.url}/emulation/run/list"), @@ -158,3 +158,54 @@ def get_emulation_runs(self, test_user_id: int | None = None): ) logger.debug("Get list of EmulationRun successfully") return [ApiEmulationRunResponse.model_validate(data) for data in response.json()] + + def get_test_user_by_user_id(self, user_id: int) -> ApiTestUserResponse: + logger.debug(f"Start get test user by user_id: {user_id}") + response = self._get( + url=httpx.URL(f"{self._settings.url}/test_user/"), + params={'user_id': user_id}, + ) + logger.debug("Get test user by user_id successfully") + return ApiTestUserResponse.model_validate(response.json()) + + def get_test_user_by_user_key(self, user_key: str) -> ApiTestUserResponse: + logger.debug(f"Start get test user by user_key: {user_key}") + response = self._get( + url=httpx.URL(f"{self._settings.url}/test_user/"), + params={'user_key': user_key}, + ) + logger.debug("Get test user by user_key successfully") + return ApiTestUserResponse.model_validate(response.json()) + + def get_test_users(self, feature_type: str, allow_update: bool) -> list[ApiTestUserResponse]: + logger.debug(f"Start get test users with feature_type: {feature_type} and allow_update: {allow_update}") + response = self._get( + url=httpx.URL(f"{self._settings.url}/test_user/list"), + params={ + 'feature_type': feature_type, + 'allow_update': allow_update, + } + ) + logger.debug("Get tests users successfully") + return [ApiTestUserResponse.model_validate(data) for data in response.json()] + + def delete_test_user(self, user_id: int) -> None: + logger.debug(f"Start delete user by user_id: {user_id}") + self._delete(url=httpx.URL(f"{self._settings.url}/test_user/{user_id}")) + logger.debug("Delete test user successfully") + + def get_test_user_specification(self, user_id: int) -> dict[str, str | None]: + logger.debug(f"Start get user specification by user_id: {user_id}") + response = self._get( + url=httpx.URL(f"{self._settings.url}/test_user/{user_id}/specification") + ) + logger.debug("Get user specification successfully") + return response.json() + + def update_test_user_specification(self, user_id: int, specification: dict[str, str | None]) -> None: + logger.debug(f"Start update user specification by user_id: {user_id}") + self._put( + url=httpx.URL(f"{self._settings.url}/test_user/{user_id}/specification"), + data=specification, + ) + logger.debug("Update user specification successfully") diff --git a/tests/integration/client/test_client_testusers.py b/tests/integration/client/test_client_testusers.py new file mode 100644 index 00000000..3dfc12ed --- /dev/null +++ b/tests/integration/client/test_client_testusers.py @@ -0,0 +1,121 @@ +import json + +import pytest as pytest +from faker import Faker +from fastapi.testclient import TestClient +from httpx import HTTPStatusError + +from overhave import db +from overhave.storage import TestUserModel, TestUserSpecification +from overhave.transport.http.api_client.client import OverhaveApiClient +from overhave.transport.http.base_client import BearerAuth +from tests.integration.api.conftest import validate_content_null +from tests.objects import LIST_TESTUSER_MODEL_ADAPTER + + +@pytest.mark.parametrize("test_user_role", [db.Role.user], indirect=True) +class TestTestUserApiClient: + """Integration tests for Overhave TestUser API Client.""" + + def test_get_user_by_id_empty( + self, api_client: OverhaveApiClient, faker: Faker, + ) -> None: + with pytest.raises(HTTPStatusError): + api_client.get_test_user_by_user_id(user_id=faker.random_int()) + + def test_get_user_by_id( + self, api_client: OverhaveApiClient, test_testuser: TestUserModel, + ) -> None: + test_user = api_client.get_test_user_by_user_id(user_id=test_testuser.id) + assert test_user.model_dump() == test_testuser.model_dump() + + def test_get_user_by_key_empty( + self, api_client: OverhaveApiClient, faker: Faker, + ) -> None: + with pytest.raises(HTTPStatusError): + api_client.get_test_user_by_user_key(user_key=faker.random_int()) + + def test_get_user_by_key( + self, api_client: OverhaveApiClient, test_testuser: TestUserModel, + ) -> None: + test_user = api_client.get_test_user_by_user_key(user_key=test_testuser.key) + assert test_user.model_dump() == test_testuser.model_dump() + + def test_delete_user_by_id_empty( + self, api_client: OverhaveApiClient, faker: Faker + ) -> None: + with pytest.raises(HTTPStatusError): + api_client.delete_test_user(user_id=faker.random_int()) + + def test_delete_user_by_id( + self, api_client: OverhaveApiClient, test_testuser: TestUserModel + ) -> None: + api_client.delete_test_user(user_id=test_testuser.id) + + @pytest.mark.parametrize("allow_update", [True, False]) + def test_get_test_user_list_feature_type_empty( + self, api_client: OverhaveApiClient, faker: Faker, allow_update: bool + ) -> None: + test_users = api_client.get_test_users( + feature_type=faker.word(), + allow_update=allow_update, + ) + assert len(test_users) == 0 + + def test_get_test_user_list( + self, api_client: OverhaveApiClient, test_testuser: TestUserModel, + ) -> None: + test_users = api_client.get_test_users( + feature_type=test_testuser.feature_type.name, + allow_update=test_testuser.allow_update, + ) + assert len(test_users) == 1 + assert test_users[0].model_dump() == test_testuser.model_dump() + + def test_get_user_spec_empty( + self, api_client: OverhaveApiClient, faker: Faker + ) -> None: + with pytest.raises(HTTPStatusError): + api_client.get_test_user_specification(user_id=faker.random_int()) + + def test_get_user_spec( + self, api_client: OverhaveApiClient, test_testuser: TestUserModel, + ) -> None: + user_spec = api_client.get_test_user_specification(user_id=test_testuser.id) + assert user_spec == test_testuser.specification + + def test_put_user_spec_no_body( + self, api_client: OverhaveApiClient, faker: Faker, + ) -> None: + with pytest.raises(HTTPStatusError): + api_client.update_test_user_specification(user_id=faker.random_int(), specification={}) + + def test_put_user_spec_no_user( + self, + api_client: OverhaveApiClient, + test_new_specification: TestUserSpecification, + faker: Faker, + ) -> None: + with pytest.raises(HTTPStatusError): + api_client.update_test_user_specification(user_id=faker.random_int(), specification=test_new_specification) + + @pytest.mark.parametrize("testuser_allow_update", [False], indirect=True) + def test_put_user_spec_not_allowed( + self, + api_client: OverhaveApiClient, + test_testuser: TestUserModel, + test_new_specification: TestUserSpecification, + ) -> None: + with pytest.raises(HTTPStatusError): + api_client.update_test_user_specification(user_id=test_testuser.id, specification=test_new_specification) + + @pytest.mark.parametrize("testuser_allow_update", [True], indirect=True) + def test_put_user_spec( + self, + api_client: OverhaveApiClient, + test_testuser: TestUserModel, + test_new_specification: TestUserSpecification, + ) -> None: + api_client.update_test_user_specification(user_id=test_testuser.id, specification=test_new_specification) + updated_user_specification = api_client.get_test_user_specification(user_id=test_testuser.id) + assert updated_user_specification == test_new_specification From 11357f387e1d9eacd675032f95791406311eb954 Mon Sep 17 00:00:00 2001 From: deffer Date: Wed, 3 Jan 2024 00:01:27 +0500 Subject: [PATCH 11/23] fixiki --- overhave/transport/http/api_client/client.py | 3 ++- tests/integration/api/conftest.py | 5 ----- .../client/test_client_feature_types.py | 1 - tests/integration/client/test_client_testusers.py | 15 +++++---------- tests/integration/conftest.py | 5 +++++ 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index 9cda12a6..6815e2f9 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -1,3 +1,4 @@ +import json import logging from typing import Any, Mapping @@ -206,6 +207,6 @@ def update_test_user_specification(self, user_id: int, specification: dict[str, logger.debug(f"Start update user specification by user_id: {user_id}") self._put( url=httpx.URL(f"{self._settings.url}/test_user/{user_id}/specification"), - data=specification, + json=json.dumps(specification), ) logger.debug("Update user specification successfully") diff --git a/tests/integration/api/conftest.py b/tests/integration/api/conftest.py index 3e5809fc..4a54cae8 100644 --- a/tests/integration/api/conftest.py +++ b/tests/integration/api/conftest.py @@ -22,11 +22,6 @@ def mock_default_value() -> str: return "" -@pytest.fixture(scope="module") -def test_new_specification() -> TestUserSpecification: - return TestUserSpecification({"new_test": "new_value"}) - - def validate_content_null(response: httpx.Response, statement: bool) -> None: assert (response.content.decode() == "null") is statement diff --git a/tests/integration/client/test_client_feature_types.py b/tests/integration/client/test_client_feature_types.py index f2d7959a..a79fd202 100644 --- a/tests/integration/client/test_client_feature_types.py +++ b/tests/integration/client/test_client_feature_types.py @@ -9,7 +9,6 @@ class TestFeatureTypesApiClient: """Integration tests for Overhave FeatureTypes API Client.""" - # TODO: этот тест как-то влияет на другой. разобраться почему. def test_get_feature_types(self, api_client: OverhaveApiClient, test_feature_type: FeatureTypeModel) -> None: feature_types = api_client.get_feature_types() assert len(feature_types) == 1 diff --git a/tests/integration/client/test_client_testusers.py b/tests/integration/client/test_client_testusers.py index 3dfc12ed..a0ba6359 100644 --- a/tests/integration/client/test_client_testusers.py +++ b/tests/integration/client/test_client_testusers.py @@ -1,16 +1,11 @@ -import json import pytest as pytest from faker import Faker -from fastapi.testclient import TestClient from httpx import HTTPStatusError from overhave import db from overhave.storage import TestUserModel, TestUserSpecification from overhave.transport.http.api_client.client import OverhaveApiClient -from overhave.transport.http.base_client import BearerAuth -from tests.integration.api.conftest import validate_content_null -from tests.objects import LIST_TESTUSER_MODEL_ADAPTER @pytest.mark.parametrize("test_user_role", [db.Role.user], indirect=True) @@ -56,11 +51,11 @@ def test_delete_user_by_id( def test_get_test_user_list_feature_type_empty( self, api_client: OverhaveApiClient, faker: Faker, allow_update: bool ) -> None: - test_users = api_client.get_test_users( - feature_type=faker.word(), - allow_update=allow_update, - ) - assert len(test_users) == 0 + with pytest.raises(HTTPStatusError): + api_client.get_test_users( + feature_type=faker.word(), + allow_update=allow_update, + ) def test_get_test_user_list( self, api_client: OverhaveApiClient, test_testuser: TestUserModel, diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index ef1e9533..5502c390 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -379,3 +379,8 @@ def test_api_bearer_auth( service_system_user: SystemUserModel, api_authenticator: OverhaveApiAuthenticator ) -> BearerAuth: return api_authenticator.get_bearer_auth(username=service_system_user.login, password=service_system_user.password) + + +@pytest.fixture(scope="module") +def test_new_specification() -> TestUserSpecification: + return TestUserSpecification({"new_test": "new_value"}) From 75e76a7eae20a47fdcd99dee101a50ed330ad0e2 Mon Sep 17 00:00:00 2001 From: deffer Date: Wed, 3 Jan 2024 00:03:24 +0500 Subject: [PATCH 12/23] fixiki --- overhave/transport/http/api_client/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index 6815e2f9..bfe17f68 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -207,6 +207,6 @@ def update_test_user_specification(self, user_id: int, specification: dict[str, logger.debug(f"Start update user specification by user_id: {user_id}") self._put( url=httpx.URL(f"{self._settings.url}/test_user/{user_id}/specification"), - json=json.dumps(specification), + data=json.dumps(specification), ) logger.debug("Update user specification successfully") From a86d4fcd921cb079c3127ee5efc64e4a6bfe11fe Mon Sep 17 00:00:00 2001 From: deffer Date: Wed, 3 Jan 2024 00:23:08 +0500 Subject: [PATCH 13/23] lint --- overhave/transport/http/api_client/client.py | 45 +++++++++++-------- overhave/transport/http/api_client/models.py | 20 +++++++-- tests/integration/api/conftest.py | 2 - .../client/test_client_emulations.py | 5 --- .../client/test_client_test_run.py | 2 +- tests/integration/conftest.py | 20 ++++++--- 6 files changed, 57 insertions(+), 37 deletions(-) diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index bfe17f68..36d46db8 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -5,8 +5,14 @@ import httpx from overhave.transport.http import BaseHttpClient, BearerAuth -from overhave.transport.http.api_client.models import ApiFeatureResponse, ApiFeatureTypeResponse, ApiTagResponse, \ - ApiTestRunResponse, ApiEmulationRunResponse, ApiTestUserResponse +from overhave.transport.http.api_client.models import ( + ApiEmulationRunResponse, + ApiFeatureResponse, + ApiFeatureTypeResponse, + ApiTagResponse, + ApiTestRunResponse, + ApiTestUserResponse, +) from overhave.transport.http.api_client.settings import OverhaveApiClientSettings from overhave.transport.http.base_client import HttpMethod @@ -84,7 +90,7 @@ def _delete( ) def get_feature_tags_item(self, value: str) -> ApiTagResponse: - logger.debug(f"Start get feature tags item with [value: {value}]") + logger.debug("Start get feature tags item with [value: %s]", value) response = self._get( url=httpx.URL(f"{self._settings.url}/feature/tags/item"), params={"value": value} @@ -94,7 +100,7 @@ def get_feature_tags_item(self, value: str) -> ApiTagResponse: return ApiTagResponse.model_validate(response.json()) def get_feature_tags_list(self, value: str) -> list[ApiTagResponse]: - logger.debug(f"Start get feature tags list with [value: {value}]") + logger.debug("Start get feature tags list with [value: %s]", value) response = self._get( url=httpx.URL(f"{self._settings.url}/feature/tags/list"), params={"value": value} @@ -104,14 +110,14 @@ def get_feature_tags_list(self, value: str) -> list[ApiTagResponse]: return [ApiTagResponse.model_validate(data) for data in response.json()] def get_feature_types(self) -> list[ApiFeatureTypeResponse]: - logger.debug(f"Start get feature types list") + logger.debug("Start get feature types list") response = self._get(url=httpx.URL(f"{self._settings.url}/feature/types/list")) logger.debug("Get feature types successfully") return [ApiFeatureTypeResponse.model_validate(data) for data in response.json()] def get_features_by_tag_id(self, tag_id: int) -> list[ApiFeatureResponse]: - logger.debug(f"Start get feature with [tag_id: {tag_id}]") + logger.debug("Start get feature with [tag_id: %s]", tag_id) response = self._get( url=httpx.URL(f"{self._settings.url}/feature/"), params={"tag_id": tag_id}, @@ -121,7 +127,7 @@ def get_features_by_tag_id(self, tag_id: int) -> list[ApiFeatureResponse]: return [ApiFeatureResponse.model_validate(data) for data in response.json()] def get_features_by_tag_value(self, tag_value: str) -> list[ApiFeatureResponse]: - logger.debug(f"Start get feature with [tag_value: {tag_value}]") + logger.debug("Start get feature with [tag_value: %s]", tag_value) response = self._get( url=httpx.URL(f"{self._settings.url}/feature/"), params={"tag_value": tag_value}, @@ -131,7 +137,7 @@ def get_features_by_tag_value(self, tag_value: str) -> list[ApiFeatureResponse]: return [ApiFeatureResponse.model_validate(data) for data in response.json()] def get_test_run(self, test_run_id: int) -> ApiTestRunResponse: - logger.debug(f"Start get test run with [test_run_id: {test_run_id}]") + logger.debug("Start get test run with [test_run_id: %s]", test_run_id) response = self._get( url=httpx.URL(f"{self._settings.url}/test_run"), params={"test_run_id": test_run_id}, @@ -141,7 +147,7 @@ def get_test_run(self, test_run_id: int) -> ApiTestRunResponse: return ApiTestRunResponse.model_validate(response.json()) def create_test_run(self, tag_value: str) -> list[str]: - logger.debug(f"Start create test run with [tag_value: {tag_value}]") + logger.debug("Start create test run with [tag_value: %s]", tag_value) response = self._post( url=httpx.URL(f"{self._settings.url}/test_run/create/"), params={"tag_value": tag_value}, @@ -150,18 +156,17 @@ def create_test_run(self, tag_value: str) -> list[str]: return response.json() - def get_emulation_runs(self, test_user_id: int | None = None) -> list[ApiEmulationRunResponse]: + def get_emulation_runs(self, test_user_id: int) -> list[ApiEmulationRunResponse]: logger.debug("Start get list of EmulationRun") - params = {'test_user_id': test_user_id} if test_user_id else {} response = self._get( url=httpx.URL(f"{self._settings.url}/emulation/run/list"), - params=params, + params={'test_user_id': test_user_id}, ) logger.debug("Get list of EmulationRun successfully") return [ApiEmulationRunResponse.model_validate(data) for data in response.json()] def get_test_user_by_user_id(self, user_id: int) -> ApiTestUserResponse: - logger.debug(f"Start get test user by user_id: {user_id}") + logger.debug("Start get test user by user_id: %s", user_id) response = self._get( url=httpx.URL(f"{self._settings.url}/test_user/"), params={'user_id': user_id}, @@ -170,7 +175,7 @@ def get_test_user_by_user_id(self, user_id: int) -> ApiTestUserResponse: return ApiTestUserResponse.model_validate(response.json()) def get_test_user_by_user_key(self, user_key: str) -> ApiTestUserResponse: - logger.debug(f"Start get test user by user_key: {user_key}") + logger.debug("Start get test user by user_key: %s", user_key) response = self._get( url=httpx.URL(f"{self._settings.url}/test_user/"), params={'user_key': user_key}, @@ -179,9 +184,11 @@ def get_test_user_by_user_key(self, user_key: str) -> ApiTestUserResponse: return ApiTestUserResponse.model_validate(response.json()) def get_test_users(self, feature_type: str, allow_update: bool) -> list[ApiTestUserResponse]: - logger.debug(f"Start get test users with feature_type: {feature_type} and allow_update: {allow_update}") + logger.debug( + "Start get test users with feature_type: %s and allow_update: %s", feature_type, allow_update + ) response = self._get( - url=httpx.URL(f"{self._settings.url}/test_user/list"), + url=httpx.URL("{self._settings.url}/test_user/list"), params={ 'feature_type': feature_type, 'allow_update': allow_update, @@ -191,12 +198,12 @@ def get_test_users(self, feature_type: str, allow_update: bool) -> list[ApiTestU return [ApiTestUserResponse.model_validate(data) for data in response.json()] def delete_test_user(self, user_id: int) -> None: - logger.debug(f"Start delete user by user_id: {user_id}") + logger.debug("Start delete user by user_id: %s", user_id) self._delete(url=httpx.URL(f"{self._settings.url}/test_user/{user_id}")) logger.debug("Delete test user successfully") def get_test_user_specification(self, user_id: int) -> dict[str, str | None]: - logger.debug(f"Start get user specification by user_id: {user_id}") + logger.debug("Start get user specification by user_id: %s", user_id) response = self._get( url=httpx.URL(f"{self._settings.url}/test_user/{user_id}/specification") ) @@ -204,7 +211,7 @@ def get_test_user_specification(self, user_id: int) -> dict[str, str | None]: return response.json() def update_test_user_specification(self, user_id: int, specification: dict[str, str | None]) -> None: - logger.debug(f"Start update user specification by user_id: {user_id}") + logger.debug("Start update user specification by user_id: %s", user_id) self._put( url=httpx.URL(f"{self._settings.url}/test_user/{user_id}/specification"), data=json.dumps(specification), diff --git a/overhave/transport/http/api_client/models.py b/overhave/transport/http/api_client/models.py index bd63c7bc..d9b113dd 100644 --- a/overhave/transport/http/api_client/models.py +++ b/overhave/transport/http/api_client/models.py @@ -3,7 +3,6 @@ from typing import Literal import allure - from pydantic import BaseModel @@ -17,17 +16,22 @@ class TokenRequestData(BaseModel): class ApiTagResponse(BaseModel): """Model for Tag response data.""" + id: int value: str created_by: str class ApiFeatureTypeResponse(BaseModel): + """Model for Feature Type response data.""" + id: int name: str class ApiFeatureResponse(BaseModel): + """Model for Feature response data.""" + id: int created_at: datetime name: str @@ -45,6 +49,8 @@ class ApiFeatureResponse(BaseModel): class ApiTestRunResponse(BaseModel): + """Model for TestRun response data.""" + id: int created_at: datetime name: str @@ -58,7 +64,9 @@ class ApiTestRunResponse(BaseModel): scenario_id: int -class EmulationStatus(enum.StrEnum): +class ApiEmulationStatus(enum.StrEnum): + """Enum for Emulation Status.""" + CREATED = "CREATED" REQUESTED = "REQUESTED" READY = "READY" @@ -66,6 +74,8 @@ class EmulationStatus(enum.StrEnum): class ApiTestUserResponse(BaseModel): + """Model for TestUser response data.""" + id: int created_at: datetime key: str @@ -79,16 +89,20 @@ class ApiTestUserResponse(BaseModel): class ApiEmulationResponse(BaseModel): + """Model for Emulation response data.""" + id: int command: str test_user: ApiTestUserResponse class ApiEmulationRunResponse(BaseModel): + """Model for EmulationRun response data.""" + id: int emulation_id: int changed_at: datetime - status: EmulationStatus + status: ApiEmulationStatus port: int | None initiated_by: str emulation: ApiEmulationResponse diff --git a/tests/integration/api/conftest.py b/tests/integration/api/conftest.py index 4a54cae8..4bd7e22a 100644 --- a/tests/integration/api/conftest.py +++ b/tests/integration/api/conftest.py @@ -4,8 +4,6 @@ import pytest from faker import Faker -from overhave.storage import TestUserSpecification - @pytest.fixture(scope="module") def envs_for_mock() -> dict[str, str | None]: diff --git a/tests/integration/client/test_client_emulations.py b/tests/integration/client/test_client_emulations.py index 892fe96c..6e14b837 100644 --- a/tests/integration/client/test_client_emulations.py +++ b/tests/integration/client/test_client_emulations.py @@ -1,6 +1,5 @@ import pytest from faker import Faker -from httpx import HTTPStatusError from overhave import db from overhave.storage import EmulationRunModel, TestUserModel @@ -11,10 +10,6 @@ class TestEmulationsApiClient: """Integration tests for Overhave Emulation API Client.""" - def test_get_emulation_run_list_no_body(self, api_client: OverhaveApiClient) -> None: - with pytest.raises(HTTPStatusError): - api_client.get_emulation_runs() - def test_get_emulation_run_list_by_test_user_id_empty(self, api_client: OverhaveApiClient, faker: Faker) -> None: emulations = api_client.get_emulation_runs(test_user_id=faker.random_int()) assert len(emulations) == 0 diff --git a/tests/integration/client/test_client_test_run.py b/tests/integration/client/test_client_test_run.py index 89515acd..ce6cf31f 100644 --- a/tests/integration/client/test_client_test_run.py +++ b/tests/integration/client/test_client_test_run.py @@ -4,7 +4,7 @@ from httpx import HTTPStatusError from overhave import db -from overhave.storage import TestRunModel, FeatureModel +from overhave.storage import FeatureModel, TestRunModel from overhave.transport.http.api_client.client import OverhaveApiClient diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 5502c390..bd88211d 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -1,19 +1,23 @@ from datetime import datetime -from typing import cast, Iterator +from typing import Iterator, cast from unittest import mock from uuid import uuid1 import allure -import pytest import httpx +import pytest from _pytest.fixtures import FixtureRequest from faker import Faker from fastapi.testclient import TestClient -from overhave import OverhaveEmulationSettings, db, OverhaveApiAuthenticator, OverhaveApiAuthenticatorSettings -from overhave import overhave_api -from overhave.db import DraftStatus, TestRunStatus, TestReportStatus -from overhave.transport.http.base_client import BearerAuth +from overhave import ( + OverhaveApiAuthenticator, + OverhaveApiAuthenticatorSettings, + OverhaveEmulationSettings, + db, + overhave_api, +) +from overhave.db import DraftStatus, TestReportStatus, TestRunStatus from overhave.storage import ( AuthStorage, DraftModel, @@ -30,11 +34,13 @@ SystemUserModel, SystemUserStorage, TagModel, + TestRunModel, TestRunStorage, TestUserModel, TestUserSpecification, - TestUserStorage, TestRunModel, + TestUserStorage, ) +from overhave.transport.http.base_client import BearerAuth from overhave.utils import get_current_time from tests.db_utils import create_test_session From c1aa51b40acb5e2c0d6960f6b5c4fbbe368b23eb Mon Sep 17 00:00:00 2001 From: deffer Date: Wed, 3 Jan 2024 00:25:32 +0500 Subject: [PATCH 14/23] fixiki --- overhave/transport/http/api_client/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index 36d46db8..1d2267f5 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -188,7 +188,7 @@ def get_test_users(self, feature_type: str, allow_update: bool) -> list[ApiTestU "Start get test users with feature_type: %s and allow_update: %s", feature_type, allow_update ) response = self._get( - url=httpx.URL("{self._settings.url}/test_user/list"), + url=httpx.URL(f"{self._settings.url}/test_user/list"), params={ 'feature_type': feature_type, 'allow_update': allow_update, From ef3357266715c6f230b9ef0fa508b8e7119f772c Mon Sep 17 00:00:00 2001 From: egregiouss Date: Tue, 16 Jan 2024 22:46:34 +0500 Subject: [PATCH 15/23] fixiki --- overhave/transport/http/api_client/client.py | 175 +++++++----------- .../transport/http/api_client/settings.py | 57 +++++- tests/integration/client/conftest.py | 2 +- .../client/test_client_emulations.py | 9 +- .../client/test_client_feature_tags.py | 20 +- .../client/test_client_feature_types.py | 4 +- .../client/test_client_features.py | 8 +- .../client/test_client_test_run.py | 26 +-- .../client/test_client_testusers.py | 87 +++++---- tests/integration/transport/redis/conftest.py | 0 10 files changed, 210 insertions(+), 178 deletions(-) mode change 100755 => 100644 tests/integration/transport/redis/conftest.py diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index 1d2267f5..44c46ca2 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -1,6 +1,6 @@ import json import logging -from typing import Any, Mapping +from typing import Any, Mapping, cast import httpx @@ -25,85 +25,26 @@ class OverhaveApiClient(BaseHttpClient[OverhaveApiClientSettings]): def __init__(self, settings: OverhaveApiClientSettings): super().__init__(settings=settings) - def _get( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - raise_for_status: bool = True, - ): - return self._make_request( + def get_feature_tags_item(self, value: str) -> ApiTagResponse: + logger.debug("Start get feature tags item with [value: %s]", value) + response = self._make_request( method=HttpMethod.GET, - url=url, - params=params, - raise_for_status=raise_for_status, - auth=BearerAuth(self._settings.auth_token), - ) - - def _post( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - json: dict[str, Any] | None = None, - data: str | bytes | Mapping[Any, Any] | None = None, - raise_for_status: bool = True, - ): - return self._make_request( - method=HttpMethod.POST, - url=url, - params=params, - json=json, - data=data, - raise_for_status=raise_for_status, - auth=BearerAuth(self._settings.auth_token), - ) - - def _put( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - json: dict[str, Any] | None = None, - data: str | bytes | Mapping[Any, Any] | None = None, - raise_for_status: bool = True, - ): - return self._make_request( - method=HttpMethod.PUT, - url=url, - params=params, - json=json, - data=data, - raise_for_status=raise_for_status, - auth=BearerAuth(self._settings.auth_token), - ) - - def _delete( - self, - url: httpx.URL, - params: dict[str, Any] | None = None, - raise_for_status: bool = True, - ): - return self._make_request( - method=HttpMethod.DELETE, - url=url, - params=params, - raise_for_status=raise_for_status, + url=self._settings.get_feature_tags_item_url, + params={"value": value}, auth=BearerAuth(self._settings.auth_token), ) - def get_feature_tags_item(self, value: str) -> ApiTagResponse: - logger.debug("Start get feature tags item with [value: %s]", value) - response = self._get( - url=httpx.URL(f"{self._settings.url}/feature/tags/item"), - params={"value": value} - ) logger.debug("Get tags item successfully") - return ApiTagResponse.model_validate(response.json()) + return cast("ApiTagResponse", self._parse_or_raise(response, ApiTagResponse)) def get_feature_tags_list(self, value: str) -> list[ApiTagResponse]: logger.debug("Start get feature tags list with [value: %s]", value) - response = self._get( - url=httpx.URL(f"{self._settings.url}/feature/tags/list"), - params={"value": value} + response = self._make_request( + method=HttpMethod.GET, + url=self._settings.get_feature_tags_list_url, + params={"value": value}, + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Get tags list successfully") @@ -111,16 +52,22 @@ def get_feature_tags_list(self, value: str) -> list[ApiTagResponse]: def get_feature_types(self) -> list[ApiFeatureTypeResponse]: logger.debug("Start get feature types list") - response = self._get(url=httpx.URL(f"{self._settings.url}/feature/types/list")) + response = self._make_request( + method=HttpMethod.GET, + url=self._settings.get_feature_types_list_url, + auth=BearerAuth(self._settings.auth_token), + ) logger.debug("Get feature types successfully") return [ApiFeatureTypeResponse.model_validate(data) for data in response.json()] def get_features_by_tag_id(self, tag_id: int) -> list[ApiFeatureResponse]: logger.debug("Start get feature with [tag_id: %s]", tag_id) - response = self._get( - url=httpx.URL(f"{self._settings.url}/feature/"), + response = self._make_request( + method=HttpMethod.GET, + url=self._settings.get_feature_url, params={"tag_id": tag_id}, + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Get feature successfully") @@ -128,9 +75,11 @@ def get_features_by_tag_id(self, tag_id: int) -> list[ApiFeatureResponse]: def get_features_by_tag_value(self, tag_value: str) -> list[ApiFeatureResponse]: logger.debug("Start get feature with [tag_value: %s]", tag_value) - response = self._get( - url=httpx.URL(f"{self._settings.url}/feature/"), + response = self._make_request( + method=HttpMethod.GET, + url=self._settings.get_feature_url, params={"tag_value": tag_value}, + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Get feature successfully") @@ -138,19 +87,23 @@ def get_features_by_tag_value(self, tag_value: str) -> list[ApiFeatureResponse]: def get_test_run(self, test_run_id: int) -> ApiTestRunResponse: logger.debug("Start get test run with [test_run_id: %s]", test_run_id) - response = self._get( - url=httpx.URL(f"{self._settings.url}/test_run"), + response = self._make_request( + method=HttpMethod.GET, + url=self._settings.get_test_run_url, params={"test_run_id": test_run_id}, + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Get test run successfully") - return ApiTestRunResponse.model_validate(response.json()) + return cast("ApiTestRunResponse", self._parse_or_raise(response, ApiTestRunResponse)) def create_test_run(self, tag_value: str) -> list[str]: logger.debug("Start create test run with [tag_value: %s]", tag_value) - response = self._post( - url=httpx.URL(f"{self._settings.url}/test_run/create/"), + response = self._make_request( + method=HttpMethod.POST, + url=self._settings.get_test_run_create_url, params={"tag_value": tag_value}, + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Create test run successfully") @@ -158,62 +111,76 @@ def create_test_run(self, tag_value: str) -> list[str]: def get_emulation_runs(self, test_user_id: int) -> list[ApiEmulationRunResponse]: logger.debug("Start get list of EmulationRun") - response = self._get( - url=httpx.URL(f"{self._settings.url}/emulation/run/list"), - params={'test_user_id': test_user_id}, + response = self._make_request( + method=HttpMethod.GET, + url=self._settings.get_emulation_run_list_url, + params={"test_user_id": test_user_id}, + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Get list of EmulationRun successfully") return [ApiEmulationRunResponse.model_validate(data) for data in response.json()] def get_test_user_by_user_id(self, user_id: int) -> ApiTestUserResponse: logger.debug("Start get test user by user_id: %s", user_id) - response = self._get( - url=httpx.URL(f"{self._settings.url}/test_user/"), - params={'user_id': user_id}, + response = self._make_request( + method=HttpMethod.GET, + url=self._settings.test_user_path, + params={"user_id": user_id}, + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Get test user by user_id successfully") - return ApiTestUserResponse.model_validate(response.json()) + return cast("ApiTestUserResponse", self._parse_or_raise(response, ApiTestUserResponse)) def get_test_user_by_user_key(self, user_key: str) -> ApiTestUserResponse: logger.debug("Start get test user by user_key: %s", user_key) - response = self._get( - url=httpx.URL(f"{self._settings.url}/test_user/"), - params={'user_key': user_key}, + response = self._make_request( + method=HttpMethod.GET, + url=self._settings.test_user_path, + params={"user_key": user_key}, + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Get test user by user_key successfully") return ApiTestUserResponse.model_validate(response.json()) def get_test_users(self, feature_type: str, allow_update: bool) -> list[ApiTestUserResponse]: - logger.debug( - "Start get test users with feature_type: %s and allow_update: %s", feature_type, allow_update - ) - response = self._get( - url=httpx.URL(f"{self._settings.url}/test_user/list"), + logger.debug("Start get test users with feature_type: %s and allow_update: %s", feature_type, allow_update) + response = self._make_request( + method=HttpMethod.GET, + url=self._settings.test_user_list_path, params={ - 'feature_type': feature_type, - 'allow_update': allow_update, - } + "feature_type": feature_type, + "allow_update": allow_update, + }, + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Get tests users successfully") return [ApiTestUserResponse.model_validate(data) for data in response.json()] def delete_test_user(self, user_id: int) -> None: logger.debug("Start delete user by user_id: %s", user_id) - self._delete(url=httpx.URL(f"{self._settings.url}/test_user/{user_id}")) + self._make_request( + method=HttpMethod.DELETE, + url=self._settings.get_test_user_id_url(user_id), + auth=BearerAuth(self._settings.auth_token), + ) logger.debug("Delete test user successfully") def get_test_user_specification(self, user_id: int) -> dict[str, str | None]: logger.debug("Start get user specification by user_id: %s", user_id) - response = self._get( - url=httpx.URL(f"{self._settings.url}/test_user/{user_id}/specification") + response = self._make_request( + method=HttpMethod.GET, + url=self._settings.get_test_user_id_spec_url(user_id), + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Get user specification successfully") return response.json() def update_test_user_specification(self, user_id: int, specification: dict[str, str | None]) -> None: logger.debug("Start update user specification by user_id: %s", user_id) - self._put( - url=httpx.URL(f"{self._settings.url}/test_user/{user_id}/specification"), + self._make_request( + method=HttpMethod.PUT, + url=self._settings.get_test_user_id_spec_url(user_id), data=json.dumps(specification), + auth=BearerAuth(self._settings.auth_token), ) logger.debug("Update user specification successfully") diff --git a/overhave/transport/http/api_client/settings.py b/overhave/transport/http/api_client/settings.py index 4534d198..e50221f5 100644 --- a/overhave/transport/http/api_client/settings.py +++ b/overhave/transport/http/api_client/settings.py @@ -1,4 +1,5 @@ import httpx +from pydantic import StrictStr from overhave.base_settings import OVERHAVE_ENV_PREFIX from overhave.transport.http.base_client import BaseHttpClientSettings @@ -18,9 +19,63 @@ def get_auth_token_url(self) -> httpx.URL: class OverhaveApiClientSettings(BaseHttpClientSettings): - """settings.""" + """Settings for :class:`OverhaveApiClient`.""" auth_token: str + feature_path: StrictStr = StrictStr("feature/") + feature_tags_item_path: StrictStr = StrictStr("feature/tags/item") + feature_tags_list_path: StrictStr = StrictStr("feature/tags/list") + feature_types_list_path: StrictStr = StrictStr("feature/types/list") + + test_run_path: StrictStr = StrictStr("test_run") + test_run_create_path: StrictStr = StrictStr("test_run/create/") + + emulation_run_list_path: StrictStr = StrictStr("emulation/run/list") + + test_user_path: StrictStr = StrictStr("test_user/") + test_user_list_path: StrictStr = StrictStr("test_user/list") + + @property + def get_feature_url(self) -> httpx.URL: + return httpx.URL(f"{self.url}/{self.feature_path}") + + @property + def get_feature_tags_item_url(self) -> httpx.URL: + return httpx.URL(f"{self.url}/{self.feature_tags_item_path}") + + @property + def get_feature_tags_list_url(self) -> httpx.URL: + return httpx.URL(f"{self.url}/{self.feature_tags_list_path}") + + @property + def get_feature_types_list_url(self) -> httpx.URL: + return httpx.URL(f"{self.url}/{self.feature_types_list_path}") + + @property + def get_test_run_url(self) -> httpx.URL: + return httpx.URL(f"{self.url}/{self.test_run_path}") + + @property + def get_test_run_create_url(self) -> httpx.URL: + return httpx.URL(f"{self.url}/{self.test_run_create_path}") + + @property + def get_emulation_run_list_url(self) -> httpx.URL: + return httpx.URL(f"{self.url}/{self.emulation_run_list_path}") + + @property + def get_test_user_url(self) -> httpx.URL: + return httpx.URL(f"{self.url}/{self.test_user}") + + @property + def get_test_user_list_url(self) -> httpx.URL: + return httpx.URL(f"{self.url}/{self.test_user_list_path}") + + def get_test_user_id_url(self, user_id: int) -> httpx.URL: + return httpx.URL(f"{self.url}/test_user/{user_id}") + + def get_test_user_id_spec_url(self, user_id: int) -> httpx.URL: + return httpx.URL(f"{self.url}/test_user/{user_id}/specification") class Config: env_prefix = "OVERHAVE_API_CLIENT" diff --git a/tests/integration/client/conftest.py b/tests/integration/client/conftest.py index 13bef79f..38b21c9d 100644 --- a/tests/integration/client/conftest.py +++ b/tests/integration/client/conftest.py @@ -28,7 +28,7 @@ def overhave_api_client_settings( @pytest.fixture() -def api_client( +def overhave_api_client( mock_envs, test_api_client: TestClient, overhave_api_client_settings: OverhaveApiClientSettings ) -> Iterator[OverhaveApiClient]: with mock.patch.object(httpx, "request", new_callable=lambda: test_api_client.request): diff --git a/tests/integration/client/test_client_emulations.py b/tests/integration/client/test_client_emulations.py index 6e14b837..b39f9090 100644 --- a/tests/integration/client/test_client_emulations.py +++ b/tests/integration/client/test_client_emulations.py @@ -3,23 +3,22 @@ from overhave import db from overhave.storage import EmulationRunModel, TestUserModel -from overhave.transport.http.api_client.client import OverhaveApiClient @pytest.mark.parametrize("test_user_role", [db.Role.user], indirect=True) class TestEmulationsApiClient: """Integration tests for Overhave Emulation API Client.""" - def test_get_emulation_run_list_by_test_user_id_empty(self, api_client: OverhaveApiClient, faker: Faker) -> None: - emulations = api_client.get_emulation_runs(test_user_id=faker.random_int()) + def test_get_emulation_run_list_by_test_user_id_empty(self, overhave_api_client, faker: Faker) -> None: + emulations = overhave_api_client.get_emulation_runs(test_user_id=faker.random_int()) assert len(emulations) == 0 def test_get_emulation_run_list_by_test_user_id( self, - api_client: OverhaveApiClient, + overhave_api_client, test_testuser: TestUserModel, test_emulation_run: EmulationRunModel, ) -> None: - emulations = api_client.get_emulation_runs(test_user_id=test_testuser.id) + emulations = overhave_api_client.get_emulation_runs(test_user_id=test_testuser.id) assert len(emulations) == 1 assert emulations[0].model_dump() == test_emulation_run.model_dump() diff --git a/tests/integration/client/test_client_feature_tags.py b/tests/integration/client/test_client_feature_tags.py index e48b0085..a7199d2a 100644 --- a/tests/integration/client/test_client_feature_tags.py +++ b/tests/integration/client/test_client_feature_tags.py @@ -13,33 +13,33 @@ class TestFeatureTagsApiClient: def test_get_feature_tags_item( self, - api_client: OverhaveApiClient, + overhave_api_client, test_tag: TagModel, ) -> None: - item = api_client.get_feature_tags_item(value=test_tag.value) + item = overhave_api_client.get_feature_tags_item(value=test_tag.value) assert item.model_dump() == test_tag.model_dump() def test_get_feature_tags_with_unknown_value( self, - api_client: OverhaveApiClient, + overhave_api_client, faker: Faker, ) -> None: with pytest.raises(HTTPStatusError): - api_client.get_feature_tags_item(value=faker.word()) + overhave_api_client.get_feature_tags_item(value=faker.word()) def test_get_feature_tags_list( self, - api_client: OverhaveApiClient, + overhave_api_client, test_tag: TagModel, ) -> None: - items = api_client.get_feature_tags_list(value=test_tag.value) + items = overhave_api_client.get_feature_tags_list(value=test_tag.value) assert len(items) >= 1 assert items[0].model_dump() == test_tag.model_dump() def test_get_feature_tags_list_with_unknown_value( - self, - api_client: OverhaveApiClient, - faker: Faker, + self, + overhave_api_client, + faker: Faker, ) -> None: - items = api_client.get_feature_tags_list(value=faker.word()) + items = overhave_api_client.get_feature_tags_list(value=faker.word()) assert len(items) == 0 diff --git a/tests/integration/client/test_client_feature_types.py b/tests/integration/client/test_client_feature_types.py index a79fd202..d9ba39b1 100644 --- a/tests/integration/client/test_client_feature_types.py +++ b/tests/integration/client/test_client_feature_types.py @@ -9,7 +9,7 @@ class TestFeatureTypesApiClient: """Integration tests for Overhave FeatureTypes API Client.""" - def test_get_feature_types(self, api_client: OverhaveApiClient, test_feature_type: FeatureTypeModel) -> None: - feature_types = api_client.get_feature_types() + def test_get_feature_types(self, overhave_api_client, test_feature_type: FeatureTypeModel) -> None: + feature_types = overhave_api_client.get_feature_types() assert len(feature_types) == 1 assert feature_types[0].model_dump() == test_feature_type.model_dump() diff --git a/tests/integration/client/test_client_features.py b/tests/integration/client/test_client_features.py index 727fc7ff..f8494d97 100644 --- a/tests/integration/client/test_client_features.py +++ b/tests/integration/client/test_client_features.py @@ -13,21 +13,21 @@ class TestFeatureApiClient: @pytest.mark.parametrize("test_severity", [allure.severity_level.NORMAL], indirect=True) def test_get_feature_by_tag_id( self, - api_client: OverhaveApiClient, + overhave_api_client: OverhaveApiClient, test_tag: TagModel, test_feature_with_tag: FeatureModel, ) -> None: - features = api_client.get_features_by_tag_id(tag_id=test_tag.id) + features = overhave_api_client.get_features_by_tag_id(tag_id=test_tag.id) assert len(features) == 1 assert features[0].model_dump() == test_feature_with_tag.model_dump() @pytest.mark.parametrize("test_severity", [allure.severity_level.NORMAL], indirect=True) def test_get_feature_by_tag_value( self, - api_client: OverhaveApiClient, + overhave_api_client: OverhaveApiClient, test_tag: TagModel, test_feature_with_tag: FeatureModel, ) -> None: - features = api_client.get_features_by_tag_value(tag_value=test_tag.value) + features = overhave_api_client.get_features_by_tag_value(tag_value=test_tag.value) assert len(features) == 1 assert features[0].model_dump() == test_feature_with_tag.model_dump() diff --git a/tests/integration/client/test_client_test_run.py b/tests/integration/client/test_client_test_run.py index ce6cf31f..c0e5dba0 100644 --- a/tests/integration/client/test_client_test_run.py +++ b/tests/integration/client/test_client_test_run.py @@ -14,28 +14,28 @@ class TestTestRunApiClient: @pytest.mark.parametrize("test_severity", [allure.severity_level.NORMAL], indirect=True) def test_get_test_run( - self, - api_client: OverhaveApiClient, - test_test_run: TestRunModel, + self, + overhave_api_client, + test_test_run: TestRunModel, ) -> None: - item = api_client.get_test_run(test_run_id=test_test_run.id) + item = overhave_api_client.get_test_run(test_run_id=test_test_run.id) assert item.model_dump() == test_test_run.model_dump() @pytest.mark.parametrize("test_severity", [allure.severity_level.NORMAL], indirect=True) def test_get_test_run_with_unknown_id( - self, - api_client: OverhaveApiClient, - test_test_run: TestRunModel, - faker: Faker, + self, + overhave_api_client, + test_test_run: TestRunModel, + faker: Faker, ) -> None: with pytest.raises(HTTPStatusError): - api_client.get_test_run(test_run_id=faker.random_int()) + overhave_api_client.get_test_run(test_run_id=faker.random_int()) @pytest.mark.parametrize("test_severity", [allure.severity_level.NORMAL], indirect=True) def test_create_test_run( - self, - api_client: OverhaveApiClient, - test_feature_with_scenario: FeatureModel, + self, + overhave_api_client, + test_feature_with_scenario: FeatureModel, ) -> None: - values = api_client.create_test_run(tag_value=test_feature_with_scenario.feature_tags[0].value) + values = overhave_api_client.create_test_run(tag_value=test_feature_with_scenario.feature_tags[0].value) assert len(values) > 0 diff --git a/tests/integration/client/test_client_testusers.py b/tests/integration/client/test_client_testusers.py index a0ba6359..1996da8c 100644 --- a/tests/integration/client/test_client_testusers.py +++ b/tests/integration/client/test_client_testusers.py @@ -1,4 +1,3 @@ - import pytest as pytest from faker import Faker from httpx import HTTPStatusError @@ -13,104 +12,116 @@ class TestTestUserApiClient: """Integration tests for Overhave TestUser API Client.""" def test_get_user_by_id_empty( - self, api_client: OverhaveApiClient, faker: Faker, + self, + overhave_api_client, + faker: Faker, ) -> None: with pytest.raises(HTTPStatusError): - api_client.get_test_user_by_user_id(user_id=faker.random_int()) + overhave_api_client.get_test_user_by_user_id(user_id=faker.random_int()) def test_get_user_by_id( - self, api_client: OverhaveApiClient, test_testuser: TestUserModel, + self, + overhave_api_client, + test_testuser: TestUserModel, ) -> None: - test_user = api_client.get_test_user_by_user_id(user_id=test_testuser.id) + test_user = overhave_api_client.get_test_user_by_user_id(user_id=test_testuser.id) assert test_user.model_dump() == test_testuser.model_dump() def test_get_user_by_key_empty( - self, api_client: OverhaveApiClient, faker: Faker, + self, + overhave_api_client, + faker: Faker, ) -> None: with pytest.raises(HTTPStatusError): - api_client.get_test_user_by_user_key(user_key=faker.random_int()) + overhave_api_client.get_test_user_by_user_key(user_key=faker.random_int()) def test_get_user_by_key( - self, api_client: OverhaveApiClient, test_testuser: TestUserModel, + self, + overhave_api_client, + test_testuser: TestUserModel, ) -> None: - test_user = api_client.get_test_user_by_user_key(user_key=test_testuser.key) + test_user = overhave_api_client.get_test_user_by_user_key(user_key=test_testuser.key) assert test_user.model_dump() == test_testuser.model_dump() - def test_delete_user_by_id_empty( - self, api_client: OverhaveApiClient, faker: Faker - ) -> None: + def test_delete_user_by_id_empty(self, overhave_api_client, faker: Faker) -> None: with pytest.raises(HTTPStatusError): - api_client.delete_test_user(user_id=faker.random_int()) + overhave_api_client.delete_test_user(user_id=faker.random_int()) - def test_delete_user_by_id( - self, api_client: OverhaveApiClient, test_testuser: TestUserModel - ) -> None: - api_client.delete_test_user(user_id=test_testuser.id) + def test_delete_user_by_id(self, overhave_api_client, test_testuser: TestUserModel) -> None: + overhave_api_client.delete_test_user(user_id=test_testuser.id) @pytest.mark.parametrize("allow_update", [True, False]) - def test_get_test_user_list_feature_type_empty( - self, api_client: OverhaveApiClient, faker: Faker, allow_update: bool - ) -> None: + def test_get_test_user_list_feature_type_empty(self, overhave_api_client, faker: Faker, allow_update: bool) -> None: with pytest.raises(HTTPStatusError): - api_client.get_test_users( + overhave_api_client.get_test_users( feature_type=faker.word(), allow_update=allow_update, ) def test_get_test_user_list( - self, api_client: OverhaveApiClient, test_testuser: TestUserModel, + self, + overhave_api_client, + test_testuser: TestUserModel, ) -> None: - test_users = api_client.get_test_users( + test_users = overhave_api_client.get_test_users( feature_type=test_testuser.feature_type.name, allow_update=test_testuser.allow_update, ) assert len(test_users) == 1 assert test_users[0].model_dump() == test_testuser.model_dump() - def test_get_user_spec_empty( - self, api_client: OverhaveApiClient, faker: Faker - ) -> None: + def test_get_user_spec_empty(self, overhave_api_client, faker: Faker) -> None: with pytest.raises(HTTPStatusError): - api_client.get_test_user_specification(user_id=faker.random_int()) + overhave_api_client.get_test_user_specification(user_id=faker.random_int()) def test_get_user_spec( - self, api_client: OverhaveApiClient, test_testuser: TestUserModel, + self, + overhave_api_client, + test_testuser: TestUserModel, ) -> None: - user_spec = api_client.get_test_user_specification(user_id=test_testuser.id) + user_spec = overhave_api_client.get_test_user_specification(user_id=test_testuser.id) assert user_spec == test_testuser.specification def test_put_user_spec_no_body( - self, api_client: OverhaveApiClient, faker: Faker, + self, + overhave_api_client, + faker: Faker, ) -> None: with pytest.raises(HTTPStatusError): - api_client.update_test_user_specification(user_id=faker.random_int(), specification={}) + overhave_api_client.update_test_user_specification(user_id=faker.random_int(), specification={}) def test_put_user_spec_no_user( self, - api_client: OverhaveApiClient, + overhave_api_client, test_new_specification: TestUserSpecification, faker: Faker, ) -> None: with pytest.raises(HTTPStatusError): - api_client.update_test_user_specification(user_id=faker.random_int(), specification=test_new_specification) + overhave_api_client.update_test_user_specification( + user_id=faker.random_int(), specification=test_new_specification + ) @pytest.mark.parametrize("testuser_allow_update", [False], indirect=True) def test_put_user_spec_not_allowed( self, - api_client: OverhaveApiClient, + overhave_api_client, test_testuser: TestUserModel, test_new_specification: TestUserSpecification, ) -> None: with pytest.raises(HTTPStatusError): - api_client.update_test_user_specification(user_id=test_testuser.id, specification=test_new_specification) + overhave_api_client.update_test_user_specification( + user_id=test_testuser.id, specification=test_new_specification + ) @pytest.mark.parametrize("testuser_allow_update", [True], indirect=True) def test_put_user_spec( self, - api_client: OverhaveApiClient, + overhave_api_client, test_testuser: TestUserModel, test_new_specification: TestUserSpecification, ) -> None: - api_client.update_test_user_specification(user_id=test_testuser.id, specification=test_new_specification) - updated_user_specification = api_client.get_test_user_specification(user_id=test_testuser.id) + overhave_api_client.update_test_user_specification( + user_id=test_testuser.id, specification=test_new_specification + ) + updated_user_specification = overhave_api_client.get_test_user_specification(user_id=test_testuser.id) assert updated_user_specification == test_new_specification diff --git a/tests/integration/transport/redis/conftest.py b/tests/integration/transport/redis/conftest.py old mode 100755 new mode 100644 From 14544547b8cf1def59354b0fe7f4f60ea3d903c6 Mon Sep 17 00:00:00 2001 From: egregiouss Date: Wed, 17 Jan 2024 14:57:42 +0500 Subject: [PATCH 16/23] fixiki --- overhave/transport/http/api_client/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overhave/transport/http/api_client/settings.py b/overhave/transport/http/api_client/settings.py index e50221f5..bd19ab86 100644 --- a/overhave/transport/http/api_client/settings.py +++ b/overhave/transport/http/api_client/settings.py @@ -78,4 +78,4 @@ def get_test_user_id_spec_url(self, user_id: int) -> httpx.URL: return httpx.URL(f"{self.url}/test_user/{user_id}/specification") class Config: - env_prefix = "OVERHAVE_API_CLIENT" + env_prefix = "OVERHAVE_API_CLIENT_" From 8e081fa6d06d8864beb2ef8c1a4040b11450b69d Mon Sep 17 00:00:00 2001 From: egregiouss Date: Fri, 19 Jan 2024 12:08:09 +0500 Subject: [PATCH 17/23] fixiki linters --- overhave/transport/http/api_client/client.py | 10 +++++----- overhave/transport/http/api_client/settings.py | 2 +- .../client/test_client_feature_tags.py | 6 +++--- .../client/test_client_feature_types.py | 2 +- .../client/test_client_testusers.py | 18 ++++++++++-------- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/overhave/transport/http/api_client/client.py b/overhave/transport/http/api_client/client.py index 7c7cd439..36e6fc75 100644 --- a/overhave/transport/http/api_client/client.py +++ b/overhave/transport/http/api_client/client.py @@ -105,7 +105,7 @@ def create_test_run(self, tag_value: str) -> list[str]: ) logger.debug("Create test run successfully") - return response.json() + return cast(list[str], response.json()) def get_emulation_runs(self, test_user_id: int) -> list[ApiEmulationRunResponse]: logger.debug("Start get list of EmulationRun") @@ -122,7 +122,7 @@ def get_test_user_by_user_id(self, user_id: int) -> ApiTestUserResponse: logger.debug("Start get test user by user_id: %s", user_id) response = self._make_request( method=HttpMethod.GET, - url=self._settings.test_user_path, + url=self._settings.get_test_user_url, params={"user_id": user_id}, auth=BearerAuth(self._settings.auth_token), ) @@ -133,7 +133,7 @@ def get_test_user_by_user_key(self, user_key: str) -> ApiTestUserResponse: logger.debug("Start get test user by user_key: %s", user_key) response = self._make_request( method=HttpMethod.GET, - url=self._settings.test_user_path, + url=self._settings.get_test_user_url, params={"user_key": user_key}, auth=BearerAuth(self._settings.auth_token), ) @@ -144,7 +144,7 @@ def get_test_users(self, feature_type: str, allow_update: bool) -> list[ApiTestU logger.debug("Start get test users with feature_type: %s and allow_update: %s", feature_type, allow_update) response = self._make_request( method=HttpMethod.GET, - url=self._settings.test_user_list_path, + url=self._settings.get_test_user_list_url, params={ "feature_type": feature_type, "allow_update": allow_update, @@ -171,7 +171,7 @@ def get_test_user_specification(self, user_id: int) -> dict[str, str | None]: auth=BearerAuth(self._settings.auth_token), ) logger.debug("Get user specification successfully") - return response.json() + return cast(dict[str, str | None], response.json()) def update_test_user_specification(self, user_id: int, specification: dict[str, str | None]) -> None: logger.debug("Start update user specification by user_id: %s", user_id) diff --git a/overhave/transport/http/api_client/settings.py b/overhave/transport/http/api_client/settings.py index bd19ab86..19c48058 100644 --- a/overhave/transport/http/api_client/settings.py +++ b/overhave/transport/http/api_client/settings.py @@ -65,7 +65,7 @@ def get_emulation_run_list_url(self) -> httpx.URL: @property def get_test_user_url(self) -> httpx.URL: - return httpx.URL(f"{self.url}/{self.test_user}") + return httpx.URL(f"{self.url}/{self.test_user_path}") @property def get_test_user_list_url(self) -> httpx.URL: diff --git a/tests/integration/client/test_client_feature_tags.py b/tests/integration/client/test_client_feature_tags.py index d92d19a0..cae06dcf 100644 --- a/tests/integration/client/test_client_feature_tags.py +++ b/tests/integration/client/test_client_feature_tags.py @@ -21,7 +21,7 @@ def test_get_feature_tags_item( def test_get_feature_tags_with_unknown_value( self, - overhave_api_client, + overhave_api_client: OverhaveApiClient, faker: Faker, ) -> None: with pytest.raises(HTTPStatusError): @@ -29,7 +29,7 @@ def test_get_feature_tags_with_unknown_value( def test_get_feature_tags_list( self, - overhave_api_client, + overhave_api_client: OverhaveApiClient, test_tag: TagModel, ) -> None: items = overhave_api_client.get_feature_tags_list(value=test_tag.value) @@ -38,7 +38,7 @@ def test_get_feature_tags_list( def test_get_feature_tags_list_with_unknown_value( self, - overhave_api_client, + overhave_api_client: OverhaveApiClient, faker: Faker, ) -> None: items = overhave_api_client.get_feature_tags_list(value=faker.word()) diff --git a/tests/integration/client/test_client_feature_types.py b/tests/integration/client/test_client_feature_types.py index ea0e1b70..0d747a2e 100644 --- a/tests/integration/client/test_client_feature_types.py +++ b/tests/integration/client/test_client_feature_types.py @@ -14,4 +14,4 @@ def test_get_feature_types( ) -> None: feature_types = overhave_api_client.get_feature_types() assert len(feature_types) == 1 - assert feature_types[0].model_dump() == test_feature_type.model_dump() + assert feature_types[0].model_dump()["id"] == test_feature_type.model_dump()["id"] diff --git a/tests/integration/client/test_client_testusers.py b/tests/integration/client/test_client_testusers.py index 0858e19a..d06e9752 100644 --- a/tests/integration/client/test_client_testusers.py +++ b/tests/integration/client/test_client_testusers.py @@ -43,7 +43,7 @@ def test_get_user_by_key( test_user = overhave_api_client.get_test_user_by_user_key(user_key=test_testuser.key) assert test_user.model_dump() == test_testuser.model_dump() - def test_delete_user_by_id_empty(self, overhave_api_client, faker: Faker) -> None: + def test_delete_user_by_id_empty(self, overhave_api_client: OverhaveApiClient, faker: Faker) -> None: with pytest.raises(HTTPStatusError): overhave_api_client.delete_test_user(user_id=faker.random_int()) @@ -51,7 +51,9 @@ def test_delete_user_by_id(self, overhave_api_client: OverhaveApiClient, test_te overhave_api_client.delete_test_user(user_id=test_testuser.id) @pytest.mark.parametrize("allow_update", [True, False]) - def test_get_test_user_list_feature_type_empty(self, overhave_api_client, faker: Faker, allow_update: bool) -> None: + def test_get_test_user_list_feature_type_empty( + self, overhave_api_client: OverhaveApiClient, faker: Faker, allow_update: bool + ) -> None: with pytest.raises(HTTPStatusError): overhave_api_client.get_test_users( feature_type=faker.word(), @@ -70,13 +72,13 @@ def test_get_test_user_list( assert len(test_users) == 1 assert test_users[0].model_dump() == test_testuser.model_dump() - def test_get_user_spec_empty(self, overhave_api_client, faker: Faker) -> None: + def test_get_user_spec_empty(self, overhave_api_client: OverhaveApiClient, faker: Faker) -> None: with pytest.raises(HTTPStatusError): overhave_api_client.get_test_user_specification(user_id=faker.random_int()) def test_get_user_spec( self, - overhave_api_client, + overhave_api_client: OverhaveApiClient, test_testuser: TestUserModel, ) -> None: user_spec = overhave_api_client.get_test_user_specification(user_id=test_testuser.id) @@ -84,7 +86,7 @@ def test_get_user_spec( def test_put_user_spec_no_body( self, - overhave_api_client, + overhave_api_client: OverhaveApiClient, faker: Faker, ) -> None: with pytest.raises(HTTPStatusError): @@ -92,7 +94,7 @@ def test_put_user_spec_no_body( def test_put_user_spec_no_user( self, - overhave_api_client, + overhave_api_client: OverhaveApiClient, test_new_specification: TestUserSpecification, faker: Faker, ) -> None: @@ -104,7 +106,7 @@ def test_put_user_spec_no_user( @pytest.mark.parametrize("testuser_allow_update", [False], indirect=True) def test_put_user_spec_not_allowed( self, - overhave_api_client, + overhave_api_client: OverhaveApiClient, test_testuser: TestUserModel, test_new_specification: TestUserSpecification, ) -> None: @@ -116,7 +118,7 @@ def test_put_user_spec_not_allowed( @pytest.mark.parametrize("testuser_allow_update", [True], indirect=True) def test_put_user_spec( self, - overhave_api_client, + overhave_api_client: OverhaveApiClient, test_testuser: TestUserModel, test_new_specification: TestUserSpecification, ) -> None: From cfdc602d9d3a30f12ed71e10ba789ebbda375311 Mon Sep 17 00:00:00 2001 From: egregiouss Date: Fri, 19 Jan 2024 13:41:16 +0500 Subject: [PATCH 18/23] add test_session into login view tests --- tests/integration/admin/views/test_login_view.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/integration/admin/views/test_login_view.py b/tests/integration/admin/views/test_login_view.py index 9ae7454b..5c1164a8 100644 --- a/tests/integration/admin/views/test_login_view.py +++ b/tests/integration/admin/views/test_login_view.py @@ -4,6 +4,7 @@ from flask.testing import FlaskClient from overhave import OverhaveAdminApp +from tests.db_utils import count_queries, create_test_session @pytest.fixture(scope="module") @@ -23,9 +24,8 @@ def test_show_flash_with_chat_for_unregistered_user( mock_support_chat_url: None, ) -> None: test_app.config["WTF_CSRF_ENABLED"] = False - - response = test_client.post("/login", data={"username": "kek", "password": "12345"}, follow_redirects=True) - + with create_test_session(): + response = test_client.post("/login", data={"username": "kek", "password": "12345"}, follow_redirects=True) assert ( "Username 'kek' is not registered! Please contact the support channel!" in response.data.decode("utf-8") @@ -37,8 +37,8 @@ def test_show_flash_without_chat_for_unregistered_user( test_client: FlaskClient, ) -> None: test_app.config["WTF_CSRF_ENABLED"] = False - - response = test_client.post("/login", data={"username": "kek", "password": "12345"}, follow_redirects=True) + with create_test_session(): + response = test_client.post("/login", data={"username": "kek", "password": "12345"}, follow_redirects=True) assert "Username 'kek' is not registered!" in response.data.decode( "utf-8" From 46195b6e3f91b4e65c744117433cec44add5febf Mon Sep 17 00:00:00 2001 From: egregiouss Date: Fri, 19 Jan 2024 17:12:05 +0500 Subject: [PATCH 19/23] fix lint --- tests/integration/admin/views/test_login_view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/admin/views/test_login_view.py b/tests/integration/admin/views/test_login_view.py index 5c1164a8..e2fc532e 100644 --- a/tests/integration/admin/views/test_login_view.py +++ b/tests/integration/admin/views/test_login_view.py @@ -4,7 +4,7 @@ from flask.testing import FlaskClient from overhave import OverhaveAdminApp -from tests.db_utils import count_queries, create_test_session +from tests.db_utils import create_test_session @pytest.fixture(scope="module") From 4923ad1f226409a577e3dab034361494dd89e35e Mon Sep 17 00:00:00 2001 From: Artemy Rogov <57125077+artamaney@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:02:09 +0500 Subject: [PATCH 20/23] Delete tests/integration/admin/views/test_feature_admin_view.py --- .../admin/views/test_feature_admin_view.py | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 tests/integration/admin/views/test_feature_admin_view.py diff --git a/tests/integration/admin/views/test_feature_admin_view.py b/tests/integration/admin/views/test_feature_admin_view.py deleted file mode 100644 index 9119c21e..00000000 --- a/tests/integration/admin/views/test_feature_admin_view.py +++ /dev/null @@ -1,22 +0,0 @@ -from http import HTTPStatus - -import pytest -from flask.testing import FlaskClient - -from overhave import db -from overhave.storage import SystemUserModel -from tests.db_utils import create_test_session - - -@pytest.mark.usefixtures("database") -class TestFeatureAdminView: - """Tests for feature view.""" - - @pytest.mark.parametrize("test_user_role", [db.Role.admin], indirect=True) - def test_edit_redirects_to_feature_index_view_if_no_feature( - self, test_client: FlaskClient, test_authorized_user: SystemUserModel - ) -> None: - with create_test_session(): - response = test_client.get("/feature/edit/") - assert response.status_code == HTTPStatus.FOUND - assert response.location == "/feature/" From b8289062f501b2c1628e23abd7813c55f2ed1cc3 Mon Sep 17 00:00:00 2001 From: Artemy Rogov <57125077+artamaney@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:08:47 +0500 Subject: [PATCH 21/23] Update tests/integration/admin/views/test_login_view.py --- tests/integration/admin/views/test_login_view.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/integration/admin/views/test_login_view.py b/tests/integration/admin/views/test_login_view.py index e2fc532e..5df0709b 100644 --- a/tests/integration/admin/views/test_login_view.py +++ b/tests/integration/admin/views/test_login_view.py @@ -24,8 +24,7 @@ def test_show_flash_with_chat_for_unregistered_user( mock_support_chat_url: None, ) -> None: test_app.config["WTF_CSRF_ENABLED"] = False - with create_test_session(): - response = test_client.post("/login", data={"username": "kek", "password": "12345"}, follow_redirects=True) + response = test_client.post("/login", data={"username": "kek", "password": "12345"}, follow_redirects=True) assert ( "Username 'kek' is not registered! Please contact the support channel!" in response.data.decode("utf-8") From 1e6933a383cf9c77fc1f38b4764504bb03329269 Mon Sep 17 00:00:00 2001 From: Artemy Rogov <57125077+artamaney@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:09:20 +0500 Subject: [PATCH 22/23] Update tests/integration/admin/views/test_login_view.py --- tests/integration/admin/views/test_login_view.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/integration/admin/views/test_login_view.py b/tests/integration/admin/views/test_login_view.py index 5df0709b..771ebae4 100644 --- a/tests/integration/admin/views/test_login_view.py +++ b/tests/integration/admin/views/test_login_view.py @@ -36,8 +36,7 @@ def test_show_flash_without_chat_for_unregistered_user( test_client: FlaskClient, ) -> None: test_app.config["WTF_CSRF_ENABLED"] = False - with create_test_session(): - response = test_client.post("/login", data={"username": "kek", "password": "12345"}, follow_redirects=True) + response = test_client.post("/login", data={"username": "kek", "password": "12345"}, follow_redirects=True) assert "Username 'kek' is not registered!" in response.data.decode( "utf-8" From 2fafeaaa9e8bfbddcc296af5845864bdd257f9a8 Mon Sep 17 00:00:00 2001 From: Artemy Rogov <57125077+artamaney@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:09:26 +0500 Subject: [PATCH 23/23] Update tests/integration/admin/views/test_login_view.py --- tests/integration/admin/views/test_login_view.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/admin/views/test_login_view.py b/tests/integration/admin/views/test_login_view.py index 771ebae4..3521ce41 100644 --- a/tests/integration/admin/views/test_login_view.py +++ b/tests/integration/admin/views/test_login_view.py @@ -4,7 +4,6 @@ from flask.testing import FlaskClient from overhave import OverhaveAdminApp -from tests.db_utils import create_test_session @pytest.fixture(scope="module")