Skip to content

Commit

Permalink
Merge pull request #33 from donatj/feature/changableDefault
Browse files Browse the repository at this point in the history
Adds Changeable Default Response
  • Loading branch information
donatj committed Aug 30, 2021
2 parents db54c1d + fb0230b commit fca7492
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 48 deletions.
51 changes: 49 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![Latest Stable Version](https://poser.pugx.org/donatj/mock-webserver/version)](https://packagist.org/packages/donatj/mock-webserver)
[![License](https://poser.pugx.org/donatj/mock-webserver/license)](https://packagist.org/packages/donatj/mock-webserver)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/donatj/mock-webserver/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/donatj/mock-webserver)
[![Build Status](https://github.com/donatj/mock-webserver/workflows/CI/badge.svg?)](https://github.com/donatj/mock-webserver/actions?query=workflow%3ACI)
[![CI](https://github.com/donatj/mock-webserver/workflows/CI/badge.svg?)](https://github.com/donatj/mock-webserver/actions?query=workflow%3ACI)
[![Build Status](https://travis-ci.org/donatj/mock-webserver.svg?branch=master)](https://travis-ci.org/donatj/mock-webserver)


Expand Down Expand Up @@ -101,7 +101,7 @@ require __DIR__ . '/../vendor/autoload.php';
$server = new MockWebServer;
$server->start();

// We define the servers response to requests of the /definedPath endpoint
// We define the server's response to requests of the /definedPath endpoint
$url = $server->setResponseOfPath(
'/definedPath',
new Response(
Expand Down Expand Up @@ -137,6 +137,53 @@ Content-type: text/html; charset=UTF-8
This is our http body response
```

### Change Default Response

```php
<?php

use donatj\MockWebServer\MockWebServer;
use donatj\MockWebServer\Responses\NotFoundResponse;

require __DIR__ . '/../vendor/autoload.php';

$server = new MockWebServer;
$server->start();

// The default response is donatj\MockWebServer\Responses\DefaultResponse
// which returns an HTTP 200 and a descriptive JSON payload.
//
// Change the default response to donatj\MockWebServer\Responses\NotFoundResponse
// to get a standard 404.
//
// Any other response may be specified as default as well.
$server->setDefaultResponse(new NotFoundResponse);

$content = file_get_contents($server->getServerRoot() . '/PageDoesNotExist', false, stream_context_create([
'http' => [ 'ignore_errors' => true ] // allow reading 404s
]));

// $http_response_header is a little known variable magically defined
// in the current scope by file_get_contents with the response headers
echo implode("\n", $http_response_header) . "\n\n";
echo $content . "\n";

```

Outputs:

```
HTTP/1.0 404 Not Found
Host: 127.0.0.1:61355
Date: Mon, 30 Aug 2021 20:02:58 GMT
Connection: close
X-Powered-By: PHP/7.3.29
Content-type: text/html; charset=UTF-8
VND.DonatStudios.MockWebServer: Resource '/PageDoesNotExist' not found!
```

### PHPUnit

```php
Expand Down
32 changes: 31 additions & 1 deletion docs/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,24 @@ Set a specified path to provide a specific response

---

### Method: MockWebServer->setDefaultResponse

```php
function setDefaultResponse(\donatj\MockWebServer\ResponseInterface $response)
```

Override the default server response, e.g. Fallback or 404

#### Parameters:

- ***\donatj\MockWebServer\ResponseInterface*** `$response`

#### Returns:

- ***void***

---

### Method: MockWebServer->getLastRequest

```php
Expand Down Expand Up @@ -273,4 +291,16 @@ Set the Response for the Given Method
#### Parameters:

- ***string*** `$method`
- ***\donatj\MockWebServer\ResponseInterface*** `$response`
- ***\donatj\MockWebServer\ResponseInterface*** `$response`

## Built-In Responses

### Class: \donatj\MockWebServer\Responses\DefaultResponse

The Built-In Default Response.

Results in an HTTP 200 with a JSON encoded version of the incoming Request

### Class: \donatj\MockWebServer\Responses\NotFoundResponse

Basic Built-In 404 Response
2 changes: 1 addition & 1 deletion example/simple.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
$server = new MockWebServer;
$server->start();

// We define the servers response to requests of the /definedPath endpoint
// We define the server's response to requests of the /definedPath endpoint
$url = $server->setResponseOfPath(
'/definedPath',
new Response(
Expand Down
9 changes: 9 additions & 0 deletions mddoc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ I would be happy to accept pull requests that correct this.
<file name="src/Response.php"/>
<file name="src/ResponseStack.php"/>
<file name="src/ResponseByMethod.php"/>
<section title="Built-In Responses">
<file name="src/Responses/DefaultResponse.php"/>
<file name="src/Responses/NotFoundResponse.php"/>
</section>
</section>
</docpage>
</section>
Expand All @@ -49,6 +53,11 @@ I would be happy to accept pull requests that correct this.
<text>Outputs:</text>
<exec cmd="php example/simple.php" format="code-block" />
</section>
<section title="Change Default Response">
<source name="example/notfound.php" lang="php"/>
<text>Outputs:</text>
<exec cmd="php example/notfound.php" format="code-block" />
</section>
<section title="PHPUnit">
<source name="example/phpunit.php" lang="php"/>
</section>
Expand Down
130 changes: 86 additions & 44 deletions src/InternalServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace donatj\MockWebServer;

use donatj\MockWebServer\Exceptions\ServerException;
use donatj\MockWebServer\Responses\DefaultResponse;
use donatj\MockWebServer\Responses\NotFoundResponse;

/**
* Class InternalServer
Expand All @@ -24,6 +26,8 @@ class InternalServer {
*/
private $header;

const DEFAULT_REF = 'default';

/**
* InternalServer constructor.
*
Expand Down Expand Up @@ -82,83 +86,121 @@ public static function aliasPath( $tmpPath, $path ) {
);
}

/**
* @param string $ref
* @return ResponseInterface|null
*/
private function responseForRef( $ref ) {
$path = $this->tmpPath . DIRECTORY_SEPARATOR . $ref;
if( !is_readable($path) ) {
return null;
}

$content = file_get_contents($path);
$response = unserialize($content);
if( !$response instanceof ResponseInterface ) {
throw new ServerException('invalid serialized response');
}

return $response;
}

public function __invoke() {
$path = $this->getDataPath();

if( $path !== false ) {
if( is_readable($path) ) {
$content = file_get_contents($path);
$response = unserialize($content);
if( !$response instanceof ResponseInterface ) {
throw new ServerException('invalid serialized response');
}

http_response_code($response->getStatus($this->request));

foreach( $response->getHeaders($this->request) as $key => $header ) {
if( is_int($key) ) {
call_user_func($this->header, $header);
} else {
call_user_func($this->header, "{$key}: {$header}");
}
}
$body = $response->getBody($this->request);

if( $response instanceof MultiResponseInterface ) {
$response->next();
self::storeResponse($this->tmpPath, $response);
}

echo $body;
$ref = $this->getRefForUri($this->request->getParsedUri()['path']);

if( $ref !== null ) {
$response = $this->responseForRef($ref);
if( $response ) {
$this->sendResponse($response);

return;
}

http_response_code(404);
echo MockWebServer::VND . ": Resource '{$path}' not found!\n";
$this->sendResponse(new NotFoundResponse);

return;
}

header('Content-Type: application/json');
$response = $this->responseForRef(self::DEFAULT_REF);
if( $response ) {
$this->sendResponse($response);

echo json_encode($this->request, JSON_PRETTY_PRINT);
return;
}

$this->sendResponse(new DefaultResponse);
}

protected function sendResponse( ResponseInterface $response ) {
http_response_code($response->getStatus($this->request));

foreach( $response->getHeaders($this->request) as $key => $header ) {
if( is_int($key) ) {
call_user_func($this->header, $header);
} else {
call_user_func($this->header, "{$key}: {$header}");
}
}

echo $response->getBody($this->request);

if( $response instanceof MultiResponseInterface ) {
$response->next();
self::storeResponse($this->tmpPath, $response);
}
}

/**
* @return false|string
* @return string|null
*/
protected function getDataPath() {
$path = false;

$uriPath = $this->request->getParsedUri()['path'];
protected function getRefForUri( $uriPath ) {
$aliasPath = self::aliasPath($this->tmpPath, $uriPath);

if( file_exists($aliasPath) ) {
if( $path = file_get_contents($aliasPath) ) {
$path = $this->tmpPath . DIRECTORY_SEPARATOR . $path;
return $path;
}
} elseif( preg_match('%^/' . preg_quote(MockWebServer::VND) . '/([0-9a-fA-F]{32})$%', $uriPath, $matches) ) {
$path = $this->tmpPath . DIRECTORY_SEPARATOR . $matches[1];
} elseif( preg_match('%^/' . preg_quote(MockWebServer::VND, '%') . '/([0-9a-fA-F]{32})$%', $uriPath, $matches) ) {
return $matches[1];
}

return $path;
return null;
}

/**
* @internal
* @param string $tmpPath
* @param \donatj\MockWebServer\ResponseInterface $response
* @return string
* @internal
*/
public static function storeResponse( $tmpPath, ResponseInterface $response ) {
$ref = $response->getRef();
$ref = $response->getRef();
self::storeRef($response, $tmpPath, $ref);

return $ref;
}

/**
* @param string $tmpPath
* @param \donatj\MockWebServer\ResponseInterface $response
* @return void
* @internal
*/
public static function storeDefaultResponse( $tmpPath, ResponseInterface $response ) {
self::storeRef($response, $tmpPath, self::DEFAULT_REF);
}

/**
* @param \donatj\MockWebServer\ResponseInterface $response
* @param string $tmpPath
* @param string $ref
*/
private static function storeRef( ResponseInterface $response, $tmpPath, $ref ) {
$content = serialize($response);

if( !file_put_contents($tmpPath . DIRECTORY_SEPARATOR . $ref, $content) ) {
throw new Exceptions\RuntimeException('Failed to write temporary content');
}

return $ref;
}

}
10 changes: 10 additions & 0 deletions src/MockWebServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@ public function setResponseOfPath( $path, ResponseInterface $response ) {
return $this->getServerRoot() . $path;
}

/**
* Override the default server response, e.g. Fallback or 404
*
* @param \donatj\MockWebServer\ResponseInterface $response
* @return void
*/
public function setDefaultResponse( ResponseInterface $response ) {
InternalServer::storeDefaultResponse($this->tmpDir, $response);
}

/**
* @return string
* @internal
Expand Down
30 changes: 30 additions & 0 deletions src/Responses/DefaultResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace donatj\MockWebServer\Responses;

use donatj\MockWebServer\MockWebServer;
use donatj\MockWebServer\RequestInfo;
use donatj\MockWebServer\ResponseInterface;

/**
* The Built-In Default Response.
* Results in an HTTP 200 with a JSON encoded version of the incoming Request
*/
class DefaultResponse implements ResponseInterface {

public function getRef() {
return md5(MockWebServer::VND . '.default-ref');
}

public function getBody( RequestInfo $request ) {
return json_encode($request, JSON_PRETTY_PRINT) . "\n";
}

public function getHeaders( RequestInfo $request ) {
return [ 'Content-Type' => 'application/json' ];
}

public function getStatus( RequestInfo $request ) {
return 200;
}
}
Loading

0 comments on commit fca7492

Please sign in to comment.