Weihua Deng

100 papers A* 2C 1Journal 89Unranked 8
YearRankTypeTitle / Venue / Authors
2026 J jnl
J. Inf. Sci.
Ming Yi, Ming Liu, Cuicui Feng, Weihua Deng
2025 J jnl
J. Comput. Phys.
Kamran Arif, Guojiang Xi, Heng Wang, Weihua Deng
2025 A* conf
AAAI
Qiyu Kang, Xuhao Li, Kai Zhao, Wenjun Cui, Yanan Zhao, Weihua Deng, Wee Peng Tay
2025 J jnl
CoRR
Qiyu Kang, Xuhao Li, Kai Zhao, Wenjun Cui, Yanan Zhao, Weihua Deng, Wee Peng Tay
2025 J jnl
Quant. Biol.
Panpan Han, Yang Zhou, Weihua Deng
2025 A* conf
AAAI
Wenjun Cui, Qiyu Kang, Xuhao Li, Kai Zhao, Wee Peng Tay, Weihua Deng, Yidong Li
2025 J jnl
CoRR
Wenjun Cui, Qiyu Kang, Xuhao Li, Kai Zhao, Wee Peng Tay, Weihua Deng, Yidong Li
2024 J jnl
Adv. Comput. Math.
Minghua Chen, Weihua Deng, Chao Min, Jiankang Shi, Martin Stynes
2024 J jnl
Comput. Stat.
Xing Liu, Weihua Deng
2024 conf
ICNSC
Xiaoqing Liu, Weihua Deng, Shengchao Li, Shixin Liu
2024 J jnl
Adv. Comput. Math.
Daxin Nie, Jing Sun, Weihua Deng
2023 J jnl
J. Sci. Comput.
Jing Sun, Daxin Nie, Weihua Deng
2023 J jnl
J. Sci. Comput.
Fugui Ma, Lijing Zhao, Weihua Deng, Yejuan Wang
2023 J jnl
CoRR
Daxin Nie, Jing Sun, Weihua Deng
2023 J jnl
CoRR
Fugui Ma, Lijing Zhao, Lijuan Wang, Weihua Deng
2023 J jnl
Comput. Math. Appl.
Fugui Ma, Lijing Zhao, Yejuan Wang, Weihua Deng
2023 J jnl
Electron. Commer. Res. Appl.
Xuguang Li, Xuekun Zhu, Yingying Lu, Dingyu Shi, Weihua Deng
2022 J jnl
SIAM J. Numer. Anal.
Daxin Nie, Weihua Deng
2022 J jnl
CoRR
Fugui Ma, Lijing Zhao, Weihua Deng, Yejuan Wang
2022 conf
EEET
Kailong Chen, Weihua Deng, Naizheng Han, Hong Lu, Zhe Jiang, Yali Liu
2022 J jnl
CoRR
Dong Liu, Weihua Deng
2022 J jnl
CoRR
Daxin Nie, Jing Sun, Weihua Deng
2022 J jnl
J. Sci. Comput.
Jing Sun, Weihua Deng, Daxin Nie
2022 J jnl
CoRR
Jing Sun, Daxin Nie, Weihua Deng
2022 J jnl
SIAM J. Numer. Anal.
Daxin Nie, Jing Sun, Weihua Deng
2021 J jnl
CoRR
Daxin Nie, Weihua Deng
2021 J jnl
CoRR
Daxin Nie, Weihua Deng
2021 J jnl
SIAM J. Math. Anal.
Zhen-Qing Chen, Weihua Deng, Pengbo Xu
2021 J jnl
CoRR
Jing Sun, Weihua Deng, Daxin Nie
2021 J jnl
J. Sci. Comput.
Xing Liu, Weihua Deng
2021 J jnl
CoRR
Chongcan Li, Yong Cong, Weihua Deng
2021 J jnl
Comput. Math. Appl.
Daxin Nie, Weihua Deng
2021 J jnl
CoRR
Daxin Nie, Weihua Deng
2021 J jnl
CoRR
Daxin Nie, Weihua Deng
2021 J jnl
CoRR
Jing Sun, Weihua Deng, Daxin Nie
2021 J jnl
CoRR
Jing Sun, Daxin Nie, Weihua Deng
2021 J jnl
Aslib J. Inf. Manag.
Ming Yi, Yingying Lu, Weihua Deng, Kun Lu, Zhanhao Zhang
2020 J jnl
Multiscale Model. Simul.
Weihua Deng, Xudong Wang, Pingwen Zhang
2020 J jnl
J. Sci. Comput.
Jing Sun, Daxin Nie, Weihua Deng
2020 J jnl
CoRR
Jing Sun, Daxin Nie, Weihua Deng
2020 J jnl
CoRR
Xing Liu, Weihua Deng
2020 J jnl
J. Sci. Comput.
Xing Liu, Weihua Deng
2020 J jnl
J. Sci. Comput.
Daxin Nie, Jing Sun, Weihua Deng
2020 J jnl
Numerische Mathematik
Daxin Nie, Jing Sun, Weihua Deng
2020 J jnl
Numer. Algorithms
Xing Liu, Weihua Deng
2020 J jnl
CoRR
Daxin Nie, Jing Sun, Weihua Deng
2020 J jnl
Aslib J. Inf. Manag.
Weihua Deng, Pei Lv, Ming Yi, Ming Liu
2020 J jnl
Online Inf. Rev.
Weihua Deng, Ming Yi, Yingying Lu
2019 J jnl
Comput. Math. Appl.
Jing Sun, Daxin Nie, Weihua Deng
2019 J jnl
CoRR
Jing Sun, Daxin Nie, Weihua Deng
2019 J jnl
CoRR
Yajing Li, Yejuan Wang, Weihua Deng
2019 J jnl
J. Sci. Comput.
Daxin Nie, Jing Sun, Weihua Deng
2019 J jnl
CoRR
Daxin Nie, Jing Sun, Weihua Deng
2019 J jnl
CoRR
Daxin Nie, Jing Sun, Weihua Deng
2019 J jnl
CoRR
Xing Liu, Weihua Deng
2018 J jnl
SIAM J. Numer. Anal.
Zhijiang Zhang, Weihua Deng, George E. Karniadakis
2018 J jnl
Multiscale Model. Simul.
Weihua Deng, Buyang Li, Wenyi Tian, Pingwen Zhang
2018 J jnl
Trans. Inst. Meas. Control
Weihua Deng, Kang Li, Jing Deng
2018 J jnl
J. Sci. Comput.
Minghua Chen, Weihua Deng
2018 J jnl
SIAM J. Numer. Anal.
Weihua Deng, Buyang Li, Zhi Qian, Hong Wang
2018 J jnl
J. Sci. Comput.
Minghua Chen, Weihua Deng, Stefano Serra-Capizzano
2017 J jnl
Appl. Math. Lett.
Minghua Chen, Weihua Deng
2017 conf
LSMS/ICSEE (3)
Weihua Deng, Pengfei Chen, Kang Li, Chuanfeng Li
2017 J jnl
SIAM J. Matrix Anal. Appl.
Minghua Chen, Weihua Deng
2017 J jnl
Appl. Math. Lett.
Mehdi Dehghan, Mostafa Abbaszadeh, Weihua Deng
2017 J jnl
SIAM J. Numer. Anal.
Yajing Li, Yejuan Wang, Weihua Deng
2017 J jnl
Adv. Comput. Math.
Zhijiang Zhang, Weihua Deng
2017 J jnl
Comput. Math. Appl.
Weihua Deng, Zhijiang Zhang
2017 conf
LSMS/ICSEE (3)
Jing Wang, Naichao Song, Enyu Jiang, Da Xu, Weihua Deng, Ling Mao
2016 J jnl
J. Sci. Comput.
Shuqin Wang, Jinyun Yuan, Weihua Deng, Yujiang Wu
2016 J jnl
Adv. Comput. Math.
Lijing Zhao, Weihua Deng
2016 J jnl
Adv. Comput. Math.
Can Li, Weihua Deng
2016 J jnl
Int. J. Autom. Comput.
Weihua Deng, Kang Li, Jing Deng
2015 J jnl
Math. Comput.
Wenyi Tian, Han Zhou, Weihua Deng
2015 J jnl
SIAM J. Sci. Comput.
Minghua Chen, Weihua Deng
2015 J jnl
J. Comput. Phys.
Liangliang Qiu, Weihua Deng, Jan S. Hesthaven
2015 J jnl
J. Sci. Comput.
Weihua Deng, Minghua Chen, Eli Barkai
2015 J jnl
Comput. Math. Appl.
Yanyan Yu, Weihua Deng, Yujiang Wu
2014 J jnl
SIAM J. Numer. Anal.
Minghua Chen, Weihua Deng
2014 J jnl
Adv. Comput. Math.
Lijing Zhao, Weihua Deng
2014 J jnl
J. Comput. Appl. Math.
Can Li, Tinggang Zhao, Weihua Deng, Yujiang Wu
2013 J jnl
Appl. Math. Lett.
Weihua Deng, Shanda Du, Yujiang Wu
2013 J jnl
Int. J. Syst. Sci.
Weihua Deng, Kang Li, George W. Irwin, Minrui Fei
2013 J jnl
J. Sci. Comput.
Han Zhou, Wenyi Tian, Weihua Deng
2012 J jnl
Appl. Math. Lett.
Kaiying Deng, Weihua Deng
2012 J jnl
Math. Comput. Simul.
Wenyi Tian, Can Li, Weihua Deng, Yujiang Wu
2012 J jnl
Int. J. Model. Identif. Control.
Minrui Fei, Weihua Deng, Kang Li, Yang Song
2011 J jnl
Comput. Math. Appl.
Can Li, Weihua Deng, Yujiang Wu
2010 conf
LSMS/ICSEE (2)
Weihua Deng, Minrui Fei, Huosheng Hu
2010 conf
LSMS/ICSEE (1)
Minrui Fei, Weihua Deng, Kang Li, Yang Song
2009 conf
BIFE
Ming Yi, Weihua Deng
2009 conf
GEC Summit
Weihua Deng, Minrui Fei
2008 J jnl
SIAM J. Numer. Anal.
Weihua Deng
2007 J jnl
Comput. Math. Appl.
Weihua Deng, Yujiang Wu, Changpin Li
2007 C conf
ISCAS
Weihua Deng, Jinhu Lu
2007 J jnl
Int. J. Bifurc. Chaos
Weihua Deng
2007 J jnl
J. Comput. Phys.
Weihua Deng
2007 J jnl
Appl. Math. Comput.
Changpin Li, Weihua Deng
2006 J jnl
Int. J. Bifurc. Chaos
Weihua Deng, Yujiang Wu, Changpin Li
2006 J jnl
J. Syst. Sci. Complex.
Weihua Deng, Jinhu Lü, Changpin Li
tests/unit/test_database_exporters.py
← Index tests/unit/test_database_exporters.py python
"""
Unit tests for database exporters.
"""
import pytest
import json
from dataclasses import dataclass, asdict
from datetime import datetime, timezone
from unittest.mock import Mock, patch, MagicMock

