Skip to content

Commit

Permalink
refactor: ruff format src and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
narenaryan committed Dec 8, 2024
1 parent 7fffdf1 commit a5c90ee
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 23 deletions.
2 changes: 2 additions & 0 deletions src/whispr/utils/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

from whispr.logging import logger


def write_to_yaml_file(config: dict, file_path: str):
"""Writes a given config object to a file in YAML format"""
if not os.path.exists(file_path):
with open(file_path, "w", encoding="utf-8") as file:
yaml.dump(config, file)
logger.info(f"{file_path} has been created.")


def load_config(file_path: str) -> dict:
"""Loads a given config file"""
try:
Expand Down
7 changes: 3 additions & 4 deletions src/whispr/utils/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

from whispr.logging import logger


def execute_command(command: tuple, no_env: bool, secrets: dict):
"""Executes a Unix/Windows command.
Arg: `no_env` decides whether secrets are passed vai environment or K:V pairs in command arguments.
Arg: `no_env` decides whether secrets are passed vai environment or K:V pairs in command arguments.
"""
if not secrets:
secrets = {}
Expand All @@ -16,9 +17,7 @@ def execute_command(command: tuple, no_env: bool, secrets: dict):

if no_env:
# Pass as --env K=V format (secure)
usr_command.extend([
f"{k}={v}" for k,v in secrets.items()
])
usr_command.extend([f"{k}={v}" for k, v in secrets.items()])
else:
# Pass via environment (slightly insecure)
os.environ.update(secrets)
Expand Down
4 changes: 3 additions & 1 deletion tests/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ def test_get_azure_vault_client_no_url(self):
with self.assertRaises(ValueError):
VaultFactory.get_vault(**config)

def test_get_gcp_vault_client(self):
@patch("google.cloud.secretmanager.SecretManagerServiceClient")
def test_get_gcp_vault_client(self, mock_client):
"""Test GCPVault client"""
config = {
"vault": "gcp",
Expand All @@ -94,6 +95,7 @@ def test_get_gcp_vault_client(self):
}
vault_instance = VaultFactory.get_vault(**config)
self.assertIsInstance(vault_instance, GCPVault)
mock_client.assert_called_once()

def test_get_gcp_vault_client_no_project_id(self):
"""Test GCPVault raises exception when project_id is not defined in config"""
Expand Down
4 changes: 1 addition & 3 deletions tests/test_gcp.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
"""Tests for GCP module"""

import unittest
from unittest.mock import Mock, patch, MagicMock
from unittest.mock import MagicMock

import google.api_core.exceptions
import structlog

from whispr.vault import SimpleVault
from whispr.gcp import GCPVault


Expand Down
10 changes: 7 additions & 3 deletions tests/test_io_utils.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

import os
import yaml
import unittest

from unittest.mock import MagicMock, patch, mock_open
from whispr.utils.io import write_to_yaml_file, load_config


class IOUtilsTestCase(unittest.TestCase):
"""Unit tests for the file utilities: write_to_yaml_file and load_config."""

Expand All @@ -18,7 +18,9 @@ def setUp(self):
@patch("whispr.utils.io.logger", new_callable=lambda: MagicMock())
@patch("builtins.open", new_callable=mock_open)
@patch("os.path.exists", return_value=False)
def test_write_to_yaml_file_creates_file(self, mock_exists, mock_open_file, mock_logger):
def test_write_to_yaml_file_creates_file(
self, mock_exists, mock_open_file, mock_logger
):
"""Test that write_to_yaml_file creates a new file and writes config data as YAML."""
write_to_yaml_file(self.config, self.file_path)

