diff --git a/ecs/crm-datafetch/src/salesforce/salesforce_api.py b/ecs/crm-datafetch/src/salesforce/salesforce_api.py index 4e4bb267..edd9aeb3 100644 --- a/ecs/crm-datafetch/src/salesforce/salesforce_api.py +++ b/ecs/crm-datafetch/src/salesforce/salesforce_api.py @@ -13,16 +13,16 @@ class SalesforceApiClient(): domain=CRM_AUTH_DOMAIN ) - def query(self, soql, include_deleted=True, conn_timeout=100, read_timeout=300): + def __query(self, soql, include_deleted=True, conn_timeout=100, read_timeout=300): return self.__sf.query(soql, include_deleted, timeout=(float(conn_timeout), float(read_timeout))) - def query_all(self, soql, include_deleted=True, conn_timeout=100, read_timeout=300): + def __query_all(self, soql, include_deleted=True, conn_timeout=100, read_timeout=300): return self.__sf.query_all(soql, include_deleted, timeout=(float(conn_timeout), float(read_timeout))) def fetch_sf_count(self, soql: str): - count_res = self.query(soql, conn_timeout=CRM_AUTH_TIMEOUT, read_timeout=CRM_GET_RECORD_COUNT_TIMEOUT) + count_res = self.__query(soql, conn_timeout=CRM_AUTH_TIMEOUT, read_timeout=CRM_GET_RECORD_COUNT_TIMEOUT) return count_res.get('records')[0].get('expr0') def fetch_sf_data(self, soql: str): - data_res = self.query_all(soql, conn_timeout=CRM_AUTH_TIMEOUT, read_timeout=CRM_FETCH_RECORD_TIMEOUT) + data_res = self.__query_all(soql, conn_timeout=CRM_AUTH_TIMEOUT, read_timeout=CRM_FETCH_RECORD_TIMEOUT) return data_res.get('records') diff --git a/ecs/crm-datafetch/src/salesforce/soql_builder.py b/ecs/crm-datafetch/src/salesforce/soql_builder.py index a84744a8..42d4ecea 100644 --- a/ecs/crm-datafetch/src/salesforce/soql_builder.py +++ b/ecs/crm-datafetch/src/salesforce/soql_builder.py @@ -1,12 +1,15 @@ -from src.config.objects import TargetObject, LastFetchDatetime +import textwrap + +from src.config.objects import LastFetchDatetime, TargetObject class SOQLBuilder: def __init__(self, target_object: TargetObject, last_fetch_datetime: LastFetchDatetime) -> None: - self.__SELECT_SOQL = """SELECT {column_or_expression} FROM {object_name} - WHERE {datetime_column} > {last_fetch_datetime_from} - AND {datetime_column} <= {last_fetch_datetime_to} - """ + self.__SELECT_SOQL = textwrap.dedent("""\ + SELECT {column_or_expression} FROM {object_name} + WHERE {datetime_column} > {last_fetch_datetime_from} + AND {datetime_column} <= {last_fetch_datetime_to} + """) self.__target_object = target_object self.__last_fetch_datetime = last_fetch_datetime diff --git a/ecs/crm-datafetch/tests/salesforce/__init__.py b/ecs/crm-datafetch/tests/salesforce/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ecs/crm-datafetch/tests/salesforce/test_salesfoce.py b/ecs/crm-datafetch/tests/salesforce/test_salesfoce.py new file mode 100644 index 00000000..b815e772 --- /dev/null +++ b/ecs/crm-datafetch/tests/salesforce/test_salesfoce.py @@ -0,0 +1,596 @@ +""" +!!!!注意!!!! +当テストコードはSalesforceのレコードに依存しています。 +Accountオブジェクトの下記SFIDのレコードはいじらないようにしてください + - 0015i00000LNywwAAD(テスト取引先1) + - 0015i00000LOClSAAX(テスト取引先2) + - 0015i00000LOCmGAAX(テスト取引先3) + +変更してしまった場合は各SOQLの取得日付とデータを修正してください +""" + +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: + 取得件数が16になる + """ + + 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 == 16 + + 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_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: + 取得できたオブジェクト件数が16件になる + """ + + 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_fetch_soql() + sut = SalesforceApiClient() + + actual = sut.fetch_sf_data(soql) + assert len(actual) == 16 + # 内容の確認は別のケースで行っているため省略 + + 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) diff --git a/ecs/crm-datafetch/tests/salesforce/test_soql_builder.py b/ecs/crm-datafetch/tests/salesforce/test_soql_builder.py new file mode 100644 index 00000000..da42d486 --- /dev/null +++ b/ecs/crm-datafetch/tests/salesforce/test_soql_builder.py @@ -0,0 +1,160 @@ + +from src.config.objects import ExecuteDateTime, LastFetchDatetime, TargetObject +from src.salesforce.soql_builder import SOQLBuilder + + +class TestSOQLBuilder: + + def test_create_count_soql(self): + """ + Cases: + 件数取得のSOQLが生成できること + Arranges: + SOQL生成用のパラメータを用意する + Expects: + 期待値通りのSOQLが生成されること + """ + test_target_object_json = { + 'object_name': 'Account', + 'columns': [ + 'Id', + 'Name', + 'SystemModstamp', + 'LastModifiedDate', + 'CustomItem1__c', + 'CustomItem2__c', + 'CustomItem3__c', + 'CustomItem4__c', + 'CustomItem5__c', + 'CustomItem6__c', + 'CustomItem7__c', + 'CustomItem8__c' + ] + } + + test_last_fetch_datetime_json = { + 'last_fetch_datetime_from': '1999-01-01T00:00:00.000Z', + 'last_fetch_datetime_to': '2000-01-01T00:00:00.000Z', + } + + execute_datetime = ExecuteDateTime() + target_object = TargetObject(test_target_object_json, execute_datetime) + test_last_fetch_datetime = LastFetchDatetime(test_last_fetch_datetime_json, execute_datetime) + + sut = SOQLBuilder(target_object, test_last_fetch_datetime) + actual = sut.create_count_soql() + + expect = """SELECT + COUNT(Id) + FROM + Account + WHERE + SystemModstamp > 1999-01-01T00:00:00.000Z AND + SystemModstamp <= 2000-01-01T00:00:00.000Z + """ + + assert actual.replace('\n', '').replace(' ', '') == expect.replace('\n', '').replace(' ', '') + + def test_create_fetch_soql(self): + """ + Cases: + データ取得用のSOQLが生成できること + Arranges: + SOQL生成用のパラメータを用意する + Expects: + 期待値通りのSOQLが生成されること + """ + test_target_object_json = { + 'object_name': 'Account', + 'columns': [ + 'Id', + 'Name', + 'SystemModstamp', + 'LastModifiedDate', + 'CustomItem1__c', + 'CustomItem2__c', + 'CustomItem3__c', + 'CustomItem4__c', + 'CustomItem5__c', + 'CustomItem6__c', + 'CustomItem7__c', + 'CustomItem8__c' + ] + } + + test_last_fetch_datetime_json = { + 'last_fetch_datetime_from': '1999-01-01T00:00:00.000Z', + 'last_fetch_datetime_to': '2000-01-01T00:00:00.000Z', + } + + execute_datetime = ExecuteDateTime() + target_object = TargetObject(test_target_object_json, execute_datetime) + test_last_fetch_datetime = LastFetchDatetime(test_last_fetch_datetime_json, execute_datetime) + + sut = SOQLBuilder(target_object, test_last_fetch_datetime) + actual = sut.create_fetch_soql() + + expect = """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 + """ + + print('actual', actual) + print('expect', expect) + + assert actual.replace('\n', '').replace(' ', '') == expect.replace('\n', '').replace(' ', '') + + def test_create_fetch_soql_no_columns(self): + """ + Cases: + データ取得用のSOQLがカラムがない状態で生成されること + Arranges: + SOQL生成用のパラメータを用意する + Expects: + 取得対象のカラムがないSOQLが生成されること + """ + test_target_object_json = { + 'object_name': 'Account', + 'columns': [] + } + + test_last_fetch_datetime_json = { + 'last_fetch_datetime_from': '1999-01-01T00:00:00.000Z', + 'last_fetch_datetime_to': '2000-01-01T00:00:00.000Z', + } + + execute_datetime = ExecuteDateTime() + target_object = TargetObject(test_target_object_json, execute_datetime) + test_last_fetch_datetime = LastFetchDatetime(test_last_fetch_datetime_json, execute_datetime) + + sut = SOQLBuilder(target_object, test_last_fetch_datetime) + actual = sut.create_fetch_soql() + + # TargetObjectのバリデーションで、columnsが空の場合はエラーになるため、本来は発生しない + expect = """SELECT + FROM + Account + WHERE + SystemModstamp > 1999-01-01T00:00:00.000Z AND + SystemModstamp <= 2000-01-01T00:00:00.000Z + """ + + print('actual', actual) + print('expect', expect) + + assert actual.replace('\n', '').replace(' ', '') == expect.replace('\n', '').replace(' ', '')