pytestmark = [pytest.mark.unit, pytest.mark.exporters]


# ============================================================================
# Sample Dataclass for Testing
# ============================================================================

@dataclass
class SampleData:
    """Sample dataclass for export testing."""
    sha256: str = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    name: str = "test_sample"
    value: int = 42
    _id: str = "test_id"


# ============================================================================
# PrintExporter Tests
# ============================================================================

class TestPrintExporter:
    """Tests for PrintExporter class."""

    def test_initialization(self, mock_logger):
        """Test PrintExporter initialization."""
        from redb.extractors.database_exporters import PrintExporter

        exporter = PrintExporter(mock_logger, "test_index")

        assert exporter.index_prefix == "test_index"
        assert exporter.log is mock_logger

    def test_export_dataclass(self, mock_logger, capsys):
        """Test exporting a dataclass."""
        from redb.extractors.database_exporters import PrintExporter

        exporter = PrintExporter(mock_logger, "test_index")
        sample = SampleData()

        result = exporter.export(sample)

        assert result is True
        captured = capsys.readouterr()
        assert "test_sample" in captured.out

    def test_export_list_of_dataclasses(self, mock_logger, capsys):
        """Test exporting a list of dataclasses."""
        from redb.extractors.database_exporters import PrintExporter

        exporter = PrintExporter(mock_logger, "test_index")
        samples = [SampleData(name="sample1"), SampleData(name="sample2")]

        result = exporter.export(samples)

        assert result is True
        captured = capsys.readouterr()
        assert "sample1" in captured.out
        assert "sample2" in captured.out

    def test_export_dict(self, mock_logger, capsys):
        """Test exporting a dictionary."""
        from redb.extractors.database_exporters import PrintExporter

        exporter = PrintExporter(mock_logger, "test_index")
        data = {"key": "value", "number": 42}

        result = exporter.export(data)

        assert result is True
        captured = capsys.readouterr()
        assert "key" in captured.out
        assert "value" in captured.out

    def test_export_none(self, mock_logger):
        """Test exporting None."""
        from redb.extractors.database_exporters import PrintExporter

        exporter = PrintExporter(mock_logger, "test_index")

        result = exporter.export(None)

        assert result is True

    def test_export_empty_list(self, mock_logger):
        """Test exporting empty list."""
        from redb.extractors.database_exporters import PrintExporter

        exporter = PrintExporter(mock_logger, "test_index")

        result = exporter.export([])

        assert result is True


