created mocks for testing

master
Guillermo Dev 7 years ago
parent e53debb98d
commit 1211af09cc

Binary file not shown.

1
.gitignore vendored

@ -2,3 +2,4 @@
logs/
*~
vendor
*.lock

@ -13,11 +13,11 @@
"repositories" : [
{
"type" : "vcs",
"url" : "https://usrpath@bitbucket.org/usrpath/bsrconfig.git"
"url" : "https://usrpath@bitbucket.org/usrpath/bsrutils.git"
}
],
"require" : {
"bsr/config" : "v0.0.1"
"bsr/utils" : "^v1.0.1"
},
"autoload": {
"psr-4": {"BSR\\" : "src/"}

43
composer.lock generated

@ -4,9 +4,46 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "e0bdda87ed25bff2590ed52de3095589",
"content-hash": "c96a273bceb8c0c36a0832819e22ed63",
"packages": [],
"hash": "d9f96343b41310f062dbbd9a1175cf6a",
"content-hash": "cc63913f1b21e50ab5e9530dfb46d2b9",
"packages": [
{
"name": "bsr/utils",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://usrpath@bitbucket.org/usrpath/bsrutils.git",
"reference": "3289696873675db9fc9fca35271d61df5e68adcd"
},
"require-dev": {
"pds/skeleton": "^1.0",
"phpdocumentor/phpdocumentor": "2.*",
"phpunit/phpunit": "^6"
},
"type": "library",
"autoload": {
"psr-4": {
"BSR\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"BSR\\": "tests/"
}
},
"authors": [
{
"name": "Simon"
},
{
"name": "Guillermo Pages",
"email": "g@lespagesweb.ch"
}
],
"description": "Bsr configuration module",
"time": "2018-10-12 14:16:01"
}
],
"packages-dev": [
{
"name": "doctrine/instantiator",

@ -24,8 +24,9 @@ return array(
'path' => 'solr/',
'result_count' => 10,
),
'renderer' => array('class' => '\BSR\Webservice\MockRenderer'),
'log' => array(
'file' => '/var/www/webservice/logs/log.txt',
'file' => realpath(dirname(__FILE__) . '/..') . '/log/log.txt',
'format' => '%ip% - [%date%] - %status% %error% - %time% - %func%',
// The greater the verbosity, the more is displayed
// 0 : no log at all

@ -0,0 +1,68 @@
index.php
web = new NetBiblio()
parent::__construct(self::$version)
web->Run() <=> parent->Run()
| Logger::start(version) // initialize static log array
| new Renderer::__construct()
| |---ob_start()
| $data = []
| try {
| $result = this->Call() //1) start session,
| | //2) call webservice method and params passed in
| | // http request after doing a few checks
| | //3) log the request
| | session_save_path(Configuration::get(session.save_path))
| | session_start()
| | $paras = GET or POST
| | if empty(params) throw NoArguments
| | if !isset(params["func"]) throw MissingMethod
| | this->func = params["func"]
| | unset(params["func"])
| | Logger::info([
| | "func" => this->func . '(' . implode(',' params) . ')'
| | ]) // add func -> string to Logger::data
| | if !is_callable([this, this->func]) throw BadMethod
| | // descriptive wrapper for NetBiblio method
| | $rm = new \ReflectionMethod(this, this->func)
| | // check whether provided params match required
| | //TODO here is where the magic happens !!!!!!!!!!!!!!!!!!!!
| |---return call_user_func_array([this, this->func], params)
| $data['result'][this->func] = $result
| } catch (WebException $e) {
| $data['error'] = ['code' => $e->getCode(), ... ]
| $this->status = 400
| Logger::info($e->getName(), 'error') // add to log
| } catch (\Exception $e) {
| $data['failure'] = ['code' => $e->getCode(), 'reason' ...]
| Logger::info($e->getMessage, 'error')
| }
| Logger::stop(['status' => $this->status])
| $renderer->render($this->status, $data) // default status:200
| | header(sprintf(
| | 'HTTP/1.0 %s %s',
| | $status, self::$statusMessages[$status]
| | ))
| | header('Access-Control-Allow-Origin: *')
| | ob_clean()
| | flush()
| | $formatter = Formatter::getFormatter();
| | | self::loadFormatters() // call init on all formatters in dir
| | | | foreach($files as f) {
| | | | //infer class name from file name
| | | | //and if it is not this current class
| | | | //call init on the class
| | | | //Ex:
| | | | Json::init()
| | | | | self::registerFormats([ //self parent
| | | | | 'application/json',
| | | | | 'application/x-json',
| | | | | ]);
| | | | | | forach($formats as $f) { // self
| | | | | | self::$formats[$f] = get_called_class()
| | | | |---|---}
| | | | }
| | | $format = self::getFormatFromHeader();
| | | |---return 'BSR\Lib\Formatter\Json';
| | |---return new $format()
| | $formatter->render($data)
|---|---|---echo json_encode($data)

@ -1,5 +1,4 @@
<?php
namespace BSR\Webservice\Formatter;
abstract class Formatter {
@ -8,16 +7,27 @@ abstract class Formatter {
/**
* @param array $formats New available formats, array(mimetype => class)
*/
protected static function registerFormats(array $formats) {
protected static function registerFormats(array $formats)
{
foreach($formats as $f) {
self::$formats[$f] = get_called_class();
}
}
/**
* See loadFormatters() init()
* @return array of registered formats by subclasses on init()
*/
public static function getRegisterdFormats()
{
return self::$formats;
}
/**
* @return Formatter The formatter to use for this request
*/
public static function getFormatter() {
public static function getFormatter()
{
self::loadFormatters();
$format = self::getFormatFromHeader();
@ -66,7 +76,6 @@ abstract class Formatter {
}
}
return 'BSR\Webservice\Formatter\Json';
}

@ -1,5 +1,4 @@
<?php
namespace BSR\Webservice\Formatter;
use BSR\Utils\Logger\Logger;
@ -132,7 +131,7 @@ class Html extends Formatter {
'status' => 'info',
);
}
$info = Logger::data();
$info = Logger::getData();
$context['time'] = $info['time'];
$panel = static::template($context, 'panel');

@ -1,5 +1,4 @@
<?php
namespace BSR\Webservice;
use BSR\Webservice\Exception\WebException;

@ -1,10 +1,10 @@
<?php
namespace BSR\Webservice;
use BSR\Webservice\Formatter\Formatter;
class Renderer {
class Renderer
{
private static $statusMessages = array(
200 => 'Ok',
400 => 'Bad request',
@ -13,13 +13,19 @@ class Renderer {
500 => 'Server Error',
);
public function __construct() {
public function __construct()
{
ob_start();
}
public function render($status, $data) {
/**
*
*/
public function render($status, $data)
{
header(sprintf('HTTP/1.0 %s %s', $status, self::$statusMessages[$status]));
header("Access-Control-Allow-Origin: *");
ob_clean();
flush();

@ -21,17 +21,19 @@ abstract class WebService
/**
* Treat the current request and output the result. This is the only
* method that should be called on the webservice directly !
* @param bool $sendSession needed for testing
*/
public function run()
public function run($sendSession = true)
{
Logger::start(array('version' => $this->version));
$renderer = new Renderer();
$rendererClass = Configuration::get('renderer.class', __NAMESPACE__ . '\Renderer');
$renderer = new $rendererClass;
$data = array();
try {
$result = $this->call();
$result = $this->call($sendSession);
$data["result"][$this->func] = $result;
// Logger::log(print_r($result, true));
@ -61,13 +63,16 @@ abstract class WebService
* Determines which method to call based on GET or POST parameters and
* call it before returning the result.
*
* @param bool $sendSession used for testing
* @return array
* @throws UsageException
*/
private function call()
private function call($sendSession = true)
{
session_save_path(Configuration::get('session.save_path'));
session_start();
if ($sendSession) {
session_save_path(Configuration::get('session.save_path'));
session_start();
}
$params = empty($_GET) ? $_POST : $_GET;
if (empty($params)) {

@ -0,0 +1,14 @@
<h2>{{ func }}</h2>
<h3>Parameters</h3>
<dl>
{{ parameters }}
</dl>
<h3>Return</h3>
{{ return }}
<h3>Description</h3>
{{ help }}

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>BSR WebService - {{ title }}</title>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css">
</head>
<body>
<nav class="navbar navbar-default navbar-static-top">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">BSR WebService [{{ version }}]</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="help.php">Help</a></li>
<li><a href="logs.php">Logs</a></li>
<li><a href="phpinfo.php">PHPInfo</a></li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid">
{{ content }}
</div>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
</body>
</html>

@ -0,0 +1,11 @@
<div class="panel panel-{{ status }}">
<div class="panel-heading">
<h3 class="panel-title">{{ title }}</h3>
</div>
<div class="panel-body">
{{ content }}
</div>
<div class="panel-footer">
Generated in : {{ time }}
</div>
</div>

@ -0,0 +1,5 @@
<dt>{{ name }} {{ optional }}</dt>
<dd>
<bold>{{ type }}</bold>
{{ doc }}
</dd>

@ -0,0 +1,2 @@
<bold>{{ type }}</bold>
{{ doc }}

@ -1,78 +1,13 @@
<?php
namespace BSR\Webservice\Formatter;
abstract class Formatter {
private static $formats = array();
/**
* @param array $formats New available formats, array(mimetype => class)
*/
protected static function registerFormats(array $formats) {
foreach($formats as $f) {
self::$formats[$f] = get_called_class();
}
}
/**
* @return Formatter The formatter to use for this request
*/
public static function getFormatter() {
self::loadFormatters();
$format = self::getFormatFromHeader();
return new $format();
}
/**
* Load all formatters in the current directory
*/
private static function loadFormatters() {
preg_match('/(.+)\\\([a-zA-Z0-9]+)/', get_called_class(), $parts);
$us = $parts[2];
$namespace = $parts[1];
use PHPUnit\Framework\TestCase;
$base = __DIR__.'/';
$ext = '.php';
$files = glob(sprintf('%s%s%s', $base, '*', $ext));
foreach($files as $f) {
$c = str_replace(array($base, $ext), '', $f);
if($c !== $us) {
$c = $namespace.'\\'.$c;
call_user_func(array($c, 'init'));
}
}
class FormatterTest extends TestCase
{
public function testFormatterAllwaysReturnsAJsonFormatter()
{
$formatter = Formatter::getFormatter();
$this->assertEquals($formatter instanceof Json, true);
}
/**
* @return string The class name to instantiate in accord to the Accept header
*/
private static function getFormatFromHeader() {
//TODO this is ugly
return 'BSR\Webservice\Formatter\Json';
if(isset($_SERVER['HTTP_ACCEPT'])) {
$formats = array_map(function($f) {
$parts = explode(';', $f);
$parts[1] = (isset($parts[1]) ? (float) preg_replace('/[^0-9\.]/', '', $parts[1]) : 1.0) * 100;
return $parts;
}, explode(',', $_SERVER['HTTP_ACCEPT']));
usort($formats, function($a, $b) { return $b[1] - $a[1]; });
foreach($formats as $f) {
if(isset(self::$formats[$f[0]])) {
return self::$formats[$f[0]];
}
}
}
return 'BSR\Webservice\Formatter\Json';
}
/**
* Output the content for the given data
* @param array $data
*/
abstract public function render($data);
}

@ -1,17 +1,34 @@
<?php
namespace BSR\Webservice\Formatter;
class Json extends Formatter {
protected static function init() {
self::registerFormats(array(
'application/json',
'application/x-json',
));
use PHPUnit\Framework\TestCase;
class JsonTest extends TestCase
{
protected $accept = array(
'application/json',
'application/x-json',
);
public function testRenderEncodesDataIntoJsonFormat()
{
$format = new Json();
$someArray = array(
'asdf' => array(1, 'a', 'b', array()),
'1' => array(3 => 'c'),
0 => 'hello',
);
ob_start();
$format->render($someArray);
$jsonRepresentation = ob_get_clean();
$this->assertSame(json_decode($jsonRepresentation, true), $someArray);
}
public function render($data) {
echo json_encode($data);
public function testRegistersItsFormatAcceptHeader()
{
Formatter::getFormatter();
$formats = Formatter::getRegisterdFormats();
$this->assertSame(array_intersect($this->accept, array_keys($formats)), $this->accept);
}
}

@ -0,0 +1,16 @@
<?php
namespace BSR\Webservice;
use BSR\Webservice\Formatter\Formatter;
class MockRenderer extends Renderer
{
/**
* Override to avoid sending headers and flushing buffers
*/
public function render($status, $data)
{
$formatter = Formatter::getFormatter();
$formatter->render($data);
}
}

@ -0,0 +1,10 @@
<?php
namespace BSR\Webservice;
class MockWebserviceSubclass extends Webservice
{
public function someMockFunction($one, $two, $threeOpt = null)
{
return 'Some Mock Function Return';
}
}

@ -3,9 +3,11 @@
namespace BSR\Webservice;
use BSR\Webservice\Formatter\Formatter;
use PHPUnit\Framework\TestCase;
class Renderer {
private static $statusMessages = array(
class RendererTest extends TestCase
{
private $someData = array(
200 => 'Ok',
400 => 'Bad request',
404 => 'Not Found',
@ -13,17 +15,15 @@ class Renderer {
500 => 'Server Error',
);
public function __construct() {
public function testThatOutputBufferGetsInializedOnConstruction()
{
$text = 'This text should be captured by the renderers ob_start()';
ob_start();
}
public function render($status, $data) {
header(sprintf('HTTP/1.0 %s %s', $status, self::$statusMessages[$status]));
header("Access-Control-Allow-Origin: *");
ob_clean();
flush();
$formatter = Formatter::getFormatter();
$formatter->render($data);
echo 'Rubish text, that is not intended to be outputed';
ob_get_clean();
$renderer = new Renderer();
echo $text;
$obcontent = ob_get_clean();
$this->assertSame($text, $obcontent);
}
}

@ -2,12 +2,131 @@
namespace BSR\Webservice;
use PHPUnit\Framework\TestCase;
use BSR\Utils\Logger\Logger;
use BSR\Utils\Configuration\Configuration;
class WebserviceTest extends TestCase
{
private $webservice;
public function setUp()
{
$this->webservice = new MockWebserviceSubclass('1.2.3');
}
private function removeLogs()
{
$logsDir = realpath(dirname(Configuration::get('log.file')));
$files = glob("$logsDir/*");
foreach($files as $file){
if(is_file($file)) unlink($file);
}
}
public function test
/**
* @see config/configuration.local.php for the mock renderer used
* @runInSeparateProcess
*/
public function testRunSavesTheRequestIntoALogFile()
{
$this->removeLogs();
$log = Logger::getLastLogs();
$this->assertEquals(Logger::NO_LOG_YET_MSG, $log);
$this->webservice->run(false);
$response = ob_get_clean();
$log = Logger::getLastLogs();
$this->assertNotEquals(Logger::NO_LOG_YET_MSG, $log);
}
/**
* @see config/configuration.local.php for the mock renderer used
* @runInSeparateProcess
*/
public function testReturnsErrorNoArgumentsWhenNoParamtersInGetPostRequest()
{
$this->removeLogs();
$log = Logger::getLastLogs();
$this->assertEquals(Logger::NO_LOG_YET_MSG, $log);
$_GET = array(); $_POST = array();
$this->webservice->run(false);
$response = ob_get_clean();
$responseArray = json_decode($response, true);
$this->assertEquals(100, $responseArray['error']['code']);
$this->assertEquals('NoArguments', $responseArray['error']['name']);
}
public function testDoesNotReturnErrorNoArgumentsWhenParamtersInGetRequest()
{
$this->removeLogs();
$log = Logger::getLastLogs();
$this->assertEquals(Logger::NO_LOG_YET_MSG, $log);
$_GET = array('a' => 'a1');
$this->webservice->run(false);
$response = ob_get_clean();
$responseArray = json_decode($response, true);
$this->assertNotEquals(100, $responseArray['error']['code']);
$this->assertNotEquals('NoArguments', $responseArray['error']['name']);
}
public function testDoesNotReturnErrorNoArgumentsWhenParamtersInPostRequest()
{
$this->removeLogs();
$log = Logger::getLastLogs();
$this->assertEquals(Logger::NO_LOG_YET_MSG, $log);
$_POST = array('a' => 'a1');
$this->webservice->run(false);
$response = ob_get_clean();
$responseArray = json_decode($response, true);
var_dump($responseArray);
$this->assertNotEquals(100, $responseArray['error']['code']);
$this->assertNotEquals('NoArguments', $responseArray['error']['name']);
}
public function testReturnsErrorMissingMethodWhenNoFuncParamInRequest()
{
$this->removeLogs();
$log = Logger::getLastLogs();
$this->assertEquals(Logger::NO_LOG_YET_MSG, $log);
$_POST = array('a' => 'a1');
$this->webservice->run(false);
$response = ob_get_clean();
$responseArray = json_decode($response, true);
$this->assertEquals(101, $responseArray['error']['code']);
$this->assertEquals('MissingMethod', $responseArray['error']['name']);
}
public function testDoesNotReturnErrorMissingMethodWhenFuncParamInRequest()
{
$this->removeLogs();
$log = Logger::getLastLogs();
$this->assertEquals(Logger::NO_LOG_YET_MSG, $log);
$_GET = array('func' => 'someMockFunction'); $_POST = array();
$this->webservice->run(false);
$response = ob_get_clean();
$responseArray = json_decode($response, true);
$this->assertEquals(100, $responseArray['error']['code']);
}
public function testRunThrowsAUsageExceptionWhenFuncParamIsNotCallableOnSubclass()
{
}
public function testRunThrowsAUsageExceptionWhenMissingRequiredParamsInRequest()
{
}
public function testRunThrowsAUsageExceptionWhenTooManyParamsInRequest()
{
}
}

Loading…
Cancel
Save