Files
sentiment-engine/sentiment_engine/tests/unit/test_output_sinks.py

153 lines
5.9 KiB
Python
Raw Normal View History

"""Tests for output sinks"""
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from sentiment_engine.output.hazelcast_sink import HazelcastSink
from sentiment_engine.output.clickhouse_sink import ClickHouseSink
from sentiment_engine.output.manager import OutputManager
from sentiment_engine.schemas.output import SentimentOutput, AssetSentiment, MarketSentiment, IndustrySentiment, PumpDumpScore, VelocityMetrics, EventFlag
class TestHazelcastSink:
"""Tests for HazelcastSink"""
@pytest.fixture
def sink(self):
return HazelcastSink()
@pytest.mark.asyncio
async def test_publish_scores(self, sink):
"""Test publishing scores to Hazelcast"""
# This would require a running Hazelcast instance
# For now, just verify the sink can be instantiated
assert sink is not None
def test_prepare_exf_data(self, sink):
"""Test preparing ExF data structure"""
from sentiment_engine.schemas.output import SentimentOutput, MarketSentiment
from datetime import datetime
market = MarketSentiment(
fear_state=25.0,
greed_state=75.0,
sentiment_index=50.0,
hype_velocity=65.0,
pub_velocity=55.0,
aggregate_pump_risk=75.0,
aggregate_dump_risk=20.0,
top_pump_assets=["BTC", "ETH"],
top_dump_assets=[],
dominant_events=[],
industry_breakdown={},
last_update_ts=1234567890.0,
total_sources=10,
total_assets=50
)
output = SentimentOutput(
timestamp=1234567890.0,
market=market,
assets={}
)
# Verify ACB signals extraction
acb = output.get_acb_signals()
assert "market_sentiment_state" in acb
assert "aggregate_pump_risk" in acb
assert "fear_state" in acb
assert "greed_state" in acb
assert "hype_velocity" in acb
class TestClickHouseSink:
"""Tests for ClickHouseSink"""
@pytest.fixture
def sink(self):
return ClickHouseSink()
def test_buffer_raw_item(self, sink):
"""Test buffering raw item for batch insert"""
from sentiment_engine.schemas.payload import NormalizedPayload, SourceType, AssetMention, EngagementMetrics
from datetime import datetime
payload = NormalizedPayload(
source_id="test",
source_type=SourceType.NEWS,
source_credibility_base=0.8,
ingest_ts=1234567890.0,
publish_ts=1234567880.0,
asset_mentions=[AssetMention(asset_id="BTC", mention_span=(0, 3), confidence=0.9, source_text="BTC", mention_type="ticker")],
raw_text="Test article",
title="Test",
url="https://test.com",
author="Test",
content_length=100,
language="en",
metadata={}
)
# This should not raise an error
sink.buffer_raw_item(payload)
assert len(sink._batch_buffer) == 1
def test_buffer_processed_item(self, sink):
"""Test buffering processed item for batch insert"""
from sentiment_engine.schemas.processed import ProcessedItem, EntityExtraction, SentimentScores, EmotionScores, EventClassification, EventType, TemporalAnchor, CredibilityScore
from datetime import datetime
item = ProcessedItem(
payload_id="test_1",
source_id="test",
source_type="news",
ingest_ts=1234567890.0,
publish_ts=1234567880.0,
entities=[EntityExtraction(asset_id="BTC", mention_span=(0, 3), confidence=0.9, entity_type="ticker", canonical_name="BTC")],
sentiment_per_asset={"BTC": SentimentScores(polarity=0.7, confidence=0.85, positive_prob=0.8, negative_prob=0.1, neutral_prob=0.1)},
emotions_per_asset={"BTC": EmotionScores(joy=0.8, fear=0.1, anger=0.05, greed=0.7, sadness=0.05, intensity=0.75)},
events=[EventClassification(event_type=EventType.LISTING, confidence=0.7, assets_involved=["BTC"], key_details={}, severity=0.5)],
temporal=TemporalAnchor(event_time=None, time_horizon="immediate", is_breaking=True, is_scheduled=False),
credibility=CredibilityScore(source_base=0.8, content_quality=0.8, engagement_authenticity=0.7, cross_source_corroboration=0.6, historical_accuracy=0.8, composite=0.78),
processed_ts=1234567895.0,
processing_latency_ms=45.2,
model_versions={}
)
sink.buffer_processed_item(item)
assert len(sink._batch_buffer) == 1
def test_buffer_score_output(self, sink):
"""Test buffering scored output"""
from sentiment_engine.schemas.output import SentimentOutput, MarketSentiment, AssetSentiment, PumpDumpScore, VelocityMetrics
import time
market = MarketSentiment(
fear_state=25.0, greed_state=75.0, sentiment_index=50.0,
hype_velocity=65.0, pub_velocity=55.0,
aggregate_pump_risk=75.0, aggregate_dump_risk=20.0,
top_pump_assets=["BTC", "ETH"],
top_dump_assets=[],
dominant_events=[],
industry_breakdown={},
last_update_ts=time.time(),
total_sources=10,
total_assets=50
)
asset = AssetSentiment(
asset_id="BTC",
fear_state=20.0,
greed_state=80.0,
sentiment_polarity=60.0,
pump_dump=PumpDumpScore(asset_id="BTC", pump_score=75.0, dump_score=15.0, pump_confidence=0.8, dump_confidence=0.7, last_update_ts=time.time()),
last_update_ts=time.time()
)
output = SentimentOutput(
timestamp=time.time(),
market=market,
assets={"BTC": asset}
)
sink.buffer_score_output(output)
assert len(sink._batch_buffer) >= 2 # asset + market