Expand All @@ -29,7 +31,9 @@ def test_write_to_yaml_file_creates_file(self, mock_exists, mock_open_file, mock
@patch("whispr.utils.io.logger", new_callable=lambda: MagicMock())
@patch("builtins.open", new_callable=mock_open)
@patch("os.path.exists", return_value=True)
def test_write_to_yaml_file_does_not_overwrite_existing_file(self, mock_exists, mock_open_file, mock_logger):
def test_write_to_yaml_file_does_not_overwrite_existing_file(
self, mock_exists, mock_open_file, mock_logger
):
"""Test that write_to_yaml_file does not overwrite an existing file."""
write_to_yaml_file(self.config, self.file_path)

Expand Down
20 changes: 15 additions & 5 deletions tests/test_process_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,30 @@ def test_execute_command_with_no_env(self, mock_subprocess_run, mock_logger):
execute_command(self.command, self.no_env, self.secrets)

expected_command = ["echo", "Hello", "API_KEY=123456"]
mock_subprocess_run.assert_called_once_with(expected_command, env=os.environ, shell=False, check=True)
mock_subprocess_run.assert_called_once_with(
expected_command, env=os.environ, shell=False, check=True
)

@patch("whispr.utils.process.logger", new_callable=lambda: MagicMock())
@patch("subprocess.run")
@patch("os.environ.update")
def test_execute_command_with_env(self, mock_env_update, mock_subprocess_run, mock_logger):
def test_execute_command_with_env(
self, mock_env_update, mock_subprocess_run, mock_logger
):
"""Test execute_command with `no_env=False`, passing secrets via environment variables."""
execute_command(self.command, no_env=False, secrets=self.secrets)

mock_env_update.assert_called_once_with(self.secrets)
expected_command = ["echo", "Hello"]
mock_subprocess_run.assert_called_once_with(expected_command, env=os.environ, shell=False, check=True)
mock_subprocess_run.assert_called_once_with(
expected_command, env=os.environ, shell=False, check=True
)

@patch("whispr.utils.process.logger", new_callable=lambda: MagicMock())
@patch("subprocess.run", side_effect=subprocess.CalledProcessError(1, "test"))
def test_execute_command_called_process_error(self, mock_subprocess_run, mock_logger):
def test_execute_command_called_process_error(
self, mock_subprocess_run, mock_logger
):
"""Test execute_command handles CalledProcessError and logs an error message."""
with self.assertRaises(subprocess.CalledProcessError):
execute_command(self.command, no_env=True, secrets=self.secrets)
Expand All @@ -54,5 +62,7 @@ def test_execute_command_without_secrets(self, mock_subprocess_run, mock_logger)
execute_command(self.command, no_env=True, secrets={})

expected_command = ["echo", "Hello"]
mock_subprocess_run.assert_called_once_with(expected_command, env=os.environ, shell=False, check=True)
mock_subprocess_run.assert_called_once_with(
expected_command, env=os.environ, shell=False, check=True
)
mock_logger.error.assert_not_called()
24 changes: 17 additions & 7 deletions tests/test_vault_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,28 @@ def test_fetch_secrets_missing_config(self, mock_logger):
)

@patch("whispr.utils.vault.logger", new_callable=lambda: MagicMock())
@patch("whispr.utils.vault.VaultFactory.get_vault", side_effect=ValueError("Invalid vault type"))
@patch(
"whispr.utils.vault.VaultFactory.get_vault",
side_effect=ValueError("Invalid vault type"),
)
def test_fetch_secrets_invalid_vault(self, mock_get_vault, mock_logger):
"""Test fetch_secrets logs an error if the vault factory raises a ValueError."""
result = fetch_secrets({
"vault": "UNKOWN",
"secret_name": "test_secret",
})
result = fetch_secrets(
{
"vault": "UNKOWN",
"secret_name": "test_secret",
}
)

self.assertEqual(result, {})
mock_logger.error.assert_called_once_with("Error creating vault instance: Invalid vault type")
mock_logger.error.assert_called_once_with(
"Error creating vault instance: Invalid vault type"
)

@patch("whispr.utils.vault.dotenv_values", return_value={"API_KEY": "", "OTHER_KEY": ""})
@patch(
"whispr.utils.vault.dotenv_values",
return_value={"API_KEY": "", "OTHER_KEY": ""},
)
@patch("whispr.utils.vault.logger", new_callable=lambda: MagicMock())
def test_get_filled_secrets_partial_match(self, mock_logger, mock_dotenv_values):
"""Test get_filled_secrets fills only matching secrets from vault_secrets."""
Expand Down

0 comments on commit a5c90ee

Please sign in to comment.