# ============================================================================
# ElasticsearchExporter Tests
# ============================================================================

class TestElasticsearchExporter:
    """Tests for ElasticsearchExporter class."""

    def test_initialization(self, mock_logger):
        """Test ElasticsearchExporter initialization."""
        with patch('redb.settings.get_elasticsearch_client') as mock_client:
            mock_client.return_value = Mock()
            from redb.extractors.database_exporters import ElasticsearchExporter

            exporter = ElasticsearchExporter(mock_logger, "test_index")

            assert exporter.index_prefix == "test_index"
            assert exporter.log is mock_logger
            assert exporter.client is not None

    def test_export_dataclass(self, mock_logger):
        """Test exporting a dataclass to Elasticsearch."""
        with patch('redb.settings.get_elasticsearch_client') as mock_get_client:
            mock_client = Mock()
            mock_get_client.return_value = mock_client

            from redb.extractors.database_exporters import ElasticsearchExporter

            exporter = ElasticsearchExporter(mock_logger, "test_index")
            sample = SampleData()

            result = exporter.export(
                sample,
                index="test_index",
                tag="test_tag",
                hashes={"sha256": sample.sha256}
            )

            assert result is True
            mock_client.index.assert_called()

    def test_export_list(self, mock_logger):
        """Test exporting a list to Elasticsearch."""
        with patch('redb.settings.get_elasticsearch_client') as mock_get_client:
            mock_client = Mock()
            mock_get_client.return_value = mock_client

            from redb.extractors.database_exporters import ElasticsearchExporter

            exporter = ElasticsearchExporter(mock_logger, "test_index")
            samples = [SampleData(name="sample1"), SampleData(name="sample2")]

            result = exporter.export(
                samples,
                index="test_index",
                tag="test_tag",
                hashes={"sha256": "test_hash"}
            )

            assert result is True
            # Should be called twice (once per sample)
            assert mock_client.index.call_count == 2

    def test_export_failure(self, mock_logger):
        """Test handling export failure."""
        with patch('redb.settings.get_elasticsearch_client') as mock_get_client:
            mock_client = Mock()
            mock_client.index.side_effect = Exception("Connection failed")
            mock_get_client.return_value = mock_client

            from redb.extractors.database_exporters import ElasticsearchExporter

            exporter = ElasticsearchExporter(mock_logger, "test_index")
            sample = SampleData()

            result = exporter.export(
                sample,
                index="test_index",
                tag="test_tag",
                hashes={"sha256": sample.sha256}
            )

            assert result is False
            mock_logger.error.assert_called()

    def test_export_with_custom_id(self, mock_logger):
        """Test exporting with custom _id field."""
        with patch('redb.settings.get_elasticsearch_client') as mock_get_client:
            mock_client = Mock()
            mock_get_client.return_value = mock_client

            from redb.extractors.database_exporters import ElasticsearchExporter

            exporter = ElasticsearchExporter(mock_logger, "test_index")
            sample = SampleData(_id="custom_id")

            result = exporter.export(
                sample,
                index="test_index",
                tag="test_tag",
                hashes={"sha256": sample.sha256}
            )

            assert result is True


