Wanfeng Shang

48 papers A* 1A 1Journal 25Unranked 21
YearRankTypeTitle / Venue / Authors
2025 J jnl
IEEE Trans. Circuits Syst. Video Technol.
Qi Zhang, Long Chen, Wanfeng Shang
2025 J jnl
IEEE Trans Autom. Sci. Eng.
Lijing Zheng, Zhengkun Yi, Tiantian Xu, Can Wang, Wanfeng Shang
2025 J jnl
Int. J. Comput. Vis.
Xiaofei Liu, Zhengkun Yi, Xin-Yu Wu, Wanfeng Shang
2024 J jnl
IEEE Trans. Intell. Transp. Syst.
Xing Li, Haotian Zhang, Yajing Shen, Lina Hao, Wanfeng Shang
2024 J jnl
IEEE Trans. Instrum. Meas.
Zhengkun Yi, Wanfeng Shang, Dong Wang, Meng Yin, Chunjie Chen, Wei Feng, Xinyu Wu
2023 J jnl
IEEE Trans. Robotics
Liu Yang, Tieshan Zhang, Han Huang, Hao Ren, Wanfeng Shang, Yajing Shen
2023 conf
RCAR
Wenqiang Huang, Wanfeng Shang, Yulu Li, Xiaofei Liu, Xinyu Wu
2023 J jnl
IEEE Trans. Intell. Transp. Syst.
Xing Li, Zhenlong Hu, Yajing Shen, Lina Hao, Wanfeng Shang
2023 J jnl
IEEE Trans. Ind. Electron.
Zhengkun Yi, Tiantian Xu, Wanfeng Shang, Weimin Li, Xinyu Wu
2023 J jnl
IEEE Trans. Intell. Transp. Syst.
Xing Li, Haotian Zhang, Yajing Shen, Lina Hao, Wanfeng Shang
2023 conf
RCAR
Yulu Li, Wanfeng Shang, Wenqiang Huang, Xiaofei Liu, Xinyu Wu
2023 J jnl
IEEE Trans Autom. Sci. Eng.
Senlin Fang, Zhengkun Yi, Tingting Mi, Zhenning Zhou, Chaoxiang Ye, Wanfeng Shang, Tiantian Xu, Xinyu Wu
2022 J jnl
IEEE Robotics Autom. Lett.
Shanxiu Zhang, Meng Yin, Zhengyu Lai, Chenyang Huang, Can Wang, Wanfeng Shang, Xinyu Wu, Yonghong Zhang, Tiantian Xu
2022 J jnl
IEEE Robotics Autom. Lett.
Wenqiang Huang, Wanfeng Shang, Yueheng Huang, Hongyu Long, Xinyu Wu
2022 J jnl
IEEE Trans. Syst. Man Cybern. Syst.
Zhengkun Yi, Wanfeng Shang, Tiantian Xu, Shifeng Guo, Xinyu Wu
2022 A conf
IROS
Xiaofei Liu, Zhengkun Yi, Xinyu Wu, Wanfeng Shang
2022 J jnl
IEEE Trans. Syst. Man Cybern. Syst.
Zhengkun Yi, Wanfeng Shang, Tiantian Xu, Xinyu Wu
2022 J jnl
IEEE Trans Autom. Sci. Eng.
Zhengkun Yi, Tiantian Xu, Wanfeng Shang, Xinyu Wu
2021 J jnl
IEEE Trans Autom. Sci. Eng.
Jia Liu, Xinyu Wu, Chenyang Huang, Laliphat Manamanchaiyaporn, Wanfeng Shang, Xiaohui Yan, Tiantian Xu
2021 A* conf
ICRA
Hao Ren, Xinyu Wu, Wanfeng Shang
2021 J jnl
IEEE Trans Autom. Sci. Eng.
Zhengkun Yi, Tiantian Xu, Shifeng Guo, Wanfeng Shang, Xinyu Wu
2021 conf
RCAR
Hao Ren, Xinyu Wu, Wanfeng Shang
2020 J jnl
Sci. Robotics
Xiong Yang, Wanfeng Shang, Haojian Lu, Yanting Liu, Liu Yang, Rong Tan, Xinyu Wu, Yajing Shen
2020 J jnl
IEEE Trans Autom. Sci. Eng.
Wanfeng Shang, Hao Ren, Mingjian Zhu, Tiantian Xu, Xinyu Wu
2020 conf
RCAR
Bin Jiang, Tadayoshi Aoyama, Wanfeng Shang
2020 conf
RCAR
Hao Ren, Wanfeng Shang, Niannian Li, Xinyu Wu
2019 conf
ARSO
Tong Wang, Zhengzhi Wu, Jianjun Wei, Chunbao Wang, Quanquan Liu, Zhixian Mao, Lihong Duan, Wanfeng Shang, Yajing Shen, Zhuohua Lin
2019 conf
ARSO
Quanquan Liu, Zhengzhi Wu, Weiguang Li, Xingguang Duan, Masakatsu G. Fujie, Chunbao Wang, Xin Zhang, Bo Zhang, Lihong Duan, Jiaxiang Dong, Wanfeng Shang, Haidong Wang, Weiping Li
2019 conf
NEMS
Wanfeng Shang, Chunbao Wang, Zhengzhi Wu
2018 conf
ISR
Jing Ye, Gong Chen, Quanquan Liu, Lihong Duan, Wanfeng Shang, Xifan Yao, Jianjun Long, Yulong Wang, Zhengzhi Wu, Chunbao Wang
2018 conf
RCAR
Xusheng Xue, Kun Ma, Hongwei Ma, Wanfeng Shang, Hongwei Fan
2018 conf
RCAR
Quanquan Liu, Xin Zhang, Wanfeng Shang, Chunbao Wang, Zhuohua Lin, Tongyang Sun, Jing Ye, Gong Chen, Jianjun Wei, Zhengzhi Wu
2018 conf
CBS
Weiguang Li, Jian Huang, Chunbao Wang, Lihong Duan, Quanquan Liu, Suntong Yang, Wanfeng Shang, Yajing Shen, Zhuohua Lin, Zhixiang Lu, Xiaojiao Chen, Jinfeng Xia, Zhengzhi Wu
2018 conf
ISR
Xiaojiao Chen, Chunbao Wang, Quanquan Liu, Gong Chen, Jianjun Long, Yulong Wang, Lihong Duan, Wanfeng Shang
2018 conf
RCAR
Chunbao Wang, Quanquan Liu, Jing Ye, Gong Chen, Yajing Shen, Wanfeng Shang, Lihong Duan
2018 conf
ISR
Quanquan Liu, Xin Zhang, Chunbao Wang, Bo Zhang, Wanfeng Shang, Zhuohua Lin, Lihong Duan, Zhengzhi Wu, Masakatsu G. Fujie
2018 J jnl
IEEE Trans. Robotics
Haojian Lu, Wanfeng Shang, Hui Xie, Yajing Shen
2018 conf
ISR
Weiguang Li, Zhen Li, Cong Ye, Jing Ye, Gong Chen, Zhuohua Lin, Wanfeng Shang, Quanquan Liu, Chunbao Wang
2017 J jnl
IEEE Trans. Robotics
Yajing Shen, Wenfeng Wan, Haojian Lu, Toshio Fukuda, Wanfeng Shang
2017 conf
ICARM
Chuan Chen, Qihong Liu, Chunbao Wang, Quanquan Liu, Lihong Duan, Tongyang Sun, Qing Shi, Yajing Shen, Wanfeng Shang, Weiguang Li, Zhengzhi Wu
2017 conf
CBS
Quanquan Liu, Chunbao Wang, Bo Zhang, Lihong Duan, Xin Zhang, Tongyang Sun, Wanfeng Shang, Yajing Shen, Zhuohua Lin, Xiaorui Li, Weiguang Li, Weiping Li, Yulong Wang, Masakatsu G. Fujie, Zhengzhi Wu
2017 conf
CBS
Wanfeng Shang, Yuanyuan Yang, Haojian Lu, Yajing Shen
2016 J jnl
J. Sensors
Wanfeng Shang, Xiangang Cao, Hongwei Ma, Hailong Zang, Pengkang Wei
2016 conf
URAI
Chuanwei Wang, Hongwei Ma, Kun Ma, Wanfeng Shang
2014 conf
ROBIO
Wanfeng Shang, Hongwei Ma, Hailong Zang
2013 J jnl
J. Multim.
Wanfeng Shang, Hongwei Ma, Xuhui Zhang
2013 J jnl
J. Syst. Control. Eng.
Wanfeng Shang, Hongwei Ma, Chuanwei Wang
2009 J jnl
Adv. Eng. Informatics
Wanfeng Shang, Shengdun Zhao, Yajing Shen
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()