| '''Проверки схемы сервиса и чтения SQLite без создания пустых баз менеджером.'''
|
|
|
| import ast
|
| import io
|
| import re
|
| import sqlite3
|
| import tempfile
|
| import unittest
|
| from contextlib import closing, redirect_stdout
|
| from pathlib import Path
|
|
|
| from mt5_control import MT5_Control
|
|
|
|
|
| class DatabaseTests(unittest.TestCase):
|
| def setUp(self):
|
| self.temp = tempfile.TemporaryDirectory()
|
| self.root = Path(self.temp.name)
|
| # Решётка и пробелы проверяют корректность URI файла SQLite.
|
| self.database = self.root / 'состояние #1.sqlite'
|
| self.control = MT5_Control({'One': {}}, str(self.root), str(self.database))
|
|
|
| def tearDown(self):
|
| self.temp.cleanup()
|
|
|
| def create_service_schema(self, connection):
|
| # Используем SQL из настоящего MQL5-исходника, чтобы проверять его
|
| # совместимость с STATE_QUERY, а не отдельную копию схемы в тестах.
|
| source = (Path(__file__).resolve().parent.parent / 'ServiceStateWriter.mq5').read_text(encoding='utf-8-sig')
|
| definitions = re.findall(r'const string sql_(?:terminals|states)\s*=\s*(.*?);', source, re.S)
|
| self.assertEqual(len(definitions), 2)
|
| for definition in definitions:
|
| sql = ''.join(ast.literal_eval(value) for value in re.findall(r'"(?:[^"\\]|\\.)*"', definition))
|
| connection.execute(sql)
|
|
|
| def test_missing_database_is_not_created_by_reader(self):
|
| with redirect_stdout(io.StringIO()) as output:
|
| self.assertIsNone(self.control.read_state('One'))
|
| self.assertFalse(self.database.exists())
|
| self.assertIn(str(self.database), output.getvalue())
|
|
|
| def test_existing_empty_database_is_reported_without_modifying_it(self):
|
| self.database.touch()
|
| with redirect_stdout(io.StringIO()) as output:
|
| self.assertIsNone(self.control.read_state('One'))
|
| self.assertIn('no such table: terminals', output.getvalue())
|
| self.assertIn(str(self.database), output.getvalue())
|
| self.assertEqual(self.database.stat().st_size, 0)
|
|
|
| def test_service_schema_initializes_existing_file_and_matches_python_query(self):
|
| self.database.touch()
|
| with closing(sqlite3.connect(self.database)) as connection:
|
| self.create_service_schema(connection)
|
| connection.execute('INSERT INTO terminals(id, folder, path) VALUES (1, ?, ?)',
|
| ('One', str(self.root / 'One')))
|
| connection.execute('INSERT INTO states(terminal_id, updated_at, equity) VALUES (1, 123, 50000)')
|
| connection.commit()
|
| # Повторное создание не удаляет уже записанные данные.
|
| self.create_service_schema(connection)
|
| connection.commit()
|
| row = self.control.read_state('One')
|
| self.assertEqual(row['equity'], 50000)
|
| self.assertEqual(row['terminal_path'], str(self.root / 'One'))
|
| self.assertIn('holder_name', row.keys())
|
|
|
| def test_readonly_connection_observes_committed_wal_updates(self):
|
| with closing(sqlite3.connect(self.database)) as writer:
|
| writer.execute('PRAGMA journal_mode=WAL')
|
| self.create_service_schema(writer)
|
| writer.execute('INSERT INTO terminals(id, folder) VALUES (1, ?)', ('One',))
|
| writer.execute('INSERT INTO states(terminal_id, updated_at, equity) VALUES (1, 123, 50000)')
|
| writer.commit()
|
| self.assertEqual(self.control.read_state('One')['equity'], 50000)
|
| writer.execute('UPDATE states SET equity=51000 WHERE terminal_id=1')
|
| writer.commit()
|
| self.assertEqual(self.control.read_state('One')['equity'], 51000)
|
|
|
|
|
| if __name__ == '__main__':
|
| unittest.main()
|