2011-02-27 22:32:13 -06:00
|
|
|
<?php
|
|
|
|
|
2011-04-13 19:33:48 -05:00
|
|
|
namespace Guzzle\Tests\Http;
|
2011-02-27 22:32:13 -06:00
|
|
|
|
2012-05-02 23:29:31 +01:00
|
|
|
use Guzzle\Http\Exception\BadResponseException;
|
2013-09-22 20:55:24 -07:00
|
|
|
use Guzzle\Http\Message\MessageFactory;
|
2011-02-27 22:32:13 -06:00
|
|
|
use Guzzle\Http\Message\Response;
|
2012-01-14 13:57:05 -06:00
|
|
|
use Guzzle\Http\Client;
|
2011-02-27 22:32:13 -06:00
|
|
|
|
|
|
|
/**
|
2011-03-11 09:08:02 -06:00
|
|
|
* The Server class is used to control a scripted webserver using node.js that
|
|
|
|
* will respond to HTTP requests with queued responses.
|
2012-03-26 20:09:18 -05:00
|
|
|
*
|
2011-03-11 09:08:02 -06:00
|
|
|
* Queued responses will be served to requests using a FIFO order. All requests
|
2012-06-14 09:49:05 -07:00
|
|
|
* received by the server are stored on the node.js server and can be retrieved
|
2011-03-11 09:08:02 -06:00
|
|
|
* by calling {@see Server::getReceivedRequests()}.
|
2012-03-26 20:09:18 -05:00
|
|
|
*
|
2011-03-11 09:08:02 -06:00
|
|
|
* Mock responses that don't require data to be transmitted over HTTP a great
|
2012-06-14 09:49:05 -07:00
|
|
|
* for testing. Mock response, however, cannot test the actual sending of an
|
2011-03-11 09:08:02 -06:00
|
|
|
* HTTP request using cURL. This test server allows the simulation of any
|
|
|
|
* number of HTTP request response transactions to test the actual sending of
|
|
|
|
* requests over the wire without having to leave an internal network.
|
2011-02-27 22:32:13 -06:00
|
|
|
*/
|
2011-03-10 22:29:13 -06:00
|
|
|
class Server
|
2011-02-27 22:32:13 -06:00
|
|
|
{
|
|
|
|
const DEFAULT_PORT = 8124;
|
2011-03-11 09:08:02 -06:00
|
|
|
const REQUEST_DELIMITER = "\n----[request]\n";
|
2011-02-27 22:32:13 -06:00
|
|
|
|
2013-05-29 22:53:59 -07:00
|
|
|
/** @var int Port that the server will listen on */
|
2011-02-27 22:32:13 -06:00
|
|
|
private $port;
|
|
|
|
|
2013-05-29 22:53:59 -07:00
|
|
|
/** @var bool Is the server running */
|
2011-02-27 22:32:13 -06:00
|
|
|
private $running = false;
|
|
|
|
|
2013-05-29 22:53:59 -07:00
|
|
|
/** @var Client */
|
2012-01-14 13:57:05 -06:00
|
|
|
private $client;
|
|
|
|
|
2011-02-27 22:32:13 -06:00
|
|
|
/**
|
|
|
|
* Create a new scripted server
|
|
|
|
*
|
2012-05-16 00:55:45 -07:00
|
|
|
* @param int $port Port to listen on (defaults to 8124)
|
2011-02-27 22:32:13 -06:00
|
|
|
*/
|
|
|
|
public function __construct($port = null)
|
|
|
|
{
|
|
|
|
$this->port = $port ?: self::DEFAULT_PORT;
|
2013-10-13 12:49:28 -07:00
|
|
|
$this->client = new Client(['base_url' => $this->getUrl()]);
|
2011-02-27 22:32:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Flush the received requests from the server
|
2013-09-22 20:55:24 -07:00
|
|
|
* @throws \RuntimeException
|
2011-02-27 22:32:13 -06:00
|
|
|
*/
|
|
|
|
public function flush()
|
|
|
|
{
|
2013-09-22 20:55:24 -07:00
|
|
|
$this->client->delete('guzzle-server/requests');
|
2011-02-27 22:32:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-03-11 09:08:02 -06:00
|
|
|
* Queue an array of responses or a single response on the server.
|
|
|
|
*
|
|
|
|
* Any currently queued responses will be overwritten. Subsequent requests
|
|
|
|
* on the server will return queued responses in FIFO order.
|
2011-02-27 22:32:13 -06:00
|
|
|
*
|
2011-03-03 12:24:51 -06:00
|
|
|
* @param array|Response $responses A single or array of Responses to queue
|
2012-05-02 23:29:31 +01:00
|
|
|
* @throws BadResponseException
|
2011-02-27 22:32:13 -06:00
|
|
|
*/
|
|
|
|
public function enqueue($responses)
|
|
|
|
{
|
|
|
|
$data = array();
|
|
|
|
foreach ((array) $responses as $response) {
|
|
|
|
|
|
|
|
// Create the response object from a string
|
|
|
|
if (is_string($response)) {
|
2012-04-21 00:23:07 -07:00
|
|
|
$response = Response::fromMessage($response);
|
2012-05-11 21:04:42 -07:00
|
|
|
} elseif (!($response instanceof Response)) {
|
2013-07-16 14:15:25 -07:00
|
|
|
throw new BadResponseException('Responses must be strings or implement Response');
|
2011-02-27 22:32:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
$data[] = array(
|
2012-04-21 00:23:07 -07:00
|
|
|
'statusCode' => $response->getStatusCode(),
|
2011-02-27 22:32:13 -06:00
|
|
|
'reasonPhrase' => $response->getReasonPhrase(),
|
2013-05-29 00:17:37 -07:00
|
|
|
'headers' => $response->getHeaders()->toArray(),
|
2012-04-21 00:23:07 -07:00
|
|
|
'body' => $response->getBody(true)
|
2011-02-27 22:32:13 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-09-22 20:55:24 -07:00
|
|
|
$this->client->put('guzzle-server/responses', null, json_encode($data));
|
2011-02-27 22:32:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the server is running
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function isRunning()
|
|
|
|
{
|
|
|
|
if ($this->running) {
|
|
|
|
return true;
|
2013-07-16 14:15:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2013-09-22 20:55:24 -07:00
|
|
|
$this->client->get('guzzle-server/perf', array(), array('timeout' => 5));
|
2013-07-16 14:15:25 -07:00
|
|
|
return $this->running = true;
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
return false;
|
2011-02-27 22:32:13 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the URL to the server
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getUrl()
|
|
|
|
{
|
|
|
|
return 'http://127.0.0.1:' . $this->getPort() . '/';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the port that the server is listening on
|
|
|
|
*
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function getPort()
|
|
|
|
{
|
|
|
|
return $this->port;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get all of the received requests
|
|
|
|
*
|
2012-05-16 00:55:45 -07:00
|
|
|
* @param bool $hydrate Set to TRUE to turn the messages into
|
2011-03-11 09:08:02 -06:00
|
|
|
* actual {@see RequestInterface} objects. If $hydrate is FALSE,
|
|
|
|
* requests will be returned as strings.
|
2011-02-27 22:32:13 -06:00
|
|
|
*
|
|
|
|
* @return array
|
2013-09-22 20:55:24 -07:00
|
|
|
* @throws \RuntimeException
|
2011-02-27 22:32:13 -06:00
|
|
|
*/
|
|
|
|
public function getReceivedRequests($hydrate = false)
|
|
|
|
{
|
2013-09-22 20:55:24 -07:00
|
|
|
$response = $this->client->get('guzzle-server/requests');
|
|
|
|
$data = array_filter(explode(self::REQUEST_DELIMITER, (string) $response->getBody()));
|
2013-07-16 14:15:25 -07:00
|
|
|
if ($hydrate) {
|
2013-09-22 20:55:24 -07:00
|
|
|
$factory = new MessageFactory();
|
|
|
|
$data = array_map(function($message) use ($factory) {
|
|
|
|
return $factory->fromMessage($message);
|
2013-07-16 14:15:25 -07:00
|
|
|
}, $data);
|
2011-02-27 22:32:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-03-11 09:08:02 -06:00
|
|
|
* Start running the node.js server in the background
|
2011-02-27 22:32:13 -06:00
|
|
|
*/
|
|
|
|
public function start()
|
|
|
|
{
|
|
|
|
if (!$this->isRunning()) {
|
|
|
|
exec('node ' . __DIR__ . \DIRECTORY_SEPARATOR . 'server.js ' . $this->port . ' >> /tmp/server.log 2>&1 &');
|
2011-03-16 13:05:57 -05:00
|
|
|
// Wait at most 5 seconds for the server the setup before proceeding
|
|
|
|
$start = time();
|
|
|
|
while (!$this->isRunning() && time() - $start < 5);
|
2013-07-16 14:15:25 -07:00
|
|
|
if (!$this->running) {
|
2013-09-22 20:55:24 -07:00
|
|
|
throw new \RuntimeException(
|
2013-07-16 14:15:25 -07:00
|
|
|
'Unable to contact server.js. Have you installed node.js v0.5.0+? node must be in your path.'
|
2011-03-16 13:05:57 -05:00
|
|
|
);
|
|
|
|
}
|
2011-02-27 22:32:13 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-03-11 09:08:02 -06:00
|
|
|
* Stop running the node.js server
|
2011-02-27 22:32:13 -06:00
|
|
|
*/
|
|
|
|
public function stop()
|
|
|
|
{
|
|
|
|
if (!$this->isRunning()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->running = false;
|
2013-09-22 20:55:24 -07:00
|
|
|
$this->client->delete('guzzle-server');
|
2011-02-27 22:32:13 -06:00
|
|
|
}
|
2012-04-21 00:23:07 -07:00
|
|
|
}
|