Skip to content

Commit

Permalink
Merge branch 'release-0.2.0' into feat/hamed-add-dollar-sign-value-cr…
Browse files Browse the repository at this point in the history
…edit-1412
  • Loading branch information
prv-proton authored Dec 12, 2024
2 parents 92773a3 + 390f6f1 commit 7fc8e8e
Show file tree
Hide file tree
Showing 21 changed files with 487 additions and 75 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/docker-auto-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ jobs:
LCFS_REDIS_PORT: 6379
LCFS_REDIS_PASSWORD: development_only
APP_ENVIRONMENT: dev
LCFS_CHES_CLIENT_ID: mock_client_id
LCFS_CHES_CLIENT_SECRET: mock_client_secret
LCFS_CHES_AUTH_URL: http://mock_auth_url
LCFS_CHES_SENDER_EMAIL: [email protected]
LCFS_CHES_SENDER_NAME: Mock Notification System
LCFS_CHES_EMAIL_URL: http://mock_email_url

- name: Upload pytest results
if: always()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,33 @@
Create Date: 2024-12-04 09:59:22.876386
"""

from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '9206124a098b'
down_revision = '26ab15f8ab18'
revision = "9206124a098b"
down_revision = "26ab15f8ab18"
branch_labels = None
depends_on = None


def upgrade():
# Add the column 'organization_name' to 'final_supply_equipment' table
op.add_column("final_supply_equipment", sa.Column("organization_name", sa.String(), nullable=True))
# Add the column 'organization_name' to 'final_supply_equipment' table with a default value
op.add_column(
"final_supply_equipment",
sa.Column("organization_name", sa.String(), nullable=False, server_default=""),
)

# Update existing rows to have the default value
op.execute(
"UPDATE final_supply_equipment SET organization_name = '' WHERE organization_name IS NULL"
)

# Remove the server default to prevent future rows from automatically getting the default value
op.alter_column("final_supply_equipment", "organization_name", server_default=None)


def downgrade():
# Remove the column 'organization_name' from 'final_supply_equipment' table
op.drop_column("final_supply_equipment", "organization_name")
op.drop_column("final_supply_equipment", "organization_name")
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import json
from lcfs.web.api.email.repo import CHESEmailRepository
import pytest

from unittest.mock import patch
from unittest.mock import patch, AsyncMock
from httpx import AsyncClient
from fastapi import FastAPI

Expand All @@ -16,6 +17,20 @@
)
from lcfs.services.s3.client import DocumentService

@pytest.fixture
def mock_email_repo():
return AsyncMock(spec=CHESEmailRepository)

@pytest.fixture
def mock_environment_vars():
with patch("lcfs.web.api.email.services.settings") as mock_settings:
mock_settings.ches_auth_url = "http://mock_auth_url"
mock_settings.ches_email_url = "http://mock_email_url"
mock_settings.ches_client_id = "mock_client_id"
mock_settings.ches_client_secret = "mock_client_secret"
mock_settings.ches_sender_email = "[email protected]"
mock_settings.ches_sender_name = "Mock Notification System"
yield mock_settings

# get_compliance_periods
@pytest.mark.anyio
Expand Down
27 changes: 26 additions & 1 deletion backend/lcfs/tests/compliance_report/test_update_service.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from fastapi import HTTPException
from lcfs.db.models.user.Role import RoleEnum
from lcfs.web.api.compliance_report.update_service import ComplianceReportUpdateService
from lcfs.web.api.notification.services import NotificationService
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from lcfs.db.models.compliance.ComplianceReport import ComplianceReport
Expand All @@ -24,6 +26,27 @@ def mock_user_has_roles():
yield mock


@pytest.fixture
def mock_notification_service():
mock_service = AsyncMock(spec=NotificationService)
with patch(
"lcfs.web.api.compliance_report.update_service.Depends",
return_value=mock_service
):
yield mock_service


@pytest.fixture
def mock_environment_vars():
with patch("lcfs.web.api.email.services.settings") as mock_settings:
mock_settings.ches_auth_url = "http://mock_auth_url"
mock_settings.ches_email_url = "http://mock_email_url"
mock_settings.ches_client_id = "mock_client_id"
mock_settings.ches_client_secret = "mock_client_secret"
mock_settings.ches_sender_email = "[email protected]"
mock_settings.ches_sender_name = "Mock Notification System"
yield mock_settings

# Mock for adjust_balance method within the OrganizationsService
@pytest.fixture
def mock_org_service():
Expand All @@ -35,7 +58,7 @@ def mock_org_service():
# update_compliance_report
@pytest.mark.anyio
async def test_update_compliance_report_status_change(
compliance_report_update_service, mock_repo
compliance_report_update_service, mock_repo, mock_notification_service
):
# Mock data
report_id = 1
Expand All @@ -55,6 +78,7 @@ async def test_update_compliance_report_status_change(
mock_repo.get_compliance_report_by_id.return_value = mock_report
mock_repo.get_compliance_report_status_by_desc.return_value = new_status
compliance_report_update_service.handle_status_change = AsyncMock()
compliance_report_update_service.notfn_service = mock_notification_service
mock_repo.update_compliance_report.return_value = mock_report

# Call the method
Expand All @@ -80,6 +104,7 @@ async def test_update_compliance_report_status_change(

assert mock_report.current_status == new_status
assert mock_report.supplemental_note == report_data.supplemental_note
mock_notification_service.send_notification.assert_called_once()


@pytest.mark.anyio
Expand Down
39 changes: 24 additions & 15 deletions backend/lcfs/tests/email/test_email_service.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from lcfs.web.api.base import NotificationTypeEnum
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from lcfs.web.api.email.repo import CHESEmailRepository
from lcfs.web.api.email.services import CHESEmailService
import os


@pytest.fixture
def mock_email_repo():
return AsyncMock(spec=CHESEmailRepository)


@pytest.fixture
def mock_environment_vars():
with patch("lcfs.web.api.email.services.settings") as mock_settings:
Expand All @@ -19,14 +22,15 @@ def mock_environment_vars():
mock_settings.ches_sender_name = "Mock Notification System"
yield mock_settings


@pytest.mark.anyio
async def test_send_notification_email_success(mock_email_repo, mock_environment_vars):
# Arrange
notification_type = "INITIATIVE_APPROVED"
notification_type = NotificationTypeEnum.BCEID__COMPLIANCE_REPORT__DIRECTOR_ASSESSMENT
notification_context = {
"subject": "Test Notification",
"user_name": "John Doe",
"message_body": "Test message content"
"message_body": "Test message content",
}
organization_id = 1

Expand All @@ -46,21 +50,24 @@ async def test_send_notification_email_success(mock_email_repo, mock_environment
# Assert
assert result is True
mock_email_repo.get_subscribed_user_emails.assert_called_once_with(
notification_type, organization_id
notification_type.value, organization_id # Ensure value is passed
)
service._render_email_template.assert_called_once_with(
notification_type, notification_context
notification_type.value, notification_context
)
service.send_email.assert_called_once()


@pytest.mark.anyio
async def test_send_notification_email_no_recipients(mock_email_repo, mock_environment_vars):
async def test_send_notification_email_no_recipients(
mock_email_repo, mock_environment_vars
):
# Arrange
notification_type = "INITIATIVE_APPROVED"
notification_type = NotificationTypeEnum.BCEID__TRANSFER__PARTNER_ACTIONS
notification_context = {
"subject": "Test Notification",
"user_name": "John Doe",
"message_body": "Test message content"
"message_body": "Test message content",
}
organization_id = 1

Expand All @@ -76,18 +83,19 @@ async def test_send_notification_email_no_recipients(mock_email_repo, mock_envir
# Assert
assert result is False
mock_email_repo.get_subscribed_user_emails.assert_called_once_with(
notification_type, organization_id
notification_type.value, organization_id # Ensure value is passed
)


@pytest.mark.anyio
async def test_get_ches_token_success(mock_environment_vars):
# Arrange
mock_token = "mock_access_token"
with patch('requests.post') as mock_post:
with patch("requests.post") as mock_post:
mock_response = MagicMock()
mock_response.json.return_value = {
"access_token": mock_token,
"expires_in": 3600
"access_token": mock_token,
"expires_in": 3600,
}
mock_post.return_value = mock_response

Expand All @@ -100,14 +108,15 @@ async def test_get_ches_token_success(mock_environment_vars):
assert token == mock_token
mock_post.assert_called_once()


@pytest.mark.anyio
async def test_get_ches_token_cached(mock_environment_vars):
# Arrange
with patch('requests.post') as mock_post:
with patch("requests.post") as mock_post:
mock_response = MagicMock()
mock_response.json.return_value = {
"access_token": "initial_token",
"expires_in": 3600
"access_token": "initial_token",
"expires_in": 3600,
}
mock_post.return_value = mock_response

Expand All @@ -124,4 +133,4 @@ async def test_get_ches_token_cached(mock_environment_vars):

# Assert
assert first_token == second_token
mock_post.assert_not_called()
mock_post.assert_not_called()
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ async def test_update_initiative_agreement(service, mock_repo, mock_request):
mock_repo.get_initiative_agreement_by_id.return_value = mock_agreement
mock_repo.get_initiative_agreement_status_by_name.return_value = mock_status
mock_repo.update_initiative_agreement.return_value = mock_agreement
service.notfn_service = AsyncMock()

update_data = InitiativeAgreementUpdateSchema(
initiative_agreement_id=1,
Expand Down
18 changes: 11 additions & 7 deletions backend/lcfs/tests/transfer/test_transfer_services.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pytest
from unittest.mock import AsyncMock
from unittest.mock import AsyncMock, patch
from lcfs.web.api.transfer.schema import TransferSchema
from datetime import date
from lcfs.db.models.transfer import Transfer
Expand Down Expand Up @@ -63,22 +63,26 @@ async def test_get_transfer_success(transfer_service, mock_transfer_repo):
@pytest.mark.anyio
async def test_create_transfer_success(transfer_service, mock_transfer_repo):
mock_transfer_repo.get_transfer_status_by_name.return_value = TransferStatus(
transfer_status_id=1, status="status"
transfer_status_id=1, status="Sent"
)
mock_transfer_repo.add_transfer_history.return_value = True

transfer_id = 1
transfer = TransferCreateSchema(
transfer_data = TransferCreateSchema(
transfer_id=transfer_id,
from_organization_id=1,
to_organization_id=2,
price_per_unit=5.75,
)
mock_transfer_repo.create_transfer.return_value = transfer
mock_transfer_repo.create_transfer.return_value = transfer_data

result = await transfer_service.create_transfer(transfer)
# Patch the _perform_notificaiton_call method
with patch.object(transfer_service, "_perform_notificaiton_call", AsyncMock()):
result = await transfer_service.create_transfer(transfer_data)

assert result.transfer_id == transfer_id
assert isinstance(result, TransferCreateSchema)
assert result.transfer_id == transfer_id
assert isinstance(result, TransferCreateSchema)
transfer_service._perform_notificaiton_call.assert_called_once()


@pytest.mark.anyio
Expand Down
22 changes: 22 additions & 0 deletions backend/lcfs/web/api/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,3 +372,25 @@ async def lcfs_cache_key_builder(

# Return the cache key
return cache_key

class NotificationTypeEnum(Enum):
BCEID__COMPLIANCE_REPORT__DIRECTOR_ASSESSMENT = "BCEID__COMPLIANCE_REPORT__DIRECTOR_ASSESSMENT"
BCEID__INITIATIVE_AGREEMENT__DIRECTOR_APPROVAL = "BCEID__INITIATIVE_AGREEMENT__DIRECTOR_APPROVAL"
BCEID__TRANSFER__DIRECTOR_DECISION = "BCEID__TRANSFER__DIRECTOR_DECISION"
BCEID__TRANSFER__PARTNER_ACTIONS = "BCEID__TRANSFER__PARTNER_ACTIONS"
IDIR_ANALYST__COMPLIANCE_REPORT__DIRECTOR_DECISION = "IDIR_ANALYST__COMPLIANCE_REPORT__DIRECTOR_DECISION"
IDIR_ANALYST__COMPLIANCE_REPORT__MANAGER_RECOMMENDATION = "IDIR_ANALYST__COMPLIANCE_REPORT__MANAGER_RECOMMENDATION"
IDIR_ANALYST__COMPLIANCE_REPORT__SUBMITTED_FOR_REVIEW = "IDIR_ANALYST__COMPLIANCE_REPORT__SUBMITTED_FOR_REVIEW"
IDIR_ANALYST__INITIATIVE_AGREEMENT__RETURNED_TO_ANALYST = "IDIR_ANALYST__INITIATIVE_AGREEMENT__RETURNED_TO_ANALYST"
IDIR_ANALYST__TRANSFER__DIRECTOR_RECORDED = "IDIR_ANALYST__TRANSFER__DIRECTOR_RECORDED"
IDIR_ANALYST__TRANSFER__RESCINDED_ACTION = "IDIR_ANALYST__TRANSFER__RESCINDED_ACTION"
IDIR_ANALYST__TRANSFER__SUBMITTED_FOR_REVIEW = "IDIR_ANALYST__TRANSFER__SUBMITTED_FOR_REVIEW"
IDIR_COMPLIANCE_MANAGER__COMPLIANCE_REPORT__ANALYST_RECOMMENDATION = "IDIR_COMPLIANCE_MANAGER__COMPLIANCE_REPORT__ANALYST_RECOMMENDATION"
IDIR_COMPLIANCE_MANAGER__COMPLIANCE_REPORT__DIRECTOR_ASSESSMENT = "IDIR_COMPLIANCE_MANAGER__COMPLIANCE_REPORT__DIRECTOR_ASSESSMENT"
IDIR_COMPLIANCE_MANAGER__COMPLIANCE_REPORT__SUBMITTED_FOR_REVIEW = "IDIR_COMPLIANCE_MANAGER__COMPLIANCE_REPORT__SUBMITTED_FOR_REVIEW"
IDIR_DIRECTOR__COMPLIANCE_REPORT__MANAGER_RECOMMENDATION = "IDIR_DIRECTOR__COMPLIANCE_REPORT__MANAGER_RECOMMENDATION"
IDIR_DIRECTOR__INITIATIVE_AGREEMENT__ANALYST_RECOMMENDATION = "IDIR_DIRECTOR__INITIATIVE_AGREEMENT__ANALYST_RECOMMENDATION"
IDIR_DIRECTOR__TRANSFER__ANALYST_RECOMMENDATION = "IDIR_DIRECTOR__TRANSFER__ANALYST_RECOMMENDATION"

def __str__(self):
return self.value
Loading

0 comments on commit 7fc8e8e

Please sign in to comment.