fix: make BusProNet response failures diagnosable and non-fatal

This commit is contained in:
2026-09-19 11:36:14 +02:00
parent 29cedd5916
commit a05143bfbe
8 changed files with 207 additions and 19 deletions
+60
View File
@@ -10,6 +10,7 @@ use App\BusProNet\Model\Pickup;
use App\BusProNet\Model\ProfileResponse;
use App\BusProNet\Model\ProfileUpdateResponse;
use App\BusProNet\ResponseParser;
use App\BusProNet\ResponseParserException;
use PHPUnit\Framework\TestCase;
class ResponseParserTest extends TestCase
@@ -178,6 +179,65 @@ class ResponseParserTest extends TestCase
$this->assertEquals('Gaststätte', $hotel->getType());
}
/**
* A broken response used to collapse into one opaque "Unable to parse XML response",
* which is what made the production import failure undiagnosable. Each shape must now
* name itself.
*/
public function testParseEmptyResponse(): void
{
$parser = $this->getParserInstance();
$this->expectException(ResponseParserException::class);
$this->expectExceptionMessage('empty response');
$parser->parseXmlString(ApiClient::TYPE_BASE_DATA_PICKUPS, '');
}
public function testParseTruncatedResponse(): void
{
$content = '<?xml version="1.0" encoding="utf-8"?><ergebnis><satz typ="STAMMZUSTIEGE"></satz><zustieg id="1"';
$parser = $this->getParserInstance();
try {
$parser->parseXmlString(ApiClient::TYPE_BASE_DATA_PICKUPS, $content);
$this->fail('Expected a ResponseParserException');
} catch (ResponseParserException $e) {
$this->assertStringContainsString('('.strlen($content).' bytes)', $e->getMessage());
$this->assertStringContainsString('line 1', $e->getMessage());
}
}
public function testParseWellFormedResponseOfAnUnknownType(): void
{
$content = '<?xml version="1.0" encoding="utf-8"?><ergebnis><satz typ="STAMMIRGENDWAS"></satz></ergebnis>';
$parser = $this->getParserInstance();
$this->expectException(ResponseParserException::class);
$this->expectExceptionMessage('Unrecognised BusProNet response type "STAMMIRGENDWAS"');
$parser->parseXmlString(ApiClient::TYPE_BASE_DATA_PICKUPS, $content);
}
public function testParsingDoesNotLeakLibxmlErrorState(): void
{
$previous = libxml_use_internal_errors(false);
try {
try {
$this->getParserInstance()->parseXmlString(ApiClient::TYPE_BASE_DATA_PICKUPS, '<ergebnis');
} catch (ResponseParserException) {
}
$this->assertFalse(libxml_use_internal_errors(false));
$this->assertSame([], libxml_get_errors());
} finally {
libxml_use_internal_errors($previous);
}
}
private function loadFixture(string $filename): string
{
return file_get_contents(__DIR__.'/../Resources/'.$filename);