from unittest import mock import pytest from test_fixtures.neo4j import Neo4jConnection _SECRETS = { 'qa/neo4j/username': 'testuser', 'qa/neo4j/password': 'testpass', 'qa/neo4j/hostname': 'bolt://neo4j.example.com:7687', } def _get_secret_side_effect(name, region='us-east-1'): return _SECRETS[name] def _make_connection(): with mock.patch( 'test_fixtures.neo4j.get_secret', side_effect=_get_secret_side_effect ): with mock.patch('neo4j.GraphDatabase.driver') as mock_driver: conn = Neo4jConnection( 'qa/neo4j/username', 'qa/neo4j/password', 'qa/neo4j/hostname' ) return conn, mock_driver.return_value def test_connects_with_bolt_uri(): with mock.patch( 'test_fixtures.neo4j.get_secret', side_effect=_get_secret_side_effect ): with mock.patch('neo4j.GraphDatabase.driver') as mock_driver: Neo4jConnection( 'qa/neo4j/username', 'qa/neo4j/password', 'qa/neo4j/hostname' ) mock_driver.assert_called_once_with( 'bolt://neo4j.example.com:7687', auth=('testuser', 'testpass') ) def test_prepends_bolt_scheme_when_missing(): secrets = {**_SECRETS, 'qa/neo4j/hostname': 'neo4j.example.com'} with mock.patch( 'test_fixtures.neo4j.get_secret', side_effect=lambda n, **_: secrets[n] ): with mock.patch('neo4j.GraphDatabase.driver') as mock_driver: Neo4jConnection( 'qa/neo4j/username', 'qa/neo4j/password', 'qa/neo4j/hostname' ) mock_driver.assert_called_once_with( 'bolt://neo4j.example.com:7687', auth=mock.ANY ) def test_prepends_bolt_scheme_but_not_port_when_hostname_has_port(): secrets = {**_SECRETS, 'qa/neo4j/hostname': 'neo4j.example.com:9999'} with mock.patch( 'test_fixtures.neo4j.get_secret', side_effect=lambda n, **_: secrets[n] ): with mock.patch('neo4j.GraphDatabase.driver') as mock_driver: Neo4jConnection( 'qa/neo4j/username', 'qa/neo4j/password', 'qa/neo4j/hostname' ) mock_driver.assert_called_once_with( 'bolt://neo4j.example.com:9999', auth=mock.ANY ) def test_raises_if_secret_is_not_string(): secrets = {**_SECRETS, 'qa/neo4j/username': {'user': 'testuser'}} with mock.patch( 'test_fixtures.neo4j.get_secret', side_effect=lambda n, **_: secrets[n] ): with mock.patch('neo4j.GraphDatabase.driver'): with pytest.raises(ValueError, match="'qa/neo4j/username'.*plain string"): Neo4jConnection( 'qa/neo4j/username', 'qa/neo4j/password', 'qa/neo4j/hostname' ) def test_run_returns_records(): conn, mock_driver = _make_connection() mock_record = mock.Mock() mock_record.data.return_value = {'name': 'Alice'} mock_driver.session.return_value.__enter__.return_value.run.return_value = [ mock_record ] result = conn.run('MATCH (n) RETURN n.name AS name') assert result == [{'name': 'Alice'}] def test_close(): conn, mock_driver = _make_connection() conn.close() mock_driver.close.assert_called_once() def test_context_manager_closes_on_exit(): with mock.patch( 'test_fixtures.neo4j.get_secret', side_effect=_get_secret_side_effect ): with mock.patch('neo4j.GraphDatabase.driver') as mock_driver: with Neo4jConnection( 'qa/neo4j/username', 'qa/neo4j/password', 'qa/neo4j/hostname' ) as conn: assert conn is not None mock_driver.return_value.close.assert_called_once()