From 1d8681447c55bce052bf251adb09b2228cfa4fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20S=C3=A1nchez?= <149783901+lsancso@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:29:00 +0100 Subject: [PATCH] connect to sql db (#9) Green test --- .pre-commit-config.yaml | 6 ------ Makefile | 3 +++ docker/docker-compose.yml | 19 +++++++++++++++++ src/domain/credentials_requests.py | 1 + src/domain/db_repository.py | 2 +- src/infrastructure/postgresql_client.py | 21 +++++++++++++++++-- src/pyproject.toml | 1 + src/tests/conftest.py | 0 src/tests/domain/test_credentials_requests.py | 2 ++ src/tests/infrastructure/test_db_client.py | 19 ++++++++++------- src/utils/__init__.py | 0 src/utils/password_generator.py | 7 +++++++ 12 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 src/tests/conftest.py create mode 100644 src/utils/__init__.py create mode 100644 src/utils/password_generator.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e10c683..ee8f229 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,9 +19,3 @@ repos: language: system stages: - pre-commit - - id: test - name: Run pytest suite - entry: make test - language: system - stages: - - pre-commit diff --git a/Makefile b/Makefile index b480fd5..0f9290e 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,9 @@ env-recreate: build env-start install-test-requirements## Force building project bash: ## Open a bash shell in project's main container $(DOCKER_COMMAND) exec app bash +bash-db: ## Open a bash shell in project's main container + $(DOCKER_COMMAND) exec db bash + test: ## Run test suite in project's main container $(DOCKER_COMMAND) exec -T app pytest -vv --color=yes diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 92ff17c..38829ac 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -16,3 +16,22 @@ services: - ../src:/app/src - ../scripts:/app/scripts - ./assets/gunicorn:/var/gunicorn/ + depends_on: + - db + db: + image: postgres:13.17-alpine + volumes: + - pgdata:/var/lib/postgresql/data + environment: + - POSTGRES_PASSWORD=test_password + - POSTGRES_USER=test_username + - POSTGRES_DB=test_db + command: --fsync=off + networks: + default: + aliases: + - db + ports: + - 5432:5432 +volumes: + pgdata: diff --git a/src/domain/credentials_requests.py b/src/domain/credentials_requests.py index 314cf0e..17a3934 100644 --- a/src/domain/credentials_requests.py +++ b/src/domain/credentials_requests.py @@ -4,5 +4,6 @@ @dataclass(frozen=True) class CredentialsRequest: username: str + password: str instance_name: str database_name: str diff --git a/src/domain/db_repository.py b/src/domain/db_repository.py index e5ceb3b..e596830 100644 --- a/src/domain/db_repository.py +++ b/src/domain/db_repository.py @@ -5,4 +5,4 @@ class DBRepository(ABC): @abstractmethod - def create_credentials(self, credentials_request: CredentialsRequest) -> str: ... + def create_credentials(self, credentials_request: CredentialsRequest) -> dict[str, str]: ... diff --git a/src/infrastructure/postgresql_client.py b/src/infrastructure/postgresql_client.py index 439a25b..efeb2cb 100644 --- a/src/infrastructure/postgresql_client.py +++ b/src/infrastructure/postgresql_client.py @@ -1,7 +1,24 @@ +import psycopg2 + from domain.credentials_requests import CredentialsRequest from domain.db_repository import DBRepository class PostgresClient(DBRepository): - def create_credentials(self, credentials_request: CredentialsRequest) -> str: - return "ChangeME!" + def __init__(self, admin_user: str, admin_password: str) -> None: + self.admin_user = admin_user + self.admin_password = admin_password + + def create_credentials(self, credentials_request: CredentialsRequest) -> dict[str, str]: + DB_URL = f"postgresql://{self.admin_user}:{self.admin_password}@{credentials_request.instance_name}/{credentials_request.database_name}" + + conn = psycopg2.connect(dsn=DB_URL) + cur = conn.cursor() + cur.execute(f"CREATE ROLE {credentials_request.username} WITH PASSWORD '{credentials_request.password}'") + + cur.execute(f"SELECT rolname FROM pg_roles WHERE rolname = '{credentials_request.username}'") + + results = cur.fetchone() + username = results[0] + credentials = {"username": username, "password": credentials_request.password} + return credentials diff --git a/src/pyproject.toml b/src/pyproject.toml index 5f78928..4c8644d 100644 --- a/src/pyproject.toml +++ b/src/pyproject.toml @@ -10,6 +10,7 @@ dependencies = [ "fastapi==0.111.0", "gunicorn==22.0.0", "mo-monitoring[fastapi]==1.0.1", + "psycopg2-binary==2.9.10", ] [tool.setuptools.packages.find] diff --git a/src/tests/conftest.py b/src/tests/conftest.py new file mode 100644 index 0000000..e69de29 diff --git a/src/tests/domain/test_credentials_requests.py b/src/tests/domain/test_credentials_requests.py index 474d3f0..27d7f3e 100644 --- a/src/tests/domain/test_credentials_requests.py +++ b/src/tests/domain/test_credentials_requests.py @@ -4,9 +4,11 @@ def test_credentials_request() -> None: request = CredentialsRequest( username="test", + password="test", instance_name="test-instance", database_name="test-database", ) assert request.username == "test" assert request.instance_name == "test-instance" assert request.database_name == "test-database" + assert request.password == "test" diff --git a/src/tests/infrastructure/test_db_client.py b/src/tests/infrastructure/test_db_client.py index 081195c..be55a76 100644 --- a/src/tests/infrastructure/test_db_client.py +++ b/src/tests/infrastructure/test_db_client.py @@ -1,18 +1,21 @@ from domain.credentials_requests import CredentialsRequest from infrastructure.postgresql_client import PostgresClient +from utils.password_generator import PasswordGenerator class TestDBClient: def test_create_users_returns_credentials(self) -> None: - request = CredentialsRequest( - username="test", - instance_name="test-instance", - database_name="test-database", + credential_request = CredentialsRequest( + username="patata", + password=PasswordGenerator().generate_password(), + instance_name="db", + database_name="test_db", ) + db_password = "test_password" - test_repo = PostgresClient() + test_repo = PostgresClient(admin_user="test_username", admin_password=db_password) - credentials = test_repo.create_credentials(credentials_request=request) + credentials = test_repo.create_credentials(credentials_request=credential_request) - assert credentials - assert credentials == "ChangeME!" + assert credentials["username"] == credential_request.username + assert credentials["password"] == credential_request.password diff --git a/src/utils/__init__.py b/src/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/utils/password_generator.py b/src/utils/password_generator.py new file mode 100644 index 0000000..6c6edcd --- /dev/null +++ b/src/utils/password_generator.py @@ -0,0 +1,7 @@ +import secrets + + +class PasswordGenerator: + def generate_password(self) -> str: + password = secrets.token_urlsafe(32) + return password