Carlos Cetina

122 papers A 19B 13C 2Journal 57Unranked 27
YearRankTypeTitle / Venue / Authors
2026 J jnl
J. Syst. Softw.
Samuel Navarro, Jorge Chueca, Daniel Blasco, Carlos Cetina, Jaime Font
2026 J jnl
Inf. Softw. Technol.
Carlos Pérez, Javier Verón, Francisca Pérez, Maángeles Moraga, Coral Calero, Carlos Cetina
2025 J jnl
Inf. Softw. Technol.
Jose Ignacio Trasobares, África Domingo, Rodrigo Casamayor, Daniel Blasco, Carlos Cetina
2025 J jnl
Softw. Syst. Model.
Rodrigo Casamayor, Lorena Arcega, Francisca Pérez, Carlos Cetina
2025 A conf
MODELS
Jose Ignacio Trasobares, África Domingo, Jorge Echeverría, Lorena Arcega, Carlos Cetina
2025 J jnl
ACM SIGSOFT Softw. Eng. Notes
Antonio Bucchiarone, Beatriz Marín, Kendra M. L. Cooper, Jeremy S. Bradbury, Carlos Cetina, Mathieu Nayrolles
2025 J jnl
ACM Trans. Softw. Eng. Methodol.
Daniel Blasco, Antonio Iglesias, Jorge Echeverría, Francisca Pérez, Carlos Cetina
2025 conf
SEIP@ICSE
Mar Zamorano, Daniel Blasco, Carlos Cetina, Federica Sarro
2024 J jnl
CoRR
Carlos Pérez, Javier Verón, Francisca Pérez, María Ángeles Moraga, Coral Calero, Carlos Cetina
2024 A conf
MODELS
Javier Verón, Carlos Pérez, Coral Calero, María Ángeles Moraga, Francisca Pérez, Carlos Cetina
2024 J jnl
IEEE Trans. Software Eng.
Ana Cristina Marcén, Antonio Iglesias, Raúl Lapeña, Francisca Pérez, Carlos Cetina
2024 J jnl
Knowl. Inf. Syst.
Katsiaryna Akhramovich, Estefanía Serral, Carlos Cetina
2024 J jnl
Inf. Softw. Technol.
Isis Roca, Óscar Pastor, Carlos Cetina, Lorena Arcega
2024 A conf
CAiSE
Isis Roca, África Domingo, Óscar Pastor, Carlos Cetina, Lorena Arcega
2024 A conf
ESEM
Mar Zamorano, África Domingo, Carlos Cetina, Federica Sarro
2024 A conf
CAiSE
Javier Verón, Raúl Lapeña, Carlos Cetina, Óscar Pastor, Francisca Pérez
2024 conf
SPLC (A)
Jorge Chueca, Daniel Blasco, Carlos Cetina, Jaime Font
2024 J jnl
Softw. Pract. Exp.
Isis Roca, Jaime Font, Lorena Arcega, Carlos Cetina
2024 conf
SPLC (B)
Samuel Navarro, Antonio Iglesias, Francisca Pérez, Carlos Cetina, Jaime Font
2024 J jnl
Inf. Softw. Technol.
Jorge Chueca, Carlos Cetina, Oscar Pastor, Jaime Font
2024 J jnl
Inf. Softw. Technol.
Jorge Chueca, Javier Verón, Jaime Font, Francisca Pérez, Carlos Cetina
2023 J jnl
CoRR
Carlos Pérez, Ana Cristina Marcén, Javier Verón, Carlos Cetina
2023 A ed.
CAiSE
Marta Indulska, Iris Reinhartz-Berger, Carlos Cetina, Oscar Pastor
2023 J jnl
J. Syst. Softw.
Jorge Chueca, Jose Ignacio Trasobares, África Domingo, Lorena Arcega, Carlos Cetina, Jaime Font
2023 ch.
Handbook of Re-Engineering Software Intensive Systems into Software Product Lines
Lorena Arcega, Jaime Font, Øystein Haugen, Carlos Cetina
2023 J jnl
ACM Trans. Softw. Eng. Methodol.
Francisca Pérez, Raúl Lapeña, Ana Cristina Marcén, Carlos Cetina
2023 J jnl
Softw. Pract. Exp.
Manuel Ballarín, Lorena Arcega, Vicente Pelechano, Carlos Cetina
2023 J jnl
Multim. Tools Appl.
Daniel Blasco, Jaime Font, Francisca Pérez, Carlos Cetina
2023 J jnl
IEEE Trans. Software Eng.
Rodrigo Casamayor, Carlos Cetina, Oscar Pastor, Francisca Pérez
2023 J jnl
CoRR
Mar Zamorano, Carlos Cetina, Federica Sarro
2022 J jnl
ACM Trans. Softw. Eng. Methodol.
Lorena Arcega, Jaime Font, Øystein Haugen, Carlos Cetina
2022 A conf
MoDELS
Rodrigo Casamayor, Lorena Arcega, Francisca Pérez, Carlos Cetina
2022 J jnl
IEEE Trans. Software Eng.
Francisca Pérez, Jaime Font, Lorena Arcega, Carlos Cetina
2022 J jnl
Softw. Syst. Model.
Ana Cristina Marcén, Francisca Pérez, Oscar Pastor, Carlos Cetina
2022 J jnl
Softw. Pract. Exp.
Ana Cristina Marcén, Francisca Pérez, Oscar Pastor, Carlos Cetina
2022 conf
SPLC (A)
Jose Ignacio Trasobares, África Domingo, Lorena Arcega, Carlos Cetina
2022 J jnl
Requir. Eng.
Raúl Lapeña, Francisca Pérez, Carlos Cetina, Oscar Pastor
2022 J jnl
Inf. Softw. Technol.
Raúl Lapeña, Francisca Pérez, Oscar Pastor, Carlos Cetina
2022 J jnl
IEEE Trans. Software Eng.
Francisca Pérez, Tewfik Ziadi, Carlos Cetina
2021 J jnl
Inf. Softw. Technol.
Jorge Echeverría, Francisca Pérez, José Ignacio Panach, Carlos Cetina
2021 J jnl
J. Syst. Softw.
Daniel Blasco, Jaime Font, Mar Zamorano, Carlos Cetina
2021 A conf
CAiSE
África Domingo, Jorge Echeverría, Oscar Pastor, Carlos Cetina
2021 J jnl
J. Syst. Softw.
Jorge Echeverría, Jaime Font, Francisca Pérez, Carlos Cetina
2021 J jnl
Inf. Softw. Technol.
África Domingo, Jorge Echeverría, Oscar Pastor, Carlos Cetina
2021 J jnl
Softw. Syst. Model.
Jaime Font, Lorena Arcega, Øystein Haugen, Carlos Cetina
2021 J jnl
Inf. Softw. Technol.
Manuel Ballarín, Ana Cristina Marcén, Vicente Pelechano, Carlos Cetina
2021 J jnl
Inf. Softw. Technol.
Francisca Pérez, Raúl Lapeña, Ana Cristina Marcén, Carlos Cetina
2020 J jnl
Inf. Softw. Technol.
Daniel Blasco, Carlos Cetina, Oscar Pastor
2020 J jnl
Inf. Softw. Technol.
Francisca Pérez, Jorge Echeverría, Raúl Lapeña, Carlos Cetina
2020 J jnl
IEEE Access
Francisca Pérez, Ana Cristina Marcén, Raúl Lapeña, Carlos Cetina
2020 A conf
CAiSE
África Domingo, Jorge Echeverría, Oscar Pastor, Carlos Cetina
2020 J jnl
J. Syst. Softw.
Ana Cristina Marcén, Raúl Lapeña, Oscar Pastor, Carlos Cetina
2019 J jnl
Softw. Syst. Model.
Lorena Arcega, Jaime Font, Øystein Haugen, Carlos Cetina
2019 J jnl
Autom. Softw. Eng.
Francisca Pérez, Jaime Font, Lorena Arcega, Carlos Cetina
2019 A conf
CAiSE
Raúl Lapeña, Francisca Pérez, Carlos Cetina, Oscar Pastor
2019 J jnl
J. Softw. Evol. Process.
Rafael Capilla, Barbara Gallina, Carlos Cetina, John M. Favaro
2019 ed.
SPLC (B)
Carlos Cetina, Oscar Díaz, Laurence Duchien, Marianne Huchard, Rick Rabiser, Camille Salinesi, Christoph Seidl, Xhevahire Tërnava, Leopoldo Teixeira, Thomas Thüm, Tewfik Ziadi
2019 J jnl
J. Softw. Evol. Process.
Rafael Capilla, Barbara Gallina, Carlos Cetina
2018 J jnl
IEEE Trans. Evol. Comput.
Jaime Font, Lorena Arcega, Øystein Haugen, Carlos Cetina
2018 J jnl
Data Knowl. Eng.
Francisca Pérez, Jaime Font, Lorena Arcega, Carlos Cetina
2018 A conf
MoDELS
Lorena Arcega, Jaime Font, Carlos Cetina
2018 A conf
CAiSE
Raúl Lapeña, Jaime Font, Carlos Cetina, Oscar Pastor
2018 J jnl
Inf. Softw. Technol.
Francisca Pérez, Raúl Lapeña, Jaime Font, Carlos Cetina
2018 J jnl
IEEE Access
Francisca Pérez, Manuel Ballarín, Raúl Lapeña, Carlos Cetina
2018 A conf
MoDELS
Manuel Ballarín, Ana Cristina Marcén, Vicente Pelechano, Carlos Cetina
2018 B ed.
ICSR
Rafael Capilla, Barbara Gallina, Carlos Cetina
2017 B conf
GPCE
Raúl Lapeña, Jaime Font, Oscar Pastor, Carlos Cetina
2017 conf
ISD
Jorge Echeverría, Francisca Pérez, Oscar Pastor, Carlos Cetina
2017 J jnl
J. Syst. Softw.
Carlos Cetina, Jaime Font, Lorena Arcega, Francisca Pérez
2017 conf
OTM Conferences (1)
Francisca Pérez, Ana Cristina Marcén, Raúl Lapeña, Carlos Cetina
2017 J jnl
Comput. Lang. Syst. Struct.
Jaime Font, Lorena Arcega, Øystein Haugen, Carlos Cetina
2017 conf
CAiSE-Forum-DC
Raúl Lapeña, Jaime Font, Carlos Cetina, Oscar Pastor
2017 B conf
ECMFA
Lorena Arcega, Jaime Font, Øystein Haugen, Carlos Cetina
2017 conf
ER Forum/Demos
Raúl Lapeña, Francisca Pérez, Carlos Cetina
2017 conf
ISD
Lorena Arcega, Jaime Font, Øystein Haugen, Carlos Cetina
2017 A conf
ER
Ana Cristina Marcén, Francisca Pérez, Carlos Cetina
2017 A conf
ESEM
Jorge Echeverría, Francisca Pérez, José Ignacio Panach, Carlos Cetina, Oscar Pastor
2017 conf
SPLC (B)
Ana Cristina Marcén, Jaime Font, Oscar Pastor, Carlos Cetina
2016 A conf
SANER
Lorena Arcega, Jaime Font, Øystein Haugen, Carlos Cetina
2016 conf
Lorena Arcega, Jaime Font, Øystein Haugen, Carlos Cetina
2016 A conf
CAiSE
Jorge Echeverría, Francisca Pérez, Carlos Cetina, Oscar Pastor
2016 A conf
ESEM
Jorge Echeverría, Francisca Pérez, Andrés Abellanas, José Ignacio Panach, Carlos Cetina, Oscar Pastor
2016 conf
SAM
Lorena Arcega, Jaime Font, Øystein Haugen, Carlos Cetina
2016 B conf
ICSR
Jaime Font, Lorena Arcega, Øystein Haugen, Carlos Cetina
2016 A conf
MoDELS
Jaime Font, Lorena Arcega, Øystein Haugen, Carlos Cetina
2016 B conf
SPLC
Raúl Lapeña, Jaime Font, Francisca Pérez, Carlos Cetina
2016 B conf
ICSR
Manuel Ballarín, Raúl Lapeña, Carlos Cetina
2016 B conf
SPLC
Raúl Lapeña, Manuel Ballarín, Carlos Cetina
2015 B conf
GPCE
Jaime Font, Lorena Arcega, Øystein Haugen, Carlos Cetina
2015 B conf
SPLC
Jaime Font, Manuel Ballarín, Øystein Haugen, Carlos Cetina
2015 B conf
SPLC
Jaime Font, Lorena Arcega, Øystein Haugen, Carlos Cetina
2015 conf
Lorena Arcega, Jaime Font, Øystein Haugen, Carlos Cetina
2015 conf
CAiSE Forum
Jorge Echeverría, Jaime Font, Carlos Cetina, Oscar Pastor
2015 J jnl
Complex Syst. Informatics Model. Q.
Jorge Echeverría, Jaime Font, Oscar Pastor, Carlos Cetina
2013 J jnl
Sci. Comput. Program.
Carlos Cetina, Pau Giner, Joan Fons, Vicente Pelechano
2013 C conf
MobiQuitous
Lorena Arcega, Jaime Font, Carlos Cetina
2013 J jnl
Sensors
Lorena Arcega, Jaime Font, Carlos Cetina
2013 ch.
Systems and Software Variability Management
Carlos Cetina, Vicente Pelechano
2012 J jnl
Sensors
Pau Giner, Carlos Cetina, Raquel Lacuesta, Guillermo Palacios
2012 J jnl
EURASIP J. Wirel. Commun. Netw.
Raquel Lacuesta Gilaberte, Guillermo Palacios, Carlos Cetina, Lourdes Peñalver, Jaime Lloret
2011 J jnl
Pers. Ubiquitous Comput.
Pau Giner, Carlos Cetina, Joan Fons, Vicente Pelechano
2010
Carlos Cetina
2010 conf
JISBD
Carlos Cetina, Pau Giner, Joan Fons, Vicente Pelechano
2010 B conf
SPLC
Carlos Cetina, Pau Giner, Joan Fons, Vicente Pelechano
2010 J jnl
IEEE Pervasive Comput.
Pau Giner, Carlos Cetina, Joan Fons, Vicente Pelechano
2009 J jnl
Computer
Carlos Cetina, Pau Giner, Joan Fons, Vicente Pelechano
2009 conf
IWANN (2)
Pau Giner, Carlos Cetina, Joan Fons, Vicente Pelechano
2009 conf
JISBD
Carlos Cetina, Pablo Trinidad, Vicente Pelechano, Antonio Ruiz Cortés, David Benavides
2009 J jnl
ERCIM News
Pau Giner, Carlos Cetina, Joan Fons, Vicente Pelechano
2009 C conf
MobiQuitous
Pau Giner, Carlos Cetina, Joan Fons, Vicente Pelechano
2009 B conf
SPLC
Carlos Cetina, Øystein Haugen, Xiaorui Zhang, Franck Fleurey, Vicente Pelechano
2009 conf
VaMoS
Francisca Pérez, Carlos Cetina, Pedro Valderas, Joan Fons
2009 conf
ICAS
Carlos Cetina, Pau Giner, Joan Fons, Vicente Pelechano
2008 conf
SPLC (2)
Carlos Cetina, Vicente Pelechano, Pablo Trinidad, Antonio Ruiz Cortés
2008 B conf
SPLC
Carlos Cetina, Joan Fons, Vicente Pelechano
2008 conf
CIbSE
Carlos Cetina, Vicente Pelechano, Sonia Montagud
2007 conf
JISBD
Estefanía Serral, Carlos Cetina, Javier Muñoz, Vicente Pelechano
2007 conf
ICPS
Javier Muñoz, Vicente Pelechano, Carlos Cetina
2007 conf
MOMPES
Carlos Cetina, Estefanía Serral, Javier Muñoz, Vicente Pelechano
2006 conf
DSDM
Vicente Pelechano, Manoli Albert, Javier Muñoz, Carlos Cetina
2006 conf
IWUC
Javier Muñoz, Vicente Pelechano, Carlos Cetina
2006 conf
CIbSE
Javier Muñoz, Carlos Cetina, Estefanía Serral, Vicente Pelechano
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()