mirror of
https://github.com/friendica/friendica
synced 2024-11-14 03:42:53 +00:00
Extend test capability for HTTP Requests
This commit is contained in:
parent
a3d0404290
commit
d4a233a149
4 changed files with 166 additions and 30 deletions
|
@ -9,6 +9,7 @@ use Friendica\Network\HTTPClient;
|
||||||
use Friendica\Network\IHTTPClient;
|
use Friendica\Network\IHTTPClient;
|
||||||
use Friendica\Util\Profiler;
|
use Friendica\Util\Profiler;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\HandlerStack;
|
||||||
use GuzzleHttp\RequestOptions;
|
use GuzzleHttp\RequestOptions;
|
||||||
use mattwright\URLResolver;
|
use mattwright\URLResolver;
|
||||||
use Psr\Http\Message\RequestInterface;
|
use Psr\Http\Message\RequestInterface;
|
||||||
|
@ -33,7 +34,14 @@ class HTTPClientFactory extends BaseFactory
|
||||||
$this->baseUrl = $baseUrl;
|
$this->baseUrl = $baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createClient(): IHTTPClient
|
/**
|
||||||
|
* Creates a IHTTPClient for communications with HTTP endpoints
|
||||||
|
*
|
||||||
|
* @param HandlerStack|null $handlerStack (optional) A handler replacement (just usefull at test environments)
|
||||||
|
*
|
||||||
|
* @return IHTTPClient
|
||||||
|
*/
|
||||||
|
public function createClient(HandlerStack $handlerStack = null): IHTTPClient
|
||||||
{
|
{
|
||||||
$proxy = $this->config->get('system', 'proxy');
|
$proxy = $this->config->get('system', 'proxy');
|
||||||
|
|
||||||
|
@ -84,6 +92,7 @@ class HTTPClientFactory extends BaseFactory
|
||||||
RequestOptions::HEADERS => [
|
RequestOptions::HEADERS => [
|
||||||
'User-Agent' => $userAgent,
|
'User-Agent' => $userAgent,
|
||||||
],
|
],
|
||||||
|
'handler' => $handlerStack ?? HandlerStack::create(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$resolver = new URLResolver();
|
$resolver = new URLResolver();
|
||||||
|
|
|
@ -21,47 +21,45 @@
|
||||||
|
|
||||||
namespace Friendica\Test;
|
namespace Friendica\Test;
|
||||||
|
|
||||||
|
use Dice\Dice;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
use Friendica\Network\HTTPClient;
|
use Friendica\Factory\HTTPClientFactory;
|
||||||
use Friendica\Network\IHTTPClient;
|
use Friendica\Network\IHTTPClient;
|
||||||
use GuzzleHttp\Client;
|
|
||||||
use GuzzleHttp\HandlerStack;
|
use GuzzleHttp\HandlerStack;
|
||||||
use mattwright\URLResolver;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class mocks some DICE dependencies because they're not direct usable for test environments
|
* This class injects a mockable handler into the IHTTPClient dependency per Dice
|
||||||
* (Like fetching data from external endpoints)
|
|
||||||
*/
|
*/
|
||||||
trait DiceTestTrait
|
trait DiceHttpMockHandlerTrait
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Handler for mocking requests anywhere for testing purpose
|
* Handler for mocking requests anywhere for testing purpose
|
||||||
*
|
*
|
||||||
* @var HandlerStack
|
* @var HandlerStack
|
||||||
*/
|
*/
|
||||||
protected static $httpRequestHandler;
|
protected $httpRequestHandler;
|
||||||
|
|
||||||
protected static function setUpDice(): void
|
protected function setupHttpMockHandler(): void
|
||||||
{
|
{
|
||||||
if (!empty(self::$httpRequestHandler) && self::$httpRequestHandler instanceof HandlerStack) {
|
if (!empty($this->httpRequestHandler) && $this->httpRequestHandler instanceof HandlerStack) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self::$httpRequestHandler = HandlerStack::create();
|
$this->httpRequestHandler = HandlerStack::create();
|
||||||
|
|
||||||
$client = new Client(['handler' => self::$httpRequestHandler]);
|
|
||||||
|
|
||||||
$resolver = \Mockery::mock(URLResolver::class);
|
|
||||||
|
|
||||||
$httpClient = new HTTPClient(DI::logger(), DI::profiler(), $client, $resolver);
|
|
||||||
|
|
||||||
$dice = DI::getDice();
|
$dice = DI::getDice();
|
||||||
$newDice = \Mockery::mock($dice)->makePartial();
|
// addRule() clones the current instance and returns a new one, so no concurrency problems :-)
|
||||||
$newDice->shouldReceive('create')->with(IHTTPClient::class)->andReturn($httpClient);
|
$newDice = $dice->addRule(IHTTPClient::class, [
|
||||||
|
'instanceOf' => HTTPClientFactory::class,
|
||||||
|
'call' => [
|
||||||
|
['createClient', [$this->httpRequestHandler], Dice::CHAIN_CALL],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
DI::init($newDice);
|
DI::init($newDice);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function tearDown() : void
|
protected function tearDown(): void
|
||||||
{
|
{
|
||||||
\Mockery::close();
|
\Mockery::close();
|
||||||
|
|
|
@ -3,10 +3,21 @@
|
||||||
namespace Friendica\Test\src\Network;
|
namespace Friendica\Test\src\Network;
|
||||||
|
|
||||||
use Friendica\Network\Probe;
|
use Friendica\Network\Probe;
|
||||||
use PHPUnit\Framework\TestCase;
|
use Friendica\Test\DiceHttpMockHandlerTrait;
|
||||||
|
use Friendica\Test\FixtureTest;
|
||||||
|
use GuzzleHttp\Middleware;
|
||||||
|
|
||||||
class ProbeTest extends TestCase
|
class ProbeTest extends FixtureTest
|
||||||
{
|
{
|
||||||
|
use DiceHttpMockHandlerTrait;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->setupHttpMockHandler();
|
||||||
|
}
|
||||||
|
|
||||||
const TEMPLATENOBASE = '
|
const TEMPLATENOBASE = '
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en-us">
|
<html lang="en-us">
|
||||||
|
@ -105,4 +116,122 @@ class ProbeTest extends TestCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function dataUri()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'@-first' => [
|
||||||
|
'uri' => '@Artists4Future_Muenchen@climatejustice.global',
|
||||||
|
'assertUri' => 'Artists4Future_Muenchen@climatejustice.global',
|
||||||
|
'assertInfos' => [
|
||||||
|
'name' => 'Artists4Future München',
|
||||||
|
'nick' => 'Artists4Future_Muenchen',
|
||||||
|
'url' => 'https://climatejustice.global/users/Artists4Future_Muenchen',
|
||||||
|
'alias' => 'https://climatejustice.global/@Artists4Future_Muenchen',
|
||||||
|
'photo' => 'https://cdn.masto.host/climatejusticeglobal/accounts/avatars/000/021/220/original/05ee9e827a5b47fc.jpg',
|
||||||
|
'header' => 'https://cdn.masto.host/climatejusticeglobal/accounts/headers/000/021/220/original/9b98b75cf696cd11.jpg',
|
||||||
|
'account-type' => 0,
|
||||||
|
'about' => 'Wir sind Künstler oder einfach gerne kreativ tätig und setzen uns unabhängig von politischen Parteien für den Klimaschutz ein. Die Bedingungen zu schaffen, die die [url=https://climatejustice.global/tags/Klimakrise]#Klimakrise[/url] verhindern/eindämmen (gemäß den Forderungen der [url=https://climatejustice.global/tags/Fridays4Future]#Fridays4Future[/url]) ist Aufgabe der Politik, muss aber gesamtgesellschaftlich getragen werden. Mit unseren künstlerischen Aktionen wollen wir einen anderen Zugang anbieten für wissenschaftlich rationale Argumente, speziell zur Erderwärmung und ihre Konsequenzen.',
|
||||||
|
'hide' => 0,
|
||||||
|
'batch' => 'https://climatejustice.global/inbox',
|
||||||
|
'notify' => 'https://climatejustice.global/users/Artists4Future_Muenchen/inbox',
|
||||||
|
'poll' => 'https://climatejustice.global/users/Artists4Future_Muenchen/outbox',
|
||||||
|
'subscribe' => 'https://climatejustice.global/authorize_interaction?uri={uri}',
|
||||||
|
'following' => 'https://climatejustice.global/users/Artists4Future_Muenchen/following',
|
||||||
|
'followers' => 'https://climatejustice.global/users/Artists4Future_Muenchen/followers',
|
||||||
|
'inbox' => 'https://climatejustice.global/users/Artists4Future_Muenchen/inbox',
|
||||||
|
'outbox' => 'https://climatejustice.global/users/Artists4Future_Muenchen/outbox',
|
||||||
|
'sharedinbox' => 'https://climatejustice.global/inbox',
|
||||||
|
'priority' => 0,
|
||||||
|
'network' => 'apub',
|
||||||
|
'pubkey' => '-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6pYKPuDKb+rmBB869uPV
|
||||||
|
uLYFPosGxMUfenWqfWmFKzEqJ87rAft0IQDAL6dCoYE55ov/lEDNROhasTZLirZf
|
||||||
|
M5b7/1JmwMrAfEiaciuYqDWT3/yDpnekOIdzP5iSClg4zt7e6HRFuClqo4+b6hIE
|
||||||
|
DTMV4ksItvq/92MIu62pZ2SZr5ADPPZ/914lJ86hIH5BanbE8ZFzDS9vJA7V74rt
|
||||||
|
Vvkr5c/OiUyuODNYApSl87Ez8cuj8Edt89YWkDCajQn3EkmXGeJY/VRjEDfcyk6r
|
||||||
|
AvdUa0ArjXud3y3NkakVFZ0d7tmB20Vn9s/CfYHU8FXzbI1kFkov2BX899VVP5Ay
|
||||||
|
xQIDAQAB
|
||||||
|
-----END PUBLIC KEY-----',
|
||||||
|
'manually-approve' => 0,
|
||||||
|
'baseurl' => 'https://climatejustice.global',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataUri
|
||||||
|
*/
|
||||||
|
public function testCleanUri(string $uri, string $assertUri, array $assertInfos)
|
||||||
|
{
|
||||||
|
self::markTestIncomplete('hard work due mocking 19 different http-requests');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests:
|
||||||
|
*
|
||||||
|
* GET : https://climatejustice.global/.well-known/webfinger?resource=acct:Artists4Future_Muenchen%40climatejustice.global
|
||||||
|
* 200
|
||||||
|
* GET : http://localhost/.well-known/nodeinfo
|
||||||
|
* 200
|
||||||
|
* GET : http://localhost/statistics.json
|
||||||
|
* 404
|
||||||
|
* GET : http://localhost
|
||||||
|
* 200
|
||||||
|
* GET : http://localhost/friendica/json
|
||||||
|
* 404
|
||||||
|
* GET : http://localhost/friendika/json
|
||||||
|
* 404
|
||||||
|
* GET : http://localhost/poco
|
||||||
|
* 403
|
||||||
|
* GET : http://localhost/api/v1/directory?limit=1
|
||||||
|
* 200
|
||||||
|
* GET : http://localhost/.well-known/x-social-relay
|
||||||
|
* 200
|
||||||
|
* GET : http://localhost/friendica
|
||||||
|
* 404
|
||||||
|
* GET : https://climatejustice.global/users/Artists4Future_Muenchen
|
||||||
|
* 200
|
||||||
|
* GET : https://climatejustice.global/users/Artists4Future_Muenchen/following
|
||||||
|
* 200
|
||||||
|
* GET : https://climatejustice.global/users/Artists4Future_Muenchen/followers
|
||||||
|
* 200
|
||||||
|
* GET : https://climatejustice.global/users/Artists4Future_Muenchen/outbox
|
||||||
|
* 200
|
||||||
|
* GET : https://climatejustice.global/.well-known/nodeinfo
|
||||||
|
* 200
|
||||||
|
* GET : https://climatejustice.global/nodeinfo/2.0
|
||||||
|
* 200
|
||||||
|
* GET : https://climatejustice.global/poco
|
||||||
|
* 404
|
||||||
|
* GET : https://climatejustice.global/api/v1/directory?limit=1
|
||||||
|
* 200
|
||||||
|
* GET : https://climatejustice.global/.well-known/webfinger?resource=acct%3AArtists4Future_Muenchen%40climatejustice.global
|
||||||
|
* 200
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
$container = [];
|
||||||
|
$history = Middleware::history($container);
|
||||||
|
|
||||||
|
$this->httpRequestHandler->push($history);
|
||||||
|
|
||||||
|
$cleaned = Probe::cleanURI($uri);
|
||||||
|
self::assertEquals($assertUri, $cleaned);
|
||||||
|
self::assertArraySubset($assertInfos, Probe::uri($cleaned, '', 0));
|
||||||
|
|
||||||
|
|
||||||
|
// Iterate over the requests and responses
|
||||||
|
foreach ($container as $transaction) {
|
||||||
|
echo $transaction['request']->getMethod() . " : " . $transaction['request']->getUri() . PHP_EOL;
|
||||||
|
//> GET, HEAD
|
||||||
|
if ($transaction['response']) {
|
||||||
|
echo $transaction['response']->getStatusCode() . PHP_EOL;
|
||||||
|
//> 200, 200
|
||||||
|
} elseif ($transaction['error']) {
|
||||||
|
echo $transaction['error'];
|
||||||
|
//> exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace Friendica\Test\src\Util;
|
namespace Friendica\Test\src\Util;
|
||||||
|
|
||||||
use Friendica\Test\DiceTestTrait;
|
use Friendica\Test\DiceHttpMockHandlerTrait;
|
||||||
use Friendica\Test\MockedTest;
|
use Friendica\Test\MockedTest;
|
||||||
use Friendica\Util\Images;
|
use Friendica\Util\Images;
|
||||||
use GuzzleHttp\Handler\MockHandler;
|
use GuzzleHttp\Handler\MockHandler;
|
||||||
|
@ -10,13 +10,13 @@ use GuzzleHttp\Psr7\Response;
|
||||||
|
|
||||||
class ImagesTest extends MockedTest
|
class ImagesTest extends MockedTest
|
||||||
{
|
{
|
||||||
use DiceTestTrait;
|
use DiceHttpMockHandlerTrait;
|
||||||
|
|
||||||
public static function setUpBeforeClass(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUpBeforeClass();
|
parent::setUp();
|
||||||
|
|
||||||
self::setUpDice();
|
$this->setupHttpMockHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dataImages()
|
public function dataImages()
|
||||||
|
@ -56,13 +56,13 @@ class ImagesTest extends MockedTest
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the Images::getInfoFromURL() method
|
* Test the Images::getInfoFromURL() method (only remote images, not local/relative!)
|
||||||
*
|
*
|
||||||
* @dataProvider dataImages
|
* @dataProvider dataImages
|
||||||
*/
|
*/
|
||||||
public function testGetInfoFromURL(string $url, array $headers, string $data, array $assertion)
|
public function testGetInfoFromRemotURL(string $url, array $headers, string $data, array $assertion)
|
||||||
{
|
{
|
||||||
self::$httpRequestHandler->setHandler(new MockHandler([
|
$this->httpRequestHandler->setHandler(new MockHandler([
|
||||||
new Response(200, $headers, $data),
|
new Response(200, $headers, $data),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue