diff --git a/ldclient/impl/integrations/files/file_data_source.py b/ldclient/impl/integrations/files/file_data_source.py index 81fb38d3..c6f86113 100644 --- a/ldclient/impl/integrations/files/file_data_source.py +++ b/ldclient/impl/integrations/files/file_data_source.py @@ -96,7 +96,7 @@ def _load_all(self): log.error('Unable to load flag data from "%s": %s' % (path, repr(e))) traceback.print_exc() if self._data_source_update_sink is not None: - self._data_source_update_sink.update_status(DataSourceState.INTERRUPTED, DataSourceErrorInfo(DataSourceErrorKind.INVALID_DATA, 0, time.time, str(e))) + self._data_source_update_sink.update_status(DataSourceState.INTERRUPTED, DataSourceErrorInfo(DataSourceErrorKind.INVALID_DATA, 0, time.time(), str(e))) return try: self._sink_or_store().init(all_data) @@ -107,7 +107,7 @@ def _load_all(self): log.error('Unable to store data: %s' % repr(e)) traceback.print_exc() if self._data_source_update_sink is not None: - self._data_source_update_sink.update_status(DataSourceState.INTERRUPTED, DataSourceErrorInfo(DataSourceErrorKind.UNKNOWN, 0, time.time, str(e))) + self._data_source_update_sink.update_status(DataSourceState.INTERRUPTED, DataSourceErrorInfo(DataSourceErrorKind.UNKNOWN, 0, time.time(), str(e))) def _load_file(self, path, all_data): content = None diff --git a/ldclient/testing/test_file_error_timestamps.py b/ldclient/testing/test_file_error_timestamps.py new file mode 100644 index 00000000..0c512933 --- /dev/null +++ b/ldclient/testing/test_file_error_timestamps.py @@ -0,0 +1,36 @@ +import time + +import pytest + +from ldclient import LDClient +from ldclient.config import Config +from ldclient.feature_store import InMemoryFeatureStore +from ldclient.integrations import Files +from ldclient.interfaces import DataSourceErrorKind + + +class FailingFeatureStore(InMemoryFeatureStore): + def init(self, all_data): + raise RuntimeError('store unavailable') + + +@pytest.mark.parametrize('failure', ['missing', 'malformed', 'store']) +def test_file_source_reports_numeric_error_timestamp(tmp_path, failure): + path = tmp_path / 'flags.json' + if failure == 'malformed': + path.write_text('{"flagValues":{') + elif failure == 'store': + path.write_text('{"flagValues":{"flag":true}}') + store = FailingFeatureStore() if failure == 'store' else InMemoryFeatureStore() + started = time.time() + with LDClient(config=Config( + 'SDK_KEY', + update_processor_class=Files.new_data_source(paths=str(path)), + feature_store=store, + send_events=False, + )) as client: + error = client.data_source_status_provider.status.error + assert error is not None + assert error.kind == (DataSourceErrorKind.UNKNOWN if failure == 'store' else DataSourceErrorKind.INVALID_DATA) + assert isinstance(error.time, float) + assert started <= error.time <= time.time()