Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prevent error when addons is null #2722

Merged
merged 2 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 2 additions & 3 deletions api/organisations/chargebee/chargebee.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,7 @@ def _convert_chargebee_subscription_to_dictionary(
) -> dict:
chargebee_subscription_dict = vars(chargebee_subscription)
# convert the addons into a list of dictionaries since vars don't do it recursively
chargebee_subscription_dict["addons"] = [
vars(addon) for addon in chargebee_subscription.addons
]
addons = chargebee_subscription.addons or []
chargebee_subscription_dict["addons"] = [vars(addon) for addon in addons]

return chargebee_subscription_dict
65 changes: 61 additions & 4 deletions api/tests/unit/organisations/chargebee/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import typing

import pytest
from pytest_mock import MockerFixture
from tests.unit.organisations.chargebee.test_unit_chargebee_chargebee import (
Expand All @@ -7,6 +9,14 @@

from organisations.chargebee.metadata import ChargebeeObjMetadata

ChargebeeCacheMocker = typing.Callable[
[
typing.Optional[dict[str, ChargebeeObjMetadata]],
typing.Optional[dict[str, ChargebeeObjMetadata]],
],
None,
]


@pytest.fixture
def chargebee_object_metadata():
Expand All @@ -17,6 +27,36 @@ def chargebee_object_metadata():
def mock_subscription_response(
mocker: MockerFixture,
chargebee_object_metadata: ChargebeeObjMetadata,
chargebee_cache_mocker: ChargebeeCacheMocker,
) -> MockChargeBeeSubscriptionResponse:
# Given
plan_id = "plan-id"
subscription_id = "subscription-id"
customer_email = "[email protected]"

# Let's create a (mocked) subscription object
mock_subscription_response = MockChargeBeeSubscriptionResponse(
subscription_id=subscription_id,
plan_id=plan_id,
customer_email=customer_email,
addons=None,
)
mocked_chargebee = mocker.patch("organisations.chargebee.chargebee.chargebee")

# tie that subscription object to the mocked chargebee object
mocked_chargebee.Subscription.retrieve.return_value = mock_subscription_response

# now, let's mock chargebee cache object
chargebee_cache_mocker({plan_id: chargebee_object_metadata}, None)

return mock_subscription_response


@pytest.fixture
def mock_subscription_response_with_addons(
mocker: MockerFixture,
chargebee_object_metadata: ChargebeeObjMetadata,
chargebee_cache_mocker: ChargebeeCacheMocker,
) -> MockChargeBeeSubscriptionResponse:
# Given
plan_id = "plan-id"
Expand All @@ -37,10 +77,27 @@ def mock_subscription_response(
mocked_chargebee.Subscription.retrieve.return_value = mock_subscription_response

# now, let's mock chargebee cache object
mocked_chargebee_cache = mocker.patch(
"organisations.chargebee.chargebee.ChargebeeCache", autospec=True
chargebee_cache_mocker(
{plan_id: chargebee_object_metadata}, {addon_id: chargebee_object_metadata}
)
mocked_chargebee_cache.return_value.plans = {plan_id: chargebee_object_metadata}
mocked_chargebee_cache.return_value.addons = {addon_id: chargebee_object_metadata}

return mock_subscription_response


@pytest.fixture()
def chargebee_cache_mocker(
mocker,
) -> typing.Callable[
[dict[str, ChargebeeObjMetadata], dict[str, ChargebeeObjMetadata]], None
]:
def mock_chargebee_cache(
plans_data: dict[str, ChargebeeObjMetadata] = None,
addons_data: dict[str, ChargebeeObjMetadata] = None,
) -> None:
mocked_chargebee_cache = mocker.patch(
"organisations.chargebee.chargebee.ChargebeeCache", autospec=True
)
mocked_chargebee_cache.return_value.plans = plans_data or {}
mocked_chargebee_cache.return_value.addons = addons_data or {}

return mock_chargebee_cache
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ def test_get_hosted_page_url_for_subscription_upgrade(self):


def test_extract_subscription_metadata(
mock_subscription_response, chargebee_object_metadata: ChargebeeObjMetadata
mock_subscription_response_with_addons,
chargebee_object_metadata: ChargebeeObjMetadata,
):
# Given
status = "status"
Expand Down Expand Up @@ -300,7 +301,8 @@ def test_extract_subscription_metadata(


def test_extract_subscription_metadata_when_addon_list_is_empty(
mock_subscription_response, chargebee_object_metadata: ChargebeeObjMetadata
mock_subscription_response_with_addons,
chargebee_object_metadata: ChargebeeObjMetadata,
):
# Given
status = "status"
Expand Down Expand Up @@ -329,16 +331,19 @@ def test_extract_subscription_metadata_when_addon_list_is_empty(


def test_get_subscription_metadata_from_id(
mock_subscription_response, chargebee_object_metadata: ChargebeeObjMetadata
mock_subscription_response_with_addons: MockChargeBeeSubscriptionResponse,
chargebee_object_metadata: ChargebeeObjMetadata,
):
# Given
customer_email = "[email protected]"
subscription_id = mock_subscription_response.subscription.id
subscription_id = mock_subscription_response_with_addons.subscription.id

# When
subscription_metadata = get_subscription_metadata_from_id(subscription_id)

# Then
# Values here are multiplied by 2 because the both the plan and the addon included in
# the mock_subscription_response_with_addons fixture contain the same values.
assert subscription_metadata.seats == chargebee_object_metadata.seats * 2
assert subscription_metadata.api_calls == chargebee_object_metadata.api_calls * 2
assert subscription_metadata.projects == chargebee_object_metadata.projects * 2
Expand Down Expand Up @@ -425,6 +430,23 @@ def test_get_subscription_metadata_from_id_returns_none_for_invalid_subscription
assert subscription_metadata is None


def test_get_subscription_metadata_from_id_returns_valid_metadata_if_addons_is_none(
mock_subscription_response: MockChargeBeeSubscriptionResponse,
chargebee_object_metadata: ChargebeeObjMetadata,
) -> None:
# Given
mock_subscription_response.addons = None
subscription_id = mock_subscription_response.subscription.id

# When
subscription_metadata = get_subscription_metadata_from_id(subscription_id)

# Then
assert subscription_metadata.seats == chargebee_object_metadata.seats
assert subscription_metadata.api_calls == chargebee_object_metadata.api_calls
assert subscription_metadata.projects == chargebee_object_metadata.projects


def test_add_single_seat_with_existing_addon(mocker):
# Given
plan_id = "plan-id"
Expand Down