439 lines
26 KiB
Python
439 lines
26 KiB
Python
import logging
|
||
from collections import OrderedDict
|
||
from unittest.mock import patch
|
||
|
||
import pytest
|
||
from requests.exceptions import ConnectTimeout, ReadTimeout
|
||
from src.config.objects import LastFetchDatetime, TargetObject
|
||
from src.error.exceptions import SalesforceAPIException
|
||
from src.fetch_crm_data_process import fetch_crm_data_process
|
||
from src.system_var.constants import FETCH_JP_NAME
|
||
from src.util.execute_datetime import ExecuteDateTime
|
||
|
||
from .test_utils.log_message import generate_log_message_tuple
|
||
|
||
common_target_object_dict = {
|
||
'object_name': 'Account',
|
||
'columns': [
|
||
'Id',
|
||
'AccountNumber',
|
||
'LastModifiedDate',
|
||
'LastModifiedById',
|
||
'SystemModstamp',
|
||
'IsDeleted'
|
||
]
|
||
}
|
||
|
||
common_last_fetch_datetime_dict = {
|
||
'last_fetch_datetime_from': '2000-01-01T00:00:00.000Z',
|
||
'last_fetch_datetime_to': '2010-01-01T00:00:00.000Z',
|
||
}
|
||
|
||
common_execute_datetime = ExecuteDateTime()
|
||
common_target_object = TargetObject(common_target_object_dict, common_execute_datetime)
|
||
common_last_fetch_datetime = LastFetchDatetime(common_last_fetch_datetime_dict, common_execute_datetime)
|
||
|
||
common_expect = [
|
||
OrderedDict([
|
||
('attributes', OrderedDict([('type', 'Account'), ('url', '/services/data/v1.0/sobjects/Account/TEST001')])),
|
||
('Id', 'TEST001'),
|
||
('AccountNumber', 'test001'),
|
||
('LastModifiedDate', '2022-06-01T00:00:00.000+0000'),
|
||
('LastModifiedById', 1.234567E+6),
|
||
('SystemModstamp', '2022-06-01T00:00:00.000+0000'),
|
||
('IsDeleted', False)
|
||
]),
|
||
OrderedDict([
|
||
('attributes', OrderedDict([('type', 'Account'), ('url', '/services/data/v1.0/sobjects/Account/TEST002')])),
|
||
('Id', 'TEST002'),
|
||
('AccountNumber', 'test002'),
|
||
('LastModifiedDate', '2022-06-01T00:00:00.000+0000'),
|
||
('LastModifiedById', 1.234567E+6),
|
||
('SystemModstamp', '2022-06-01T00:00:00.000+0000'),
|
||
('IsDeleted', False)
|
||
]),
|
||
OrderedDict([
|
||
('attributes', OrderedDict([('type', 'Account'), ('url', '/services/data/v1.0/sobjects/Account/TEST002')])),
|
||
('Id', 'TEST002'),
|
||
('AccountNumber', 'test002'),
|
||
('LastModifiedDate', '2022-06-01T00:00:00.000+0000'),
|
||
('LastModifiedById', 1.234567E+6),
|
||
('SystemModstamp', '2022-06-01T00:00:00.000+0000'),
|
||
('IsDeleted', False)
|
||
]),
|
||
]
|
||
|
||
|
||
class TestFetchCrmDataProcess:
|
||
|
||
def test_run_process_success(self, monkeypatch, caplog):
|
||
"""
|
||
Cases:
|
||
CRMデータ取得処理が正常終了し、期待通りの結果が返ること
|
||
Arranges:
|
||
- SalesforceApiClientクラスをモック化し、固定の値を返すようにする
|
||
Expects:
|
||
- CRMから取得した取得オブジェクトのリストが返却される
|
||
- CRMデータ取得処理の仕様に沿った正常系ログが出力されること(デバッグログは除く)
|
||
"""
|
||
# Arrange
|
||
|
||
# モック化
|
||
with patch('src.fetch_crm_data_process.SalesforceApiClient') as mock:
|
||
instance = mock.return_value
|
||
instance.fetch_sf_count.return_value = len(common_expect)
|
||
instance.fetch_sf_data.return_value = common_expect
|
||
# Act
|
||
actual_crm_data_response = fetch_crm_data_process(common_target_object, common_last_fetch_datetime)
|
||
|
||
# Assert
|
||
|
||
# 返り値の期待値チェック
|
||
assert isinstance(actual_crm_data_response, list)
|
||
assert isinstance(actual_crm_data_response[0], OrderedDict)
|
||
assert actual_crm_data_response == common_expect
|
||
|
||
# ログの確認
|
||
assert generate_log_message_tuple(log_message='I-FETCH-01 [Account] のCRMからのデータ取得処理を開始します') in caplog.record_tuples
|
||
assert generate_log_message_tuple(log_message='I-FETCH-02 [Account] の件数取得を開始します') in caplog.record_tuples
|
||
assert generate_log_message_tuple(log_message='I-FETCH-03 [Account] の件数:[3]') in caplog.record_tuples
|
||
assert generate_log_message_tuple(log_message='I-FETCH-04 [Account] のレコード取得を開始します') in caplog.record_tuples
|
||
assert generate_log_message_tuple(log_message='I-FETCH-05 [Account] のレコード取得が成功しました') in caplog.record_tuples
|
||
assert generate_log_message_tuple(log_message='I-FETCH-06 [Account] のCRMからのデータ取得処理を終了します') in caplog.record_tuples
|
||
|
||
def test_call_depended_modules(self):
|
||
"""
|
||
Cases:
|
||
CRMデータ取得処理内で依存しているモジュールが正しく呼ばれていること
|
||
Arranges:
|
||
- CRMデータ取得処理の依存モジュールをモック化する
|
||
Expects:
|
||
- 依存しているモジュールが正しく呼ばれている
|
||
"""
|
||
|
||
# Arrange
|
||
with patch('src.fetch_crm_data_process.CounterObject', ) as mock_counter, \
|
||
patch('src.fetch_crm_data_process.SOQLBuilder') as mock_soql_builder, \
|
||
patch('src.fetch_crm_data_process.SalesforceApiClient') as mock_api_client:
|
||
# モック化
|
||
mock_counter_inst = mock_counter.return_value
|
||
mock_counter_inst.describe.return_value = 1
|
||
mock_counter_inst.increment.return_value = 1
|
||
mock_builder_inst = mock_soql_builder.return_value
|
||
mock_builder_inst.create_count_soql.return_value = ''
|
||
mock_builder_inst.create_fetch_soql.return_value = ''
|
||
mock_client_inst = mock_api_client.return_value
|
||
mock_client_inst.fetch_sf_count.return_value = 1
|
||
mock_client_inst.fetch_sf_data.return_value = common_expect
|
||
|
||
# Act
|
||
fetch_crm_data_process(common_target_object, common_last_fetch_datetime)
|
||
|
||
# Assert
|
||
|
||
assert mock_counter.call_count == 2, 'リトライカウント用クラスのインスタンスが生成されていること'
|
||
assert mock_counter_inst.describe.called is False, 'リトライ用のカウントが取得されていないこと'
|
||
assert mock_counter_inst.increment.called is False, 'リトライ用のカウントが足されていないこと'
|
||
assert mock_soql_builder.call_count == 1, 'SOQL生成クラスのインスタンスが生成されていること'
|
||
assert mock_builder_inst.create_count_soql.called is True, '件数取得SOQLが生成されていること'
|
||
assert mock_builder_inst.create_fetch_soql.called is True, 'データ取得SOQLが生成されていること'
|
||
assert mock_api_client.call_count == 2, 'Salesforce APIクライアントのインスタンスが生成されていること'
|
||
assert mock_client_inst.fetch_sf_count.called is True, '件数の取得が呼ばれていること'
|
||
assert mock_client_inst.fetch_sf_data.called is True, 'レコードの取得が呼ばれていること'
|
||
|
||
def test_raise_create_count_soql(self, monkeypatch, caplog):
|
||
"""
|
||
Cases:
|
||
件数取得用SOQLが生成できない場合、エラーが発生すること
|
||
Arranges:
|
||
- 件数取得用SOQL生成処理で例外が発生するようにする
|
||
Expects:
|
||
- 例外が発生する
|
||
- データ件数取得に失敗した旨のエラーが出力される
|
||
"""
|
||
|
||
# Arrange
|
||
with patch('src.fetch_crm_data_process.SOQLBuilder') as mock_soql_builder, \
|
||
patch('src.fetch_crm_data_process.SalesforceApiClient') as mock_api_client:
|
||
# モック化
|
||
mock_builder_inst = mock_soql_builder.return_value
|
||
mock_builder_inst.create_count_soql.side_effect = Exception('生成エラー')
|
||
mock_builder_inst.create_fetch_soql.return_value = ''
|
||
mock_client_inst = mock_api_client.return_value
|
||
mock_client_inst.fetch_sf_count.return_value = 1
|
||
mock_client_inst.fetch_sf_data.return_value = common_expect
|
||
|
||
# Act
|
||
with pytest.raises(SalesforceAPIException) as e:
|
||
fetch_crm_data_process(common_target_object, common_last_fetch_datetime)
|
||
|
||
# Assert
|
||
|
||
assert e.value.error_id == 'E-FETCH-01'
|
||
assert e.value.func_name == FETCH_JP_NAME
|
||
assert e.value.args[0] == f'[Account] の件数取得に失敗しました エラー内容:[生成エラー]'
|
||
|
||
def test_raise_create_fetch_soql(self, monkeypatch, caplog):
|
||
"""
|
||
Cases:
|
||
データ取得用SOQLが生成できない場合、エラーが発生すること
|
||
Arranges:
|
||
- データ取得用SOQL生成処理で例外が発生するようにする
|
||
Expects:
|
||
- 例外が発生する
|
||
- データ取得に失敗した旨のエラーが出力される
|
||
"""
|
||
|
||
# Arrange
|
||
with patch('src.fetch_crm_data_process.SOQLBuilder') as mock_soql_builder, \
|
||
patch('src.fetch_crm_data_process.SalesforceApiClient') as mock_api_client:
|
||
# モック化
|
||
mock_builder_inst = mock_soql_builder.return_value
|
||
mock_builder_inst.create_count_soql.return_value = ''
|
||
mock_builder_inst.create_fetch_soql.side_effect = Exception('生成エラー')
|
||
mock_client_inst = mock_api_client.return_value
|
||
mock_client_inst.fetch_sf_count.return_value = 1
|
||
mock_client_inst.fetch_sf_data.return_value = common_expect
|
||
|
||
# Act
|
||
with pytest.raises(SalesforceAPIException) as e:
|
||
fetch_crm_data_process(common_target_object, common_last_fetch_datetime)
|
||
|
||
# Assert
|
||
|
||
assert e.value.error_id == 'E-FETCH-02'
|
||
assert e.value.func_name == FETCH_JP_NAME
|
||
assert e.value.args[0] == f'[Account] のレコード取得に失敗しました エラー内容:[生成エラー]'
|
||
|
||
@pytest.mark.parametrize('timeout_env_name, exception, expect_message', [
|
||
('CRM_AUTH_TIMEOUT', ConnectTimeout('接続タイムアウト'), 'W-FETCH-01 CRMの接続処理がタイムアウトしため、リトライします:[1] エラー内容:[接続タイムアウト]'),
|
||
('CRM_GET_RECORD_COUNT_TIMEOUT', ReadTimeout('読み取りタイムアウト'), 'W-FETCH-02 [Account] の件数取得処理がタイムアウトしたため、リトライします:[1] エラー内容:[読み取りタイムアウト]'),
|
||
('CRM_AUTH_TIMEOUT', Exception('予期せぬ例外'), 'W-FETCH-03 [Account] の件数取得に失敗したため、リトライします エラー内容:[予期せぬ例外]'),
|
||
], ids=['connection_timeout', 'read_timeout', 'unexpected_exception'])
|
||
def test_raise_fetch_sf_count_with_retry_success(self, monkeypatch, caplog, timeout_env_name, exception, expect_message):
|
||
"""
|
||
Cases:
|
||
1. データ件数取得処理で接続タイムアウト例外が発生した場合、リトライした結果復旧し、正常終了すること
|
||
2. データ件数取得処理で読み取りタイムアウト例外が発生した場合、リトライした結果復旧し、正常終了すること
|
||
3. データ件数取得処理で予期せぬ例外が発生した場合、リトライした結果復旧し、正常終了すること
|
||
Arranges:
|
||
- データ件数取得処理の最大リトライ試行回数を3に設定する
|
||
- timeout_env_nameに指定されたリトライタイムアウト時間の秒数を1に設定する
|
||
- データ件数取得処理の初回に接続タイムアウト例外が発生するようにする
|
||
Expects:
|
||
- 正常終了する
|
||
- データ件数取得に失敗した旨のエラーが出力されない
|
||
"""
|
||
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_MAX_RETRY_ATTEMPT', 3)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_RETRY_MAX_INTERVAL', 1)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_RETRY_MIN_INTERVAL', 1)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_RETRY_INTERVAL', 1)
|
||
monkeypatch.setattr(f'src.fetch_crm_data_process.{timeout_env_name}', 1)
|
||
# Arrange
|
||
with patch('src.fetch_crm_data_process.CounterObject', ) as mock_counter, \
|
||
patch('src.fetch_crm_data_process.SOQLBuilder') as mock_soql_builder, \
|
||
patch('src.fetch_crm_data_process.SalesforceApiClient') as mock_api_client:
|
||
# モック化
|
||
mock_counter_inst = mock_counter.return_value
|
||
mock_counter_inst.describe.side_effect = [1, 2, 3]
|
||
mock_counter_inst.increment.side_effect = [2, 3, 4]
|
||
mock_builder_inst = mock_soql_builder.return_value
|
||
mock_builder_inst.create_count_soql.return_value = ''
|
||
mock_builder_inst.create_fetch_soql.return_value = ''
|
||
mock_client_inst = mock_api_client.return_value
|
||
mock_client_inst.fetch_sf_count.side_effect = [exception, len(common_expect)]
|
||
mock_client_inst.fetch_sf_data.return_value = common_expect
|
||
# Act
|
||
fetch_crm_data_process(common_target_object, common_last_fetch_datetime)
|
||
|
||
# Assert
|
||
|
||
assert mock_counter_inst.describe.call_count == 1
|
||
assert mock_counter_inst.increment.call_count == 1
|
||
|
||
assert generate_log_message_tuple(
|
||
log_level=logging.WARNING,
|
||
log_message=expect_message) in caplog.record_tuples
|
||
called_log_counts = len([log for log in caplog.messages if log == expect_message])
|
||
assert called_log_counts == 1
|
||
assert generate_log_message_tuple(log_message='I-FETCH-06 [Account] のCRMからのデータ取得処理を終了します') in caplog.record_tuples
|
||
|
||
@pytest.mark.parametrize('timeout_env_name, exception, expect_message', [
|
||
('CRM_AUTH_TIMEOUT', ConnectTimeout('接続タイムアウト'), 'W-FETCH-01 CRMの接続処理がタイムアウトしため、リトライします:[1] エラー内容:[接続タイムアウト]'),
|
||
('CRM_GET_RECORD_COUNT_TIMEOUT', ReadTimeout('読み取りタイムアウト'), 'W-FETCH-02 [Account] の件数取得処理がタイムアウトしたため、リトライします:[1] エラー内容:[読み取りタイムアウト]'),
|
||
('CRM_AUTH_TIMEOUT', Exception('予期せぬ例外'), 'W-FETCH-03 [Account] の件数取得に失敗したため、リトライします エラー内容:[予期せぬ例外]'),
|
||
], ids=['connection_timeout', 'read_timeout', 'unexpected_exception'])
|
||
def test_raise_fetch_sf_count_with_retry_fail(self, monkeypatch, caplog, timeout_env_name, exception, expect_message):
|
||
"""
|
||
Cases:
|
||
1. データ件数取得処理で接続タイムアウト例外が発生した場合、リトライした結果復旧せず、異常終了すること
|
||
2. データ件数取得処理で読み取りタイムアウト例外が発生した場合、リトライした結果復旧せず、異常終了すること
|
||
3. データ件数取得処理で予期せぬ例外が発生した場合、リトライした結果復旧せず、異常終了すること
|
||
Arranges:
|
||
- データ件数取得処理の最大リトライ試行回数を3に設定する
|
||
- timeout_env_nameに指定されたリトライタイムアウト時間の秒数を1に設定する
|
||
- データ件数取得処理の1回目、2回目、3回目で接続タイムアウト例外が発生するようにする
|
||
Expects:
|
||
- 異常終了する
|
||
- データ件数取得に失敗した旨のエラーが出力される
|
||
"""
|
||
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_MAX_RETRY_ATTEMPT', 3)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_RETRY_MAX_INTERVAL', 1)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_RETRY_MIN_INTERVAL', 1)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_RETRY_INTERVAL', 1)
|
||
monkeypatch.setattr(f'src.fetch_crm_data_process.{timeout_env_name}', 1)
|
||
# Arrange
|
||
with patch('src.fetch_crm_data_process.CounterObject', ) as mock_counter, \
|
||
patch('src.fetch_crm_data_process.SOQLBuilder') as mock_soql_builder, \
|
||
patch('src.fetch_crm_data_process.SalesforceApiClient') as mock_api_client:
|
||
# モック化
|
||
mock_counter_inst = mock_counter.return_value
|
||
mock_counter_inst.describe.side_effect = [1, 2, 3]
|
||
mock_counter_inst.increment.side_effect = [2, 3, 4]
|
||
mock_builder_inst = mock_soql_builder.return_value
|
||
mock_builder_inst.create_count_soql.return_value = ''
|
||
mock_builder_inst.create_fetch_soql.return_value = ''
|
||
mock_client_inst = mock_api_client.return_value
|
||
mock_client_inst.fetch_sf_count.side_effect = [exception, exception, exception]
|
||
mock_client_inst.fetch_sf_data.return_value = common_expect
|
||
# Act
|
||
with pytest.raises(SalesforceAPIException) as e:
|
||
fetch_crm_data_process(common_target_object, common_last_fetch_datetime)
|
||
|
||
# Assert
|
||
|
||
# 取得は3回行われる
|
||
assert mock_counter_inst.describe.call_count == 3
|
||
# 足し込みは2回のみ
|
||
assert mock_counter_inst.increment.call_count == 2
|
||
|
||
assert generate_log_message_tuple(
|
||
log_level=logging.WARNING,
|
||
log_message=expect_message) in caplog.record_tuples
|
||
called_log_counts = len([log for log in caplog.messages if log == expect_message])
|
||
assert called_log_counts == 2
|
||
assert generate_log_message_tuple(log_message='I-FETCH-06 [Account] のCRMからのデータ取得処理を終了します') not in caplog.record_tuples
|
||
|
||
assert e.value.error_id == 'E-FETCH-01'
|
||
assert e.value.func_name == FETCH_JP_NAME
|
||
# リトライ例外のオブジェクトIDが違うため、in句で比較
|
||
assert f'[Account] の件数取得に失敗しました エラー内容:[RetryError' in e.value.args[0]
|
||
|
||
@pytest.mark.parametrize('timeout_env_name, exception, expect_message', [
|
||
('CRM_AUTH_TIMEOUT', ConnectTimeout('接続タイムアウト'), 'W-FETCH-04 CRMの接続処理がタイムアウトしため、リトライします:[1] エラー内容:[接続タイムアウト]'),
|
||
('CRM_FETCH_RECORD_TIMEOUT', ReadTimeout('読み取りタイムアウト'), 'W-FETCH-05 [Account] のレコード取得処理がタイムアウトしたため、リトライします:[1] エラー内容:[読み取りタイムアウト]'),
|
||
('CRM_AUTH_TIMEOUT', Exception('予期せぬ例外'), 'W-FETCH-06 [Account] のレコード取得に失敗したため、リトライします エラー内容:[予期せぬ例外]'),
|
||
], ids=['connection_timeout', 'read_timeout', 'unexpected_exception'])
|
||
def test_raise_fetch_sf_data_with_retry_success(self, monkeypatch, caplog, timeout_env_name, exception, expect_message):
|
||
"""
|
||
Cases:
|
||
1. レコード取得処理で接続タイムアウト例外が発生した場合、リトライした結果復旧し、正常終了すること
|
||
2. レコード取得処理で読み取りタイムアウト例外が発生した場合、リトライした結果復旧し、正常終了すること
|
||
3. レコード取得処理で予期せぬ例外が発生した場合、リトライした結果復旧し、正常終了すること
|
||
Arranges:
|
||
- レコード取得処理の最大リトライ試行回数を3に設定する
|
||
- timeout_env_nameに指定されたリトライタイムアウト時間の秒数を1に設定する
|
||
- レコード取得処理の初回に接続タイムアウト例外が発生するようにする
|
||
Expects:
|
||
- 正常終了する
|
||
- データレコード取得に失敗した旨のエラーが出力されない
|
||
"""
|
||
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_MAX_RETRY_ATTEMPT', 3)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_RETRY_MAX_INTERVAL', 1)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_RETRY_MIN_INTERVAL', 1)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_GET_RECORD_COUNT_RETRY_INTERVAL', 1)
|
||
monkeypatch.setattr(f'src.fetch_crm_data_process.{timeout_env_name}', 1)
|
||
# Arrange
|
||
with patch('src.fetch_crm_data_process.CounterObject', ) as mock_counter, \
|
||
patch('src.fetch_crm_data_process.SOQLBuilder') as mock_soql_builder, \
|
||
patch('src.fetch_crm_data_process.SalesforceApiClient') as mock_api_client:
|
||
# モック化
|
||
mock_counter_inst = mock_counter.return_value
|
||
mock_counter_inst.describe.side_effect = [1, 2, 3]
|
||
mock_counter_inst.increment.side_effect = [2, 3, 4]
|
||
mock_builder_inst = mock_soql_builder.return_value
|
||
mock_builder_inst.create_count_soql.return_value = ''
|
||
mock_builder_inst.create_fetch_soql.return_value = ''
|
||
mock_client_inst = mock_api_client.return_value
|
||
mock_client_inst.fetch_sf_count.return_value = 1
|
||
mock_client_inst.fetch_sf_data.side_effect = [exception, common_expect]
|
||
# Act
|
||
fetch_crm_data_process(common_target_object, common_last_fetch_datetime)
|
||
|
||
# Assert
|
||
|
||
assert mock_counter_inst.describe.call_count == 1
|
||
assert mock_counter_inst.increment.call_count == 1
|
||
|
||
assert generate_log_message_tuple(
|
||
log_level=logging.WARNING,
|
||
log_message=expect_message) in caplog.record_tuples
|
||
called_log_counts = len([log for log in caplog.messages if log == expect_message])
|
||
assert called_log_counts == 1
|
||
assert generate_log_message_tuple(log_message='I-FETCH-06 [Account] のCRMからのデータ取得処理を終了します') in caplog.record_tuples
|
||
|
||
@pytest.mark.parametrize('timeout_env_name, exception, expect_message', [
|
||
('CRM_AUTH_TIMEOUT', ConnectTimeout('接続タイムアウト'), 'W-FETCH-04 CRMの接続処理がタイムアウトしため、リトライします:[1] エラー内容:[接続タイムアウト]'),
|
||
('CRM_FETCH_RECORD_TIMEOUT', ReadTimeout('読み取りタイムアウト'), 'W-FETCH-05 [Account] のレコード取得処理がタイムアウトしたため、リトライします:[1] エラー内容:[読み取りタイムアウト]'),
|
||
('CRM_AUTH_TIMEOUT', Exception('予期せぬ例外'), 'W-FETCH-06 [Account] のレコード取得に失敗したため、リトライします エラー内容:[予期せぬ例外]'),
|
||
], ids=['connection_timeout', 'read_timeout', 'unexpected_exception'])
|
||
def test_raise_fetch_sf_data_with_retry_fail(self, monkeypatch, caplog, timeout_env_name, exception, expect_message):
|
||
"""
|
||
Cases:
|
||
1. レコード取得処理で接続タイムアウト例外が発生した場合、リトライした結果復旧せず、異常終了すること
|
||
2. レコード取得処理で読み取りタイムアウト例外が発生した場合、リトライした結果復旧せず、異常終了すること
|
||
3. レコード取得処理で予期せぬ例外が発生した場合、リトライした結果復旧せず、異常終了すること
|
||
Arranges:
|
||
- レコード取得処理の最大リトライ試行回数を3に設定する
|
||
- timeout_env_nameに指定されたリトライタイムアウト時間の秒数を1に設定する
|
||
- レコード取得処理の1回目、2回目、3回目で接続タイムアウト例外が発生するようにする
|
||
Expects:
|
||
- 異常終了する
|
||
- データレコード取得に失敗した旨のエラーが出力される
|
||
"""
|
||
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_FETCH_RECORD_MAX_RETRY_ATTEMPT', 3)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_FETCH_RECORD_RETRY_MAX_INTERVAL', 1)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_FETCH_RECORD_RETRY_MIN_INTERVAL', 1)
|
||
monkeypatch.setattr('src.fetch_crm_data_process.CRM_FETCH_RECORD_RETRY_INTERVAL', 1)
|
||
monkeypatch.setattr(f'src.fetch_crm_data_process.{timeout_env_name}', 1)
|
||
# Arrange
|
||
with patch('src.fetch_crm_data_process.CounterObject', ) as mock_counter, \
|
||
patch('src.fetch_crm_data_process.SOQLBuilder') as mock_soql_builder, \
|
||
patch('src.fetch_crm_data_process.SalesforceApiClient') as mock_api_client:
|
||
# モック化
|
||
mock_counter_inst = mock_counter.return_value
|
||
mock_counter_inst.describe.side_effect = [1, 2, 3]
|
||
mock_counter_inst.increment.side_effect = [2, 3, 4]
|
||
mock_builder_inst = mock_soql_builder.return_value
|
||
mock_builder_inst.create_count_soql.return_value = ''
|
||
mock_builder_inst.create_fetch_soql.return_value = ''
|
||
mock_client_inst = mock_api_client.return_value
|
||
mock_client_inst.fetch_sf_count.return_value = 1
|
||
mock_client_inst.fetch_sf_data.side_effect = [exception, exception, exception]
|
||
# Act
|
||
with pytest.raises(SalesforceAPIException) as e:
|
||
fetch_crm_data_process(common_target_object, common_last_fetch_datetime)
|
||
|
||
# Assert
|
||
|
||
# 取得は3回行われる
|
||
assert mock_counter_inst.describe.call_count == 3
|
||
# 足し込みは2回のみ
|
||
assert mock_counter_inst.increment.call_count == 2
|
||
|
||
assert generate_log_message_tuple(
|
||
log_level=logging.WARNING,
|
||
log_message=expect_message) in caplog.record_tuples
|
||
called_log_counts = len([log for log in caplog.messages if log == expect_message])
|
||
assert called_log_counts == 2
|
||
assert generate_log_message_tuple(log_message='I-FETCH-06 [Account] のCRMからのデータ取得処理を終了します') not in caplog.record_tuples
|
||
|
||
assert e.value.error_id == 'E-FETCH-02'
|
||
assert e.value.func_name == FETCH_JP_NAME
|
||
# リトライ例外のオブジェクトIDが違うため、in句で比較
|
||
assert f'[Account] のレコード取得に失敗しました エラー内容:[RetryError' in e.value.args[0]
|