Skip to content
Open
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
51 changes: 45 additions & 6 deletions src/ssb_dash_framework/modules/nspek/nspek.py
Original file line number Diff line number Diff line change
Expand Up @@ -953,10 +953,20 @@ class Naeringsspesifikasjon:
]
)

def __init__(self, time_units: list[str], db_user: str | None) -> None:
def __init__(
self,
time_units: list[str],
db_user: str | None,
db_host: str = "localhost",
db_port: int = 5432,
db_name: str = "nspek",
) -> None:
"""Explanation of module."""
set_nspek_connection(
db_user if db_user else "strukt-naering-developers@dapla-group-sa-p-ye.iam"
db_user if db_user else "strukt-naering-developers@dapla-group-sa-p-ye.iam",
host=db_host,
port=db_port,
database=db_name,
)
self.module_number = Naeringsspesifikasjon._id_number
self.module_name = self.__class__.__name__
Expand Down Expand Up @@ -3167,16 +3177,45 @@ def validate_nspek_data_exists(orgnr, aar, alert_store, refresh_data):
class NaeringsspesifikasjonTab(TabImplementation, Naeringsspesifikasjon):
"""NaeringsspesifikasjonTab is an implementation of the Naeringsspesifikasjon module as a tab in a Dash application."""

def __init__(self, time_units: list[str], db_user: str | None = None) -> None:
def __init__(
self,
time_units: list[str],
db_user: str | None = None,
db_host: str = "localhost",
db_port: int = 5432,
db_name: str = "nspek",
) -> None:
"""Initializes the NaeringsspesifikasjonTab class."""
Naeringsspesifikasjon.__init__(self, time_units=time_units, db_user=db_user)
Naeringsspesifikasjon.__init__(
self,
time_units=time_units,
db_user=db_user,
db_host=db_host,
db_port=db_port,
db_name=db_name,
)
TabImplementation.__init__(self)


class NaeringsspesifikasjonWindow(WindowImplementation, Naeringsspesifikasjon):
"""NaeringsspesifikasjonWindow is an implementation of the Naeringsspesifikasjon module as a tab in a Dash application."""

def __init__(self, time_units: list[str], db_user: str | None = None, **kwargs: Any) -> None:
def __init__(
self,
time_units: list[str],
db_user: str | None = None,
db_host: str = "localhost",
db_port: int = 5432,
db_name: str = "nspek",
**kwargs: Any,
) -> None:
"""Initializes the NaeringsspesifikasjonWindow class."""
Naeringsspesifikasjon.__init__(self, time_units=time_units, db_user=db_user)
Naeringsspesifikasjon.__init__(
self,
time_units=time_units,
db_user=db_user,
db_host=db_host,
db_port=db_port,
db_name=db_name,
)
WindowImplementation.__init__(self, **kwargs)
32 changes: 25 additions & 7 deletions src/ssb_dash_framework/modules/nspek/nspek_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,40 @@
_CONNECTION_CALLABLE_NSPEK: Callable[..., Any] | None = None


def set_nspek_connection(database_user: str | None = None) -> None:
"""Helper function to configure a pooled connection to a postgres database.
def _build_nspek_conn_url(
database_user: str,
host: str = "localhost",
port: int = 5432,
database: str = "nspek",
) -> str:
"""Build the psycopg ``conninfo`` URL for the nspek postgres connection."""
encoded_user = quote_plus(database_user)
return f"postgresql://{encoded_user}@{host}:{port}/{database}"

Check failure on line 26 in src/ssb_dash_framework/modules/nspek/nspek_utils.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add password protection to this database.

See more on https://sonarcloud.io/project/issues?id=statisticsnorway_ssb-dash-framework&issues=AZ76K49pJ052HC-oWn81&open=AZ76K49pJ052HC-oWn81&pullRequest=389


def set_nspek_connection(
database_user: str | None = None,
host: str = "localhost",
port: int = 5432,
database: str = "nspek",
) -> None:
"""Helper function to configure a pooled connection to the nspek postgres database.

