Skip to content

Commit

Permalink
Merge pull request #140 from Tinkoff/overhave-api
Browse files Browse the repository at this point in the history
Overhave api
  • Loading branch information
livestreamx authored Mar 8, 2022
2 parents 471f887 + 09dc8be commit 5e78eb4
Show file tree
Hide file tree
Showing 24 changed files with 201 additions and 78 deletions.
2 changes: 1 addition & 1 deletion makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CODE = overhave
VENV ?= .venv
WORK_DIR ?= .
MIN_COVERAGE ?= 83.2
MIN_COVERAGE ?= 83.6
BUILD_DIR ?= dist
PYTHON_VERSION ?= 3.10

Expand Down
1 change: 1 addition & 0 deletions overhave/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# flake8: noqa
from overhave.admin import OverhaveAdminApp, overhave_app
from overhave.api import create_overhave_api as overhave_api
from overhave.authorization import AuthorizationStrategy, OverhaveAuthorizationSettings, OverhaveLdapClientSettings
from overhave.base_settings import DataBaseSettings as OverhaveDBSettings
from overhave.base_settings import LoggingSettings as OverhaveLoggingSettings
Expand Down
8 changes: 4 additions & 4 deletions overhave/api/app.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import fastapi as fastapi

from overhave.api.views import receive_test_user
from overhave.api.views import test_user_handler


def create_overhave_api() -> fastapi.FastAPI:
router = fastapi.APIRouter(prefix="/api", tags=["test_users"])
router.add_api_route("/test_users", receive_test_user, methods=["GET", "POST", "UPDATE", "DELETE"])
test_user_router = fastapi.APIRouter()
test_user_router.add_api_route("/", test_user_handler, methods=["GET"])

app = fastapi.FastAPI()
app.include_router(router)
app.include_router(test_user_router, prefix="/test_user", tags=["test_users"])
return app
5 changes: 5 additions & 0 deletions overhave/api/deps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from overhave.storage import ITestUserStorage, TestUserStorage


def get_test_user_storage() -> ITestUserStorage:
return TestUserStorage()
45 changes: 43 additions & 2 deletions overhave/api/views.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,43 @@
def receive_test_user() -> None:
pass
import logging
from http import HTTPStatus
from typing import Optional

import fastapi

from overhave.api.deps import get_test_user_storage
from overhave.entities.converters import TestUserModel
from overhave.storage import ITestUserStorage

logger = logging.getLogger(__name__)


def _test_user_id_handler(user_id: int, test_user_storage: ITestUserStorage) -> TestUserModel:
logger.info("Getting %s with user_id=%s...", TestUserModel.__name__, user_id)
test_user = test_user_storage.get_test_user_by_id(user_id)
if test_user is None:
raise fastapi.HTTPException(status_code=HTTPStatus.NOT_FOUND, detail=f"User with id={user_id} does not exist")
return test_user


def _test_user_name_handler(user_name: str, test_user_storage: ITestUserStorage) -> TestUserModel:
logger.info("Getting %s with user_name='%s'...", TestUserModel.__name__, user_name)
test_user = test_user_storage.get_test_user_by_name(user_name)
if test_user is None:
raise fastapi.HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail=f"User with name='{user_name}' does not exist"
)
return test_user


def test_user_handler(
user_id: Optional[int] = None,
user_name: Optional[str] = None,
test_user_storage: ITestUserStorage = fastapi.Depends(get_test_user_storage),
) -> TestUserModel:
if user_id is not None:
return _test_user_id_handler(user_id=user_id, test_user_storage=test_user_storage)
if user_name is not None:
return _test_user_name_handler(user_name=user_name, test_user_storage=test_user_storage)
raise fastapi.HTTPException(
status_code=HTTPStatus.BAD_REQUEST, detail="'user_id' or 'user_name' query parameter should be set"
)
2 changes: 1 addition & 1 deletion overhave/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# flake8: noqa
from .admin import admin
from .consumers import consumer
from .db import set_config_to_context
from .db_cmds import set_config_to_context
from .group import overhave
from .synchronization import synchronize
File renamed without changes.
2 changes: 1 addition & 1 deletion overhave/cli/db/group.py → overhave/cli/db_cmds/group.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import typer

