Initial commit of the immensely immense task of setting up functional tests for AzuraCast that will integrate with Travis CI and run upon each commit.
This commit is contained in:
parent
62b575467c
commit
1f23fbc50a
|
@ -27,3 +27,4 @@ app/.env
|
|||
/ansible/
|
||||
/util/ansible/deploy.retry
|
||||
/util/ansible/update.retry
|
||||
tests/_output/*
|
|
@ -0,0 +1,18 @@
|
|||
language: php
|
||||
|
||||
php:
|
||||
- 7.0
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- vendor
|
||||
- $HOME/.composer/cache
|
||||
|
||||
sudo: true
|
||||
|
||||
install:
|
||||
- chmod a+x install.sh
|
||||
- install.sh
|
||||
|
||||
script:
|
||||
- php codecept run
|
|
@ -7,6 +7,9 @@
|
|||
define("APP_IS_COMMAND_LINE", (PHP_SAPI == "cli"));
|
||||
define("APP_IS_SECURE", (!APP_IS_COMMAND_LINE && (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on")) ? TRUE : FALSE);
|
||||
|
||||
if (!defined('APP_TESTING_MODE'))
|
||||
define('APP_TESTING_MODE', false);
|
||||
|
||||
// General includes
|
||||
define("APP_INCLUDE_BASE", dirname(__FILE__));
|
||||
define("APP_INCLUDE_ROOT", realpath(APP_INCLUDE_BASE.'/..'));
|
||||
|
@ -41,11 +44,9 @@ if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']))
|
|||
$autoloader = require(APP_INCLUDE_VENDOR . '/autoload.php');
|
||||
$autoloader->add('App', APP_INCLUDE_LIB);
|
||||
|
||||
// Include general utility functions
|
||||
include(APP_INCLUDE_VENDOR.'/packaged/helpers/src/includes/Phutil.php');
|
||||
|
||||
// Set up DI container.
|
||||
$app_settings = [
|
||||
'outputBuffering' => false,
|
||||
'displayErrorDetails' => true,
|
||||
'addContentLengthHeader' => false,
|
||||
];
|
||||
|
@ -216,6 +217,9 @@ $di['url'] = function($di) {
|
|||
|
||||
// Register session service.
|
||||
$di['session'] = function($di) {
|
||||
// Depends on cache driver.
|
||||
$di->get('cache_driver');
|
||||
|
||||
return new \App\Session;
|
||||
};
|
||||
|
||||
|
@ -304,10 +308,13 @@ if (!APP_IS_COMMAND_LINE)
|
|||
}
|
||||
|
||||
// Set up application and routing.
|
||||
$di['app'] = function($di) use ($modules) {
|
||||
|
||||
$app = new \Slim\App($di);
|
||||
|
||||
// Remove trailing slash from all URLs when routing.
|
||||
$app->add(function (\Psr\Http\Message\RequestInterface $request, \Psr\Http\Message\ResponseInterface $response, callable $next) {
|
||||
$app->add(function (\Psr\Http\Message\RequestInterface $request, \Psr\Http\Message\ResponseInterface $response, callable $next)
|
||||
{
|
||||
$uri = $request->getUri();
|
||||
$path = $uri->getPath();
|
||||
|
||||
|
@ -330,3 +337,9 @@ foreach($modules as $module)
|
|||
if (file_exists($routes_file))
|
||||
include($routes_file);
|
||||
}
|
||||
|
||||
return $app;
|
||||
|
||||
};
|
||||
|
||||
return $di;
|
|
@ -69,7 +69,7 @@ class Auth
|
|||
*/
|
||||
public function isLoggedIn()
|
||||
{
|
||||
if (APP_IS_COMMAND_LINE)
|
||||
if (APP_IS_COMMAND_LINE && !APP_TESTING_MODE)
|
||||
return false;
|
||||
|
||||
$user = $this->getUser();
|
||||
|
@ -135,7 +135,7 @@ class Auth
|
|||
public function setUser(User $user)
|
||||
{
|
||||
// Prevent any previous identity from being used.
|
||||
session_regenerate_id(TRUE);
|
||||
// @session_regenerate_id(true);
|
||||
|
||||
$this->_session->user_id = $user->id;
|
||||
|
||||
|
|
|
@ -12,10 +12,11 @@ class EntityManagerFactory
|
|||
return false;
|
||||
|
||||
// Register custom data types.
|
||||
if (!Type::hasType('json'))
|
||||
Type::addType('json', 'App\Doctrine\Type\Json');
|
||||
|
||||
if (!Type::hasType('unixdatetime'))
|
||||
Type::addType('unixdatetime', 'App\Doctrine\Type\UnixDateTime');
|
||||
Type::addType('binary_uuid', 'App\Doctrine\Type\BinaryUuid');
|
||||
Type::addType('ip_integer', 'App\Doctrine\Type\IpAddrInteger');
|
||||
|
||||
Type::overrideType('array', 'App\Doctrine\Type\SoftArray');
|
||||
Type::overrideType('datetime', 'App\Doctrine\Type\UTCDateTime');
|
||||
|
@ -24,7 +25,7 @@ class EntityManagerFactory
|
|||
$config = new \Doctrine\ORM\Configuration;
|
||||
|
||||
// Handling for class names specified as platform types.
|
||||
if ($options['conn']['platform'])
|
||||
if (!empty($options['conn']['platform']))
|
||||
{
|
||||
$class_obj = new \ReflectionClass($options['conn']['platform']);
|
||||
$options['conn']['platform'] = $class_obj->newInstance();
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
namespace App\Doctrine\Type;
|
||||
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\BinaryType;
|
||||
|
||||
class BinaryUuid extends BinaryType
|
||||
{
|
||||
const BINARY_UUID = 'binary_uuid';
|
||||
|
||||
public function requiresSQLCommentHint(AbstractPlatform $platform)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
return self::uuidToBin($value);
|
||||
}
|
||||
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
if ($value === null)
|
||||
return null;
|
||||
|
||||
$value = (is_resource($value)) ? stream_get_contents($value, -1) : $value;
|
||||
|
||||
return self::binToUuid($value);
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return self::BINARY_UUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force all fields to be the BINARY type, length 16 (the UUID binary length).
|
||||
*/
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
{
|
||||
if ($fieldDeclaration['length'] != 16)
|
||||
die('"'.$fieldDeclaration['name'].'": Binary UUID fields must all have a length of 16.');
|
||||
|
||||
if (!$fieldDeclaration['fixed'])
|
||||
die('"'.$fieldDeclaration['name'].'": Binary UUID fields must all be fixed length.');
|
||||
|
||||
return parent::getSQLDeclaration($fieldDeclaration, $platform);
|
||||
}
|
||||
|
||||
public static function uuidToBin($uuid)
|
||||
{
|
||||
return pack("H*" , str_replace('-', '', $uuid));
|
||||
}
|
||||
|
||||
public static function binToUuid($bin)
|
||||
{
|
||||
return preg_replace('/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/', '$1-$2-$3-$4-$5', bin2hex($bin));
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
<?php
|
||||
namespace App\Doctrine\Type;
|
||||
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\IntegerType;
|
||||
|
||||
/**
|
||||
* Substitutes for MySQL's INET_NTOA and INET_ATON functions to handle IPs as unsigned integers.
|
||||
*
|
||||
* Class IpAddrInteger
|
||||
* @package App\Doctrine\Type
|
||||
*/
|
||||
class IpAddrInteger extends IntegerType
|
||||
{
|
||||
const IP_INTEGER = 'ip_integer';
|
||||
|
||||
public function requiresSQLCommentHint(AbstractPlatform $platform)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
return self::inetAtoN($value);
|
||||
}
|
||||
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
if ($value === null)
|
||||
return null;
|
||||
|
||||
$value = (is_resource($value)) ? stream_get_contents($value, -1) : $value;
|
||||
|
||||
return self::inetNtoA($value);
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return self::IP_INTEGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force all fields to use unsigned integers (if DB layer supports it).
|
||||
*/
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
{
|
||||
if (!$fieldDeclaration['unsigned'])
|
||||
throw new \Exception('"'.$fieldDeclaration['name'].'": IPInteger fields must always be unsigned.');
|
||||
|
||||
return parent::getSQLDeclaration($fieldDeclaration, $platform);
|
||||
}
|
||||
|
||||
public static function inetAtoN($ip)
|
||||
{
|
||||
$ip = trim($ip);
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) return 0;
|
||||
return sprintf("%u", ip2long($ip));
|
||||
}
|
||||
|
||||
public static function inetNtoA($num)
|
||||
{
|
||||
$num = trim($num);
|
||||
if ($num == "0") return "0.0.0.0";
|
||||
return long2ip(-(4294967295 - ($num - 1)));
|
||||
}
|
||||
}
|
|
@ -101,8 +101,11 @@ class Form
|
|||
if (empty($options['groups']))
|
||||
$options['groups'] = array();
|
||||
|
||||
if (!empty($options['elements']))
|
||||
{
|
||||
$options['groups'][] = ['elements' => $options['elements']];
|
||||
unset($options['elements']);
|
||||
}
|
||||
|
||||
// Standardize some field input.
|
||||
$field_type_lookup = [
|
||||
|
|
|
@ -46,14 +46,16 @@ class Controller
|
|||
$this->url = $di['url'];
|
||||
$this->em = $di['em'];
|
||||
|
||||
$this->view->reset();
|
||||
|
||||
$common_views_dir = APP_INCLUDE_MODULES.'/'.$module.'/views/scripts';
|
||||
if (is_dir($common_views_dir))
|
||||
{
|
||||
$this->view->addFolder('common', $common_views_dir);
|
||||
$this->view->setFolder('common', $common_views_dir);
|
||||
|
||||
$controller_views_dir = $common_views_dir.'/'.$controller;
|
||||
if (is_dir($controller_views_dir))
|
||||
$this->view->addFolder('controller', $controller_views_dir);
|
||||
$this->view->setFolder('controller', $controller_views_dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,6 +68,14 @@ class Controller
|
|||
/** @var array */
|
||||
protected $params;
|
||||
|
||||
/**
|
||||
* Handle the MVC-style dispatching of a controller action.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param $args
|
||||
* @return Response
|
||||
*/
|
||||
public function dispatch(Request $request, Response $response, $args)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
@ -93,8 +103,11 @@ class Controller
|
|||
return $action_result;
|
||||
|
||||
$template = $this->view->render('controller::'.$this->action);
|
||||
$this->response->getBody()->write($template);
|
||||
return $this->response;
|
||||
|
||||
$body = $this->response->getBody();
|
||||
$body->write($template);
|
||||
|
||||
return $this->response->withBody($body);
|
||||
}
|
||||
|
||||
public function __get($key)
|
||||
|
@ -241,9 +254,11 @@ class Controller
|
|||
$this->response = $this->response->withHeader('Content-type', 'text/html; charset=utf-8');
|
||||
|
||||
$template = $this->view->render($template_name, $template_args);
|
||||
$this->response->getBody()->write($template);
|
||||
|
||||
return $this->response;
|
||||
$body = $this->response->getBody();
|
||||
$body->write($template);
|
||||
|
||||
return $this->response->withBody($body);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -283,10 +298,12 @@ class Controller
|
|||
{
|
||||
$this->doNotRender();
|
||||
|
||||
$this->response = $this->response->withHeader('Content-type', 'application/json; charset=utf-8');
|
||||
$this->response->getBody()->write(json_encode($json_data));
|
||||
$body = $this->response->getBody();
|
||||
$body->write(json_encode($json_data));
|
||||
|
||||
return $this->response;
|
||||
return $this->response
|
||||
->withHeader('Content-type', 'application/json; charset=utf-8')
|
||||
->withBody($body);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -334,8 +351,10 @@ class Controller
|
|||
if ($file_name !== null)
|
||||
$this->response = $this->response->withHeader('Content-Disposition', 'attachment; filename='.$file_name);
|
||||
|
||||
$this->response->getBody()->write($file_data);
|
||||
return $this->response;
|
||||
$body = $this->response->getBody();
|
||||
$body->write($file_data);
|
||||
|
||||
return $this->response->withBody($body);
|
||||
}
|
||||
|
||||
/* URL Redirection */
|
||||
|
|
|
@ -35,6 +35,18 @@ class ErrorHandler
|
|||
$home_url = $di['url']->named('home');
|
||||
return $res->withStatus(302)->withHeader('Location', $home_url);
|
||||
}
|
||||
elseif (APP_IS_COMMAND_LINE)
|
||||
{
|
||||
$body = $res->getBody();
|
||||
$body->write(json_encode([
|
||||
'code' => $e->getCode(),
|
||||
'message' => $e->getMessage(),
|
||||
'stack_trace' => $e->getTraceAsString(),
|
||||
]));
|
||||
|
||||
return $res->withStatus(500)
|
||||
->withBody($body);
|
||||
}
|
||||
else
|
||||
{
|
||||
$show_debug = false;
|
||||
|
@ -48,8 +60,6 @@ class ErrorHandler
|
|||
if (APP_APPLICATION_ENV != 'production')
|
||||
$show_debug = true;
|
||||
|
||||
$res->withStatus(500);
|
||||
|
||||
if ($show_debug)
|
||||
{
|
||||
$view = $di->get('view');
|
||||
|
@ -62,19 +72,24 @@ class ErrorHandler
|
|||
$run = new \Whoops\Run;
|
||||
$run->pushHandler($handler);
|
||||
|
||||
$res->getBody()->write($run->handleException($e));
|
||||
$body = $res->getBody();
|
||||
$body->write($run->handleException($e));
|
||||
|
||||
return $res;
|
||||
return $res->withStatus(500)
|
||||
->withBody($body);
|
||||
}
|
||||
else
|
||||
{
|
||||
$view = $di->get('view');
|
||||
|
||||
$view->exception = $e;
|
||||
|
||||
$template = $view->render('system/error_general');
|
||||
$res->getBody()->write($template);
|
||||
return $res;
|
||||
|
||||
$body = $res->getBody();
|
||||
$body->write($template);
|
||||
|
||||
return $res->withStatus(500)
|
||||
->withBody($body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,12 @@ class View extends \League\Plates\Engine
|
|||
protected $rendered = false;
|
||||
protected $disabled = false;
|
||||
|
||||
public function reset()
|
||||
{
|
||||
$this->rendered = false;
|
||||
$this->disabled = false;
|
||||
}
|
||||
|
||||
public function disable()
|
||||
{
|
||||
$this->disabled = true;
|
||||
|
@ -74,4 +80,12 @@ class View extends \League\Plates\Engine
|
|||
return parent::render($name, $data);
|
||||
}
|
||||
|
||||
public function setFolder($name, $directory, $fallback = false)
|
||||
{
|
||||
if ($this->folders->exists($name))
|
||||
$this->folders->remove($name);
|
||||
|
||||
$this->folders->add($name, $directory, $fallback);
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -20,7 +20,8 @@ class Session
|
|||
if (!$this->isActive())
|
||||
return false;
|
||||
|
||||
$this->_is_started = session_start();
|
||||
$this->_is_started = @session_start();
|
||||
|
||||
return $this->_is_started;
|
||||
}
|
||||
|
||||
|
@ -117,7 +118,7 @@ class Session
|
|||
*/
|
||||
public function isActive()
|
||||
{
|
||||
if (APP_IS_COMMAND_LINE)
|
||||
if (APP_IS_COMMAND_LINE && !APP_TESTING_MODE)
|
||||
return false;
|
||||
|
||||
if ($this->_prevent_sessions)
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
/**
|
||||
* Based on Herloct's Slim 3.0 Connector
|
||||
* https://github.com/herloct/codeception-slim-module
|
||||
*/
|
||||
|
||||
namespace App\Tests;
|
||||
|
||||
use Codeception\Lib\Connector\Shared\PhpSuperGlobalsConverter;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
|
||||
use Slim\App;
|
||||
use Slim\Http\Environment;
|
||||
use Slim\Http\Headers;
|
||||
use Slim\Http\Cookies;
|
||||
use Slim\Http\RequestBody;
|
||||
use Slim\Http\Stream;
|
||||
use Slim\Http\UploadedFile;
|
||||
use Slim\Http\Uri;
|
||||
|
||||
use Symfony\Component\BrowserKit\Client;
|
||||
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
|
||||
use Symfony\Component\BrowserKit\Response as BrowserKitResponse;
|
||||
|
||||
class Connector extends Client
|
||||
{
|
||||
use PhpSuperGlobalsConverter;
|
||||
|
||||
/**
|
||||
* @var App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* @param App $app
|
||||
*/
|
||||
public function setApp(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request.
|
||||
*
|
||||
* @param BrowserKitRequest $request An origin request instance
|
||||
*
|
||||
* @return BrowserKitResponse An origin response instance
|
||||
*/
|
||||
public function doRequest($request)
|
||||
{
|
||||
$_COOKIE = $request->getCookies();
|
||||
$_SERVER = $request->getServer();
|
||||
$_FILES = $this->remapFiles($request->getFiles());
|
||||
|
||||
$uri = str_replace('http://localhost', '', $request->getUri());
|
||||
|
||||
$_REQUEST = $this->remapRequestParameters($request->getParameters());
|
||||
if (strtoupper($request->getMethod()) == 'GET')
|
||||
{
|
||||
$_GET = $_REQUEST;
|
||||
$_POST = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
$_GET = [];
|
||||
$_POST = $_REQUEST;
|
||||
}
|
||||
|
||||
$_SERVER['REQUEST_METHOD'] = strtoupper($request->getMethod());
|
||||
$_SERVER['REQUEST_URI'] = $uri;
|
||||
|
||||
$slimRequest = $this->convertRequest($request);
|
||||
|
||||
$container = $this->app->getContainer();
|
||||
|
||||
/* @var $slimResponse ResponseInterface */
|
||||
$slimResponse = $container->get('response');
|
||||
|
||||
// reset body stream
|
||||
$slimResponse = $slimResponse->withBody(new Stream(fopen('php://temp', 'w+')));
|
||||
|
||||
$slimResponse = $this->app->process($slimRequest, $slimResponse);
|
||||
|
||||
return new BrowserKitResponse(
|
||||
(string) $slimResponse->getBody(),
|
||||
$slimResponse->getStatusCode(),
|
||||
$slimResponse->getHeaders()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to PSR-7's ServerRequestInterface.
|
||||
*
|
||||
* @param BrowserKitRequest $request
|
||||
* @return ServerRequestInterface
|
||||
*/
|
||||
protected function convertRequest(BrowserKitRequest $request)
|
||||
{
|
||||
$environment = Environment::mock($request->getServer());
|
||||
$uri = Uri::createFromString($request->getUri());
|
||||
$headers = Headers::createFromEnvironment($environment);
|
||||
$cookies = Cookies::parseHeader($headers->get('Cookie', []));
|
||||
|
||||
$container = $this->app->getContainer();
|
||||
|
||||
/* @var $slimRequest ServerRequestInterface */
|
||||
$slimRequest = $container->get('request');
|
||||
|
||||
$slimRequest = $slimRequest->withMethod($request->getMethod())
|
||||
->withUri($uri)
|
||||
->withUploadedFiles($this->convertFiles($request->getFiles()))
|
||||
->withCookieParams($cookies);
|
||||
|
||||
foreach ($headers->keys() as $key) {
|
||||
$slimRequest = $slimRequest->withHeader($key, $headers->get($key));
|
||||
}
|
||||
|
||||
if ($request->getContent() !== null) {
|
||||
$body = new RequestBody();
|
||||
$body->write($request->getContent());
|
||||
$slimRequest = $slimRequest
|
||||
->withBody($body);
|
||||
}
|
||||
|
||||
$parsed = [];
|
||||
if ($request->getMethod() !== 'GET') {
|
||||
$parsed = $request->getParameters();
|
||||
}
|
||||
|
||||
// make sure we do not overwrite a request with a parsed body
|
||||
if (!$slimRequest->getParsedBody()) {
|
||||
$slimRequest = $slimRequest
|
||||
->withParsedBody($parsed);
|
||||
}
|
||||
|
||||
return $slimRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to PSR-7's UploadedFileInterface.
|
||||
*
|
||||
* @param array $files
|
||||
* @return array
|
||||
*/
|
||||
protected function convertFiles(array $files)
|
||||
{
|
||||
$fileObjects = [];
|
||||
foreach ($files as $fieldName => $file) {
|
||||
if ($file instanceof UploadedFileInterface) {
|
||||
$fileObjects[$fieldName] = $file;
|
||||
} elseif (!isset($file['tmp_name']) && !isset($file['name'])) {
|
||||
$fileObjects[$fieldName] = $this->convertFiles($file);
|
||||
} else {
|
||||
$fileObjects[$fieldName] = new UploadedFile(
|
||||
$file['tmp_name'],
|
||||
$file['name'],
|
||||
$file['type'],
|
||||
$file['size'],
|
||||
$file['error']
|
||||
);
|
||||
}
|
||||
}
|
||||
return $fileObjects;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
/**
|
||||
* Based on Herloct's Slim 3.0 Connector
|
||||
* https://github.com/herloct/codeception-slim-module
|
||||
*/
|
||||
|
||||
namespace App\Tests;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Interop\Container\ContainerInterface;
|
||||
use Codeception\Configuration;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\Lib\Interfaces\DoctrineProvider;
|
||||
use Slim\App;
|
||||
|
||||
class Module extends Framework implements DoctrineProvider
|
||||
{
|
||||
protected $requiredFields = ['container'];
|
||||
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
public $container;
|
||||
|
||||
/**
|
||||
* @var App
|
||||
*/
|
||||
public $app;
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
public $em;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
if (!defined('APP_TESTING_MODE'))
|
||||
define('APP_TESTING_MODE', true);
|
||||
|
||||
$cwd = getcwd();
|
||||
chdir(Configuration::projectDir());
|
||||
$this->container = include Configuration::projectDir() . $this->config['container'];
|
||||
chdir($cwd);
|
||||
|
||||
$this->app = $this->container->get('app');
|
||||
$this->em = $this->container->get('em');
|
||||
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->client = new Connector();
|
||||
$this->client->setApp($this->app);
|
||||
|
||||
parent::_before($test);
|
||||
}
|
||||
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
if (session_status() === PHP_SESSION_ACTIVE) {
|
||||
session_write_close();
|
||||
}
|
||||
|
||||
$_GET = [];
|
||||
$_POST = [];
|
||||
$_COOKIE = [];
|
||||
|
||||
parent::_after($test);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityManagerInterface
|
||||
*/
|
||||
public function _getEntityManager()
|
||||
{
|
||||
return $this->em;
|
||||
}
|
||||
}
|
|
@ -31,7 +31,10 @@ class Url
|
|||
*/
|
||||
public function current($absolute = false)
|
||||
{
|
||||
if (!empty($_SERVER['REQUEST_URI']))
|
||||
return $this->getUrl($_SERVER['REQUEST_URI'], $absolute);
|
||||
else
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,7 +53,10 @@ class Url
|
|||
*/
|
||||
public function referrer($default_url = null)
|
||||
{
|
||||
if (isset($_SERVER['HTTP_REFERER']))
|
||||
return $this->getUrl($_SERVER['HTTP_REFERER']);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -96,10 +96,12 @@ class Station extends \App\Doctrine\Entity
|
|||
{
|
||||
$this->radio_base_dir = $new_dir;
|
||||
|
||||
mkdir($this->radio_base_dir, 0777);
|
||||
mkdir($this->getRadioMediaDir(), 0777);
|
||||
mkdir($this->getRadioPlaylistsDir(), 0777);
|
||||
mkdir($this->getRadioConfigDir(), 0777);
|
||||
$radio_dirs = [$this->radio_base_dir, $this->getRadioMediaDir(), $this->getRadioPlaylistsDir(), $this->getRadioConfigDir()];
|
||||
foreach($radio_dirs as $radio_dir)
|
||||
{
|
||||
if (!file_exists($radio_dir))
|
||||
mkdir($radio_dir, 0777);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ class SetupController extends BaseController
|
|||
$existing_settings = $settings_repo->fetchArray(FALSE);
|
||||
$form->setDefaults($existing_settings);
|
||||
|
||||
if (!empty($_POST) && $form->isValid($_POST))
|
||||
if ($this->request->getMethod() == 'POST' && $form->isValid($this->request->getQueryParams()))
|
||||
{
|
||||
$data = $form->getValues();
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<h3 class="text-left"><?=sprintf(_('Welcome to %s!'), $config->application->name) ?></h3>
|
||||
<p class="text-left"><?=_('Please log in to continue.') ?></p>
|
||||
|
||||
<form action="" method="post">
|
||||
<form id="login-form" action="" method="post">
|
||||
<div class="input-group m-b-20">
|
||||
<span class="input-group-addon"><i class="zmdi zmdi-account"></i></span>
|
||||
<div class="fg-line">
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<h3 class="text-left"><?=sprintf(_('Welcome to %s!'), $config->application->name) ?>!</h3>
|
||||
<P class="text-left"><?=_('Begin setup by creating a Super Administrator account.') ?></p>
|
||||
|
||||
<form action="" method="post">
|
||||
<form id="login-form" action="" method="post">
|
||||
<div class="input-group m-b-20">
|
||||
<span class="input-group-addon"><i class="zmdi zmdi-account"></i></span>
|
||||
<div class="fg-line">
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
actor: Tester
|
||||
paths:
|
||||
tests: tests
|
||||
log: tests/_output
|
||||
data: tests/_data
|
||||
support: tests/_support
|
||||
envs: tests/_envs
|
||||
settings:
|
||||
bootstrap: _bootstrap.php
|
||||
colors: true
|
||||
memory_limit: 1024M
|
||||
extensions:
|
||||
enabled:
|
||||
- Codeception\Extension\RunFailed
|
||||
modules:
|
||||
config:
|
||||
Db:
|
||||
dsn: ''
|
||||
user: ''
|
||||
password: ''
|
||||
dump: tests/_data/dump.sql
|
|
@ -23,6 +23,7 @@
|
|||
"packaged/helpers": "^1.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeception/codeception": "^2.2"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
// This is global bootstrap for autoloading
|
||||
$autoloader = require __DIR__.'/../vendor/autoload.php';
|
||||
$autoloader->add('App', __DIR__.'/../app/library');
|
||||
$autoloader->addClassMap([
|
||||
'CestAbstract' => __DIR__.'/functional/CestAbstract.php',
|
||||
]);
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* Inherited Methods
|
||||
* @method void wantToTest($text)
|
||||
* @method void wantTo($text)
|
||||
* @method void execute($callable)
|
||||
* @method void expectTo($prediction)
|
||||
* @method void expect($prediction)
|
||||
* @method void amGoingTo($argumentation)
|
||||
* @method void am($role)
|
||||
* @method void lookForwardTo($achieveValue)
|
||||
* @method void comment($description)
|
||||
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
|
||||
*
|
||||
* @SuppressWarnings(PHPMD)
|
||||
*/
|
||||
class FunctionalTester extends \Codeception\Actor
|
||||
{
|
||||
use _generated\FunctionalTesterActions;
|
||||
|
||||
/**
|
||||
* Define custom actions here
|
||||
*/
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,14 @@
|
|||
# Codeception Test Suite Configuration
|
||||
#
|
||||
# Suite for functional (integration) tests
|
||||
# Emulate web requests and make application process them
|
||||
# Include one of framework modules (Symfony2, Yii2, Laravel5) to use it
|
||||
|
||||
class_name: FunctionalTester
|
||||
modules:
|
||||
enabled:
|
||||
- \App\Tests\Module:
|
||||
container: app/bootstrap.php
|
||||
- Doctrine2:
|
||||
depends: \App\Tests\Module
|
||||
error_level: "E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED"
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
use Slim\App;
|
||||
use Interop\Container\ContainerInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
abstract class CestAbstract
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $di;
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
protected $em;
|
||||
|
||||
protected function _inject(\App\Tests\Module $tests_module)
|
||||
{
|
||||
$this->di = $tests_module->container;
|
||||
$this->em = $tests_module->em;
|
||||
}
|
||||
|
||||
public function _before(FunctionalTester $I)
|
||||
{
|
||||
if (!empty($this->login_cookie))
|
||||
{
|
||||
$I->setCookie('PHPSESSID', $this->login_cookie);
|
||||
}
|
||||
}
|
||||
|
||||
public function _after(FunctionalTester $I)
|
||||
{}
|
||||
|
||||
protected $login_username = 'azuracast@azuracast.com';
|
||||
protected $login_password = 'AzuraCastFunctionalTests!';
|
||||
protected $login_cookie = null;
|
||||
|
||||
protected function setupIncomplete(FunctionalTester $I)
|
||||
{
|
||||
$settings_repo = $this->em->getRepository(\Entity\Settings::class);
|
||||
$settings_repo->setSetting('setup_complete', 0);
|
||||
|
||||
$this->_cleanTables();
|
||||
}
|
||||
|
||||
protected function setupComplete(FunctionalTester $I)
|
||||
{
|
||||
$settings_repo = $this->em->getRepository(\Entity\Settings::class);
|
||||
$settings_repo->setSetting('setup_complete', time());
|
||||
|
||||
$this->_cleanTables();
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected function _cleanTables()
|
||||
{
|
||||
$clean_tables = ['Entity\User', 'Entity\Role', 'Entity\Station'];
|
||||
foreach($clean_tables as $clean_table)
|
||||
$this->em->createQuery('DELETE FROM '.$clean_table.' t')->execute();
|
||||
}
|
||||
|
||||
protected function login(FunctionalTester $I)
|
||||
{
|
||||
if (empty($this->login_cookie))
|
||||
{
|
||||
$I->wantTo('Log in to the application.');
|
||||
|
||||
$I->amOnPage('/');
|
||||
$I->seeInCurrentUrl('/login');
|
||||
|
||||
$I->submitForm('#login-form', [
|
||||
'username' => $this->login_username,
|
||||
'password' => $this->login_password,
|
||||
]);
|
||||
|
||||
$I->seeInSource('Logged in');
|
||||
|
||||
$this->login_cookie = $I->grabCookie('PHPSESSID');
|
||||
}
|
||||
}
|
||||
|
||||
protected function logout(FunctionalTester $I)
|
||||
{
|
||||
if (!empty($this->login_cookie))
|
||||
{
|
||||
$I->wantTo('Log out of the application.');
|
||||
|
||||
$I->amOnPage('/logout');
|
||||
$I->seeInCurrentUrl('/login');
|
||||
|
||||
$this->login_cookie = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
/**
|
||||
* @group frontend
|
||||
*/
|
||||
class Frontend_SetupCest extends CestAbstract
|
||||
{
|
||||
/**
|
||||
* @before setupIncomplete
|
||||
* @after setupRegister
|
||||
* @after setupStation
|
||||
* @after setupSettings
|
||||
*/
|
||||
public function setupStart(FunctionalTester $I)
|
||||
{
|
||||
$I->wantTo('Check for a setup redirect.');
|
||||
$I->amOnPage('/');
|
||||
|
||||
$I->see('Begin setup');
|
||||
$I->seeCurrentUrlEquals('/setup/register');
|
||||
}
|
||||
|
||||
protected function setupRegister(FunctionalTester $I)
|
||||
{
|
||||
$I->wantTo('Create a user account.');
|
||||
$I->amOnPage('/setup/register');
|
||||
|
||||
$I->submitForm('#login-form', [
|
||||
'username' => $this->login_username,
|
||||
'password' => $this->login_password,
|
||||
]);
|
||||
|
||||
$I->seeInSource('continue the setup process');
|
||||
$I->seeInRepository('Entity\User', ['email' => $this->login_username]);
|
||||
|
||||
$this->login_cookie = $I->grabCookie('PHPSESSID');
|
||||
}
|
||||
|
||||
protected function setupStation(FunctionalTester $I)
|
||||
{
|
||||
$I->wantTo('Set up a station.');
|
||||
$I->amOnPage('/setup/station');
|
||||
|
||||
$I->seeCurrentUrlEquals('/setup/station');
|
||||
|
||||
$I->see('continue the setup process');
|
||||
|
||||
$I->submitForm('.form', [
|
||||
'app_form' => [
|
||||
'name' => 'Functional Test Radio',
|
||||
'description' => 'Test radio station.',
|
||||
],
|
||||
]);
|
||||
|
||||
$I->seeCurrentUrlEquals('/setup/settings');
|
||||
}
|
||||
|
||||
protected function setupSettings(FunctionalTester $I)
|
||||
{
|
||||
$I->wantTo('Set up site settings.');
|
||||
$I->amOnPage('/setup/settings');
|
||||
|
||||
$I->submitForm('.form', []);
|
||||
|
||||
$I->wantTo('See a set up site.');
|
||||
|
||||
$I->seeResponseCodeIs(200);
|
||||
$I->seeCurrentUrlEquals('/');
|
||||
$I->seeInSource('Setup is now complete!');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
<?php
|
||||
/* Placeholder */
|
|
@ -26,10 +26,11 @@
|
|||
- php7.0-cli
|
||||
- php7.0-gd
|
||||
- php7.0-curl
|
||||
- php7.0-xml
|
||||
- php7.0-zip
|
||||
- php7.0-mysqlnd
|
||||
- php7.0-intl
|
||||
- php7.0-xml # IceCast XML config
|
||||
- php7.0-zip # Composer installs
|
||||
- php7.0-mysqlnd # MySQL Native Driver (Doctrine)
|
||||
- php7.0-mbstring # Codeception Tests
|
||||
- php7.0-intl # Localization
|
||||
|
||||
- name: List locales
|
||||
shell: "cd {{ www_base }}/app/locale/; for i in $(ls -d */); do echo ${i%%/}; done"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
require dirname(__FILE__).'/../app/bootstrap.php';
|
||||
$di = require dirname(__FILE__).'/../app/bootstrap.php';
|
||||
|
||||
$em = $di['em'];
|
||||
$db = $em->getConnection();
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<?php
|
||||
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
||||
|
||||
require __DIR__ . '/../app/bootstrap.php';
|
||||
$di = require __DIR__ . '/../app/bootstrap.php';
|
||||
|
||||
/** @var \Slim\App $app */
|
||||
$app = $di['app'];
|
||||
|
||||
$app->run();
|
Loading…
Reference in New Issue