Args:
database_url: Connection url for the database. Gets passed to psycopg_pool.ConnectionPool as conninfo argument.
database_user: Database user (IAM principal) to connect as. Defaults to the
``nspek-developers`` service account.
host: Database host. Defaults to "localhost" (e.g. a local CloudSQL proxy).
port: Database port. Defaults to 5432.
database: Database name. Defaults to "nspek". Override this (and host/port as
needed) when the nspek data lives in a differently named database.
"""
global _IS_POOLED_NSPEK, _CONNECTION_NSPEK, _CONNECTION_CALLABLE_NSPEK

DB_USER = (
database_user if database_user else "nspek-developers@dapla-group-sa-p-ye.iam"
)

encoded_user = quote_plus(DB_USER)
conn_url = f"postgresql://{encoded_user}@localhost:5432/nspek"
if DB_USER.startswith("nspek-developers"):
print(conn_url)
conn_url = _build_nspek_conn_url(DB_USER, host=host, port=port, database=database)

_IS_POOLED_NSPEK = True

Expand Down
59 changes: 59 additions & 0 deletions tests/test_nspek_connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""Tests for the configurable nspek postgres connection (host/port/database)."""

from unittest.mock import MagicMock
from unittest.mock import patch

from ibis import BaseBackend

from ssb_dash_framework.modules.nspek import nspek_utils


def test_build_nspek_conn_url_defaults() -> None:
"""Defaults reproduce the previous hardcoded localhost:5432/nspek URL."""
url = nspek_utils._build_nspek_conn_url("nspek-developers@dapla-group-sa-p-ye.iam")
assert url == (
"postgresql://nspek-developers%40dapla-group-sa-p-ye.iam@localhost:5432/nspek"

Check failure on line 15 in tests/test_nspek_connection.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add password protection to this database.

See more on https://sonarcloud.io/project/issues?id=statisticsnorway_ssb-dash-framework&issues=AZ76K5ABJ052HC-oWn82&open=AZ76K5ABJ052HC-oWn82&pullRequest=389
)


def test_build_nspek_conn_url_custom_target() -> None:
"""Host, port and database are all overridable."""
url = nspek_utils._build_nspek_conn_url(
"user@iam", host="10.0.0.5", port=6432, database="strukt_naering"

Check warning on line 22 in tests/test_nspek_connection.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make sure using this hardcoded IP address "10.0.0.5" is safe here.

See more on https://sonarcloud.io/project/issues?id=statisticsnorway_ssb-dash-framework&issues=AZ76K5ABJ052HC-oWn83&open=AZ76K5ABJ052HC-oWn83&pullRequest=389
)
assert url == "postgresql://user%40iam@10.0.0.5:6432/strukt_naering"

Check failure on line 24 in tests/test_nspek_connection.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add password protection to this database.

See more on https://sonarcloud.io/project/issues?id=statisticsnorway_ssb-dash-framework&issues=AZ76K5ABJ052HC-oWn84&open=AZ76K5ABJ052HC-oWn84&pullRequest=389


def test_set_nspek_connection_forwards_target_to_pool() -> None:
"""set_nspek_connection builds the conninfo from host/port/database and passes it on."""
with (
patch.object(nspek_utils, "ConnectionPool") as pool_cls,
patch.object(nspek_utils, "Backend") as backend,
):
# Make the post-construction validation pass without a real DB.
backend.from_connection.return_value = MagicMock(spec=BaseBackend)
nspek_utils.set_nspek_connection(
database_user="user@iam",
host="db.internal",
port=6432,
database="strukt_naering",
)

pool_cls.assert_called_once_with(
conninfo="postgresql://user%40iam@db.internal:6432/strukt_naering",

Check failure on line 43 in tests/test_nspek_connection.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add password protection to this database.

See more on https://sonarcloud.io/project/issues?id=statisticsnorway_ssb-dash-framework&issues=AZ76K5ABJ052HC-oWn85&open=AZ76K5ABJ052HC-oWn85&pullRequest=389
min_size=1,
max_size=1,
)


def test_set_nspek_connection_defaults_unchanged() -> None:
"""Omitting the new args keeps the original localhost:5432/nspek behavior."""
with (
patch.object(nspek_utils, "ConnectionPool") as pool_cls,
patch.object(nspek_utils, "Backend") as backend,
):
backend.from_connection.return_value = MagicMock(spec=BaseBackend)
nspek_utils.set_nspek_connection(database_user="nspek-developers@x")

_, kwargs = pool_cls.call_args
assert kwargs["conninfo"] == "postgresql://nspek-developers%40x@localhost:5432/nspek"

Check failure on line 59 in tests/test_nspek_connection.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add password protection to this database.

See more on https://sonarcloud.io/project/issues?id=statisticsnorway_ssb-dash-framework&issues=AZ76K5ABJ052HC-oWn86&open=AZ76K5ABJ052HC-oWn86&pullRequest=389
Loading