325 lines
13 KiB
Python
325 lines
13 KiB
Python
"""
|
|
Unit tests for the Audi Stock Car Service parser and normalization logic.
|
|
"""
|
|
from datetime import date
|
|
from decimal import Decimal
|
|
import pytest
|
|
|
|
from oem_crawler.crawlers.base import CrawlerRegistry
|
|
from oem_crawler.crawlers.audi.parser import (
|
|
map_audi_drivetrain,
|
|
map_audi_fuel_type,
|
|
map_audi_series,
|
|
map_audi_transmission,
|
|
parse_audi_vehicle,
|
|
parse_german_date,
|
|
parse_power,
|
|
)
|
|
from oem_crawler.db.schemas import (
|
|
BatteryCapacityUnit,
|
|
DrivetrainType,
|
|
FuelType,
|
|
TransmissionType,
|
|
VehicleCondition,
|
|
VehicleStatus,
|
|
)
|
|
|
|
|
|
class TestAudiParser:
|
|
def test_registry_contains_audi(self):
|
|
assert "audi" in CrawlerRegistry.supported_brands()
|
|
crawler_cls = CrawlerRegistry.get("audi")
|
|
crawler = crawler_cls(market_country="DE")
|
|
assert crawler.brand_name == "AUDI"
|
|
assert crawler.get_market_code("new") == "de"
|
|
assert crawler.get_market_code("used") == "deuc"
|
|
|
|
def test_map_fuel_type(self):
|
|
assert map_audi_fuel_type({"code": "E", "description": "Elektro"}) == FuelType.BEV
|
|
assert map_audi_fuel_type("Elektro") == FuelType.BEV
|
|
assert map_audi_fuel_type({"code": "H", "description": "Hybrid (Benzin/Elektro)"}) == FuelType.PHEV
|
|
assert map_audi_fuel_type({"code": "B", "description": "Benzin"}) == FuelType.PETROL
|
|
assert map_audi_fuel_type({"code": "D", "description": "Diesel"}) == FuelType.DIESEL
|
|
assert map_audi_fuel_type("Mild-Hybrid") == FuelType.MHEV
|
|
assert map_audi_fuel_type("g-tron Erdgas") == FuelType.CNG
|
|
|
|
def test_map_transmission(self):
|
|
assert map_audi_transmission({"code": "s-tronic", "description": "S tronic"}) == TransmissionType.AUTOMATIC
|
|
assert map_audi_transmission("tiptronic") == TransmissionType.AUTOMATIC
|
|
assert map_audi_transmission("Automatik") == TransmissionType.AUTOMATIC
|
|
assert map_audi_transmission({"code": "manual", "description": "Handschaltung"}) == TransmissionType.MANUAL
|
|
assert map_audi_transmission("Schaltgetriebe") == TransmissionType.MANUAL
|
|
assert map_audi_transmission(None) is None
|
|
|
|
def test_map_drivetrain(self):
|
|
assert map_audi_drivetrain({"code": "quattro", "description": "quattro"}) == DrivetrainType.AWD
|
|
assert map_audi_drivetrain("Allradantrieb") == DrivetrainType.AWD
|
|
assert map_audi_drivetrain({"code": "fwd", "description": "Frontantrieb"}) == DrivetrainType.FWD
|
|
assert map_audi_drivetrain("Heckantrieb") == DrivetrainType.RWD
|
|
assert map_audi_drivetrain(None) is None
|
|
|
|
def test_map_series(self):
|
|
assert map_audi_series({"description": "A3"}) == "A3"
|
|
assert map_audi_series({"description": "Q4 e-tron"}) == "Q4 e-tron"
|
|
assert map_audi_series(None, "Audi A1 Sportback 25 TFSI") == "A1"
|
|
assert map_audi_series(None, "Audi e-tron GT quattro 350 kW") == "e-tron GT"
|
|
assert map_audi_series(None, "Audi RS6 Avant performance TFSI") == "RS6"
|
|
assert map_audi_series(None, "Audi Q8 50 TDI quattro") == "Q8"
|
|
|
|
def test_parse_power(self):
|
|
kw, hp = parse_power("110 kW (150 PS)")
|
|
assert kw == 110
|
|
assert hp == 150
|
|
|
|
kw2, hp2 = parse_power("70 kW")
|
|
assert kw2 == 70
|
|
assert hp2 == 95
|
|
|
|
kw3, hp3 = parse_power(None)
|
|
assert kw3 is None
|
|
assert hp3 is None
|
|
|
|
def test_parse_german_date(self):
|
|
assert parse_german_date("21.07.2015") == date(2015, 7, 21)
|
|
assert parse_german_date("2021-10-20") == date(2021, 10, 20)
|
|
assert parse_german_date(1319068800000) == date(2011, 10, 20)
|
|
assert parse_german_date(None) is None
|
|
|
|
def test_parse_audi_new_ice_vehicle(self):
|
|
basic_item = {
|
|
"id": "REVVMjA2NjUxNzdBQlNXMzQyMDI1=",
|
|
"carId": "DEU20665177ABSW342025",
|
|
"decodedCarId": "DEU20665177ABSW342025",
|
|
"commissionNumber": "177ABSW342025",
|
|
"model": {
|
|
"code": "aacv",
|
|
"description": "Audi A1 Sportback 25 TFSI 70 kW (95 PS) Schaltgetriebe",
|
|
},
|
|
"symbolicCarlineGroup": {
|
|
"description": "A1",
|
|
},
|
|
"bodyType": {
|
|
"description": "Sportback",
|
|
},
|
|
"driveType": {
|
|
"code": "drive.fwd",
|
|
"description": "Frontantrieb",
|
|
},
|
|
"gearType": {
|
|
"code": "gear-type.manual",
|
|
"description": "Handschaltung",
|
|
},
|
|
"fuel": {
|
|
"code": "B",
|
|
"description": "Benzin",
|
|
},
|
|
"powerDisplay": "70 kW (95 PS)",
|
|
"modelYear": 2025,
|
|
"typedPrices": [
|
|
{"amount": 356.0, "currencyCode": "EUR", "type": "financeRate"},
|
|
{"amount": 21480.0, "currencyCode": "EUR", "type": "retail"},
|
|
],
|
|
"dealer": {
|
|
"id": "20665",
|
|
"name": "Autohaus Schnitzler GmbH & Co. KG",
|
|
"street": "Westring 20-22",
|
|
"zipCode": "40721",
|
|
"city": "Hilden",
|
|
"geoLocation": {
|
|
"lat": 51.17704,
|
|
"lon": 6.91641,
|
|
},
|
|
},
|
|
"used": {},
|
|
"extColor": {"description": "Gletscherweiß Metallic", "code": "2Y2Y"},
|
|
"intColor": {"description": "Schwarz"},
|
|
"tilesPictures": ["https://mediaservice.audi.com/media/tile.jpg"],
|
|
"pictures": ["https://mediaservice.audi.com/media/full.jpg"],
|
|
}
|
|
|
|
v = parse_audi_vehicle(basic_item=basic_item, market_country="DE", requested_stock_type="new")
|
|
|
|
assert v.brand == "AUDI"
|
|
assert v.oem_vehicle_id == "DEU20665177ABSW342025"
|
|
assert v.series == "A1"
|
|
assert v.model_name == "Audi A1 Sportback 25 TFSI 70 kW (95 PS) Schaltgetriebe"
|
|
assert v.body_type == "Sportback"
|
|
assert v.condition == VehicleCondition.NEW
|
|
assert v.fuel_type == FuelType.PETROL
|
|
assert v.transmission == TransmissionType.MANUAL
|
|
assert v.drivetrain == DrivetrainType.FWD
|
|
assert v.power_kw == 70
|
|
assert v.power_hp == 95
|
|
assert v.model_year == 2025
|
|
assert v.mileage_km == 0
|
|
assert v.price_gross == Decimal("21480.0")
|
|
assert v.monthly_rate == Decimal("356.0")
|
|
assert v.dealer_name == "Autohaus Schnitzler GmbH & Co. KG"
|
|
assert v.dealer_id == "20665"
|
|
assert v.location_city == "Hilden"
|
|
assert v.location_postal_code == "40721"
|
|
assert v.latitude == Decimal("51.17704")
|
|
assert v.longitude == Decimal("6.91641")
|
|
assert v.exterior_color == "Gletscherweiß Metallic"
|
|
assert v.status == VehicleStatus.IN_STOCK
|
|
assert "REVVMjA2NjUxNzdBQlNXMzQyMDI1=" in v.vehicle_url
|
|
assert len(v.image_urls) == 2
|
|
|
|
def test_parse_audi_used_vehicle(self):
|
|
basic_item = {
|
|
"id": "REVVMjIyNjNHVzE4ODMw=",
|
|
"carId": "DEU22263GW18830",
|
|
"model": {
|
|
"description": "Audi A3 Sportback 1.4 TFSI attraction",
|
|
},
|
|
"symbolicCarlineGroup": {
|
|
"description": "A3",
|
|
},
|
|
"fuel": {
|
|
"code": "B",
|
|
"description": "Benzin",
|
|
},
|
|
"gearType": {
|
|
"description": "Handschaltung",
|
|
},
|
|
"driveType": {
|
|
"description": "Frontantrieb",
|
|
},
|
|
"powerDisplay": "92 kW (125 PS)",
|
|
"typedPrices": [
|
|
{"amount": 10890.0, "currencyCode": "EUR", "type": "retail"}
|
|
],
|
|
"dealer": {
|
|
"name": "Autohaus Pietsch.Bünde GmbH",
|
|
"city": "Bünde",
|
|
"zipCode": "32257",
|
|
"geoLocation": {"lat": 52.2025, "lon": 8.57877},
|
|
},
|
|
"warrantyPlus": True,
|
|
"used": {
|
|
"initialRegistration": "21.07.2015",
|
|
"mileage": 108859.0,
|
|
"numPreviousOwners": 2,
|
|
"pictureUrls": ["https://vtpimages.audi.com/carimg2/used.jpg"],
|
|
},
|
|
}
|
|
|
|
v = parse_audi_vehicle(basic_item=basic_item, market_country="DE", requested_stock_type="used")
|
|
|
|
assert v.brand == "AUDI"
|
|
assert v.series == "A3"
|
|
assert v.condition == VehicleCondition.CERTIFIED_PRE_OWNED # warrantyPlus is True
|
|
assert v.mileage_km == 108859
|
|
assert v.first_registration_date == date(2015, 7, 21)
|
|
assert v.previous_owners_count == 2
|
|
assert v.price_gross == Decimal("10890.0")
|
|
assert v.latitude == Decimal("52.2025")
|
|
assert v.longitude == Decimal("8.57877")
|
|
assert "gebrauchtwagenboerse" in v.vehicle_url
|
|
|
|
def test_parse_audi_ev_with_detail(self):
|
|
basic_item = {
|
|
"id": "REVVNDcyNTIxNzdaWlpZNDMyMDI2=",
|
|
"carId": "DEU47252177ZZZY432026",
|
|
"model": {
|
|
"description": "Audi Q4 Sportback e-tron 150 kW",
|
|
},
|
|
"symbolicCarlineGroup": {
|
|
"description": "Q4 e-tron",
|
|
},
|
|
"fuel": {
|
|
"code": "E",
|
|
"description": "Elektro",
|
|
},
|
|
"gearType": {
|
|
"description": "Automatik",
|
|
},
|
|
"powerDisplay": "150 kW (204 PS)",
|
|
"typedPrices": [
|
|
{"amount": 48900.0, "currencyCode": "EUR", "type": "retail"}
|
|
],
|
|
"dealer": {
|
|
"name": "Audi Zentrum Hamburg",
|
|
"city": "Hamburg",
|
|
"zipCode": "22525",
|
|
"geoLocation": {"lat": 53.58, "lon": 9.92},
|
|
},
|
|
}
|
|
|
|
detail_data = {
|
|
"vehicle": {
|
|
"detail": {
|
|
"techData": {
|
|
"fields": [
|
|
{"name": "Netto-Batterie-Kapazität", "value": "59 kWh"},
|
|
{"name": "Brutto-Batterie-Kapazität", "value": "63 kWh"},
|
|
{"name": "Max. Ladeleistung AC / HPC", "value": "11 kW / 160 kW"},
|
|
{"name": "Ladedauer DC 10-80% bei max. Ladeleistung", "value": "27 min"},
|
|
{"name": "Elektrische Reichweite kombiniert (WLTP)", "value": "415 km"},
|
|
]
|
|
},
|
|
"features": [
|
|
{
|
|
"key": "5SL",
|
|
"prno": "MASL5SL",
|
|
"name": "Außenspiegel links, asphärisch",
|
|
"groupName": "Außenausstattung",
|
|
"kind": "serie",
|
|
},
|
|
{
|
|
"key": "KA2",
|
|
"prno": "MKA2KA2",
|
|
"name": "Rückfahrkamera",
|
|
"groupName": "Assistenzsysteme",
|
|
"kind": "sonder",
|
|
},
|
|
],
|
|
}
|
|
}
|
|
}
|
|
|
|
v = parse_audi_vehicle(
|
|
basic_item=basic_item,
|
|
detail_data=detail_data,
|
|
market_country="DE",
|
|
requested_stock_type="new",
|
|
)
|
|
|
|
assert v.brand == "AUDI"
|
|
assert v.series == "Q4 e-tron"
|
|
assert v.fuel_type == FuelType.BEV
|
|
assert v.battery_capacity == Decimal("59")
|
|
assert v.battery_capacity_net_kwh == Decimal("59")
|
|
assert v.battery_capacity_gross_kwh == Decimal("63")
|
|
assert v.battery_capacity_unit == BatteryCapacityUnit.KWH
|
|
assert v.charging_power_ac_kw == Decimal("11")
|
|
assert v.charging_power_dc_kw == Decimal("160")
|
|
assert v.charging_time_dc_minutes == 27
|
|
assert v.electric_range_wltp_km == 415
|
|
|
|
# Check options
|
|
assert len(v.options) == 2
|
|
assert v.options[0].option_code == "5SL"
|
|
assert v.options[0].is_standard is True
|
|
assert v.options[1].option_code == "KA2"
|
|
assert v.options[1].is_standard is False
|
|
assert v.options[1].category == "Assistenzsysteme"
|
|
|
|
def test_fetch_search_page_pagination_params(self):
|
|
from unittest.mock import MagicMock
|
|
from oem_crawler.crawlers.audi.crawler import AudiStockCrawler
|
|
|
|
crawler = AudiStockCrawler(market_country="DE")
|
|
mock_client = MagicMock()
|
|
mock_resp = MagicMock()
|
|
mock_resp.status_code = 200
|
|
mock_resp.json.return_value = {"totalCount": 100, "vehicleBasic": []}
|
|
mock_client.get.return_value = mock_resp
|
|
|
|
crawler.fetch_search_page(mock_client, market_code="de", page=2, size=50)
|
|
|
|
mock_client.get.assert_called_once()
|
|
call_kwargs = mock_client.get.call_args.kwargs
|
|
assert call_kwargs["params"]["from"] == 100
|
|
assert call_kwargs["params"]["size"] == 50
|
|
|