From: =?utf-8?q?David_Pr=C3=A9vot?= <taffit@debian.org>
Date: Tue, 14 Oct 2014 18:05:14 -0400
Subject: Add tests parts from RingPHP

---
 vendor/guzzlehttp/ringphp/tests/Client/Server.php | 183 ++++++++++++++++++++++
 vendor/guzzlehttp/ringphp/tests/Client/server.js  | 161 +++++++++++++++++++
 2 files changed, 344 insertions(+)
 create mode 100644 vendor/guzzlehttp/ringphp/tests/Client/Server.php
 create mode 100644 vendor/guzzlehttp/ringphp/tests/Client/server.js

diff --git a/vendor/guzzlehttp/ringphp/tests/Client/Server.php b/vendor/guzzlehttp/ringphp/tests/Client/Server.php
new file mode 100644
index 0000000..14665a5
--- /dev/null
+++ b/vendor/guzzlehttp/ringphp/tests/Client/Server.php
@@ -0,0 +1,183 @@
+<?php
+namespace GuzzleHttp\Tests\Ring\Client;
+
+use GuzzleHttp\Ring\Client\StreamHandler;
+use GuzzleHttp\Ring\Core;
+
+/**
+ * Class uses to control the test webserver.
+ *
+ * Queued responses will be served to requests using a FIFO order.  All requests
+ * received by the server are stored on the node.js server and can be retrieved
+ * by calling {@see Server::received()}.
+ *
+ * Mock responses that don't require data to be transmitted over HTTP a great
+ * for testing.  Mock response, however, cannot test the actual sending of an
+ * 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.
+ */
+class Server
+{
+    public static $started;
+    public static $url = 'http://127.0.0.1:8125/';
+    public static $host = '127.0.0.1:8125';
+    public static $port = 8125;
+
+    /**
+     * Flush the received requests from the server
+     * @throws \RuntimeException
+     */
+    public static function flush()
+    {
+        self::send('DELETE', '/guzzle-server/requests');
+    }
+
+    /**
+     * 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.
+     *
+     * @param array $responses An array of responses. The shape of a response
+     *                         is the shape described in the RingPHP spec.
+     * @throws \Exception
+     */
+    public static function enqueue(array $responses)
+    {
+        $data = [];
+
+        foreach ($responses as $response) {
+            if (!is_array($response)) {
+                throw new \Exception('Each response must be an array');
+            }
+
+            if (isset($response['body'])) {
+                $response['body'] = base64_encode($response['body']);
+            }
+
+            $response += ['headers' => [], 'reason' => '', 'body' => ''];
+            $data[] = $response;
+        }
+
+        self::send('PUT', '/guzzle-server/responses', json_encode($data));
+    }
+
+    /**
+     * Get all of the received requests as a RingPHP request structure.
+     *
+     * @return array
+     * @throws \RuntimeException
+     */
+    public static function received()
+    {
+        if (!self::$started) {
+            return [];
+        }
+
+        $response = self::send('GET', '/guzzle-server/requests');
+        $body = Core::body($response);
+        $result = json_decode($body, true);
+        if ($result === false) {
+            throw new \RuntimeException('Error decoding response: '
+                . json_last_error());
+        }
+
+        foreach ($result as &$res) {
+            if (isset($res['uri'])) {
+                $res['resource'] = $res['uri'];
+            }
+            if (isset($res['query_string'])) {
+                $res['resource'] .= '?' . $res['query_string'];
+            }
+            if (!isset($res['resource'])) {
+                $res['resource'] = '';
+            }
+            // Ensure that headers are all arrays
+            if (isset($res['headers'])) {
+                foreach ($res['headers'] as &$h) {
+                    $h = (array) $h;
+                }
+                unset($h);
+            }
+        }
+
+        unset($res);
+        return $result;
+    }
+
+    /**
+     * Stop running the node.js server
+     */
+    public static function stop()
+    {
+        if (self::$started) {
+            self::send('DELETE', '/guzzle-server');
+        }
+
+        self::$started = false;
+    }
+
+    public static function wait($maxTries = 20)
+    {
+        $tries = 0;
+        while (!self::isListening() && ++$tries < $maxTries) {
+            usleep(100000);
+        }
+
+        if (!self::isListening()) {
+            throw new \RuntimeException('Unable to contact node.js server');
+        }
+    }
+
+    public static function start()
+    {
+        if (self::$started) {
+            return;
+        }
+
+        try {
+            self::wait();
+        } catch (\Exception $e) {
+            exec('node ' . __DIR__ . \DIRECTORY_SEPARATOR . 'server.js '
+                . self::$port . ' >> /tmp/server.log 2>&1 &');
+            self::wait();
+        }
+
+        self::$started = true;
+    }
+
+    private static function isListening()
+    {
+        $response = self::send('GET', '/guzzle-server/perf', null, [
+            'connect_timeout' => 1,
+            'timeout'         => 1
+        ]);
+
+        return !isset($response['error']);
+    }
+
+    private static function send(
+        $method,
+        $path,
+        $body = null,
+        array $client = []
+    ) {
+        $handler = new StreamHandler();
+
+        $request = [
+            'http_method'  => $method,
+            'uri'          => $path,
+            'request_port' => 8125,
+            'headers'      => ['host' => ['127.0.0.1:8125']],
+            'body'         => $body,
+            'client'       => $client,
+        ];
+
+        if ($body) {
+            $request['headers']['content-length'] = [strlen($body)];
+        }
+
+        return $handler($request);
+    }
+}
diff --git a/vendor/guzzlehttp/ringphp/tests/Client/server.js b/vendor/guzzlehttp/ringphp/tests/Client/server.js
new file mode 100644
index 0000000..5642c0f
--- /dev/null
+++ b/vendor/guzzlehttp/ringphp/tests/Client/server.js
@@ -0,0 +1,161 @@
+/**
+ * Guzzle node.js test server to return queued responses to HTTP requests and
+ * expose a RESTful API for enqueueing responses and retrieving the requests
+ * that have been received.
+ *
+ * - Delete all requests that have been received:
+ *      > DELETE /guzzle-server/requests
+ *      > Host: 127.0.0.1:8125
+ *
+ *  - Enqueue responses
+ *      > PUT /guzzle-server/responses
+ *      > Host: 127.0.0.1:8125
+ *      >
+ *      > [{'status': 200, 'reason': 'OK', 'headers': {}, 'body': '' }]
+ *
+ *  - Get the received requests
+ *      > GET /guzzle-server/requests
+ *      > Host: 127.0.0.1:8125
+ *
+ *      < HTTP/1.1 200 OK
+ *      <
+ *      < [{'http_method': 'GET', 'uri': '/', 'headers': {}, 'body': 'string'}]
+ *
+ *  - Shutdown the server
+ *      > DELETE /guzzle-server
+ *      > Host: 127.0.0.1:8125
+ *
+ * @package Guzzle PHP <http://www.guzzlephp.org>
+ * @license See the LICENSE file that was distributed with this source code.
+ */
+
+var http = require('http');
+var url = require('url');
+
+/**
+ * Guzzle node.js server
+ * @class
+ */
+var GuzzleServer = function(port, log) {
+
+    this.port = port;
+    this.log = log;
+    this.responses = [];
+    this.requests = [];
+    var that = this;
+
+    var controlRequest = function(request, req, res) {
+        if (req.url == '/guzzle-server/perf') {
+            res.writeHead(200, 'OK', {'Content-Length': 16});
+            res.end('Body of response');
+        } else if (req.method == 'DELETE') {
+            if (req.url == '/guzzle-server/requests') {
+                // Clear the received requests
+                that.requests = [];
+                res.writeHead(200, 'OK', { 'Content-Length': 0 });
+                res.end();
+                if (that.log) {
+                    console.log('Flushing requests');
+                }
+            } else if (req.url == '/guzzle-server') {
+                // Shutdown the server
+                res.writeHead(200, 'OK', { 'Content-Length': 0, 'Connection': 'close' });
+                res.end();
+                if (that.log) {
+                    console.log('Shutting down');
+                }
+                that.server.close();
+            }
+        } else if (req.method == 'GET') {
+            if (req.url === '/guzzle-server/requests') {
+                if (that.log) {
+                    console.log('Sending received requests');
+                }
+                // Get received requests
+                var body = JSON.stringify(that.requests);
+                res.writeHead(200, 'OK', { 'Content-Length': body.length });
+                res.end(body);
+            }
+        } else if (req.method == 'PUT' && req.url == '/guzzle-server/responses') {
+            if (that.log) {
+                console.log('Adding responses...');
+            }
+            if (!request.body) {
+                if (that.log) {
+                    console.log('No response data was provided');
+                }
+                res.writeHead(400, 'NO RESPONSES IN REQUEST', { 'Content-Length': 0 });
+            } else {
+                that.responses = eval('(' + request.body + ')');
+                for (var i = 0; i < that.responses.length; i++) {
+                    if (that.responses[i].body) {
+                        that.responses[i].body = new Buffer(that.responses[i].body, 'base64');
+                    }
+                }
+                if (that.log) {
+                    console.log(that.responses);
+                }
+                res.writeHead(200, 'OK', { 'Content-Length': 0 });
+            }
+            res.end();
+        }
+    };
+
+    var receivedRequest = function(request, req, res) {
+        if (req.url.indexOf('/guzzle-server') === 0) {
+            controlRequest(request, req, res);
+        } else if (req.url.indexOf('/guzzle-server') == -1 && !that.responses.length) {
+            res.writeHead(500);
+            res.end('No responses in queue');
+        } else {
+            if (that.log) {
+                console.log('Returning response from queue and adding request');
+            }
+            that.requests.push(request);
+            var response = that.responses.shift();
+            res.writeHead(response.status, response.reason, response.headers);
+            res.end(response.body);
+        }
+    };
+
+    this.start = function() {
+
+        that.server = http.createServer(function(req, res) {
+
+            var parts = url.parse(req.url, false);
+            var request = {
+                http_method: req.method,
+                scheme: parts.scheme,
+                uri: parts.pathname,
+                query_string: parts.query,
+                headers: req.headers,
+                version: req.httpVersion,
+                body: ''
+            };
+
+            // Receive each chunk of the request body
+            req.addListener('data', function(chunk) {
+                request.body += chunk;
+            });
+
+            // Called when the request completes
+            req.addListener('end', function() {
+                receivedRequest(request, req, res);
+            });
+        });
+
+        that.server.listen(this.port, '127.0.0.1');
+
+        if (this.log) {
+            console.log('Server running at http://127.0.0.1:8125/');
+        }
+    };
+};
+
+// Get the port from the arguments
+port = process.argv.length >= 3 ? process.argv[2] : 8125;
+log = process.argv.length >= 4 ? process.argv[3] : false;
+
+// Start the server
+server = new GuzzleServer(port, log);
+server.start();
