import os import feed_file_exporter as ffe from constants import database as db_consts, files as file_consts def _file_rows(name): return [ { db_consts.RECORD_TYPE: 'H', db_consts.BODY_CONTENT: 'H', db_consts.FILE_NAME: name, }, { db_consts.RECORD_TYPE: 'N', db_consts.BODY_CONTENT: 'B1', db_consts.FILE_NAME: name, }, { db_consts.RECORD_TYPE: 'I', db_consts.BODY_CONTENT: 'B2', db_consts.FILE_NAME: name, }, { db_consts.RECORD_TYPE: 'T', db_consts.BODY_CONTENT: 'T', db_consts.FILE_NAME: name, }, ] def test_split_rows_to_files_multiple_files_and_types(tmp_path, mocker): rows = _file_rows('A.txt') + _file_rows('B.txt') spy = mocker.spy(ffe, 'write_rows_to_file') count, upload_list, gen_list = ffe.split_rows_to_files(rows, str(tmp_path)) assert count == len(rows) assert set(upload_list) == {'A.txt', 'B.txt'} assert len(gen_list) == 1 assert spy.call_count == 1 # single write for aggregated rows # Validate aggregated contents for last file name with open(gen_list[0], 'r', encoding='utf8') as f: content = f.read() expected = 'H' + file_consts.LINE_TERMINATOR expected += 'B1' + file_consts.LINE_TERMINATOR expected += 'B2' + file_consts.LINE_TERMINATOR expected += 'B1' + file_consts.LINE_TERMINATOR expected += 'B2' + file_consts.LINE_TERMINATOR expected += 'T' assert content.replace('\r\n', '\n') == expected.replace('\r\n', '\n') class _Row: def __init__(self, d): self._d = d def keys(self): return list(self._d.keys()) def __iter__(self): return iter(self._d.values()) class _RP: def __init__(self, rows): self._rows = rows def fetchone(self): return _Row(self._rows[0]) def __iter__(self): for r in self._rows[1:]: yield _Row(r) def test_split_res_to_files_multiple_body_types(tmp_path): rows = _file_rows('C.txt') rp = _RP(rows) count, gen_list = ffe.split_res_to_files(rp, str(tmp_path)) assert count == len(rows) assert len(gen_list) == 1 with open(gen_list[0], 'r', encoding='utf8') as f: content = f.read() expected = 'H' + file_consts.LINE_TERMINATOR expected += 'B1' + file_consts.LINE_TERMINATOR expected += 'B2' + file_consts.LINE_TERMINATOR expected += 'T' assert content.replace('\r\n', '\n') == expected.replace('\r\n', '\n') def test_enable_local_sftp_if_requested(tmp_path, monkeypatch): # Enable local mock mode conditions monkeypatch.setenv('SFTP_HOST', 'localhost') monkeypatch.setenv('ENVIRONMENT', 'DEV') monkeypatch.setenv('SFTP_USER', 'u') monkeypatch.setenv('SFTP_PASSWORD', 'p') # Point local root to a temp dir by chdir into tmp workspace cwd = os.getcwd() try: os.chdir(tmp_path) ffe._enable_local_sftp_if_requested() import paramiko # type: ignore client = paramiko.SSHClient() # Should accept our credentials client.connect( 'localhost', username='u', password='p', port=22, timeout=5 ) sftp = client.open_sftp() src = tmp_path / 'src.txt' src.write_text('data') sftp.put(str(src), 'monthly/src.txt') dest = tmp_path / 'tmp' / 'local_sftp_root' / 'monthly' / 'src.txt' assert dest.exists() client.close() finally: os.chdir(cwd)