122 lines
4.2 KiB
Python
122 lines
4.2 KiB
Python
"""Unit tests for data collectors"""
|
|
|
|
import pytest
|
|
from datetime import datetime
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
from app.services.collectors.top500 import TOP500Collector
|
|
from app.services.collectors.base import BaseCollector, HTTPCollector
|
|
|
|
|
|
class TestBaseCollector:
|
|
"""Tests for BaseCollector"""
|
|
|
|
def test_base_collector_attributes(self):
|
|
"""Test base collector has correct default attributes via concrete class"""
|
|
collector = TOP500Collector()
|
|
assert collector.name == "top500"
|
|
assert collector.priority == "P0"
|
|
assert collector.module == "L1"
|
|
assert collector.frequency_hours == 4
|
|
|
|
|
|
class TestTOP500Collector:
|
|
"""Tests for TOP500Collector"""
|
|
|
|
def test_parse_coordinate_valid_float(self):
|
|
"""Test parsing valid float coordinate"""
|
|
collector = TOP500Collector()
|
|
assert collector._parse_coordinate(45.5) == 45.5
|
|
|
|
def test_parse_coordinate_valid_string(self):
|
|
"""Test parsing valid string coordinate"""
|
|
collector = TOP500Collector()
|
|
assert collector._parse_coordinate("45.5") == 45.5
|
|
|
|
def test_parse_coordinate_invalid_string(self):
|
|
"""Test parsing invalid string coordinate"""
|
|
collector = TOP500Collector()
|
|
assert collector._parse_coordinate("invalid") == 0.0
|
|
|
|
def test_parse_coordinate_none(self):
|
|
"""Test parsing None coordinate"""
|
|
collector = TOP500Collector()
|
|
assert collector._parse_coordinate(None) == 0.0
|
|
|
|
def test_parse_response_empty(self):
|
|
"""Test parsing empty response"""
|
|
collector = TOP500Collector()
|
|
result = collector.parse_response("<html><body><table></table></body></html>")
|
|
assert len(result) > 0
|
|
|
|
def test_parse_response_single_item(self):
|
|
"""Test parsing single item response"""
|
|
collector = TOP500Collector()
|
|
response = """
|
|
<table class="top500-table">
|
|
<tr><th>Rank</th><th>System</th><th>Cores</th><th>Rmax</th><th>Rpeak</th><th>Power</th></tr>
|
|
<tr>
|
|
<td>1</td>
|
|
<td><a href="/system/1/">Test Supercomputer</a>, Test Corp\nTest Site\nUSA</td>
|
|
<td>100000</td>
|
|
<td>100 PFLOP/s</td>
|
|
<td>150 PFLOP/s</td>
|
|
<td>5000</td>
|
|
</tr>
|
|
</table>
|
|
"""
|
|
result = collector.parse_response(response)
|
|
assert len(result) == 1
|
|
assert result[0]["source_id"] == "top500_1"
|
|
assert result[0]["name"] == "Test Supercomputer"
|
|
assert result[0]["country"] == "USA"
|
|
assert result[0]["metadata"]["rank"] == 1
|
|
assert "Test Corp" in result[0]["metadata"]["manufacturer"]
|
|
|
|
def test_parse_response_skips_invalid_item(self):
|
|
"""Test parsing skips items with missing data"""
|
|
collector = TOP500Collector()
|
|
response = """
|
|
<table class="top500-table">
|
|
<tr><th>Rank</th><th>System</th><th>Cores</th><th>Rmax</th><th>Rpeak</th><th>Power</th></tr>
|
|
<tr>
|
|
<td>1</td>
|
|
<td>Valid\nVendor\nSite\nUSA</td>
|
|
<td>1000</td>
|
|
<td>10 PFLOP/s</td>
|
|
<td>12 PFLOP/s</td>
|
|
<td>100</td>
|
|
</tr>
|
|
<tr>
|
|
<td>-</td>
|
|
<td>Invalid</td>
|
|
<td>1000</td>
|
|
<td>10 PFLOP/s</td>
|
|
<td>12 PFLOP/s</td>
|
|
<td>100</td>
|
|
</tr>
|
|
</table>
|
|
"""
|
|
result = collector.parse_response(response)
|
|
assert len(result) == 1
|
|
assert result[0]["name"] == "Valid"
|
|
|
|
|
|
class TestHTTPCollector:
|
|
"""Tests for HTTPCollector"""
|
|
|
|
def test_http_collector_attributes(self):
|
|
"""Test HTTP collector has correct default attributes via concrete class"""
|
|
collector = TOP500Collector()
|
|
assert collector.name == "top500"
|
|
assert collector.priority == "P0"
|
|
assert hasattr(collector, "fetch")
|
|
|
|
def test_collector_has_required_methods(self):
|
|
"""Test HTTP collector has required methods"""
|
|
collector = TOP500Collector()
|
|
assert hasattr(collector, "fetch")
|
|
assert hasattr(collector, "parse_response")
|
|
assert callable(collector.fetch)
|
|
assert callable(collector.parse_response)
|