-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
1,611 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from dataclasses import dataclass | ||
from typing import List | ||
|
||
from mypy_boto3_organizations.type_defs import AccountTypeDef | ||
|
||
@dataclass | ||
class AccountType(AccountTypeDef): | ||
pass | ||
|
||
@dataclass | ||
class AccountTypeWithTags(AccountType): | ||
Tags: List[dict] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import datetime | ||
from json import JSONEncoder | ||
|
||
class JSONDateTimeEncoder(JSONEncoder): | ||
'''Encode JSON when datetime objects are present''' | ||
|
||
def default(self, obj): | ||
if isinstance(obj, (datetime.datetime, datetime.date)): | ||
return obj.isoformat() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,15 @@ | |
import jsonschema | ||
import os | ||
from types import ModuleType | ||
from typing import Generator | ||
from typing import Generator, List | ||
|
||
import pytest | ||
from pytest_mock import MockerFixture | ||
|
||
|
||
import boto3 | ||
from mypy_boto3_organizations import OrganizationsClient | ||
from mypy_boto3_organizations.type_defs import AccountTypeDef, TagTypeDef | ||
from mypy_boto3_sns import SNSClient | ||
from moto import mock_aws | ||
|
||
|
@@ -59,18 +61,69 @@ def mocked_aws(aws_credentials): | |
with mock_aws(): | ||
yield | ||
|
||
@pytest.fixture() | ||
def mock_orgs_client(mocked_aws) -> Generator[OrganizationsClient, None, None]: | ||
orgs_client = boto3.client('organizations') | ||
yield orgs_client | ||
|
||
@pytest.fixture() | ||
def mock_sns_client(mocked_aws) -> Generator[SNSClient, None, None]: | ||
sns_client = boto3.client('sns') | ||
yield sns_client | ||
|
||
@pytest.fixture() | ||
def mock_sns_topic_name(mock_sns_client) -> str: | ||
def mock_sns_topic_arn(mock_sns_client) -> str: | ||
'''Create a mock resource''' | ||
mock_topic_name = 'MockTopic' | ||
mock_sns_client.create_topic(Name=mock_topic_name) | ||
return mock_topic_name | ||
r = mock_sns_client.create_topic(Name=mock_topic_name) | ||
return r.get('TopicArn') | ||
|
||
@pytest.fixture() | ||
def mock_organization(mock_orgs_client) -> None: | ||
'''Mock organization''' | ||
mock_orgs_client.create_organization() | ||
|
||
|
||
@pytest.fixture() | ||
def mock_account( | ||
mock_orgs_client: OrganizationsClient, | ||
mock_organization | ||
) -> AccountTypeDef: | ||
'''Mock account''' | ||
account_config = { | ||
'Email': '[email protected]', | ||
'AccountName': 'Mock Account', | ||
'Tags': [ | ||
{ | ||
"Key": "org:system", | ||
"Value": "mock_system" | ||
}, | ||
{ | ||
"Key": "org:domain", | ||
"Value": "mock_domain" | ||
}, | ||
{ | ||
"Key": "org:owner", | ||
"Value": "group:mock_group" | ||
} | ||
] | ||
} | ||
|
||
response = mock_orgs_client.create_account(**account_config) | ||
account_id = response.get('CreateAccountStatus', {}).get('AccountId', '') | ||
return mock_orgs_client.describe_account(AccountId=account_id).get('Account') | ||
|
||
|
||
@pytest.fixture() | ||
def mock_account_tags( | ||
mock_orgs_client: OrganizationsClient, | ||
mock_account: AccountTypeDef, | ||
) -> List[TagTypeDef]: | ||
'''Return account tags''' | ||
return mock_orgs_client.list_tags_for_resource( | ||
ResourceId=mock_account.get('Id', '') | ||
).get('Tags', []) | ||
|
||
|
||
# Function | ||
@pytest.fixture() | ||
|
@@ -80,7 +133,7 @@ def mock_context(function_name=FN_NAME): | |
|
||
@pytest.fixture() | ||
def mock_fn( | ||
mock_sns_topic_name: str, | ||
mock_sns_topic_arn: str, | ||
mocker: MockerFixture | ||
) -> Generator[ModuleType, None, None]: | ||
'''Return mocked function''' | ||
|
@@ -89,7 +142,7 @@ def mock_fn( | |
# NOTE: use mocker to mock any top-level variables outside of the handler function. | ||
mocker.patch( | ||
'src.handlers.ListAccounts.function.SNS_TOPIC_ARN', | ||
mock_sns_topic_name | ||
mock_sns_topic_arn | ||
) | ||
|
||
yield fn | ||
|
@@ -103,20 +156,54 @@ def test_validate_event(mock_event, event_schema): | |
|
||
|
||
### Code Tests | ||
def test__get_account_tags( | ||
mock_fn: ModuleType, | ||
mock_account: AccountTypeDef, | ||
mock_account_tags: List[TagTypeDef], | ||
): | ||
'''Test _get_account_tags function''' | ||
account_with_tags = mock_fn._get_account_tags([mock_account])[0] | ||
assert 'Tags' in account_with_tags | ||
assert len(account_with_tags['Tags']) > 0 | ||
assert account_with_tags['Tags'] == mock_account_tags | ||
|
||
|
||
def test__list_all_accounts( | ||
mock_fn: ModuleType, | ||
mock_orgs_client: OrganizationsClient, | ||
mock_account: AccountTypeDef, | ||
): | ||
'''Test _list_all_accounts function''' | ||
# Call the function | ||
accounts = mock_fn._list_all_accounts() | ||
account_ids = [account.get('Id', '') for account in accounts] | ||
|
||
# Assertions | ||
assert len(accounts) > 0 | ||
assert mock_account.get('Id') in account_ids | ||
|
||
|
||
def test__publish_accounts( | ||
mock_fn: ModuleType, | ||
mock_account: AccountTypeDef, | ||
): | ||
'''Test _publish_accounts function''' | ||
account_with_tags = mock_fn._get_account_tags([mock_account])[0] | ||
response = mock_fn._publish_accounts([account_with_tags]) | ||
assert len(response) > 0 | ||
|
||
|
||
def test__main( | ||
mock_fn: ModuleType, | ||
mock_data | ||
): | ||
'''Test _main function''' | ||
mock_fn._main(mock_data) | ||
mock_fn._main() | ||
|
||
|
||
def test_handler( | ||
mock_fn: ModuleType, | ||
mock_context, | ||
mock_event: EventBridgeEvent, | ||
mock_data | ||
mock_sns_client: SNSClient, | ||
): | ||
'''Test calling handler''' | ||
# Call the function | ||
|