from overhave.base_settings import DataBaseSettings
from overhave.cli.db.regular import create_schema, drop_schema, set_config_to_context
from overhave.cli.db_cmds.regular import create_schema, drop_schema, set_config_to_context


def _config_callback(ctx: typer.Context) -> None:
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion overhave/cli/group.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import typer as typer

from overhave.cli.db import db_app
from overhave.cli.db_cmds import db_app
from overhave.cli.s3 import s3_app

overhave = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]})
Expand Down
2 changes: 2 additions & 0 deletions overhave/emulation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# flake8: noqa
from .emulator import Emulator
File renamed without changes.
1 change: 0 additions & 1 deletion overhave/entities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
TestRunModel,
TestUserSpecification,
)
from .emulator import Emulator
from .feature import (
FeatureExtractor,
FeatureTypeExtractionError,
Expand Down
2 changes: 1 addition & 1 deletion overhave/factory/components/emulation_factory.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import abc
from functools import cached_property

from overhave.entities import Emulator
from overhave.emulation import Emulator
from overhave.factory.base_factory import BaseOverhaveFactory, IOverhaveFactory
from overhave.factory.components.abstract_consumer import ITaskConsumerFactory
from overhave.factory.context import OverhaveEmulationContext
Expand Down
2 changes: 1 addition & 1 deletion overhave/gunicorn_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from overhave.base_settings import OVERHAVE_ENV_PREFIX

worker_class = os.environ.get(OVERHAVE_ENV_PREFIX + "GUNICORN_WORKER_CLASS", "uvicorn.workers.UvicornWorker")
workers = os.environ.get(OVERHAVE_ENV_PREFIX + "GUNICORN_WORKERS", 4)
workers = os.environ.get(OVERHAVE_ENV_PREFIX + "GUNICORN_WORKERS", 1)
threads = os.environ.get(OVERHAVE_ENV_PREFIX + "GUNICORN_THREADS", 1)
worker_connections = os.environ.get(OVERHAVE_ENV_PREFIX + "GUNICORN_CONNECTIONS", 1000)
timeout = os.environ.get(OVERHAVE_ENV_PREFIX + "GUNICORN_TIMEOUT", 10)
Expand Down
1 change: 1 addition & 0 deletions overhave/storage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
from .system_user_group_storage import ISystemUserGroupStorage, SystemUserGroupStorage
from .system_user_storage import ISystemUserStorage, SystemUserStorage
from .test_run_storage import ITestRunStorage, TestRunStorage
from .test_user_storage import ITestUserStorage, TestUserStorage
13 changes: 13 additions & 0 deletions overhave/storage/test_user_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ class TestUserDoesNotExistError(BaseTestUserStorageException):
class ITestUserStorage(abc.ABC):
"""Abstract class for Test User storage."""

@staticmethod
@abc.abstractmethod
def get_test_user_by_id(user_id: int) -> Optional[TestUserModel]:
pass

@staticmethod
@abc.abstractmethod
def get_test_user_by_name(name: str) -> Optional[TestUserModel]:
Expand All @@ -40,6 +45,14 @@ def update_test_user_specification(user_id: int, specification: TestUserSpecific
class TestUserStorage(ITestUserStorage):
"""Class for Test User storage."""

@staticmethod
def get_test_user_by_id(user_id: int) -> Optional[TestUserModel]:
with create_session() as session:
user: Optional[db.TestUser] = session.query(db.TestUser).get(user_id)
if user is not None:
return cast(TestUserModel, TestUserModel.from_orm(user))
return None

@staticmethod
def get_test_user_by_name(name: str) -> Optional[TestUserModel]:
with create_session() as session:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "overhave"
version = "2.8.0"
version = "2.8.1"
description = "Overhave - web-framework for BDD"
readme = "README.rst"
authors = [
Expand Down
9 changes: 9 additions & 0 deletions tests/integration/api/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import pytest
from fastapi.testclient import TestClient

from overhave import overhave_api


@pytest.fixture()
def test_api_client(database: None) -> TestClient:
return TestClient(overhave_api())
40 changes: 40 additions & 0 deletions tests/integration/api/test_testusers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import pytest as pytest
from faker import Faker
from fastapi.testclient import TestClient

from overhave import db
from overhave.entities.converters import TestUserModel


@pytest.mark.parametrize("test_user_role", [db.Role.user], indirect=True)
class TestTestUserAPi:
"""Integration tests for Overhave TestUser API."""

def test_get_user_no_query(self, test_api_client: TestClient, test_user_role: db.Role) -> None:
response = test_api_client.get("/test_user/")
assert response.status_code == 400
assert response.content is not None

def test_get_user_by_id_empty(self, test_api_client: TestClient, faker: Faker, test_user_role: db.Role) -> None:
response = test_api_client.get(f"/test_user/?user_id={faker.random_int()}")
assert response.status_code == 404
assert response.content is not None

def test_get_user_by_id(self, test_api_client: TestClient, test_testuser: TestUserModel) -> None:
response = test_api_client.get(f"/test_user/?user_id={test_testuser.id}")
assert response.status_code == 200
assert response.json()
obj = TestUserModel.parse_obj(response.json())
assert obj == test_testuser

def test_get_user_by_name_empty(self, test_api_client: TestClient, faker: Faker, test_user_role: db.Role) -> None:
response = test_api_client.get(f"/test_user/?user_name={faker.random_int()}")
assert response.status_code == 404
assert response.content is not None

def test_get_user_by_name(self, test_api_client: TestClient, test_testuser: TestUserModel) -> None:
response = test_api_client.get(f"/test_user/?user_name={test_testuser.name}")
assert response.status_code == 200
assert response.json()
obj = TestUserModel.parse_obj(response.json())
assert obj == test_testuser
61 changes: 60 additions & 1 deletion tests/integration/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
from typing import cast

import pytest
from _pytest.fixtures import FixtureRequest
from faker import Faker
from pydantic import SecretStr

from overhave.storage import SystemUserGroupStorage, SystemUserStorage
from overhave import db
from overhave.entities import FeatureTypeModel, SystemUserModel, TestUserSpecification
from overhave.entities.converters import TestUserModel
from overhave.storage import SystemUserGroupStorage, SystemUserStorage, TestUserStorage


@pytest.fixture(scope="package")
Expand All @@ -11,3 +19,54 @@ def test_system_user_storage() -> SystemUserStorage:
@pytest.fixture(scope="package")
def test_system_user_group_storage() -> SystemUserGroupStorage:
return SystemUserGroupStorage()


@pytest.fixture(scope="package")
def test_user_storage() -> TestUserStorage:
return TestUserStorage()


@pytest.fixture()
def test_feature_type(database: None, faker: Faker) -> FeatureTypeModel:
with db.create_session() as session:
feature_type = db.FeatureType(name=cast(str, faker.word()))
session.add(feature_type)
session.flush()
return cast(FeatureTypeModel, FeatureTypeModel.from_orm(feature_type))


@pytest.fixture()
def test_user_role(request: FixtureRequest) -> db.Role:
if hasattr(request, "param"):
return request.param
raise NotImplementedError


@pytest.fixture()
def test_system_user(
test_system_user_storage: SystemUserStorage, database: None, faker: Faker, test_user_role: db.Role
) -> SystemUserModel:
return test_system_user_storage.create_user(
login=faker.word(), password=SecretStr(faker.word()), role=test_user_role
)


@pytest.fixture()
def test_specification() -> TestUserSpecification:
return TestUserSpecification({"test": "value"})


@pytest.fixture()
def test_testuser(
test_system_user: SystemUserModel, faker: Faker, test_feature_type, test_specification: TestUserSpecification
) -> TestUserModel:
with db.create_session() as session:
test_user = db.TestUser(
feature_type_id=test_feature_type.id,
name=cast(str, faker.word()),
created_by=test_system_user.login,
specification=test_specification,
)
session.add(test_user)
session.flush()
return cast(TestUserModel, TestUserModel.from_orm(test_user))
Loading

0 comments on commit 5e78eb4

Please sign in to comment.