-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #20 from keboola/roman-fix-exception-handler
Fix parsing exception
- Loading branch information
Showing
3 changed files
with
291 additions
and
32 deletions.
There are no files selected for viewing
87 changes: 87 additions & 0 deletions
87
src/Keboola/GoogleDriveExtractor/Extractor/ExceptionHandler.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
|
||
namespace Keboola\GoogleDriveExtractor\Extractor; | ||
|
||
use GuzzleHttp\Exception\RequestException; | ||
use Keboola\GoogleDriveExtractor\Exception\ApplicationException; | ||
use Keboola\GoogleDriveExtractor\Exception\UserException; | ||
|
||
class ExceptionHandler | ||
{ | ||
public function handleGetSpreadsheetException(\Exception $e, array $sheet) | ||
{ | ||
if (($e instanceof RequestException) && ($e->getResponse() !== null)) { | ||
if ($e->getResponse()->getStatusCode() === 404) { | ||
throw new UserException(sprintf('File "%s" not found in Google Drive', $sheet['sheetTitle']), 404, $e); | ||
} | ||
|
||
$errorSpec = json_decode($e->getResponse()->getBody(), true); | ||
|
||
if (array_key_exists('error', $errorSpec)) { | ||
if ($errorSpec['error'] === 'invalid_grant') { | ||
throw new UserException(sprintf( | ||
'Invalid OAuth grant when fetching "%s", try reauthenticating the extractor', | ||
$sheet['fileTitle'] | ||
), 0, $e); | ||
} | ||
|
||
if (count($errorSpec['error']) > 1 && !isset($errorSpec['error_description'])) { | ||
throw new UserException(sprintf( | ||
'"%s" (%s) for "%s"', | ||
$errorSpec['error']['message'], | ||
$errorSpec['error']['status'], | ||
$sheet['sheetTitle'] | ||
), 0, $e); | ||
} | ||
|
||
if (isset($errorSpec['error_description'])) { | ||
throw new UserException(sprintf( | ||
'"%s" (%s)', | ||
$errorSpec['error_description'], | ||
$errorSpec['error'] | ||
), 0, $e); | ||
} | ||
} | ||
|
||
$userException = new UserException("Google Drive Error: " . $e->getMessage(), 400, $e); | ||
$userException->setData([ | ||
'message' => $e->getMessage(), | ||
'reason' => $e->getResponse()->getReasonPhrase(), | ||
'sheet' => $sheet, | ||
]); | ||
throw $userException; | ||
} | ||
throw new ApplicationException( | ||
$e->getMessage(), | ||
$e->getCode(), | ||
$e | ||
); | ||
} | ||
|
||
public function handleExportException(\Exception $e, $sheet) | ||
{ | ||
if (($e instanceof RequestException) && ($e->getResponse() !== null)) { | ||
$userException = new UserException( | ||
sprintf( | ||
"Error importing file - sheet: '%s - %s'", | ||
$sheet['fileTitle'], | ||
$sheet['sheetTitle'] | ||
), | ||
400, | ||
$e | ||
); | ||
$userException->setData(array( | ||
'message' => $e->getMessage(), | ||
'reason' => $e->getResponse()->getReasonPhrase(), | ||
'body' => substr($e->getResponse()->getBody()->getContents(), 0, 300), | ||
'sheet' => $sheet | ||
)); | ||
throw $userException; | ||
} | ||
throw new ApplicationException( | ||
$e->getMessage(), | ||
$e->getCode(), | ||
$e | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
<?php | ||
|
||
namespace Keboola\GoogleDriveExtractor\Tests\Extractor; | ||
|
||
use GuzzleHttp\Exception\RequestException; | ||
use GuzzleHttp\Psr7\Request; | ||
use GuzzleHttp\Psr7\Response; | ||
use Keboola\GoogleDriveExtractor\Exception\ApplicationException; | ||
use Keboola\GoogleDriveExtractor\Exception\UserException; | ||
use Keboola\GoogleDriveExtractor\Extractor\ExceptionHandler; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
class ExceptionHandleTest extends TestCase | ||
{ | ||
/** | ||
* @dataProvider provideExceptionsForGetSpreadsheet | ||
*/ | ||
public function testHandlingOfExceptions( | ||
$expectedExceptionClass, | ||
$expectedExceptionMessage, | ||
\Exception $caughtException, | ||
array $sheet | ||
) { | ||
$handler = new ExceptionHandler(); | ||
$this->expectException($expectedExceptionClass); | ||
$this->expectExceptionMessage($expectedExceptionMessage); | ||
$handler->handleGetSpreadsheetException($caughtException, $sheet); | ||
} | ||
/** | ||
* @return mixed[][] | ||
*/ | ||
public function provideExceptionsForGetSpreadsheet() | ||
{ | ||
return [ | ||
'invalid grant' => [ | ||
UserException::class, | ||
'Invalid OAuth grant when fetching "File title", try reauthenticating the extractor', | ||
new RequestException( | ||
'Client error: `POST https://www.googleapis.com/oauth2/v3/token` resulted in a `400 Bad Request` response: { "error": "invalid_grant", "error_description": "Bad Request" }', | ||
new Request('whatever', 'git'), | ||
new Response(400, [], '{ "error": "invalid_grant", "error_description": "Bad Request" }') | ||
), | ||
[ | ||
"id" => 2, | ||
"fileId" => "1y_XXXXXXXXXXX", | ||
"fileTitle" => "File title", | ||
"sheetId" => "SheetIdXxxxx", | ||
"sheetTitle" => "Title XXXXXX", | ||
"outputTable" => "table", | ||
"header" => ["rows" => 1, "columns" => []], | ||
"enabled" => true, | ||
], | ||
], | ||
'http404' => [ | ||
UserException::class, | ||
'File "Title XXXXXX" not found in Google Drive', | ||
new RequestException( | ||
'Client error: `POST https://www.googleapis.com/oauth2/v3/token` resulted in a `400 Bad Request` response: { "error": "invalid_grant", "error_description": "Bad Request" }', | ||
new Request('whatever', 'git'), | ||
new Response(404, [], '{}') | ||
), | ||
[ | ||
"id" => 2, | ||
"fileId" => "1y_XXXXXXXXXXX", | ||
"fileTitle" => "FileIdXxxxxx", | ||
"sheetId" => "SheetIdXxxxx", | ||
"sheetTitle" => "Title XXXXXX", | ||
"outputTable" => "table", | ||
"header" => ["rows" => 1, "columns" => []], | ||
"enabled" => true, | ||
], | ||
], | ||
'other request exception without description' => [ | ||
UserException::class, | ||
'Google Drive Error: Client error: `POST https://www.googleapis.com/oauth2/v3/token` resulted in a `400 Bad Request` response: { "error": "invalid_grant", "error_description": "Bad Request" }', | ||
new RequestException( | ||
'Client error: `POST https://www.googleapis.com/oauth2/v3/token` resulted in a `400 Bad Request` response: { "error": "invalid_grant", "error_description": "Bad Request" }', | ||
new Request('whatever', 'git'), | ||
new Response(403, [], '{}') | ||
), | ||
[ | ||
"id" => 2, | ||
"fileId" => "1y_XXXXXXXXXXX", | ||
"fileTitle" => "FileIdXxxxxx", | ||
"sheetId" => "SheetIdXxxxx", | ||
"sheetTitle" => "Title XXXXXX", | ||
"outputTable" => "table", | ||
"header" => ["rows" => 1, "columns" => []], | ||
"enabled" => true, | ||
], | ||
], | ||
'other request exception with description' => [ | ||
UserException::class, | ||
'"The column AX is not in the sheet" (out_of_range)', | ||
new RequestException( | ||
'Client error: `POST | ||
https://www.googleapis.com/oauth2/v3/token` resulted in a `400 Bad Request` response: { "error": | ||
"out_of_range", "error_description": "The column AX is not in the sheet" }', | ||
new Request('whatever', 'git'), | ||
new Response(403, [], '{ "error": "out_of_range", "error_description": "The column AX is not in the sheet" }') | ||
), | ||
[ | ||
"id" => 2, | ||
"fileId" => "1y_XXXXXXXXXXX", | ||
"fileTitle" => "FileIdXxxxxx", | ||
"sheetId" => "SheetIdXxxxx", | ||
"sheetTitle" => "Title XXXXXX", | ||
"outputTable" => "table", | ||
"header" => ["rows" => 1, "columns" => []], | ||
"enabled" => true, | ||
], | ||
], | ||
'other random exception' => [ | ||
ApplicationException::class, | ||
'Timeout', | ||
new \Exception( | ||
'Timeout' | ||
), | ||
[ | ||
"id" => 2, | ||
"fileId" => "1y_XXXXXXXXXXX", | ||
"fileTitle" => "FileIdXxxxxx", | ||
"sheetId" => "SheetIdXxxxx", | ||
"sheetTitle" => "Title XXXXXX", | ||
"outputTable" => "table", | ||
"header" => ["rows" => 1, "columns" => []], | ||
"enabled" => true, | ||
], | ||
], | ||
'exception with another response array ' => [ | ||
UserException::class, | ||
'"The caller does not have permission" (PERMISSION_DENIED) for "Title XXXXXX"', | ||
new RequestException( | ||
'Client error: `POST | ||
https://sheets.googleapis.com/v4/spreadsheets/123` resulted in a `403 Forbidden` response: { "error": { | ||
"code": 403, | ||
"message": "The caller does not have permission", | ||
"status": "PERMISSION_DENIED" | ||
}}', | ||
new Request('whatever', 'git'), | ||
new Response(400, [], '{ "error": { "code": 403, "message": "The caller does not have permission", "status": "PERMISSION_DENIED" } }') | ||
), | ||
[ | ||
"id" => 2, | ||
"fileId" => "1y_XXXXXXXXXXX", | ||
"fileTitle" => "File title", | ||
"sheetId" => "SheetIdXxxxx", | ||
"sheetTitle" => "Title XXXXXX", | ||
"outputTable" => "table", | ||
"header" => ["rows" => 1, "columns" => []], | ||
"enabled" => true, | ||
], | ||
], | ||
]; | ||
} | ||
/** | ||
* @dataProvider provideExceptionsForExport | ||
*/ | ||
public function testExportExceptionHandling( | ||
$expectedExceptionClass, | ||
$expectedExceptionMessage, | ||
\Exception $caughtException, | ||
array $sheet | ||
) { | ||
$handler = new ExceptionHandler(); | ||
$this->expectException($expectedExceptionClass); | ||
$this->expectExceptionMessage($expectedExceptionMessage); | ||
$handler->handleExportException($caughtException, $sheet); | ||
} | ||
/** | ||
* @return mixed[][] | ||
*/ | ||
public function provideExceptionsForExport() | ||
{ | ||
return [ | ||
'Rate limit exceeded' => [ | ||
UserException::class, | ||
"Error importing file - sheet: 'FileIdXxxxxx - Title XXXXXX'", | ||
new RequestException( | ||
'Some eeror message... Resulted in HTTP 429', | ||
new Request('whatever', 'git'), | ||
// phpcs:disable Generic.Files.LineLength | ||
new Response(429, [], '{"error": {"errors": [{"domain": "usageLimits","reason": "rateLimitExceeded","message": "Rate Limit Exceeded"}],"code": 429,"message": "Rate Limit Exceeded"}}') | ||
), | ||
[ | ||
"id" => 2, | ||
"fileId" => "1y_XXXXXXXXXXX", | ||
"fileTitle" => "FileIdXxxxxx", | ||
"sheetId" => "SheetIdXxxxx", | ||
"sheetTitle" => "Title XXXXXX", | ||
"outputTable" => "table", | ||
"header" => ["rows" => 1, "columns" => []], | ||
"enabled" => true, | ||
], | ||
], | ||
]; | ||
} | ||
} |