# ============================================================================
# ClickHouseExporter Tests
# ============================================================================

class TestClickHouseExporter:
    """Tests for ClickHouseExporter class."""

    def test_initialization(self, mock_logger):
        """Test ClickHouseExporter initialization."""
        from redb.extractors.database_exporters import ClickHouseExporter

        mock_client = Mock()
        exporter = ClickHouseExporter(mock_logger, "test_index", client=mock_client)

        assert exporter.index_prefix == "test_index"
        assert exporter.log is mock_logger
        assert exporter.client is mock_client

    def test_export_tuple_data(self, mock_logger):
        """Test exporting tuple data to ClickHouse."""
        with patch('redb.settings.create_clickhouse_client') as mock_create:
            mock_client = Mock()
            mock_client.insert.return_value = True
            mock_create.return_value = mock_client

            from redb.extractors.database_exporters import ClickHouseExporter

            exporter = ClickHouseExporter(mock_logger, "test_index")

            data = [["hash123", "sample.exe", 1024]]
            column_names = ["sha256", "name", "size"]
            column_type_names = ["String", "String", "UInt64"]

            result = exporter.export(
                (data, column_names, column_type_names),
                table="test_table"
            )

            assert result is True

    def test_export_multi_table(self, mock_logger):
        """Test exporting multi-table data to ClickHouse."""
        with patch('redb.settings.create_clickhouse_client') as mock_create:
            mock_client = Mock()
            mock_client.insert.return_value = True
            mock_create.return_value = mock_client

            from redb.extractors.database_exporters import ClickHouseExporter

            exporter = ClickHouseExporter(mock_logger, "test_index")

            data = {
                'multi_table': True,
                'table1': {
                    'table': 'test_table1',
                    'data': [["hash123", "sample.exe"]],
                    'column_names': ["sha256", "name"],
                    'column_type_names': ["String", "String"]
                }
            }

            result = exporter.export(data)

            assert result is True

    def test_export_failure(self, mock_logger):
        """Test handling export failure."""
        with patch('redb.settings.create_clickhouse_client') as mock_create:
            mock_client = Mock()
            mock_client.insert.side_effect = Exception("Connection failed")
            mock_create.return_value = mock_client

            from redb.extractors.database_exporters import ClickHouseExporter

            exporter = ClickHouseExporter(mock_logger, "test_index")

            data = [["hash123", "sample.exe", 1024]]
            column_names = ["sha256", "name", "size"]
            column_type_names = ["String", "String", "UInt64"]

            result = exporter.export(
                (data, column_names, column_type_names),
                table="test_table"
            )

            assert result is False

    def test_export_missing_table(self, mock_logger):
        """Test export without table name raises error."""
        with patch('redb.settings.create_clickhouse_client') as mock_create:
            mock_client = Mock()
            mock_create.return_value = mock_client

            from redb.extractors.database_exporters import ClickHouseExporter

            exporter = ClickHouseExporter(mock_logger, "test_index")

            data = [["hash123", "sample.exe", 1024]]
            column_names = ["sha256", "name", "size"]
            column_type_names = ["String", "String", "UInt64"]

            result = exporter.export(
                (data, column_names, column_type_names)
                # Missing table parameter
            )

            assert result is False

    def test_get_client(self, mock_logger):
        """Test get_client method."""
        from redb.extractors.database_exporters import ClickHouseExporter

        mock_client = Mock()
        exporter = ClickHouseExporter(mock_logger, "test_index", client=mock_client)

        result = exporter.get_client()

        assert result is mock_client

    def test_get_client_creates_new(self, mock_logger):
        """Test get_client creates new client if none exists."""
        with patch('redb.settings.create_clickhouse_client') as mock_create:
            mock_new_client = Mock()
            mock_create.return_value = mock_new_client

            from redb.extractors.database_exporters import ClickHouseExporter

            exporter = ClickHouseExporter(mock_logger, "test_index")

            result = exporter.get_client()

            assert result is mock_new_client


