Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions gs/backend/api/backend_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from gs.backend.api.v1.mcc.endpoints.commands import commands_router
from gs.backend.api.v1.mcc.endpoints.main_commands import main_commands_router
from gs.backend.api.v1.mcc.endpoints.telemetry import telemetry_router
from gs.backend.config.config import backend_config
from gs.backend.config.config import settings


def setup_routes(app: FastAPI) -> None:
Expand All @@ -38,7 +38,7 @@ def setup_middlewares(app: FastAPI) -> None:
app.add_middleware(AuthMiddleware)
app.add_middleware(
LoggerMiddleware,
excluded_endpoints=backend_config.logger_config.excluded_endpoints,
excluded_endpoints=settings.logger.excluded_endpoints,
)


Expand Down
10 changes: 5 additions & 5 deletions gs/backend/api/middleware/cors_middleware.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from gs.backend.config.config import backend_config
from gs.backend.config.config import settings


def add_cors_middleware(app: FastAPI) -> None:
Expand All @@ -12,8 +12,8 @@ def add_cors_middleware(app: FastAPI) -> None:
"""
app.add_middleware(
CORSMiddleware,
allow_origins=backend_config.cors_config.allow_origins,
allow_credentials=backend_config.cors_config.allow_credentials,
allow_methods=backend_config.cors_config.allow_methods,
allow_headers=backend_config.cors_config.allow_headers,
allow_origins=settings.cors.allow_origins,
allow_credentials=settings.cors.allow_credentials,
allow_methods=settings.cors.allow_methods,
allow_headers=settings.cors.allow_headers,
)
44 changes: 7 additions & 37 deletions gs/backend/config/config.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
# TODO:(335) Improve loading the configuration
from os import environ
from typing import Final

from dotenv import load_dotenv

from .cors_config import CORSConfig
from .logger_config import LoggerConfig

load_dotenv()
from gs.backend.config.cors_config import CORSConfig
from gs.backend.config.database_config import DatabaseConfig
from gs.backend.config.logger_config import LoggerConfig


class BackendConfiguration:
Expand All @@ -16,34 +11,9 @@ class BackendConfiguration:
"""

def __init__(self) -> None:
self.cors_config = CORSConfig()
self.logger_config = LoggerConfig()


backend_config = BackendConfiguration()


def getenv(config: str) -> str:
"""
Validates whether or not database env values exist in .env. If not, throws a value error.

:param config: Variable in .env
:type config: str
:return: Value of variable in .env
:rtype: str
"""
value = environ.get(config)
if not value:
raise ValueError(f"{config} is missing from .env.")
return value

self.cors = CORSConfig()
self.logger = LoggerConfig()
self.db = DatabaseConfig()

GS_DATABASE_USER = getenv("GS_DATABASE_USER")
GS_DATABASE_PASSWORD = getenv("GS_DATABASE_PASSWORD")
GS_DATABASE_LOCATION = getenv("GS_DATABASE_LOCATION")
GS_DATABASE_PORT = getenv("GS_DATABASE_PORT")
GS_DATABASE_NAME = getenv("GS_DATABASE_NAME")

DATABASE_CONNECTION_STRING: Final[
str
] = f"postgresql+psycopg2://{GS_DATABASE_USER}:{GS_DATABASE_PASSWORD}@{GS_DATABASE_LOCATION}:{GS_DATABASE_PORT}/{GS_DATABASE_NAME}"
settings = BackendConfiguration()
25 changes: 25 additions & 0 deletions gs/backend/config/database_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from pydantic import SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict


class DatabaseConfig(BaseSettings):
"""
Pydantic class for storing database configuration settings
"""

model_config = SettingsConfigDict(env_prefix="GS_DATABASE_")

user: str
password: SecretStr
location: str
port: int
name: str

@property
def connection_string(self) -> str:
"""
Returns the database connection string
"""

pwd = self.password.get_secret_value()
return f"postgresql://{self.user}:{pwd}@{self.location}:{self.port}/{self.name}"
4 changes: 2 additions & 2 deletions gs/backend/data/database/engine.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from sqlalchemy import Engine
from sqlmodel import Session, create_engine, text

from gs.backend.config.config import DATABASE_CONNECTION_STRING
from gs.backend.config.config import settings
from gs.backend.data.tables.aro_user_tables import ARO_USER_SCHEMA_NAME
from gs.backend.data.tables.main_tables import MAIN_SCHEMA_NAME
from gs.backend.data.tables.transactional_tables import TRANSACTIONAL_SCHEMA_NAME
Expand All @@ -13,7 +13,7 @@ def get_db_engine() -> Engine:

:return: engine
"""
return create_engine(DATABASE_CONNECTION_STRING)
return create_engine(settings.db.connection_string)


def get_db_session() -> Session:
Expand Down
6 changes: 6 additions & 0 deletions python_test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
import subprocess
from datetime import datetime

os.environ.setdefault("GS_DATABASE_USER", "testuser")
os.environ.setdefault("GS_DATABASE_PASSWORD", "testpassword")
os.environ.setdefault("GS_DATABASE_LOCATION", "localhost")
os.environ.setdefault("GS_DATABASE_PORT", "5432")
os.environ.setdefault("GS_DATABASE_NAME", "testdb")

import pytest
from gs.backend.data.database.engine import setup_database
from gs.backend.data.tables.transactional_tables import CommsSession
Expand Down
74 changes: 68 additions & 6 deletions python_test/test_config_manager.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import importlib

from gs.backend.config import config
import pytest
from gs.backend.config.config import BackendConfiguration, settings
from gs.backend.config.cors_config import CORSConfig
from gs.backend.config.database_config import DatabaseConfig
from gs.backend.config.logger_config import LoggerConfig
from pydantic import ValidationError


def test_logger_config_default():
cfg = LoggerConfig()

assert cfg.excluded_endpoints == []


Expand All @@ -21,9 +25,67 @@ def test_cors_config_default():

def test_backend_configuration_from_env(monkeypatch):
monkeypatch.setenv("LOGGER_EXCLUDED_ENDPOINTS", '["/test"]')
monkeypatch.setenv("CORS_ALLOW_ORIGINS", '["http://test.com"]')

importlib.reload(config)
cfg = config.backend_config
assert "/test" in cfg.logger_config.excluded_endpoints
assert "http://test.com" in cfg.cors_config.allow_origins
monkeypatch.setenv("CORS_ALLOW_ORIGINS", '["http://localhost:5173"]')
monkeypatch.setenv("CORS_ALLOW_CREDENTIALS", "True")
monkeypatch.setenv("CORS_ALLOW_METHODS", '["*"]')
monkeypatch.setenv("CORS_ALLOW_HEADERS", '["*"]')

monkeypatch.setenv("GS_DATABASE_USER", "testuser")
monkeypatch.setenv("GS_DATABASE_PASSWORD", "testpassword")
monkeypatch.setenv("GS_DATABASE_LOCATION", "localhost")
monkeypatch.setenv("GS_DATABASE_PORT", "5432")
monkeypatch.setenv("GS_DATABASE_NAME", "testdb")

cfg = BackendConfiguration()

assert "/test" in cfg.logger.excluded_endpoints
assert "http://localhost:5173" in cfg.cors.allow_origins
assert cfg.db.user == "testuser"
assert cfg.db.password.get_secret_value() == "testpassword"
assert cfg.db.location == "localhost"
assert cfg.db.port == 5432
assert cfg.db.name == "testdb"


def test_database_connection_string(monkeypatch):
monkeypatch.setenv("GS_DATABASE_USER", "testuser")
monkeypatch.setenv("GS_DATABASE_PASSWORD", "testpassword")
monkeypatch.setenv("GS_DATABASE_LOCATION", "localhost")
monkeypatch.setenv("GS_DATABASE_PORT", "5432")
monkeypatch.setenv("GS_DATABASE_NAME", "testdb")

cfg = BackendConfiguration()
db = cfg.db

assert db.password.get_secret_value() == "testpassword"
expected_url = "postgresql://testuser:testpassword@localhost:5432/testdb"
assert db.connection_string == expected_url


def test_database_missing_env(monkeypatch):
monkeypatch.setenv("GS_DATABASE_USER", "testuser")
monkeypatch.setenv("GS_DATABASE_PASSWORD", "testpassword")
monkeypatch.setenv("GS_DATABASE_LOCATION", "localhost")
monkeypatch.setenv("GS_DATABASE_PORT", "5432")
monkeypatch.setenv("GS_DATABASE_NAME", "testdb")

monkeypatch.delenv("GS_DATABASE_PASSWORD")

with pytest.raises(ValidationError):
DatabaseConfig()


def test_invalid_env(monkeypatch):
monkeypatch.setenv("GS_DATABASE_PORT", "test")
monkeypatch.setenv("CORS_ALLOW_CREDENTIALS", "3")
monkeypatch.setenv("LOGGER_EXCLUDED_ENDPOINTS", "3")

with pytest.raises(ValidationError):
DatabaseConfig()

with pytest.raises(ValidationError):
CORSConfig()

with pytest.raises(ValidationError):
LoggerConfig()
Loading