""" !!!!注意!!!! 当テストコードはSalesforceのレコードに依存しています。 Accountオブジェクトの下記SFIDのレコードはいじらないようにしてください - 0015i00000LNywwAAD(テスト取引先1) - 0015i00000LOClSAAX(テスト取引先2) - 0015i00000LOCmGAAX(テスト取引先3) 変更してしまった場合は各SOQLの取得日付とデータを修正してください """ from typing import OrderedDict import pytest from requests.exceptions import ConnectTimeout, ReadTimeout from src.config.objects import LastFetchDatetime, TargetObject from src.salesforce.salesforce_api import SalesforceApiClient from src.salesforce.soql_builder import SOQLBuilder from src.util.execute_datetime import ExecuteDateTime class TestSalesforceApiClient: def test_fetch_sf_count(self): """ Cases: Salesforceからオブジェクトの件数が取得できること Arranges: SalesforceのAccountオブジェクトに、レコードを作成する(手作業、コード上では行わない) Expects: 取得件数が1件以上になる """ soql = """SELECT COUNT(Id) FROM Account WHERE SystemModstamp > 2022-08-04T00:00:00.000Z AND SystemModstamp <= 2022-08-06T00:00:00.000Z """ sut = SalesforceApiClient() actual = sut.fetch_sf_count(soql) assert actual >= 1 def test_fetch_sf_count_zero_record(self): """ Cases: 取得範囲外の場合、Salesforceからオブジェクトの件数が取得できないこと Arranges: SalesforceのAccountオブジェクトに、レコードを作成する(手作業、コード上では行わない) Expects: 取得件数が0件になる """ soql = """SELECT COUNT(Id) FROM Account WHERE SystemModstamp > 1999-01-01T00:00:00.000Z AND SystemModstamp <= 2000-01-01T00:00:00.000Z """ sut = SalesforceApiClient() actual = sut.fetch_sf_count(soql) assert actual >= 0 def test_fetch_sf_count_by_soql_builder_system_modstamp_lt_from_and_to_ge(self): """ Cases: - SOQLBuilderから生成したSOQLで、Salesforceからオブジェクトの件数が取得できること - SystemModStampがFrom指定日付未満のレコードは取得できないこと - SystemModStampのToが指定日付以上のレコードは取得できること Arranges: - SalesforceのAccountオブジェクトに、レコードを作成する - LastFetchDatetimeのFromがSystemModstamp未満になるように指定する(UTC指定) - LastFetchDatetimeのToがSystemModstampピッタリになるように指定する(UTC指定) Expects: 取得件数が1になる """ execute_datetime = ExecuteDateTime() last_fetch_datetime = LastFetchDatetime({ 'last_fetch_datetime_from': '2022-08-05T11:14:07.000Z', 'last_fetch_datetime_to': '2022-08-05T11:15:29.000Z', }, execute_datetime) target_object = TargetObject({ 'object_name': 'Account', 'columns': [ 'Id', 'Name', 'SystemModstamp', 'LastModifiedDate', 'CustomItem1__c', 'CustomItem2__c', 'CustomItem3__c', 'CustomItem4__c', 'CustomItem5__c', 'CustomItem6__c', 'CustomItem7__c', 'CustomItem8__c' ] }, execute_datetime) soql_builder = SOQLBuilder(target_object, last_fetch_datetime) soql = soql_builder.create_count_soql() sut = SalesforceApiClient() actual = sut.fetch_sf_count(soql) assert actual == 1 def test_fetch_sf_count_by_soql_builder_system_modstamp_gt_from_and_to_lt(self): """ Cases: - SOQLBuilderから生成したSOQLで、Salesforceからオブジェクトの件数が取得できること - SystemModStampのFromが指定日付のより大きいレコードは取得できること - SystemModStampのToが指定日付未満のレコードは取得できないこと Arranges: - SalesforceのAccountオブジェクトに、レコードを作成する - LastFetchDatetimeのFromがSystemModstampより大きくなるように指定する(UTC指定) - LastFetchDatetimeのToがSystemModstamp未満になるように指定する(UTC指定) Expects: 取得件数が1になる """ execute_datetime = ExecuteDateTime() last_fetch_datetime = LastFetchDatetime({ 'last_fetch_datetime_from': '2022-08-05T11:14:06.000Z', 'last_fetch_datetime_to': '2022-08-05T11:15:28.000Z', }, execute_datetime) target_object = TargetObject({ 'object_name': 'Account', 'columns': [ 'Id', 'Name', 'SystemModstamp', 'LastModifiedDate', 'CustomItem1__c', 'CustomItem2__c', 'CustomItem3__c', 'CustomItem4__c', 'CustomItem5__c', 'CustomItem6__c', 'CustomItem7__c', 'CustomItem8__c' ] }, execute_datetime) soql_builder = SOQLBuilder(target_object, last_fetch_datetime) soql = soql_builder.create_count_soql() sut = SalesforceApiClient() actual = sut.fetch_sf_count(soql) assert actual == 1 def test_fetch_sf_count_by_soql_builder_system_modstamp_all_range(self): """ Cases: - SOQLBuilderから生成したSOQLで、Salesforceからオブジェクトの件数が取得できること - SystemModStampのFromが2000年1月1日以降のレコードが取得できること - SystemModStampのToが2100年12月31日未満のレコードが取得できること Arranges: - SalesforceのAccountオブジェクトに、レコードを作成する - LastFetchDatetimeのFromに2000年1月1日を指定する - LastFetchDatetimeのToに2100年12月31日を指定する Expects: 取得件数が17になる """ execute_datetime = ExecuteDateTime() last_fetch_datetime = LastFetchDatetime({ 'last_fetch_datetime_from': '2000-01-01T00:00:00.000Z', 'last_fetch_datetime_to': '2100-12-31T23:59:59.000Z', }, execute_datetime) target_object = TargetObject({ 'object_name': 'Account', 'columns': [ 'Id', 'Name', 'SystemModstamp', 'LastModifiedDate', 'CustomItem1__c', 'CustomItem2__c', 'CustomItem3__c', 'CustomItem4__c', 'CustomItem5__c', 'CustomItem6__c', 'CustomItem7__c', 'CustomItem8__c' ] }, execute_datetime) soql_builder = SOQLBuilder(target_object, last_fetch_datetime) soql = soql_builder.create_count_soql() sut = SalesforceApiClient() actual = sut.fetch_sf_count(soql) assert actual == 17 def test_fetch_sf_data_one_record(self): """ Cases: Salesforceからオブジェクトが取得できること Arranges: SalesforceのAccountオブジェクトに、レコードを作成する(手作業、コード上では行わない) Expects: オブジェクトが取得でき、期待値と一致していること """ soql = """SELECT Id, Name, SystemModstamp, LastModifiedDate, CustomItem1__c, CustomItem2__c, CustomItem3__c, CustomItem4__c, CustomItem5__c, CustomItem6__c, CustomItem7__c, CustomItem8__c FROM Account WHERE SystemModstamp > 2022-08-04T00:00:00.000Z AND SystemModstamp <= 2022-08-06T00:00:00.000Z """ sut = SalesforceApiClient() expect = { 'Name': 'テスト取引先名1', 'CustomItem1__c': 'テスト', 'CustomItem2__c': 1.0, 'CustomItem3__c': True, 'CustomItem4__c': '01:15:00.000Z', 'CustomItem5__c': '1;2;3;4', 'CustomItem6__c': '改行ありの\r\nテスト\r\n項目です', 'CustomItem7__c': '2022-08-04', 'CustomItem8__c': '2022-08-04T03:00:00.000+0000', } actual = sut.fetch_sf_data(soql) assert len(actual) >= 1 # 複数取れるが、アサーション対象は1つだけ actual = [record for record in actual if record['Name'] == 'テスト取引先名1'] # Id, SystemModstamp, LastModifiedDateは自動生成なので、キーの有無だけ確認する # Attributesも assert 'Id' in actual[0].keys() assert 'SystemModstamp' in actual[0].keys() assert 'LastModifiedDate' in actual[0].keys() assert 'attributes' in actual[0].keys() del actual[0]['Id'] del actual[0]['SystemModstamp'] del actual[0]['LastModifiedDate'] del actual[0]['attributes'] assert dict(actual[0]) == expect def test_fetch_sf_data_zero_record(self): """ Cases: 取得範囲外の場合、Salesforceからオブジェクトが取得できないこと Arranges: SalesforceのAccountオブジェクトに、レコードを作成する(手作業、コード上では行わない) Expects: 取得件数が0件になる """ soql = """SELECT Id, Name, SystemModstamp, LastModifiedDate, CustomItem1__c, CustomItem2__c, CustomItem3__c, CustomItem4__c, CustomItem5__c, CustomItem6__c, CustomItem7__c, CustomItem8__c FROM Account WHERE SystemModstamp > 1999-01-01T00:00:00.000Z AND SystemModstamp <= 2000-01-01T00:00:00.000Z """ sut = SalesforceApiClient() actual = sut.fetch_sf_data(soql) assert len(actual) >= 0 def test_fetch_sf_data_by_soql_builder_system_modstamp_lt_from_and_to_ge(self): """ Cases: - SOQLBuilderから生成したSOQLで、Salesforceからオブジェクトが取得できること - SystemModStampがFrom指定日付未満のレコードは取得できないこと - SystemModStampのToが指定日付以上のレコードは取得できること Arranges: - SalesforceのAccountオブジェクトに、レコードを作成する - LastFetchDatetimeのFromがSystemModstamp未満になるように指定する(UTC指定) - LastFetchDatetimeのToがSystemModstampピッタリになるように指定する(UTC指定) Expects: 取得できたオブジェクト1件が期待値どおりであること """ execute_datetime = ExecuteDateTime() last_fetch_datetime = LastFetchDatetime({ 'last_fetch_datetime_from': '2022-08-05T11:14:07.000Z', 'last_fetch_datetime_to': '2022-08-05T11:15:29.000Z', }, execute_datetime) target_object = TargetObject({ 'object_name': 'Account', 'columns': [ 'Id', 'Name', 'SystemModstamp', 'LastModifiedDate', 'CustomItem1__c', 'CustomItem2__c', 'CustomItem3__c', 'CustomItem4__c', 'CustomItem5__c', 'CustomItem6__c', 'CustomItem7__c', 'CustomItem8__c' ] }, execute_datetime) soql_builder = SOQLBuilder(target_object, last_fetch_datetime) soql = soql_builder.create_fetch_soql() sut = SalesforceApiClient() actual = sut.fetch_sf_data(soql) assert len(actual) == 1 # Id, SystemModstamp, LastModifiedDateは自動生成なので、キーの有無だけ確認する # Attributesも assert 'Id' in actual[0].keys() assert 'SystemModstamp' in actual[0].keys() assert 'LastModifiedDate' in actual[0].keys() assert 'attributes' in actual[0].keys() del actual[0]['Id'] del actual[0]['SystemModstamp'] del actual[0]['LastModifiedDate'] del actual[0]['attributes'] expect = { 'Name': 'テスト取引先名3', 'CustomItem1__c': 'テスト3', 'CustomItem2__c': 3.0, 'CustomItem3__c': True, 'CustomItem4__c': '00:45:00.000Z', 'CustomItem5__c': '2;3', 'CustomItem6__c': 'かいぎょ', 'CustomItem7__c': '2022-08-06', 'CustomItem8__c': '2022-08-06T00:00:00.000+0000', } assert dict(actual[0]) == expect def test_fetch_sf_data_by_soql_builder_system_modstamp_gt_from_and_to_lt(self): """ Cases: - SOQLBuilderから生成したSOQLで、Salesforceからオブジェクトが取得できること - SystemModStampのFromが指定日付のより大きいレコードは取得できること - SystemModStampのToが指定日付未満のレコードは取得できないこと Arranges: - SalesforceのAccountオブジェクトに、レコードを作成する - LastFetchDatetimeのFromがSystemModstampより大きくなるように指定する(UTC指定) - LastFetchDatetimeのToがSystemModstamp未満になるように指定する(UTC指定) Expects: 取得できたオブジェクト1件が期待値どおりであること """ execute_datetime = ExecuteDateTime() last_fetch_datetime = LastFetchDatetime({ 'last_fetch_datetime_from': '2022-08-05T11:14:06.000Z', 'last_fetch_datetime_to': '2022-08-05T11:15:28.000Z', }, execute_datetime) target_object = TargetObject({ 'object_name': 'Account', 'columns': [ 'Id', 'Name', 'SystemModstamp', 'LastModifiedDate', 'CustomItem1__c', 'CustomItem2__c', 'CustomItem3__c', 'CustomItem4__c', 'CustomItem5__c', 'CustomItem6__c', 'CustomItem7__c', 'CustomItem8__c' ] }, execute_datetime) soql_builder = SOQLBuilder(target_object, last_fetch_datetime) soql = soql_builder.create_fetch_soql() sut = SalesforceApiClient() actual = sut.fetch_sf_data(soql) assert len(actual) == 1 # Id, SystemModstamp, LastModifiedDateは自動生成なので、キーの有無だけ確認する # Attributesも assert 'Id' in actual[0].keys() assert 'SystemModstamp' in actual[0].keys() assert 'LastModifiedDate' in actual[0].keys() assert 'attributes' in actual[0].keys() del actual[0]['Id'] del actual[0]['SystemModstamp'] del actual[0]['LastModifiedDate'] del actual[0]['attributes'] expect = { 'Name': 'テスト取引先名2', 'CustomItem1__c': 'テスト2', 'CustomItem2__c': 2.0, 'CustomItem3__c': False, 'CustomItem4__c': '00:30:00.000Z', 'CustomItem5__c': '1;4', 'CustomItem6__c': '改行あり項目', 'CustomItem7__c': '2022-08-05', 'CustomItem8__c': '2022-08-04T23:30:00.000+0000', } assert dict(actual[0]) == expect def test_fetch_sf_data_by_soql_builder_address_item_check(self): """ Cases: - SOQLBuilderから生成したSOQLで、Salesforceからオブジェクトが取得できること - SystemModStampのFromが2000年1月1日以降のレコードが取得できること - SystemModStampのToが2100年12月31日未満のレコードが取得できること Arranges: - SalesforceのAccountオブジェクトに、レコードを作成する - LastFetchDatetimeのFromに2000年1月1日を指定する - LastFetchDatetimeのToに2100年12月31日を指定する Expects: 取得できたオブジェクト件数が1件になる 住所項目(BillingAddress)が想定通りの値になっていること """ execute_datetime = ExecuteDateTime() last_fetch_datetime = LastFetchDatetime({ 'last_fetch_datetime_from': '2022-08-19T05:53:29.000Z', 'last_fetch_datetime_to': '2022-08-19T05:53:30.000Z', }, execute_datetime) target_object = TargetObject({ 'object_name': 'Account', 'columns': [ 'Id', 'Name', 'SystemModstamp', 'LastModifiedDate', 'BillingAddress', 'CustomItem1__c', 'CustomItem2__c', 'CustomItem3__c', 'CustomItem4__c', 'CustomItem5__c', 'CustomItem6__c', 'CustomItem7__c', 'CustomItem8__c' ] }, execute_datetime) soql_builder = SOQLBuilder(target_object, last_fetch_datetime) soql = soql_builder.create_fetch_soql() sut = SalesforceApiClient() actual = sut.fetch_sf_data(soql) assert len(actual) == 1 expect_address = OrderedDict([ ("city", '〇〇区'), ("country", "日本"), ("geocodeAccuracy", None), ("latitude", None), ("longitude", None), ("postalCode", '999-9999'), ("state", '東京都'), ("street", '△△-✗✗'), ]) assert actual[0]['BillingAddress'] == expect_address def test_fetch_sf_data_by_soql_builder_system_modstamp_all_range(self): """ Cases: - SOQLBuilderから生成したSOQLで、Salesforceからオブジェクトが取得できること - SystemModStampのFromが2000年1月1日以降のレコードが取得できること - SystemModStampのToが2100年12月31日未満のレコードが取得できること Arranges: - SalesforceのAccountオブジェクトに、レコードを作成する - LastFetchDatetimeのFromに2000年1月1日を指定する - LastFetchDatetimeのToに2100年12月31日を指定する Expects: 取得できたオブジェクト件数が17件になる """ execute_datetime = ExecuteDateTime() last_fetch_datetime = LastFetchDatetime({ 'last_fetch_datetime_from': '2000-01-01T00:00:00.000Z', 'last_fetch_datetime_to': '2100-12-31T23:59:59.000Z', }, execute_datetime) target_object = TargetObject({ 'object_name': 'Account', 'columns': [ 'Id', 'Name', 'SystemModstamp', 'LastModifiedDate', 'BillingAddress', 'CustomItem1__c', 'CustomItem2__c', 'CustomItem3__c', 'CustomItem4__c', 'CustomItem5__c', 'CustomItem6__c', 'CustomItem7__c', 'CustomItem8__c' ] }, execute_datetime) soql_builder = SOQLBuilder(target_object, last_fetch_datetime) soql = soql_builder.create_fetch_soql() sut = SalesforceApiClient() actual = sut.fetch_sf_data(soql) assert len(actual) == 17 # 内容の確認は別のケースで行っているため省略 def test_raise_create_instance_cause_auth_failed(self, monkeypatch): """ Cases: 存在しないユーザを指定した場合、エラーが発生すること Arranges: CRMのユーザ名を保持する環境変数に、存在しないユーザー名を指定する Expects: ユーザ認証でエラーが発生すること """ monkeypatch.setattr('src.salesforce.salesforce_api.CRM_USER_NAME', 'invalid_username') with pytest.raises(Exception): SalesforceApiClient() def test_raise_fetch_sf_count_auth_timeout(self, monkeypatch): """ Cases: 認証タイムアウトが発生した場合、エラーが発生すること Arranges: 認証タイムアウト秒数を保持する環境変数に、0.0000000001を指定する Expects: コネクションタイムアウトエラーが発生すること """ monkeypatch.setattr('src.salesforce.salesforce_api.CRM_AUTH_TIMEOUT', 0.0000000001) sf = SalesforceApiClient() soql = """SELECT COUNT(Id) FROM Account WHERE SystemModstamp > 2022-08-04T00:00:00.000Z AND SystemModstamp <= 2022-08-06T00:00:00.000Z """ with pytest.raises(ConnectTimeout): sf.fetch_sf_count(soql) def test_raise_fetch_sf_count_read_timeout(self, monkeypatch): """ Cases: 読み取りタイムアウトが発生した場合、エラーが発生すること Arranges: CRMの件数取得タイムアウト秒数を保持する環境変数に、0.0000000001を指定する Expects: 読み取りタイムアウトエラーが発生すること """ monkeypatch.setattr('src.salesforce.salesforce_api.CRM_GET_RECORD_COUNT_TIMEOUT', 0.0000000001) sf = SalesforceApiClient() soql = """SELECT COUNT(Id) FROM Account WHERE SystemModstamp > 2022-08-04T00:00:00.000Z AND SystemModstamp <= 2022-08-06T00:00:00.000Z """ with pytest.raises(ReadTimeout): sf.fetch_sf_count(soql) def test_raise_fetch_sf_count_invalid_soql(self, monkeypatch): """ Cases: 不正なSOQLを指定した場合に、エラーが発生すること Arranges: 不正なSOQLを作成する Expects: エラーが発生すること """ sf = SalesforceApiClient() soql = "SELECT" with pytest.raises(Exception): sf.fetch_sf_count(soql) def test_raise_fetch_sf_data_auth_timeout(self, monkeypatch): """ Cases: 認証タイムアウトが発生した場合、エラーが発生すること Arranges: 認証タイムアウト秒数を保持する環境変数に、0.0000000001を指定する Expects: コネクションタイムアウトエラーが発生すること """ monkeypatch.setattr('src.salesforce.salesforce_api.CRM_AUTH_TIMEOUT', 0.0000000001) sf = SalesforceApiClient() soql = """SELECT COUNT(Id) FROM Account WHERE SystemModstamp > 2022-08-04T00:00:00.000Z AND SystemModstamp <= 2022-08-06T00:00:00.000Z """ with pytest.raises(ConnectTimeout): sf.fetch_sf_data(soql) def test_raise_fetch_sf_data_read_timeout(self, monkeypatch): """ Cases: 読み取りタイムアウトが発生した場合、エラーが発生すること Arranges: CRMのデータ取得タイムアウト秒数を保持する環境変数に、0.0000000001を指定する Expects: 読み取りタイムアウトエラーが発生すること """ monkeypatch.setattr('src.salesforce.salesforce_api.CRM_FETCH_RECORD_TIMEOUT', 0.0000000001) sf = SalesforceApiClient() soql = """SELECT COUNT(Id) FROM Account WHERE SystemModstamp > 2022-08-04T00:00:00.000Z AND SystemModstamp <= 2022-08-06T00:00:00.000Z """ with pytest.raises(ReadTimeout): sf.fetch_sf_data(soql) def test_raise_fetch_sf_data_invalid_soql(self, monkeypatch): """ Cases: 不正なSOQLを指定した場合に、エラーが発生すること Arranges: 不正なSOQLを作成する Expects: エラーが発生すること """ sf = SalesforceApiClient() soql = "SELECT" with pytest.raises(Exception): sf.fetch_sf_data(soql)