# ============================================================================
# DatabaseExporter Abstract Base Class Tests
# ============================================================================

class TestDatabaseExporter:
    """Tests for DatabaseExporter abstract base class."""

    def test_cannot_instantiate_abstract(self):
        """Test that DatabaseExporter cannot be instantiated directly."""
        from redb.extractors.database_exporters import DatabaseExporter

        with pytest.raises(TypeError):
            DatabaseExporter()

    def test_subclass_must_implement_export(self):
        """Test that subclasses must implement export method."""
        from redb.extractors.database_exporters import DatabaseExporter

        # Define incomplete subclass
        class IncompleteExporter(DatabaseExporter):
            pass

        with pytest.raises(TypeError):
            IncompleteExporter()


# ============================================================================
# Null/Edge Case Tests
# ============================================================================

class TestExporterEdgeCases:
    """Tests for edge cases in exporters."""

    def test_print_exporter_with_complex_nested_data(self, mock_logger, capsys):
        """Test PrintExporter with complex nested data."""
        from redb.extractors.database_exporters import PrintExporter

        exporter = PrintExporter(mock_logger, "test_index")
        data = {
            "level1": {
                "level2": {
                    "level3": [1, 2, 3]
                }
            },
            "array": [{"a": 1}, {"b": 2}]
        }

        result = exporter.export(data)

        assert result is True
        captured = capsys.readouterr()
        assert "level1" in captured.out

    def test_clickhouse_null_handling(self, mock_logger):
        """Test ClickHouse exporter handles null values."""
        with patch('redb.settings.create_clickhouse_client') as mock_create:
            mock_client = Mock()
            mock_client.insert.return_value = True
            mock_create.return_value = mock_client

            from redb.extractors.database_exporters import ClickHouseExporter

            exporter = ClickHouseExporter(mock_logger, "test_index")

            # Multi-table data with null values
            data = {
                'multi_table': True,
                'table1': {
                    'table': 'test_table',
                    'data': [[None, "sample.exe", None]],
                    'column_names': ["sha256", "name", "size"],
                    'column_type_names': ["Nullable(String)", "String", "Nullable(UInt64)"]
                }
            }

            result = exporter.export(data)

            # Should handle nulls appropriately
            assert result is True

    def test_clickhouse_array_handling(self, mock_logger):
        """Test ClickHouse exporter handles array types."""
        with patch('redb.settings.create_clickhouse_client') as mock_create:
            mock_client = Mock()
            mock_client.insert.return_value = True
            mock_create.return_value = mock_client

            from redb.extractors.database_exporters import ClickHouseExporter

            exporter = ClickHouseExporter(mock_logger, "test_index")

            data = {
                'multi_table': True,
                'table1': {
                    'table': 'test_table',
                    'data': [["hash", ["tag1", "tag2"]]],
                    'column_names': ["sha256", "tags"],
                    'column_type_names': ["String", "Array(String)"]
                }
            }

            result = exporter.export(data)

            assert result is True


# ============================================================================
# Type Conversion Tests
# ============================================================================

class TestExporterTypeConversions:
    """Tests for type conversions in exporters."""

    def test_clickhouse_datetime_handling(self, mock_logger):
        """Test ClickHouse exporter handles datetime values."""
        with patch('redb.settings.create_clickhouse_client') as mock_create:
            mock_client = Mock()
            mock_client.insert.return_value = True
            mock_create.return_value = mock_client

            from redb.extractors.database_exporters import ClickHouseExporter

            exporter = ClickHouseExporter(mock_logger, "test_index")

            now = datetime.now(timezone.utc)
            data = {
                'multi_table': True,
                'table1': {
                    'table': 'test_table',
                    'data': [["hash", now]],
                    'column_names': ["sha256", "timestamp"],
                    'column_type_names': ["String", "DateTime64(3, 'UTC')"]
                }
            }

            result = exporter.export(data)

            assert result is True

    def test_print_exporter_datetime_serialization(self, mock_logger, capsys):
        """Test PrintExporter handles datetime serialization."""
        from redb.extractors.database_exporters import PrintExporter

        exporter = PrintExporter(mock_logger, "test_index")
        now = datetime.now(timezone.utc)
        data = {"timestamp": now, "name": "test"}

        result = exporter.export(data)

        assert result is True
        captured = capsys.readouterr()
        assert "timestamp" in captured.out


# ============================================================================
# Connection Context Manager Tests
# ============================================================================

class TestClickHouseConnectionManager:
    """Tests for ClickHouse connection context manager."""

    def test_clickhouse_connection_context(self, mock_logger):
        """Test clickhouse_connection context manager."""
        with patch('redb.settings.create_clickhouse_client') as mock_create:
            mock_client = Mock()
            mock_create.return_value = mock_client

            from redb.extractors.database_exporters import ClickHouseExporter

            exporter = ClickHouseExporter(mock_logger, "test_index")

            with exporter.clickhouse_connection() as client:
                assert client is mock_client

            # Client should be closed after context exits
            mock_client.close.assert_called()

    def test_clickhouse_connection_close_on_error(self, mock_logger):
        """Test client is closed even if operation fails."""
        with patch('redb.settings.create_clickhouse_client') as mock_create:
            mock_client = Mock()
            mock_create.return_value = mock_client

            from redb.extractors.database_exporters import ClickHouseExporter

            exporter = ClickHouseExporter(mock_logger, "test_index")

            try:
                with exporter.clickhouse_connection() as client:
                    raise ValueError("Test error")
            except ValueError:
                pass

            # Client should still be closed
            mock_client.close.assert_called()