init
This commit is contained in:
390
vendor/codeception/base/src/Codeception/Module/AMQP.php
vendored
Normal file
390
vendor/codeception/base/src/Codeception/Module/AMQP.php
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Exception\ModuleException as ModuleException;
|
||||
use Codeception\Lib\Interfaces\RequiresPackage;
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\TestInterface;
|
||||
use Exception;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Exception\AMQPProtocolChannelException;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
|
||||
/**
|
||||
* This module interacts with message broker software that implements
|
||||
* the Advanced Message Queuing Protocol (AMQP) standard. For example, RabbitMQ (tested).
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* To use this module with Composer you need <em>"php-amqplib/php-amqplib": "~2.4"</em> package.
|
||||
* </div>
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * host: localhost - host to connect
|
||||
* * username: guest - username to connect
|
||||
* * password: guest - password to connect
|
||||
* * vhost: '/' - vhost to connect
|
||||
* * cleanup: true - defined queues will be purged before running every test.
|
||||
* * queues: [mail, twitter] - queues to cleanup
|
||||
* * single_channel - create and use only one channel during test execution
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* modules:
|
||||
* enabled:
|
||||
* - AMQP:
|
||||
* host: 'localhost'
|
||||
* port: '5672'
|
||||
* username: 'guest'
|
||||
* password: 'guest'
|
||||
* vhost: '/'
|
||||
* queues: [queue1, queue2]
|
||||
* single_channel: false
|
||||
*
|
||||
* ## Public Properties
|
||||
*
|
||||
* * connection - AMQPStreamConnection - current connection
|
||||
*/
|
||||
class AMQP extends CodeceptionModule implements RequiresPackage
|
||||
{
|
||||
protected $config = [
|
||||
'host' => 'localhost',
|
||||
'username' => 'guest',
|
||||
'password' => 'guest',
|
||||
'port' => '5672',
|
||||
'vhost' => '/',
|
||||
'cleanup' => true,
|
||||
'single_channel' => false
|
||||
];
|
||||
|
||||
/**
|
||||
* @var AMQPStreamConnection
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $channelId;
|
||||
|
||||
protected $requiredFields = ['host', 'username', 'password', 'vhost'];
|
||||
|
||||
public function _requires()
|
||||
{
|
||||
return ['PhpAmqpLib\Connection\AMQPStreamConnection' => '"php-amqplib/php-amqplib": "~2.4"'];
|
||||
}
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$host = $this->config['host'];
|
||||
$port = $this->config['port'];
|
||||
$username = $this->config['username'];
|
||||
$password = $this->config['password'];
|
||||
$vhost = $this->config['vhost'];
|
||||
|
||||
try {
|
||||
$this->connection = new AMQPStreamConnection($host, $port, $username, $password, $vhost);
|
||||
} catch (Exception $e) {
|
||||
throw new ModuleException(__CLASS__, $e->getMessage() . ' while establishing connection to MQ server');
|
||||
}
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
if ($this->config['cleanup']) {
|
||||
$this->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends message to exchange by sending exchange name, message
|
||||
* and (optionally) a routing key
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->pushToExchange('exchange.emails', 'thanks');
|
||||
* $I->pushToExchange('exchange.emails', new AMQPMessage('Thanks!'));
|
||||
* $I->pushToExchange('exchange.emails', new AMQPMessage('Thanks!'), 'severity');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $exchange
|
||||
* @param string|\PhpAmqpLib\Message\AMQPMessage $message
|
||||
* @param string $routing_key
|
||||
*/
|
||||
public function pushToExchange($exchange, $message, $routing_key = null)
|
||||
{
|
||||
$message = $message instanceof AMQPMessage
|
||||
? $message
|
||||
: new AMQPMessage($message);
|
||||
$this->getChannel()->basic_publish($message, $exchange, $routing_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends message to queue
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->pushToQueue('queue.jobs', 'create user');
|
||||
* $I->pushToQueue('queue.jobs', new AMQPMessage('create'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue
|
||||
* @param string|\PhpAmqpLib\Message\AMQPMessage $message
|
||||
*/
|
||||
public function pushToQueue($queue, $message)
|
||||
{
|
||||
$message = $message instanceof AMQPMessage
|
||||
? $message
|
||||
: new AMQPMessage($message);
|
||||
|
||||
$this->getChannel()->queue_declare($queue);
|
||||
$this->getChannel()->basic_publish($message, '', $queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares an exchange
|
||||
*
|
||||
* This is an alias of method `exchange_declare` of `PhpAmqpLib\Channel\AMQPChannel`.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->declareExchange(
|
||||
* 'nameOfMyExchange', // exchange name
|
||||
* 'topic' // exchange type
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* @param string $exchange
|
||||
* @param string $type
|
||||
* @param bool $passive
|
||||
* @param bool $durable
|
||||
* @param bool $auto_delete
|
||||
* @param bool $internal
|
||||
* @param bool $nowait
|
||||
* @param array $arguments
|
||||
* @param int $ticket
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function declareExchange(
|
||||
$exchange,
|
||||
$type,
|
||||
$passive = false,
|
||||
$durable = false,
|
||||
$auto_delete = true,
|
||||
$internal = false,
|
||||
$nowait = false,
|
||||
$arguments = null,
|
||||
$ticket = null
|
||||
) {
|
||||
return $this->getChannel()->exchange_declare(
|
||||
$exchange,
|
||||
$type,
|
||||
$passive,
|
||||
$durable,
|
||||
$auto_delete,
|
||||
$internal,
|
||||
$nowait,
|
||||
$arguments,
|
||||
$ticket
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares queue, creates if needed
|
||||
*
|
||||
* This is an alias of method `queue_declare` of `PhpAmqpLib\Channel\AMQPChannel`.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->declareQueue(
|
||||
* 'nameOfMyQueue', // exchange name
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* @param string $queue
|
||||
* @param bool $passive
|
||||
* @param bool $durable
|
||||
* @param bool $exclusive
|
||||
* @param bool $auto_delete
|
||||
* @param bool $nowait
|
||||
* @param array $arguments
|
||||
* @param int $ticket
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function declareQueue(
|
||||
$queue = '',
|
||||
$passive = false,
|
||||
$durable = false,
|
||||
$exclusive = false,
|
||||
$auto_delete = true,
|
||||
$nowait = false,
|
||||
$arguments = null,
|
||||
$ticket = null
|
||||
) {
|
||||
return $this->getChannel()->queue_declare(
|
||||
$queue,
|
||||
$passive,
|
||||
$durable,
|
||||
$exclusive,
|
||||
$auto_delete,
|
||||
$nowait,
|
||||
$arguments,
|
||||
$ticket
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a queue to an exchange
|
||||
*
|
||||
* This is an alias of method `queue_bind` of `PhpAmqpLib\Channel\AMQPChannel`.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->bindQueueToExchange(
|
||||
* 'nameOfMyQueueToBind', // name of the queue
|
||||
* 'transactionTracking.transaction', // exchange name to bind to
|
||||
* 'your.routing.key' // Optionally, provide a binding key
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* @param string $queue
|
||||
* @param string $exchange
|
||||
* @param string $routing_key
|
||||
* @param bool $nowait
|
||||
* @param array $arguments
|
||||
* @param int $ticket
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function bindQueueToExchange(
|
||||
$queue,
|
||||
$exchange,
|
||||
$routing_key = '',
|
||||
$nowait = false,
|
||||
$arguments = null,
|
||||
$ticket = null
|
||||
) {
|
||||
return $this->getChannel()->queue_bind(
|
||||
$queue,
|
||||
$exchange,
|
||||
$routing_key,
|
||||
$nowait,
|
||||
$arguments,
|
||||
$ticket
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if message containing text received.
|
||||
*
|
||||
* **This method drops message from queue**
|
||||
* **This method will wait for message. If none is sent the script will stuck**.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->pushToQueue('queue.emails', 'Hello, davert');
|
||||
* $I->seeMessageInQueueContainsText('queue.emails','davert');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue
|
||||
* @param string $text
|
||||
*/
|
||||
public function seeMessageInQueueContainsText($queue, $text)
|
||||
{
|
||||
$msg = $this->getChannel()->basic_get($queue);
|
||||
if (!$msg) {
|
||||
$this->fail("Message was not received");
|
||||
}
|
||||
if (!$msg instanceof AMQPMessage) {
|
||||
$this->fail("Received message is not format of AMQPMessage");
|
||||
}
|
||||
$this->debugSection("Message", $msg->body);
|
||||
$this->assertContains($text, $msg->body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes last message from queue.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $message = $I->grabMessageFromQueue('queue.emails');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue
|
||||
* @return \PhpAmqpLib\Message\AMQPMessage
|
||||
*/
|
||||
public function grabMessageFromQueue($queue)
|
||||
{
|
||||
$message = $this->getChannel()->basic_get($queue);
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge a specific queue defined in config.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->purgeQueue('queue.emails');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queueName
|
||||
*/
|
||||
public function purgeQueue($queueName = '')
|
||||
{
|
||||
if (! in_array($queueName, $this->config['queues'])) {
|
||||
throw new ModuleException(__CLASS__, "'$queueName' doesn't exist in queues config list");
|
||||
}
|
||||
|
||||
$this->getChannel()->queue_purge($queueName, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge all queues defined in config.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->purgeAllQueues();
|
||||
* ?>
|
||||
* ```
|
||||
*/
|
||||
public function purgeAllQueues()
|
||||
{
|
||||
$this->cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \PhpAmqpLib\Channel\AMQPChannel
|
||||
*/
|
||||
protected function getChannel()
|
||||
{
|
||||
if ($this->config['single_channel'] && $this->channelId === null) {
|
||||
$this->channelId = $this->connection->get_free_channel_id();
|
||||
}
|
||||
return $this->connection->channel($this->channelId);
|
||||
}
|
||||
|
||||
protected function cleanup()
|
||||
{
|
||||
if (!isset($this->config['queues'])) {
|
||||
throw new ModuleException(__CLASS__, "please set queues for cleanup");
|
||||
}
|
||||
if (!$this->connection) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->config['queues'] as $queue) {
|
||||
try {
|
||||
$this->getChannel()->queue_purge($queue);
|
||||
} catch (AMQPProtocolChannelException $e) {
|
||||
// ignore if exchange/queue doesn't exist and rethrow exception if it's something else
|
||||
if ($e->getCode() !== 404) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
144
vendor/codeception/base/src/Codeception/Module/AngularJS.php
vendored
Normal file
144
vendor/codeception/base/src/Codeception/Module/AngularJS.php
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Step;
|
||||
use Codeception\TestInterface;
|
||||
use Facebook\WebDriver\WebDriverBy;
|
||||
|
||||
/**
|
||||
* Module for AngularJS testing, based on [WebDriver module](http://codeception.com/docs/modules/WebDriver) and [Protractor](http://angular.github.io/protractor/).
|
||||
*
|
||||
* Performs **synchronization to ensure that page content is fully rendered**.
|
||||
* Uses Angular's and Protractor internals methods to synchronize with the page.
|
||||
*
|
||||
* ## Configuration
|
||||
*
|
||||
* The same as for [WebDriver](http://codeception.com/docs/modules/WebDriver#Configuration), but few new options added:
|
||||
*
|
||||
* * `el` - element where Angular application is defined (default: `body`)
|
||||
* * `script_timeout` - for how long in seconds to wait for angular operations to finish (default: 5)
|
||||
*
|
||||
* ### Example (`acceptance.suite.yml`)
|
||||
*
|
||||
* modules:
|
||||
* enabled:
|
||||
* - AngularJS:
|
||||
* url: 'http://localhost/'
|
||||
* browser: firefox
|
||||
* script_timeout: 10
|
||||
*
|
||||
*
|
||||
* ### Additional Features
|
||||
*
|
||||
* Can perform matching elements by model. In this case you should provide a strict locator with `model` set.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```php
|
||||
* $I->selectOption(['model' => 'customerId'], '3');
|
||||
* ```
|
||||
*/
|
||||
class AngularJS extends WebDriver
|
||||
{
|
||||
protected $insideApplication = true;
|
||||
|
||||
protected $defaultAngularConfig = [
|
||||
'script_timeout' => 5,
|
||||
'el' => 'body',
|
||||
];
|
||||
|
||||
protected $waitForAngular = <<<EOF
|
||||
var rootSelector = arguments[0];
|
||||
var callback = arguments[1];
|
||||
var el = document.querySelector(rootSelector);
|
||||
|
||||
try {
|
||||
if (window.getAngularTestability) {
|
||||
window.getAngularTestability(el).whenStable(callback);
|
||||
return;
|
||||
}
|
||||
if (!window.angular) {
|
||||
throw new Error('window.angular is undefined. This could be either ' +
|
||||
'because this is a non-angular page or because your test involves ' +
|
||||
'client-side navigation, which can interfere with Protractor\'s ' +
|
||||
'bootstrapping. See http://git.io/v4gXM for details');
|
||||
}
|
||||
if (angular.getTestability) {
|
||||
angular.getTestability(el).whenStable(callback);
|
||||
} else {
|
||||
if (!angular.element(el).injector()) {
|
||||
throw new Error('root element (' + rootSelector + ') has no injector.' +
|
||||
' this may mean it is not inside ng-app.');
|
||||
}
|
||||
angular.element(el).injector().get('\$browser').
|
||||
notifyWhenNoOutstandingRequests(callback);
|
||||
}
|
||||
} catch (err) {
|
||||
callback(err.message);
|
||||
}
|
||||
EOF;
|
||||
|
||||
|
||||
public function _setConfig($config)
|
||||
{
|
||||
parent::_setConfig(array_merge($this->defaultAngularConfig, $config));
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
parent::_before($test);
|
||||
$this->webDriver->manage()->timeouts()->setScriptTimeout($this->config['script_timeout']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables Angular mode (enabled by default).
|
||||
* Waits for Angular to finish rendering after each action.
|
||||
*/
|
||||
public function amInsideAngularApp()
|
||||
{
|
||||
$this->insideApplication = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disabled Angular mode.
|
||||
*
|
||||
* Falls back to original WebDriver, in case web page does not contain Angular app.
|
||||
*/
|
||||
public function amOutsideAngularApp()
|
||||
{
|
||||
$this->insideApplication = false;
|
||||
}
|
||||
|
||||
public function _afterStep(Step $step)
|
||||
{
|
||||
if (!$this->insideApplication) {
|
||||
return;
|
||||
}
|
||||
$actions = [
|
||||
'amOnPage',
|
||||
'click',
|
||||
'fillField',
|
||||
'selectOption',
|
||||
'checkOption',
|
||||
'uncheckOption',
|
||||
'unselectOption',
|
||||
'doubleClick',
|
||||
'appendField',
|
||||
'clickWithRightButton',
|
||||
'dragAndDrop'
|
||||
];
|
||||
if (in_array($step->getAction(), $actions)) {
|
||||
$this->webDriver->executeAsyncScript($this->waitForAngular, [$this->config['el']]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getStrictLocator(array $by)
|
||||
{
|
||||
$type = key($by);
|
||||
$value = $by[$type];
|
||||
if ($type === 'model') {
|
||||
return WebDriverBy::cssSelector(sprintf('[ng-model="%s"]', $value));
|
||||
}
|
||||
return parent::getStrictLocator($by);
|
||||
}
|
||||
}
|
||||
260
vendor/codeception/base/src/Codeception/Module/Apc.php
vendored
Normal file
260
vendor/codeception/base/src/Codeception/Module/Apc.php
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Module;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Exception\ModuleException;
|
||||
|
||||
/**
|
||||
* This module interacts with the [Alternative PHP Cache (APC)](http://php.net/manual/en/intro.apcu.php)
|
||||
* using either _APCu_ or _APC_ extension.
|
||||
*
|
||||
* Performs a cleanup by flushing all values after each test run.
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **Serghei Iakovlev**
|
||||
* * Stability: **stable**
|
||||
* * Contact: serghei@phalconphp.com
|
||||
*
|
||||
* ### Example (`unit.suite.yml`)
|
||||
*
|
||||
* ```yaml
|
||||
* modules:
|
||||
* - Apc
|
||||
* ```
|
||||
*
|
||||
* Be sure you don't use the production server to connect.
|
||||
*
|
||||
*/
|
||||
class Apc extends Module
|
||||
{
|
||||
/**
|
||||
* Code to run before each test.
|
||||
*
|
||||
* @param TestInterface $test
|
||||
* @throws ModuleException
|
||||
*/
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
if (!extension_loaded('apc') && !extension_loaded('apcu')) {
|
||||
throw new ModuleException(
|
||||
__CLASS__,
|
||||
'The APC(u) extension not loaded.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!ini_get('apc.enabled') || (PHP_SAPI === 'cli' && !ini_get('apc.enable_cli'))) {
|
||||
throw new ModuleException(
|
||||
__CLASS__,
|
||||
'The "apc.enable_cli" parameter must be set to "On".'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Code to run after each test.
|
||||
*
|
||||
* @param TestInterface $test
|
||||
*/
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
$this->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs value from APC(u) by key.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $users_count = $I->grabValueFromApc('users_count');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string|string[] $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function grabValueFromApc($key)
|
||||
{
|
||||
$value = $this->fetch($key);
|
||||
$this->debugSection('Value', $value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks item in APC(u) exists and the same as expected.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // With only one argument, only checks the key exists
|
||||
* $I->seeInApc('users_count');
|
||||
*
|
||||
* // Checks a 'users_count' exists and has the value 200
|
||||
* $I->seeInApc('users_count', 200);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string|string[] $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function seeInApc($key, $value = null)
|
||||
{
|
||||
if (null === $value) {
|
||||
$this->assertTrue($this->exists($key), "Cannot find key '$key' in APC(u).");
|
||||
return;
|
||||
}
|
||||
|
||||
$actual = $this->grabValueFromApc($key);
|
||||
$this->assertEquals($value, $actual, "Cannot find key '$key' in APC(u) with the provided value.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks item in APC(u) doesn't exist or is the same as expected.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // With only one argument, only checks the key does not exist
|
||||
* $I->dontSeeInApc('users_count');
|
||||
*
|
||||
* // Checks a 'users_count' exists does not exist or its value is not the one provided
|
||||
* $I->dontSeeInApc('users_count', 200);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string|string[] $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function dontSeeInApc($key, $value = null)
|
||||
{
|
||||
if (null === $value) {
|
||||
$this->assertFalse($this->exists($key), "The key '$key' exists in APC(u).");
|
||||
return;
|
||||
}
|
||||
|
||||
$actual = $this->grabValueFromApc($key);
|
||||
if (false !== $actual) {
|
||||
$this->assertEquals($value, $actual, "The key '$key' exists in APC(u) with the provided value.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores an item `$value` with `$key` on the APC(u).
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* // Array
|
||||
* $I->haveInApc('users', ['name' => 'miles', 'email' => 'miles@davis.com']);
|
||||
*
|
||||
* // Object
|
||||
* $I->haveInApc('user', UserRepository::findFirst());
|
||||
*
|
||||
* // Key as array of 'key => value'
|
||||
* $entries = [];
|
||||
* $entries['key1'] = 'value1';
|
||||
* $entries['key2'] = 'value2';
|
||||
* $entries['key3'] = ['value3a','value3b'];
|
||||
* $entries['key4'] = 4;
|
||||
* $I->haveInApc($entries, null);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string|array $key
|
||||
* @param mixed $value
|
||||
* @param int $expiration
|
||||
* @return mixed
|
||||
*/
|
||||
public function haveInApc($key, $value, $expiration = null)
|
||||
{
|
||||
$this->store($key, $value, $expiration);
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the APC(u) cache
|
||||
*/
|
||||
public function flushApc()
|
||||
{
|
||||
// Returns TRUE always
|
||||
$this->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the APC(u) cache.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function clear()
|
||||
{
|
||||
if (function_exists('apcu_clear_cache')) {
|
||||
return apcu_clear_cache();
|
||||
}
|
||||
|
||||
return apc_clear_cache('user');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if entry exists
|
||||
*
|
||||
* @param string|string[] $key
|
||||
*
|
||||
* @return bool|\string[]
|
||||
*/
|
||||
protected function exists($key)
|
||||
{
|
||||
if (function_exists('apcu_exists')) {
|
||||
return apcu_exists($key);
|
||||
}
|
||||
|
||||
return apc_exists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a stored variable from the cache
|
||||
*
|
||||
* @param string|string[] $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function fetch($key)
|
||||
{
|
||||
$success = false;
|
||||
|
||||
if (function_exists('apcu_fetch')) {
|
||||
$data = apcu_fetch($key, $success);
|
||||
} else {
|
||||
$data = apc_fetch($key, $success);
|
||||
}
|
||||
|
||||
$this->debugSection('Fetching a stored variable', $success ? 'OK' : 'FAILED');
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache a variable in the data store.
|
||||
*
|
||||
* @param string|array $key
|
||||
* @param mixed $var
|
||||
* @param int $ttl
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
protected function store($key, $var, $ttl = 0)
|
||||
{
|
||||
if (function_exists('apcu_store')) {
|
||||
return apcu_store($key, $var, $ttl);
|
||||
}
|
||||
|
||||
return apc_store($key, $var, $ttl);
|
||||
}
|
||||
}
|
||||
494
vendor/codeception/base/src/Codeception/Module/Asserts.php
vendored
Normal file
494
vendor/codeception/base/src/Codeception/Module/Asserts.php
vendored
Normal file
@@ -0,0 +1,494 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
|
||||
/**
|
||||
* Special module for using asserts in your tests.
|
||||
*/
|
||||
class Asserts extends CodeceptionModule
|
||||
{
|
||||
|
||||
/**
|
||||
* Checks that two variables are equal. If you're comparing floating-point values,
|
||||
* you can specify the optional "delta" parameter which dictates how great of a precision
|
||||
* error are you willing to tolerate in order to consider the two values equal.
|
||||
*
|
||||
* Regular example:
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->assertEquals($element->getChildrenCount(), 5);
|
||||
* ```
|
||||
*
|
||||
* Floating-point example:
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->assertEquals($calculator->add(0.1, 0.2), 0.3, 'Calculator should add the two numbers correctly.', 0.01);
|
||||
* ```
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
* @param float $delta
|
||||
*/
|
||||
public function assertEquals($expected, $actual, $message = '', $delta = 0.0)
|
||||
{
|
||||
parent::assertEquals($expected, $actual, $message, $delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that two variables are not equal. If you're comparing floating-point values,
|
||||
* you can specify the optional "delta" parameter which dictates how great of a precision
|
||||
* error are you willing to tolerate in order to consider the two values not equal.
|
||||
*
|
||||
* Regular example:
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->assertNotEquals($element->getChildrenCount(), 0);
|
||||
* ```
|
||||
*
|
||||
* Floating-point example:
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->assertNotEquals($calculator->add(0.1, 0.2), 0.4, 'Calculator should add the two numbers correctly.', 0.01);
|
||||
* ```
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
* @param float $delta
|
||||
*/
|
||||
public function assertNotEquals($expected, $actual, $message = '', $delta = 0.0)
|
||||
{
|
||||
parent::assertNotEquals($expected, $actual, $message, $delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that two variables are same
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertSame($expected, $actual, $message = '')
|
||||
{
|
||||
parent::assertSame($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that two variables are not same
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertNotSame($expected, $actual, $message = '')
|
||||
{
|
||||
parent::assertNotSame($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that actual is greater than expected
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertGreaterThan($expected, $actual, $message = '')
|
||||
{
|
||||
parent::assertGreaterThan($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that actual is greater or equal than expected
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertGreaterThanOrEqual($expected, $actual, $message = '')
|
||||
{
|
||||
parent::assertGreaterThanOrEqual($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that actual is less than expected
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertLessThan($expected, $actual, $message = '')
|
||||
{
|
||||
parent::assertLessThan($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that actual is less or equal than expected
|
||||
*
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertLessThanOrEqual($expected, $actual, $message = '')
|
||||
{
|
||||
parent::assertLessThanOrEqual($expected, $actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that haystack contains needle
|
||||
*
|
||||
* @param $needle
|
||||
* @param $haystack
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertContains($needle, $haystack, $message = '')
|
||||
{
|
||||
parent::assertContains($needle, $haystack, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that haystack doesn't contain needle.
|
||||
*
|
||||
* @param $needle
|
||||
* @param $haystack
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertNotContains($needle, $haystack, $message = '')
|
||||
{
|
||||
parent::assertNotContains($needle, $haystack, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that string match with pattern
|
||||
*
|
||||
* @param string $pattern
|
||||
* @param string $string
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertRegExp($pattern, $string, $message = '')
|
||||
{
|
||||
parent::assertRegExp($pattern, $string, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that string not match with pattern
|
||||
*
|
||||
* @param string $pattern
|
||||
* @param string $string
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertNotRegExp($pattern, $string, $message = '')
|
||||
{
|
||||
parent::assertNotRegExp($pattern, $string, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a string starts with the given prefix.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param string $string
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertStringStartsWith($prefix, $string, $message = '')
|
||||
{
|
||||
parent::assertStringStartsWith($prefix, $string, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a string doesn't start with the given prefix.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param string $string
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertStringStartsNotWith($prefix, $string, $message = '')
|
||||
{
|
||||
parent::assertStringStartsNotWith($prefix, $string, $message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that variable is empty.
|
||||
*
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertEmpty($actual, $message = '')
|
||||
{
|
||||
parent::assertEmpty($actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that variable is not empty.
|
||||
*
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertNotEmpty($actual, $message = '')
|
||||
{
|
||||
parent::assertNotEmpty($actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that variable is NULL
|
||||
*
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertNull($actual, $message = '')
|
||||
{
|
||||
parent::assertNull($actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that variable is not NULL
|
||||
*
|
||||
* @param $actual
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertNotNull($actual, $message = '')
|
||||
{
|
||||
parent::assertNotNull($actual, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that condition is positive.
|
||||
*
|
||||
* @param $condition
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertTrue($condition, $message = '')
|
||||
{
|
||||
parent::assertTrue($condition, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the condition is NOT true (everything but true)
|
||||
*
|
||||
* @param $condition
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertNotTrue($condition, $message = '')
|
||||
{
|
||||
parent::assertNotTrue($condition, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that condition is negative.
|
||||
*
|
||||
* @param $condition
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertFalse($condition, $message = '')
|
||||
{
|
||||
parent::assertFalse($condition, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the condition is NOT false (everything but false)
|
||||
*
|
||||
* @param $condition
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertNotFalse($condition, $message = '')
|
||||
{
|
||||
parent::assertNotFalse($condition, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if file exists
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertFileExists($filename, $message = '')
|
||||
{
|
||||
parent::assertFileExists($filename, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if file doesn't exist
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertFileNotExists($filename, $message = '')
|
||||
{
|
||||
parent::assertFileNotExists($filename, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
public function assertGreaterOrEquals($expected, $actual, $description = '')
|
||||
{
|
||||
$this->assertGreaterThanOrEqual($expected, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $expected
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
public function assertLessOrEquals($expected, $actual, $description = '')
|
||||
{
|
||||
$this->assertLessThanOrEqual($expected, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
public function assertIsEmpty($actual, $description = '')
|
||||
{
|
||||
$this->assertEmpty($actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
public function assertArrayHasKey($key, $actual, $description = '')
|
||||
{
|
||||
parent::assertArrayHasKey($key, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
public function assertArrayNotHasKey($key, $actual, $description = '')
|
||||
{
|
||||
parent::assertArrayNotHasKey($key, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that array contains subset.
|
||||
*
|
||||
* @param array $subset
|
||||
* @param array $array
|
||||
* @param bool $strict
|
||||
* @param string $message
|
||||
*/
|
||||
public function assertArraySubset($subset, $array, $strict = false, $message = '')
|
||||
{
|
||||
parent::assertArraySubset($subset, $array, $strict, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $expectedCount
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
public function assertCount($expectedCount, $actual, $description = '')
|
||||
{
|
||||
parent::assertCount($expectedCount, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
public function assertInstanceOf($class, $actual, $description = '')
|
||||
{
|
||||
parent::assertInstanceOf($class, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
public function assertNotInstanceOf($class, $actual, $description = '')
|
||||
{
|
||||
parent::assertNotInstanceOf($class, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param $actual
|
||||
* @param $description
|
||||
*/
|
||||
public function assertInternalType($type, $actual, $description = '')
|
||||
{
|
||||
parent::assertInternalType($type, $actual, $description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fails the test with message.
|
||||
*
|
||||
* @param $message
|
||||
*/
|
||||
public function fail($message)
|
||||
{
|
||||
parent::fail($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles and checks exception called inside callback function.
|
||||
* Either exception class name or exception instance should be provided.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->expectException(MyException::class, function() {
|
||||
* $this->doSomethingBad();
|
||||
* });
|
||||
*
|
||||
* $I->expectException(new MyException(), function() {
|
||||
* $this->doSomethingBad();
|
||||
* });
|
||||
* ```
|
||||
* If you want to check message or exception code, you can pass them with exception instance:
|
||||
* ```php
|
||||
* <?php
|
||||
* // will check that exception MyException is thrown with "Don't do bad things" message
|
||||
* $I->expectException(new MyException("Don't do bad things"), function() {
|
||||
* $this->doSomethingBad();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param $exception string or \Exception
|
||||
* @param $callback
|
||||
*/
|
||||
public function expectException($exception, $callback)
|
||||
{
|
||||
$code = null;
|
||||
$msg = null;
|
||||
if (is_object($exception)) {
|
||||
/** @var $exception \Exception **/
|
||||
$class = get_class($exception);
|
||||
$msg = $exception->getMessage();
|
||||
$code = $exception->getCode();
|
||||
} else {
|
||||
$class = $exception;
|
||||
}
|
||||
try {
|
||||
$callback();
|
||||
} catch (\Exception $e) {
|
||||
if (!$e instanceof $class) {
|
||||
$this->fail(sprintf("Exception of class $class expected to be thrown, but %s caught", get_class($e)));
|
||||
}
|
||||
if (null !== $msg and $e->getMessage() !== $msg) {
|
||||
$this->fail(sprintf(
|
||||
"Exception of $class expected to be '$msg', but actual message was '%s'",
|
||||
$e->getMessage()
|
||||
));
|
||||
}
|
||||
if (null !== $code and $e->getCode() !== $code) {
|
||||
$this->fail(sprintf(
|
||||
"Exception of $class expected to have code $code, but actual code was %s",
|
||||
$e->getCode()
|
||||
));
|
||||
}
|
||||
$this->assertTrue(true); // increment assertion counter
|
||||
return;
|
||||
}
|
||||
$this->fail("Expected exception of $class to be thrown, but nothing was caught");
|
||||
}
|
||||
}
|
||||
117
vendor/codeception/base/src/Codeception/Module/Cli.php
vendored
Normal file
117
vendor/codeception/base/src/Codeception/Module/Cli.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\TestInterface;
|
||||
|
||||
/**
|
||||
* Wrapper for basic shell commands and shell output
|
||||
*
|
||||
* ## Responsibility
|
||||
* * Maintainer: **davert**
|
||||
* * Status: **stable**
|
||||
* * Contact: codecept@davert.mail.ua
|
||||
*
|
||||
* *Please review the code of non-stable modules and provide patches if you have issues.*
|
||||
*/
|
||||
class Cli extends CodeceptionModule
|
||||
{
|
||||
public $output = '';
|
||||
|
||||
public $result = null;
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->output = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a shell command.
|
||||
* Fails If exit code is > 0. You can disable this by setting second parameter to false
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->runShellCommand('phpunit');
|
||||
*
|
||||
* // do not fail test when command fails
|
||||
* $I->runShellCommand('phpunit', false);
|
||||
* ```
|
||||
*
|
||||
* @param $command
|
||||
* @param bool $failNonZero
|
||||
*/
|
||||
public function runShellCommand($command, $failNonZero = true)
|
||||
{
|
||||
$data = [];
|
||||
exec("$command", $data, $resultCode);
|
||||
$this->result = $resultCode;
|
||||
$this->output = implode("\n", $data);
|
||||
if ($this->output === null) {
|
||||
\PHPUnit\Framework\Assert::fail("$command can't be executed");
|
||||
}
|
||||
if ($resultCode !== 0 && $failNonZero) {
|
||||
\PHPUnit\Framework\Assert::fail("Result code was $resultCode.\n\n" . $this->output);
|
||||
}
|
||||
$this->debug(preg_replace('~s/\e\[\d+(?>(;\d+)*)m//g~', '', $this->output));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that output from last executed command contains text
|
||||
*
|
||||
* @param $text
|
||||
*/
|
||||
public function seeInShellOutput($text)
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertContains($text, $this->output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that output from latest command doesn't contain text
|
||||
*
|
||||
* @param $text
|
||||
*
|
||||
*/
|
||||
public function dontSeeInShellOutput($text)
|
||||
{
|
||||
$this->debug($this->output);
|
||||
\PHPUnit\Framework\Assert::assertNotContains($text, $this->output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $regex
|
||||
*/
|
||||
public function seeShellOutputMatches($regex)
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertRegExp($regex, $this->output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks result code
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeResultCodeIs(0);
|
||||
* ```
|
||||
*
|
||||
* @param $code
|
||||
*/
|
||||
public function seeResultCodeIs($code)
|
||||
{
|
||||
$this->assertEquals($this->result, $code, "result code is $code");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks result code
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeResultCodeIsNot(0);
|
||||
* ```
|
||||
*
|
||||
* @param $code
|
||||
*/
|
||||
public function seeResultCodeIsNot($code)
|
||||
{
|
||||
$this->assertNotEquals($this->result, $code, "result code is $code");
|
||||
}
|
||||
}
|
||||
284
vendor/codeception/base/src/Codeception/Module/DataFactory.php
vendored
Normal file
284
vendor/codeception/base/src/Codeception/Module/DataFactory.php
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Lib\Interfaces\DataMapper;
|
||||
use Codeception\Lib\Interfaces\DependsOnModule;
|
||||
use Codeception\Lib\Interfaces\ORM;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Lib\Interfaces\RequiresPackage;
|
||||
use Codeception\TestInterface;
|
||||
use League\FactoryMuffin\FactoryMuffin;
|
||||
use League\FactoryMuffin\Stores\RepositoryStore;
|
||||
|
||||
/**
|
||||
* DataFactory allows you to easily generate and create test data using [**FactoryMuffin**](https://github.com/thephpleague/factory-muffin).
|
||||
* DataFactory uses an ORM of your application to define, save and cleanup data. Thus, should be used with ORM or Framework modules.
|
||||
*
|
||||
* This module requires packages installed:
|
||||
*
|
||||
* ```json
|
||||
* {
|
||||
* "league/factory-muffin": "^3.0",
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Generation rules can be defined in a factories file. You will need to create `factories.php` (it is recommended to store it in `_support` dir)
|
||||
* Follow [FactoryMuffin documentation](https://github.com/thephpleague/factory-muffin) to set valid rules.
|
||||
* Random data provided by [Faker](https://github.com/fzaninotto/Faker) library.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* use League\FactoryMuffin\Faker\Facade as Faker;
|
||||
*
|
||||
* $fm->define(User::class)->setDefinitions([
|
||||
* 'name' => Faker::name(),
|
||||
*
|
||||
* // generate email
|
||||
* 'email' => Faker::email(),
|
||||
* 'body' => Faker::text(),
|
||||
*
|
||||
* // generate a profile and return its Id
|
||||
* 'profile_id' => 'factory|Profile'
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* Configure this module to load factory definitions from a directory.
|
||||
* You should also specify a module with an ORM as a dependency.
|
||||
*
|
||||
* ```yaml
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Yii2:
|
||||
* configFile: path/to/config.php
|
||||
* - DataFactory:
|
||||
* factories: tests/_support/factories
|
||||
* depends: Yii2
|
||||
* ```
|
||||
*
|
||||
* (you can also use Laravel5 and Phalcon).
|
||||
*
|
||||
* In this example factories are loaded from `tests/_support/factories` directory. Please note that this directory is relative from the codeception.yml file (so for Yii2 it would be codeception/_support/factories).
|
||||
* You should create this directory manually and create PHP files in it with factories definitions following [official documentation](https://github.com/thephpleague/factory-muffin#usage).
|
||||
*
|
||||
* In cases you want to use data from database inside your factory definitions you can define them in Helper.
|
||||
* For instance, if you use Doctrine, this allows you to access `EntityManager` inside a definition.
|
||||
*
|
||||
* To proceed you should create Factories helper via `generate:helper` command and enable it:
|
||||
*
|
||||
* ```
|
||||
* modules:
|
||||
* enabled:
|
||||
* - DataFactory:
|
||||
* depends: Doctrine2
|
||||
* - \Helper\Factories
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* In this case you can define factories from a Helper class with `_define` method.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* public function _beforeSuite()
|
||||
* {
|
||||
* $factory = $this->getModule('DataFactory');
|
||||
* // let us get EntityManager from Doctrine
|
||||
* $em = $this->getModule('Doctrine2')->_getEntityManager();
|
||||
*
|
||||
* $factory->_define(User::class, [
|
||||
*
|
||||
* // generate random user name
|
||||
* // use League\FactoryMuffin\Faker\Facade as Faker;
|
||||
* 'name' => Faker::name(),
|
||||
*
|
||||
* // get real company from database
|
||||
* 'company' => $em->getRepository(Company::class)->find(),
|
||||
*
|
||||
* // let's generate a profile for each created user
|
||||
* // receive an entity and set it via `setProfile` method
|
||||
* // UserProfile factory should be defined as well
|
||||
* 'profile' => 'entity|'.UserProfile::class
|
||||
* ]);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Factory Definitions are described in official [Factory Muffin Documentation](https://github.com/thephpleague/factory-muffin)
|
||||
*
|
||||
* ### Related Models Generators
|
||||
*
|
||||
* If your module relies on other model you can generate them both.
|
||||
* To create a related module you can use either `factory` or `entity` prefix, depending on ORM you use.
|
||||
*
|
||||
* In case your ORM expects an Id of a related record (Eloquent) to be set use `factory` prefix:
|
||||
*
|
||||
* ```php
|
||||
* 'user_id' => 'factory|User'
|
||||
* ```
|
||||
*
|
||||
* In case your ORM expects a related record itself (Doctrine) then you should use `entity` prefix:
|
||||
*
|
||||
* ```php
|
||||
* 'user' => 'entity|User'
|
||||
* ```
|
||||
*/
|
||||
class DataFactory extends \Codeception\Module implements DependsOnModule, RequiresPackage
|
||||
{
|
||||
protected $dependencyMessage = <<<EOF
|
||||
ORM module (like Doctrine2) or Framework module with ActiveRecord support is required:
|
||||
--
|
||||
modules:
|
||||
enabled:
|
||||
- DataFactory:
|
||||
depends: Doctrine2
|
||||
--
|
||||
EOF;
|
||||
|
||||
/**
|
||||
* ORM module on which we we depend on.
|
||||
*
|
||||
* @var ORM
|
||||
*/
|
||||
public $ormModule;
|
||||
|
||||
/**
|
||||
* @var FactoryMuffin
|
||||
*/
|
||||
public $factoryMuffin;
|
||||
|
||||
protected $config = ['factories' => null];
|
||||
|
||||
public function _requires()
|
||||
{
|
||||
return [
|
||||
'League\FactoryMuffin\FactoryMuffin' => '"league/factory-muffin": "^3.0"',
|
||||
];
|
||||
}
|
||||
|
||||
public function _beforeSuite($settings = [])
|
||||
{
|
||||
$store = $this->getStore();
|
||||
$this->factoryMuffin = new FactoryMuffin($store);
|
||||
|
||||
if ($this->config['factories']) {
|
||||
foreach ((array) $this->config['factories'] as $factoryPath) {
|
||||
$realpath = realpath(codecept_root_dir().$factoryPath);
|
||||
if ($realpath === false) {
|
||||
throw new ModuleException($this, 'The path to one of your factories is not correct. Please specify the directory relative to the codeception.yml file (ie. _support/factories).');
|
||||
}
|
||||
$this->factoryMuffin->loadFactories($realpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return StoreInterface|null
|
||||
*/
|
||||
protected function getStore()
|
||||
{
|
||||
return $this->ormModule instanceof DataMapper
|
||||
? new RepositoryStore($this->ormModule->_getEntityManager()) // for Doctrine
|
||||
: null;
|
||||
}
|
||||
|
||||
public function _inject(ORM $orm)
|
||||
{
|
||||
$this->ormModule = $orm;
|
||||
}
|
||||
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
$skipCleanup = array_key_exists('cleanup', $this->config) && $this->config['cleanup'] === false;
|
||||
if ($skipCleanup || $this->ormModule->_getConfig('cleanup')) {
|
||||
return;
|
||||
}
|
||||
$this->factoryMuffin->deleteSaved();
|
||||
}
|
||||
|
||||
public function _depends()
|
||||
{
|
||||
return ['Codeception\Lib\Interfaces\ORM' => $this->dependencyMessage];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a model definition. This can be used from a helper:.
|
||||
*
|
||||
* ```php
|
||||
* $this->getModule('{{MODULE_NAME}}')->_define('User', [
|
||||
* 'name' => $faker->name,
|
||||
* 'email' => $faker->email
|
||||
* ]);
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* @param string $model
|
||||
* @param array $fields
|
||||
*
|
||||
* @return \League\FactoryMuffin\Definition
|
||||
*
|
||||
* @throws \League\FactoryMuffin\Exceptions\DefinitionAlreadyDefinedException
|
||||
*/
|
||||
public function _define($model, $fields)
|
||||
{
|
||||
return $this->factoryMuffin->define($model)->setDefinitions($fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and saves a record,.
|
||||
*
|
||||
* ```php
|
||||
* $I->have('User'); // creates user
|
||||
* $I->have('User', ['is_active' => true]); // creates active user
|
||||
* ```
|
||||
*
|
||||
* Returns an instance of created user.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $extraAttrs
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function have($name, array $extraAttrs = [])
|
||||
{
|
||||
return $this->factoryMuffin->create($name, $extraAttrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a record instance.
|
||||
*
|
||||
* This does not save it in the database. Use `have` for that.
|
||||
*
|
||||
* ```php
|
||||
* $user = $I->make('User'); // return User instance
|
||||
* $activeUser = $I->make('User', ['is_active' => true]); // return active user instance
|
||||
* ```
|
||||
*
|
||||
* Returns an instance of created user without creating a record in database.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $extraAttrs
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function make($name, array $extraAttrs = [])
|
||||
{
|
||||
return $this->factoryMuffin->instance($name, $extraAttrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and saves a record multiple times.
|
||||
*
|
||||
* ```php
|
||||
* $I->haveMultiple('User', 10); // create 10 users
|
||||
* $I->haveMultiple('User', 10, ['is_active' => true]); // create 10 active users
|
||||
* ```
|
||||
*
|
||||
* @param string $name
|
||||
* @param int $times
|
||||
* @param array $extraAttrs
|
||||
*
|
||||
* @return \object[]
|
||||
*/
|
||||
public function haveMultiple($name, $times, array $extraAttrs = [])
|
||||
{
|
||||
return $this->factoryMuffin->seed($times, $name, $extraAttrs);
|
||||
}
|
||||
}
|
||||
682
vendor/codeception/base/src/Codeception/Module/Db.php
vendored
Normal file
682
vendor/codeception/base/src/Codeception/Module/Db.php
vendored
Normal file
@@ -0,0 +1,682 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Lib\Interfaces\Db as DbInterface;
|
||||
use Codeception\Lib\Driver\Db as Driver;
|
||||
use Codeception\Lib\DbPopulator;
|
||||
use Codeception\TestInterface;
|
||||
|
||||
/**
|
||||
* Access a database.
|
||||
*
|
||||
* The most important function of this module is to clean a database before each test.
|
||||
* This module also provides actions to perform checks in a database, e.g. [seeInDatabase()](http://codeception.com/docs/modules/Db#seeInDatabase)
|
||||
*
|
||||
* In order to have your database populated with data you need a raw SQL dump.
|
||||
* Simply put the dump in the `tests/_data` directory (by default) and specify the path in the config.
|
||||
* The next time after the database is cleared, all your data will be restored from the dump.
|
||||
* Don't forget to include `CREATE TABLE` statements in the dump.
|
||||
*
|
||||
* Supported and tested databases are:
|
||||
*
|
||||
* * MySQL
|
||||
* * SQLite (i.e. just one file)
|
||||
* * PostgreSQL
|
||||
*
|
||||
* Also available:
|
||||
*
|
||||
* * MS SQL
|
||||
* * Oracle
|
||||
*
|
||||
* Connection is done by database Drivers, which are stored in the `Codeception\Lib\Driver` namespace.
|
||||
* [Check out the drivers](https://github.com/Codeception/Codeception/tree/2.3/src/Codeception/Lib/Driver)
|
||||
* if you run into problems loading dumps and cleaning databases.
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * dsn *required* - PDO DSN
|
||||
* * user *required* - username to access database
|
||||
* * password *required* - password
|
||||
* * dump - path to database dump
|
||||
* * populate: false - whether the the dump should be loaded before the test suite is started
|
||||
* * cleanup: false - whether the dump should be reloaded before each test
|
||||
* * reconnect: false - whether the module should reconnect to the database before each test
|
||||
* * waitlock: 0 - wait lock (in seconds) that the database session should use for DDL statements
|
||||
* * ssl_key - path to the SSL key (MySQL specific, @see http://php.net/manual/de/ref.pdo-mysql.php#pdo.constants.mysql-attr-key)
|
||||
* * ssl_cert - path to the SSL certificate (MySQL specific, @see http://php.net/manual/de/ref.pdo-mysql.php#pdo.constants.mysql-attr-ssl-cert)
|
||||
* * ssl_ca - path to the SSL certificate authority (MySQL specific, @see http://php.net/manual/de/ref.pdo-mysql.php#pdo.constants.mysql-attr-ssl-ca)
|
||||
* * ssl_verify_server_cert - disables certificate CN verification (MySQL specific, @see http://php.net/manual/de/ref.pdo-mysql.php)
|
||||
* * ssl_cipher - list of one or more permissible ciphers to use for SSL encryption (MySQL specific, @see http://php.net/manual/de/ref.pdo-mysql.php#pdo.constants.mysql-attr-cipher)
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Db:
|
||||
* dsn: 'mysql:host=localhost;dbname=testdb'
|
||||
* user: 'root'
|
||||
* password: ''
|
||||
* dump: 'tests/_data/dump.sql'
|
||||
* populate: true
|
||||
* cleanup: true
|
||||
* reconnect: true
|
||||
* waitlock: 10
|
||||
* ssl_key: '/path/to/client-key.pem'
|
||||
* ssl_cert: '/path/to/client-cert.pem'
|
||||
* ssl_ca: '/path/to/ca-cert.pem'
|
||||
* ssl_verify_server_cert: false
|
||||
* ssl_cipher: 'AES256-SHA'
|
||||
*
|
||||
* ## SQL data dump
|
||||
*
|
||||
* There are two ways of loading the dump into your database:
|
||||
*
|
||||
* ### Populator
|
||||
*
|
||||
* The recommended approach is to configure a `populator`, an external command to load a dump. Command parameters like host, username, password, database
|
||||
* can be obtained from the config and inserted into placeholders:
|
||||
*
|
||||
* For MySQL:
|
||||
*
|
||||
* ```yaml
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Db:
|
||||
* dsn: 'mysql:host=localhost;dbname=testdb'
|
||||
* user: 'root'
|
||||
* password: ''
|
||||
* dump: 'tests/_data/dump.sql'
|
||||
* populate: true # run populator before all tests
|
||||
* cleanup: true # run populator before each test
|
||||
* populator: 'mysql -u $user -h $host $dbname < $dump'
|
||||
* ```
|
||||
*
|
||||
* For PostgreSQL (using pg_restore)
|
||||
*
|
||||
* ```
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Db:
|
||||
* dsn: 'pgsql:host=localhost;dbname=testdb'
|
||||
* user: 'root'
|
||||
* password: ''
|
||||
* dump: 'tests/_data/db_backup.dump'
|
||||
* populate: true # run populator before all tests
|
||||
* cleanup: true # run populator before each test
|
||||
* populator: 'pg_restore -u $user -h $host -D $dbname < $dump'
|
||||
* ```
|
||||
*
|
||||
* Variable names are being taken from config and DSN which has a `keyword=value` format, so you should expect to have a variable named as the
|
||||
* keyword with the full value inside it.
|
||||
*
|
||||
* PDO dsn elements for the supported drivers:
|
||||
* * MySQL: [PDO_MYSQL DSN](https://secure.php.net/manual/en/ref.pdo-mysql.connection.php)
|
||||
* * SQLite: [PDO_SQLITE DSN](https://secure.php.net/manual/en/ref.pdo-sqlite.connection.php)
|
||||
* * PostgreSQL: [PDO_PGSQL DSN](https://secure.php.net/manual/en/ref.pdo-pgsql.connection.php)
|
||||
* * MSSQL: [PDO_SQLSRV DSN](https://secure.php.net/manual/en/ref.pdo-sqlsrv.connection.php)
|
||||
* * Oracle: [PDO_OCI DSN](https://secure.php.net/manual/en/ref.pdo-oci.connection.php)
|
||||
*
|
||||
* ### Dump
|
||||
*
|
||||
* Db module by itself can load SQL dump without external tools by using current database connection.
|
||||
* This approach is system-independent, however, it is slower than using a populator and may have parsing issues (see below).
|
||||
*
|
||||
* Provide a path to SQL file in `dump` config option:
|
||||
*
|
||||
* ```yaml
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Db:
|
||||
* dsn: 'mysql:host=localhost;dbname=testdb'
|
||||
* user: 'root'
|
||||
* password: ''
|
||||
* populate: true # load dump before all tests
|
||||
* cleanup: true # load dump for each test
|
||||
* dump: 'tests/_data/dump.sql'
|
||||
* ```
|
||||
*
|
||||
* To parse SQL Db file, it should follow this specification:
|
||||
* * Comments are permitted.
|
||||
* * The `dump.sql` may contain multiline statements.
|
||||
* * The delimiter, a semi-colon in this case, must be on the same line as the last statement:
|
||||
*
|
||||
* ```sql
|
||||
* -- Add a few contacts to the table.
|
||||
* REPLACE INTO `Contacts` (`created`, `modified`, `status`, `contact`, `first`, `last`) VALUES
|
||||
* (NOW(), NOW(), 1, 'Bob Ross', 'Bob', 'Ross'),
|
||||
* (NOW(), NOW(), 1, 'Fred Flintstone', 'Fred', 'Flintstone');
|
||||
*
|
||||
* -- Remove existing orders for testing.
|
||||
* DELETE FROM `Order`;
|
||||
* ```
|
||||
* ## Query generation
|
||||
*
|
||||
* `seeInDatabase`, `dontSeeInDatabase`, `seeNumRecords`, `grabFromDatabase` and `grabNumRecords` methods
|
||||
* accept arrays as criteria. WHERE condition is generated using item key as a field name and
|
||||
* item value as a field value.
|
||||
*
|
||||
* Example:
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeInDatabase('users', array('name' => 'Davert', 'email' => 'davert@mail.com'));
|
||||
*
|
||||
* ```
|
||||
* Will generate:
|
||||
*
|
||||
* ```sql
|
||||
* SELECT COUNT(*) FROM `users` WHERE `name` = 'Davert' AND `email` = 'davert@mail.com'
|
||||
* ```
|
||||
* Since version 2.1.9 it's possible to use LIKE in a condition, as shown here:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeInDatabase('users', array('name' => 'Davert', 'email like' => 'davert%'));
|
||||
*
|
||||
* ```
|
||||
* Will generate:
|
||||
*
|
||||
* ```sql
|
||||
* SELECT COUNT(*) FROM `users` WHERE `name` = 'Davert' AND `email` LIKE 'davert%'
|
||||
* ```
|
||||
* ## Public Properties
|
||||
* * dbh - contains the PDO connection
|
||||
* * driver - contains the Connection Driver
|
||||
*
|
||||
*/
|
||||
class Db extends CodeceptionModule implements DbInterface
|
||||
{
|
||||
/**
|
||||
* @api
|
||||
* @var
|
||||
*/
|
||||
public $dbh;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $sql = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [
|
||||
'populate' => false,
|
||||
'cleanup' => false,
|
||||
'reconnect' => false,
|
||||
'waitlock' => 0,
|
||||
'dump' => null,
|
||||
'populator' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $populated = false;
|
||||
|
||||
/**
|
||||
* @var \Codeception\Lib\Driver\Db
|
||||
*/
|
||||
public $driver;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $insertedRows = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $requiredFields = ['dsn', 'user', 'password'];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->connect();
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
public function _beforeSuite($settings = [])
|
||||
{
|
||||
if (!$this->config['populator']
|
||||
&& $this->config['dump']
|
||||
&& ($this->config['cleanup'] || ($this->config['populate']))
|
||||
) {
|
||||
$this->readSql();
|
||||
}
|
||||
|
||||
$this->connect();
|
||||
|
||||
// starting with loading dump
|
||||
if ($this->config['populate']) {
|
||||
if ($this->config['cleanup']) {
|
||||
$this->_cleanup();
|
||||
}
|
||||
$this->_loadDump();
|
||||
}
|
||||
|
||||
if ($this->config['reconnect']) {
|
||||
$this->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private function readSql()
|
||||
{
|
||||
if (!file_exists(Configuration::projectDir() . $this->config['dump'])) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"\nFile with dump doesn't exist.\n"
|
||||
. "Please, check path for sql file: "
|
||||
. $this->config['dump']
|
||||
);
|
||||
}
|
||||
|
||||
$sql = file_get_contents(Configuration::projectDir() . $this->config['dump']);
|
||||
|
||||
// remove C-style comments (except MySQL directives)
|
||||
$sql = preg_replace('%/\*(?!!\d+).*?\*/%s', '', $sql);
|
||||
|
||||
if (!empty($sql)) {
|
||||
// split SQL dump into lines
|
||||
$this->sql = preg_split('/\r\n|\n|\r/', $sql, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
private function connect()
|
||||
{
|
||||
$options = [];
|
||||
|
||||
/**
|
||||
* @see http://php.net/manual/en/pdo.construct.php
|
||||
* @see http://php.net/manual/de/ref.pdo-mysql.php#pdo-mysql.constants
|
||||
*/
|
||||
if (array_key_exists('ssl_key', $this->config)
|
||||
&& !empty($this->config['ssl_key'])
|
||||
&& defined('\PDO::MYSQL_ATTR_SSL_KEY')
|
||||
) {
|
||||
$options[\PDO::MYSQL_ATTR_SSL_KEY] = (string) $this->config['ssl_key'];
|
||||
}
|
||||
|
||||
if (array_key_exists('ssl_cert', $this->config)
|
||||
&& !empty($this->config['ssl_cert'])
|
||||
&& defined('\PDO::MYSQL_ATTR_SSL_CERT')
|
||||
) {
|
||||
$options[\PDO::MYSQL_ATTR_SSL_CERT] = (string) $this->config['ssl_cert'];
|
||||
}
|
||||
|
||||
if (array_key_exists('ssl_ca', $this->config)
|
||||
&& !empty($this->config['ssl_ca'])
|
||||
&& defined('\PDO::MYSQL_ATTR_SSL_CA')
|
||||
) {
|
||||
$options[\PDO::MYSQL_ATTR_SSL_CA] = (string) $this->config['ssl_ca'];
|
||||
}
|
||||
|
||||
if (array_key_exists('ssl_cipher', $this->config)
|
||||
&& !empty($this->config['ssl_cipher'])
|
||||
&& defined('\PDO::MYSQL_ATTR_SSL_CIPHER')
|
||||
) {
|
||||
$options[\PDO::MYSQL_ATTR_SSL_CIPHER] = (string) $this->config['ssl_cipher'];
|
||||
}
|
||||
|
||||
if (array_key_exists('ssl_verify_server_cert', $this->config)
|
||||
&& defined('\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT')
|
||||
) {
|
||||
$options[\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = (boolean) $this->config[ 'ssl_verify_server_cert' ];
|
||||
}
|
||||
|
||||
try {
|
||||
$this->driver = Driver::create($this->config['dsn'], $this->config['user'], $this->config['password'], $options);
|
||||
} catch (\PDOException $e) {
|
||||
$message = $e->getMessage();
|
||||
if ($message === 'could not find driver') {
|
||||
list ($missingDriver, ) = explode(':', $this->config['dsn'], 2);
|
||||
$message = "could not find $missingDriver driver";
|
||||
}
|
||||
|
||||
throw new ModuleException(__CLASS__, $message . ' while creating PDO connection');
|
||||
}
|
||||
|
||||
if ($this->config['waitlock']) {
|
||||
$this->driver->setWaitLock($this->config['waitlock']);
|
||||
}
|
||||
|
||||
$this->debugSection('Db', 'Connected to ' . $this->driver->getDb());
|
||||
$this->dbh = $this->driver->getDbh();
|
||||
}
|
||||
|
||||
private function disconnect()
|
||||
{
|
||||
$this->driver = null;
|
||||
$this->dbh = null;
|
||||
$this->debugSection('Db', 'Disconnected');
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
if ($this->config['reconnect']) {
|
||||
$this->disconnect();
|
||||
$this->connect();
|
||||
}
|
||||
if ($this->config['cleanup'] && !$this->populated) {
|
||||
$this->_cleanup();
|
||||
$this->_loadDump();
|
||||
}
|
||||
parent::_before($test);
|
||||
}
|
||||
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
$this->removeInserted();
|
||||
if ($this->config['reconnect']) {
|
||||
$this->disconnect();
|
||||
}
|
||||
parent::_after($test);
|
||||
}
|
||||
|
||||
protected function removeInserted()
|
||||
{
|
||||
foreach (array_reverse($this->insertedRows) as $row) {
|
||||
try {
|
||||
$this->driver->deleteQueryByCriteria($row['table'], $row['primary']);
|
||||
} catch (\Exception $e) {
|
||||
$this->debug("couldn't delete record " . json_encode($row['primary']) ." from {$row['table']}");
|
||||
}
|
||||
}
|
||||
$this->insertedRows = [];
|
||||
$this->populated = false;
|
||||
}
|
||||
|
||||
public function _cleanup()
|
||||
{
|
||||
$dbh = $this->driver->getDbh();
|
||||
if (!$dbh) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
'No connection to database. Remove this module from config if you don\'t need database repopulation'
|
||||
);
|
||||
}
|
||||
try {
|
||||
// don't clear database for empty dump
|
||||
if (!count($this->sql)) {
|
||||
return;
|
||||
}
|
||||
$this->driver->cleanup();
|
||||
$this->populated = false;
|
||||
} catch (\Exception $e) {
|
||||
throw new ModuleException(__CLASS__, $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function isPopulated()
|
||||
{
|
||||
return $this->populated;
|
||||
}
|
||||
|
||||
public function _loadDump()
|
||||
{
|
||||
if ($this->config['populator']) {
|
||||
$this->loadDumpUsingPopulator();
|
||||
return;
|
||||
}
|
||||
$this->loadDumpUsingDriver();
|
||||
}
|
||||
|
||||
protected function loadDumpUsingPopulator()
|
||||
{
|
||||
$populator = new DbPopulator($this->config);
|
||||
$this->populated = $populator->run();
|
||||
}
|
||||
|
||||
protected function loadDumpUsingDriver()
|
||||
{
|
||||
if (!$this->sql) {
|
||||
$this->debugSection('Db', 'No SQL loaded, loading dump skipped');
|
||||
return;
|
||||
}
|
||||
$this->driver->load($this->sql);
|
||||
$this->populated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an SQL record into a database. This record will be erased after the test.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->haveInDatabase('users', array('name' => 'miles', 'email' => 'miles@davis.com'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $data
|
||||
*
|
||||
* @return integer $id
|
||||
*/
|
||||
public function haveInDatabase($table, array $data)
|
||||
{
|
||||
$lastInsertId = $this->_insertInDatabase($table, $data);
|
||||
|
||||
$this->addInsertedRow($table, $data, $lastInsertId);
|
||||
|
||||
return $lastInsertId;
|
||||
}
|
||||
|
||||
public function _insertInDatabase($table, array $data)
|
||||
{
|
||||
$query = $this->driver->insert($table, $data);
|
||||
$parameters = array_values($data);
|
||||
$this->debugSection('Query', $query);
|
||||
$this->debugSection('Parameters', $parameters);
|
||||
$this->driver->executeQuery($query, $parameters);
|
||||
|
||||
try {
|
||||
$lastInsertId = (int)$this->driver->lastInsertId($table);
|
||||
} catch (\PDOException $e) {
|
||||
// ignore errors due to uncommon DB structure,
|
||||
// such as tables without _id_seq in PGSQL
|
||||
$lastInsertId = 0;
|
||||
}
|
||||
return $lastInsertId;
|
||||
}
|
||||
|
||||
private function addInsertedRow($table, array $row, $id)
|
||||
{
|
||||
$primaryKey = $this->driver->getPrimaryKey($table);
|
||||
$primary = [];
|
||||
if ($primaryKey) {
|
||||
if ($id && count($primaryKey) === 1) {
|
||||
$primary [$primaryKey[0]] = $id;
|
||||
} else {
|
||||
foreach ($primaryKey as $column) {
|
||||
if (isset($row[$column])) {
|
||||
$primary[$column] = $row[$column];
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
'Primary key field ' . $column . ' is not set for table ' . $table
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$primary = $row;
|
||||
}
|
||||
|
||||
$this->insertedRows[] = [
|
||||
'table' => $table,
|
||||
'primary' => $primary,
|
||||
];
|
||||
}
|
||||
|
||||
public function seeInDatabase($table, $criteria = [])
|
||||
{
|
||||
$res = $this->countInDatabase($table, $criteria);
|
||||
$this->assertGreaterThan(
|
||||
0,
|
||||
$res,
|
||||
'No matching records found for criteria ' . json_encode($criteria) . ' in table ' . $table
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given number of records were found in the database.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeNumRecords(1, 'users', ['name' => 'davert'])
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param int $expectedNumber Expected number
|
||||
* @param string $table Table name
|
||||
* @param array $criteria Search criteria [Optional]
|
||||
*/
|
||||
public function seeNumRecords($expectedNumber, $table, array $criteria = [])
|
||||
{
|
||||
$actualNumber = $this->countInDatabase($table, $criteria);
|
||||
$this->assertEquals(
|
||||
$expectedNumber,
|
||||
$actualNumber,
|
||||
sprintf(
|
||||
'The number of found rows (%d) does not match expected number %d for criteria %s in table %s',
|
||||
$actualNumber,
|
||||
$expectedNumber,
|
||||
json_encode($criteria),
|
||||
$table
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function dontSeeInDatabase($table, $criteria = [])
|
||||
{
|
||||
$count = $this->countInDatabase($table, $criteria);
|
||||
$this->assertLessThan(
|
||||
1,
|
||||
$count,
|
||||
'Unexpectedly found matching records for criteria ' . json_encode($criteria) . ' in table ' . $table
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count rows in a database
|
||||
*
|
||||
* @param string $table Table name
|
||||
* @param array $criteria Search criteria [Optional]
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function countInDatabase($table, array $criteria = [])
|
||||
{
|
||||
return (int) $this->proceedSeeInDatabase($table, 'count(*)', $criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all values from the column in database.
|
||||
* Provide table name, desired column and criteria.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $column
|
||||
* @param array $criteria
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function proceedSeeInDatabase($table, $column, $criteria)
|
||||
{
|
||||
$query = $this->driver->select($column, $table, $criteria);
|
||||
$parameters = array_values($criteria);
|
||||
$this->debugSection('Query', $query);
|
||||
if (!empty($parameters)) {
|
||||
$this->debugSection('Parameters', $parameters);
|
||||
}
|
||||
$sth = $this->driver->executeQuery($query, $parameters);
|
||||
|
||||
return $sth->fetchColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all values from the column in database.
|
||||
* Provide table name, desired column and criteria.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $mails = $I->grabColumnFromDatabase('users', 'email', array('name' => 'RebOOter'));
|
||||
* ```
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $column
|
||||
* @param array $criteria
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function grabColumnFromDatabase($table, $column, array $criteria = [])
|
||||
{
|
||||
$query = $this->driver->select($column, $table, $criteria);
|
||||
$parameters = array_values($criteria);
|
||||
$this->debugSection('Query', $query);
|
||||
$this->debugSection('Parameters', $parameters);
|
||||
$sth = $this->driver->executeQuery($query, $parameters);
|
||||
|
||||
return $sth->fetchAll(\PDO::FETCH_COLUMN, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all values from the column in database.
|
||||
* Provide table name, desired column and criteria.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $mails = $I->grabFromDatabase('users', 'email', array('name' => 'RebOOter'));
|
||||
* ```
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $column
|
||||
* @param array $criteria
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function grabFromDatabase($table, $column, $criteria = [])
|
||||
{
|
||||
return $this->proceedSeeInDatabase($table, $column, $criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a database
|
||||
*
|
||||
* @param string $table Table name
|
||||
* @param array $criteria Search criteria [Optional]
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function grabNumRecords($table, array $criteria = [])
|
||||
{
|
||||
return $this->countInDatabase($table, $criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an SQL record into a database.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->updateInDatabase('users', array('isAdmin' => true), array('email' => 'miles@davis.com'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $data
|
||||
* @param array $criteria
|
||||
*/
|
||||
public function updateInDatabase($table, array $data, array $criteria = [])
|
||||
{
|
||||
$query = $this->driver->update($table, $data, $criteria);
|
||||
$parameters = array_merge(array_values($data), array_values($criteria));
|
||||
$this->debugSection('Query', $query);
|
||||
if (!empty($parameters)) {
|
||||
$this->debugSection('Parameters', $parameters);
|
||||
}
|
||||
$this->driver->executeQuery($query, $parameters);
|
||||
}
|
||||
}
|
||||
529
vendor/codeception/base/src/Codeception/Module/Doctrine2.php
vendored
Normal file
529
vendor/codeception/base/src/Codeception/Module/Doctrine2.php
vendored
Normal file
@@ -0,0 +1,529 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Lib\Interfaces\DataMapper;
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Lib\Interfaces\DependsOnModule;
|
||||
use Codeception\Lib\Interfaces\DoctrineProvider;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Util\Stub;
|
||||
|
||||
/**
|
||||
* Access the database using [Doctrine2 ORM](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/).
|
||||
*
|
||||
* When used with Zend Framework 2 or Symfony2, Doctrine's Entity Manager is automatically retrieved from Service Locator.
|
||||
* Set up your `functional.suite.yml` like this:
|
||||
*
|
||||
* ```
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Symfony # 'ZF2' or 'Symfony'
|
||||
* - Doctrine2:
|
||||
* depends: Symfony
|
||||
* cleanup: true # All doctrine queries will be wrapped in a transaction, which will be rolled back at the end of each test
|
||||
* ```
|
||||
*
|
||||
* If you don't use Symfony or Zend Framework, you need to specify a callback function to retrieve the Entity Manager:
|
||||
*
|
||||
* ```
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Doctrine2:
|
||||
* connection_callback: ['MyDb', 'createEntityManager']
|
||||
* cleanup: true # All doctrine queries will be wrapped in a transaction, which will be rolled back at the end of each test
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* This will use static method of `MyDb::createEntityManager()` to establish the Entity Manager.
|
||||
*
|
||||
* By default, the module will wrap everything into a transaction for each test and roll it back afterwards. By doing this
|
||||
* tests will run much faster and will be isolated from each other.
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **davert**
|
||||
* * Stability: **stable**
|
||||
* * Contact: codecept@davert.mail.ua
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* ## Public Properties
|
||||
*
|
||||
* * `em` - Entity Manager
|
||||
*/
|
||||
|
||||
class Doctrine2 extends CodeceptionModule implements DependsOnModule, DataMapper
|
||||
{
|
||||
|
||||
protected $config = [
|
||||
'cleanup' => true,
|
||||
'connection_callback' => false,
|
||||
'depends' => null
|
||||
];
|
||||
|
||||
protected $dependencyMessage = <<<EOF
|
||||
Provide connection_callback function to establish database connection and get Entity Manager:
|
||||
|
||||
modules:
|
||||
enabled:
|
||||
- Doctrine2:
|
||||
connection_callback: [My\ConnectionClass, getEntityManager]
|
||||
|
||||
Or set a dependent module, which can be either Symfony or ZF2 to get EM from service locator:
|
||||
|
||||
modules:
|
||||
enabled:
|
||||
- Doctrine2:
|
||||
depends: Symfony
|
||||
EOF;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManagerInterface
|
||||
*/
|
||||
public $em = null;
|
||||
|
||||
/**
|
||||
* @var \Codeception\Lib\Interfaces\DoctrineProvider
|
||||
*/
|
||||
private $dependentModule;
|
||||
|
||||
public function _depends()
|
||||
{
|
||||
if ($this->config['connection_callback']) {
|
||||
return [];
|
||||
}
|
||||
return ['Codeception\Lib\Interfaces\DoctrineProvider' => $this->dependencyMessage];
|
||||
}
|
||||
|
||||
public function _inject(DoctrineProvider $dependentModule = null)
|
||||
{
|
||||
$this->dependentModule = $dependentModule;
|
||||
}
|
||||
|
||||
public function _beforeSuite($settings = [])
|
||||
{
|
||||
$this->retrieveEntityManager();
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->retrieveEntityManager();
|
||||
if ($this->config['cleanup']) {
|
||||
$this->em->getConnection()->beginTransaction();
|
||||
$this->debugSection('Database', 'Transaction started');
|
||||
}
|
||||
}
|
||||
|
||||
protected function retrieveEntityManager()
|
||||
{
|
||||
if ($this->dependentModule) {
|
||||
$this->em = $this->dependentModule->_getEntityManager();
|
||||
} else {
|
||||
if (is_callable($this->config['connection_callback'])) {
|
||||
$this->em = call_user_func($this->config['connection_callback']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->em) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"EntityManager can't be obtained.\n \n"
|
||||
. "Please specify either `connection_callback` config option\n"
|
||||
. "with callable which will return instance of EntityManager or\n"
|
||||
. "pass a dependent module which are Symfony or ZF2\n"
|
||||
. "to connect to Doctrine using Dependency Injection Container"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (!($this->em instanceof \Doctrine\ORM\EntityManagerInterface)) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"Connection object is not an instance of \\Doctrine\\ORM\\EntityManagerInterface.\n"
|
||||
. "Use `connection_callback` or dependent framework modules to specify one"
|
||||
);
|
||||
}
|
||||
|
||||
$this->em->getConnection()->connect();
|
||||
}
|
||||
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
if (!$this->em instanceof \Doctrine\ORM\EntityManagerInterface) {
|
||||
return;
|
||||
}
|
||||
if ($this->config['cleanup'] && $this->em->getConnection()->isTransactionActive()) {
|
||||
try {
|
||||
$this->em->getConnection()->rollback();
|
||||
$this->debugSection('Database', 'Transaction cancelled; all changes reverted.');
|
||||
} catch (\PDOException $e) {
|
||||
}
|
||||
}
|
||||
$this->clean();
|
||||
$this->em->getConnection()->close();
|
||||
}
|
||||
|
||||
protected function clean()
|
||||
{
|
||||
$em = $this->em;
|
||||
|
||||
$reflectedEm = new \ReflectionClass($em);
|
||||
if ($reflectedEm->hasProperty('repositories')) {
|
||||
$property = $reflectedEm->getProperty('repositories');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($em, []);
|
||||
}
|
||||
$this->em->clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs $em->flush();
|
||||
*/
|
||||
public function flushToDatabase()
|
||||
{
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds entity to repository and flushes. You can redefine it's properties with the second parameter.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->persistEntity(new \Entity\User, array('name' => 'Miles'));
|
||||
* $I->persistEntity($user, array('name' => 'Miles'));
|
||||
* ```
|
||||
*
|
||||
* @param $obj
|
||||
* @param array $values
|
||||
*/
|
||||
public function persistEntity($obj, $values = [])
|
||||
{
|
||||
if ($values) {
|
||||
$reflectedObj = new \ReflectionClass($obj);
|
||||
foreach ($values as $key => $val) {
|
||||
$property = $reflectedObj->getProperty($key);
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($obj, $val);
|
||||
}
|
||||
}
|
||||
|
||||
$this->em->persist($obj);
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocks the repository.
|
||||
*
|
||||
* With this action you can redefine any method of any repository.
|
||||
* Please, note: this fake repositories will be accessible through entity manager till the end of test.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
*
|
||||
* $I->haveFakeRepository('Entity\User', array('findByUsername' => function($username) { return null; }));
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* This creates a stub class for Entity\User repository with redefined method findByUsername,
|
||||
* which will always return the NULL value.
|
||||
*
|
||||
* @param $classname
|
||||
* @param array $methods
|
||||
*/
|
||||
public function haveFakeRepository($classname, $methods = [])
|
||||
{
|
||||
$em = $this->em;
|
||||
|
||||
$metadata = $em->getMetadataFactory()->getMetadataFor($classname);
|
||||
$customRepositoryClassName = $metadata->customRepositoryClassName;
|
||||
|
||||
if (!$customRepositoryClassName) {
|
||||
$customRepositoryClassName = '\Doctrine\ORM\EntityRepository';
|
||||
}
|
||||
|
||||
$mock = Stub::make(
|
||||
$customRepositoryClassName,
|
||||
array_merge(
|
||||
[
|
||||
'_entityName' => $metadata->name,
|
||||
'_em' => $em,
|
||||
'_class' => $metadata
|
||||
],
|
||||
$methods
|
||||
)
|
||||
);
|
||||
|
||||
$em->clear();
|
||||
$reflectedEm = new \ReflectionClass($em);
|
||||
|
||||
|
||||
if ($reflectedEm->hasProperty('repositories')) {
|
||||
//Support doctrine versions before 2.4.0
|
||||
|
||||
$property = $reflectedEm->getProperty('repositories');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($em, array_merge($property->getValue($em), [$classname => $mock]));
|
||||
} elseif ($reflectedEm->hasProperty('repositoryFactory')) {
|
||||
//For doctrine 2.4.0+ versions
|
||||
|
||||
$repositoryFactoryProperty = $reflectedEm->getProperty('repositoryFactory');
|
||||
$repositoryFactoryProperty->setAccessible(true);
|
||||
$repositoryFactory = $repositoryFactoryProperty->getValue($em);
|
||||
|
||||
$reflectedRepositoryFactory = new \ReflectionClass($repositoryFactory);
|
||||
|
||||
if ($reflectedRepositoryFactory->hasProperty('repositoryList')) {
|
||||
$repositoryListProperty = $reflectedRepositoryFactory->getProperty('repositoryList');
|
||||
$repositoryListProperty->setAccessible(true);
|
||||
|
||||
$repositoryListProperty->setValue(
|
||||
$repositoryFactory,
|
||||
[$classname => $mock]
|
||||
);
|
||||
|
||||
$repositoryFactoryProperty->setValue($em, $repositoryFactory);
|
||||
} else {
|
||||
$this->debugSection(
|
||||
'Warning',
|
||||
'Repository can\'t be mocked, the EventManager\'s repositoryFactory doesn\'t have "repositoryList" property'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$this->debugSection(
|
||||
'Warning',
|
||||
'Repository can\'t be mocked, the EventManager class doesn\'t have "repositoryFactory" or "repositories" property'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists record into repository.
|
||||
* This method creates an entity, and sets its properties directly (via reflection).
|
||||
* Setters of entity won't be executed, but you can create almost any entity and save it to database.
|
||||
* Returns id using `getId` of newly created entity.
|
||||
*
|
||||
* ```php
|
||||
* $I->haveInRepository('Entity\User', array('name' => 'davert'));
|
||||
* ```
|
||||
*/
|
||||
public function haveInRepository($entity, array $data)
|
||||
{
|
||||
$reflectedEntity = new \ReflectionClass($entity);
|
||||
$entityObject = $reflectedEntity->newInstance();
|
||||
foreach ($reflectedEntity->getProperties() as $property) {
|
||||
/** @var $property \ReflectionProperty */
|
||||
if (!isset($data[$property->name])) {
|
||||
continue;
|
||||
}
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($entityObject, $data[$property->name]);
|
||||
}
|
||||
$this->em->persist($entityObject);
|
||||
$this->em->flush();
|
||||
|
||||
if (method_exists($entityObject, 'getId')) {
|
||||
$id = $entityObject->getId();
|
||||
$this->debug("$entity entity created with id:$id");
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes changes to database, and executes a query with parameters defined in an array.
|
||||
* You can use entity associations to build complex queries.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeInRepository('AppBundle:User', array('name' => 'davert'));
|
||||
* $I->seeInRepository('User', array('name' => 'davert', 'Company' => array('name' => 'Codegyre')));
|
||||
* $I->seeInRepository('Client', array('User' => array('Company' => array('name' => 'Codegyre')));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Fails if record for given criteria can\'t be found,
|
||||
*
|
||||
* @param $entity
|
||||
* @param array $params
|
||||
*/
|
||||
public function seeInRepository($entity, $params = [])
|
||||
{
|
||||
$res = $this->proceedSeeInRepository($entity, $params);
|
||||
$this->assert($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes changes to database and performs `findOneBy()` call for current repository.
|
||||
*
|
||||
* @param $entity
|
||||
* @param array $params
|
||||
*/
|
||||
public function dontSeeInRepository($entity, $params = [])
|
||||
{
|
||||
$res = $this->proceedSeeInRepository($entity, $params);
|
||||
$this->assertNot($res);
|
||||
}
|
||||
|
||||
protected function proceedSeeInRepository($entity, $params = [])
|
||||
{
|
||||
// we need to store to database...
|
||||
$this->em->flush();
|
||||
$data = $this->em->getClassMetadata($entity);
|
||||
$qb = $this->em->getRepository($entity)->createQueryBuilder('s');
|
||||
$this->buildAssociationQuery($qb, $entity, 's', $params);
|
||||
$this->debug($qb->getDQL());
|
||||
$res = $qb->getQuery()->getArrayResult();
|
||||
|
||||
return ['True', (count($res) > 0), "$entity with " . json_encode($params)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects field value from repository.
|
||||
* It builds query based on array of parameters.
|
||||
* You can use entity associations to build complex queries.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $email = $I->grabFromRepository('User', 'email', array('name' => 'davert'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @version 1.1
|
||||
* @param $entity
|
||||
* @param $field
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function grabFromRepository($entity, $field, $params = [])
|
||||
{
|
||||
// we need to store to database...
|
||||
$this->em->flush();
|
||||
$data = $this->em->getClassMetadata($entity);
|
||||
$qb = $this->em->getRepository($entity)->createQueryBuilder('s');
|
||||
$qb->select('s.' . $field);
|
||||
$this->buildAssociationQuery($qb, $entity, 's', $params);
|
||||
$this->debug($qb->getDQL());
|
||||
return $qb->getQuery()->getSingleScalarResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects entities from repository.
|
||||
* It builds query based on array of parameters.
|
||||
* You can use entity associations to build complex queries.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $users = $I->grabEntitiesFromRepository('AppBundle:User', array('name' => 'davert'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @version 1.1
|
||||
* @param $entity
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function grabEntitiesFromRepository($entity, $params = [])
|
||||
{
|
||||
// we need to store to database...
|
||||
$this->em->flush();
|
||||
$data = $this->em->getClassMetadata($entity);
|
||||
$qb = $this->em->getRepository($entity)->createQueryBuilder('s');
|
||||
$qb->select('s');
|
||||
$this->buildAssociationQuery($qb, $entity, 's', $params);
|
||||
$this->debug($qb->getDQL());
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a single entity from repository.
|
||||
* It builds query based on array of parameters.
|
||||
* You can use entity associations to build complex queries.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $user = $I->grabEntityFromRepository('User', array('id' => '1234'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @version 1.1
|
||||
* @param $entity
|
||||
* @param array $params
|
||||
* @return object
|
||||
*/
|
||||
public function grabEntityFromRepository($entity, $params = [])
|
||||
{
|
||||
// we need to store to database...
|
||||
$this->em->flush();
|
||||
$data = $this->em->getClassMetadata($entity);
|
||||
$qb = $this->em->getRepository($entity)->createQueryBuilder('s');
|
||||
$qb->select('s');
|
||||
$this->buildAssociationQuery($qb, $entity, 's', $params);
|
||||
$this->debug($qb->getDQL());
|
||||
|
||||
return $qb->getQuery()->getSingleResult();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* It's Fuckin Recursive!
|
||||
*
|
||||
* @param $qb
|
||||
* @param $assoc
|
||||
* @param $alias
|
||||
* @param $params
|
||||
*/
|
||||
protected function buildAssociationQuery($qb, $assoc, $alias, $params)
|
||||
{
|
||||
$data = $this->em->getClassMetadata($assoc);
|
||||
foreach ($params as $key => $val) {
|
||||
if (isset($data->associationMappings)) {
|
||||
if ($map = array_key_exists($key, $data->associationMappings)) {
|
||||
if (is_array($val)) {
|
||||
$qb->innerJoin("$alias.$key", "_$key");
|
||||
foreach ($val as $column => $v) {
|
||||
if (is_array($v)) {
|
||||
$this->buildAssociationQuery($qb, $map['targetEntity'], $column, $v);
|
||||
continue;
|
||||
}
|
||||
$paramname = "_$key" . '__' . $column;
|
||||
$qb->andWhere("_$key.$column = :$paramname");
|
||||
$qb->setParameter($paramname, $v);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($val === null) {
|
||||
$qb->andWhere("s.$key IS NULL");
|
||||
} else {
|
||||
$paramname = str_replace(".", "", "s_$key");
|
||||
$qb->andWhere("s.$key = :$paramname");
|
||||
$qb->setParameter($paramname, $val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function _getEntityManager()
|
||||
{
|
||||
if (is_null($this->em)) {
|
||||
$this->retrieveEntityManager();
|
||||
}
|
||||
return $this->em;
|
||||
}
|
||||
}
|
||||
883
vendor/codeception/base/src/Codeception/Module/FTP.php
vendored
Normal file
883
vendor/codeception/base/src/Codeception/Module/FTP.php
vendored
Normal file
@@ -0,0 +1,883 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\TestInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
* Works with SFTP/FTP servers.
|
||||
*
|
||||
* In order to test the contents of a specific file stored on any remote FTP/SFTP system
|
||||
* this module downloads a temporary file to the local system. The temporary directory is
|
||||
* defined by default as ```tests/_data``` to specify a different directory set the tmp config
|
||||
* option to your chosen path.
|
||||
*
|
||||
* Don't forget to create the folder and ensure its writable.
|
||||
*
|
||||
* Supported and tested FTP types are:
|
||||
*
|
||||
* * FTP
|
||||
* * SFTP
|
||||
*
|
||||
* Connection uses php build in FTP client for FTP,
|
||||
* connection to SFTP uses [phpseclib](http://phpseclib.sourceforge.net/) pulled in using composer.
|
||||
*
|
||||
* For SFTP, add [phpseclib](http://phpseclib.sourceforge.net/) to require list.
|
||||
* ```
|
||||
* "require": {
|
||||
* "phpseclib/phpseclib": "0.3.6"
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **nathanmac**
|
||||
* * Stability:
|
||||
* - FTP: **stable**
|
||||
* - SFTP: **stable**
|
||||
* * Contact: nathan.macnamara@outlook.com
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * type: ftp - type of connection ftp/sftp (defaults to ftp).
|
||||
* * host *required* - hostname/ip address of the ftp server.
|
||||
* * port: 21 - port number for the ftp server
|
||||
* * timeout: 90 - timeout settings for connecting the ftp server.
|
||||
* * user: anonymous - user to access ftp server, defaults to anonymous authentication.
|
||||
* * password - password, defaults to empty for anonymous.
|
||||
* * key - path to RSA key for sftp.
|
||||
* * tmp - path to local directory for storing tmp files.
|
||||
* * passive: true - Turns on or off passive mode (FTP only)
|
||||
* * cleanup: true - remove tmp files from local directory on completion.
|
||||
*
|
||||
* ### Example
|
||||
* #### Example (FTP)
|
||||
*
|
||||
* modules:
|
||||
* enabled: [FTP]
|
||||
* config:
|
||||
* FTP:
|
||||
* type: ftp
|
||||
* host: '127.0.0.1'
|
||||
* port: 21
|
||||
* timeout: 120
|
||||
* user: 'root'
|
||||
* password: 'root'
|
||||
* key: ~/.ssh/id_rsa
|
||||
* tmp: 'tests/_data/ftp'
|
||||
* passive: true
|
||||
* cleanup: false
|
||||
*
|
||||
* #### Example (SFTP)
|
||||
*
|
||||
* modules:
|
||||
* enabled: [FTP]
|
||||
* config:
|
||||
* FTP:
|
||||
* type: sftp
|
||||
* host: '127.0.0.1'
|
||||
* port: 22
|
||||
* timeout: 120
|
||||
* user: 'root'
|
||||
* password: 'root'
|
||||
* key: ''
|
||||
* tmp: 'tests/_data/ftp'
|
||||
* cleanup: false
|
||||
*
|
||||
*
|
||||
* This module extends the Filesystem module, file contents methods are inherited from this module.
|
||||
*/
|
||||
|
||||
class FTP extends Filesystem
|
||||
{
|
||||
/**
|
||||
* FTP/SFTP connection handler
|
||||
*/
|
||||
protected $ftp = null;
|
||||
|
||||
/**
|
||||
* Configuration options and default settings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [
|
||||
'type' => 'ftp',
|
||||
'port' => 21,
|
||||
'timeout' => 90,
|
||||
'user' => 'anonymous',
|
||||
'password' => '',
|
||||
'key' => '',
|
||||
'tmp' => 'tests/_data',
|
||||
'passive' => false,
|
||||
'cleanup' => true
|
||||
];
|
||||
|
||||
/**
|
||||
* Required configuration fields
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $requiredFields = ['host'];
|
||||
|
||||
// ----------- SETUP METHODS BELOW HERE -------------------------//
|
||||
|
||||
/**
|
||||
* Setup connection and login with config settings
|
||||
*
|
||||
* @param \Codeception\TestInterface $test
|
||||
*/
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
// Login using config settings
|
||||
$this->loginAs($this->config['user'], $this->config['password']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the FTP connection & Clear up
|
||||
*/
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
$this->_closeConnection();
|
||||
|
||||
// Clean up temp files
|
||||
if ($this->config['cleanup']) {
|
||||
if (file_exists($this->config['tmp'] . '/ftp_data_file.tmp')) {
|
||||
unlink($this->config['tmp'] . '/ftp_data_file.tmp');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the logged in user mid-way through your test, this closes the
|
||||
* current connection to the server and initialises and new connection.
|
||||
*
|
||||
* On initiation of this modules you are automatically logged into
|
||||
* the server using the specified config options or defaulted
|
||||
* to anonymous user if not provided.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->loginAs('user','password');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param String $user
|
||||
* @param String $password
|
||||
*/
|
||||
public function loginAs($user = 'anonymous', $password = '')
|
||||
{
|
||||
$this->_openConnection($user, $password); // Create new connection and login.
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters a directory on the ftp system - FTP root directory is used by default
|
||||
*
|
||||
* @param $path
|
||||
*/
|
||||
public function amInPath($path)
|
||||
{
|
||||
$this->_changeDirectory($this->path = $this->absolutizePath($path) . ($path == '/' ? '' : DIRECTORY_SEPARATOR));
|
||||
$this->debug('Moved to ' . $this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve path
|
||||
*
|
||||
* @param $path
|
||||
* @return string
|
||||
*/
|
||||
protected function absolutizePath($path)
|
||||
{
|
||||
if (strpos($path, '/') === 0) {
|
||||
return $path;
|
||||
}
|
||||
return $this->path . $path;
|
||||
}
|
||||
|
||||
// ----------- SEARCH METHODS BELOW HERE ------------------------//
|
||||
|
||||
/**
|
||||
* Checks if file exists in path on the remote FTP/SFTP system.
|
||||
* DOES NOT OPEN the file when it's exists
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeFileFound('UserModel.php','app/models');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $filename
|
||||
* @param string $path
|
||||
*/
|
||||
public function seeFileFound($filename, $path = '')
|
||||
{
|
||||
$files = $this->grabFileList($path);
|
||||
$this->debug("see file: {$filename}");
|
||||
$this->assertContains($filename, $files, "file {$filename} not found in {$path}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if file exists in path on the remote FTP/SFTP system, using regular expression as filename.
|
||||
* DOES NOT OPEN the file when it's exists
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeFileFoundMatches('/^UserModel_([0-9]{6}).php$/','app/models');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $regex
|
||||
* @param string $path
|
||||
*/
|
||||
public function seeFileFoundMatches($regex, $path = '')
|
||||
{
|
||||
foreach ($this->grabFileList($path) as $filename) {
|
||||
preg_match($regex, $filename, $matches);
|
||||
if (!empty($matches)) {
|
||||
$this->debug("file '{$filename}' matches '{$regex}'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->fail("no file matches found for '{$regex}'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if file does not exist in path on the remote FTP/SFTP system
|
||||
*
|
||||
* @param $filename
|
||||
* @param string $path
|
||||
*/
|
||||
public function dontSeeFileFound($filename, $path = '')
|
||||
{
|
||||
$files = $this->grabFileList($path);
|
||||
$this->debug("don't see file: {$filename}");
|
||||
$this->assertNotContains($filename, $files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if file does not exist in path on the remote FTP/SFTP system, using regular expression as filename.
|
||||
* DOES NOT OPEN the file when it's exists
|
||||
*
|
||||
* @param $regex
|
||||
* @param string $path
|
||||
*/
|
||||
public function dontSeeFileFoundMatches($regex, $path = '')
|
||||
{
|
||||
foreach ($this->grabFileList($path) as $filename) {
|
||||
preg_match($regex, $filename, $matches);
|
||||
if (!empty($matches)) {
|
||||
$this->fail("file matches found for {$regex}");
|
||||
}
|
||||
}
|
||||
$this->assertTrue(true);
|
||||
$this->debug("no files match '{$regex}'");
|
||||
}
|
||||
|
||||
// ----------- UTILITY METHODS BELOW HERE -------------------------//
|
||||
|
||||
/**
|
||||
* Opens a file (downloads from the remote FTP/SFTP system to a tmp directory for processing)
|
||||
* and stores it's content.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->openFile('composer.json');
|
||||
* $I->seeInThisFile('codeception/codeception');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $filename
|
||||
*/
|
||||
public function openFile($filename)
|
||||
{
|
||||
$this->_openFile($this->absolutizePath($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves contents to tmp file and uploads the FTP/SFTP system.
|
||||
* Overwrites current file on server if exists.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->writeToFile('composer.json', 'some data here');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $filename
|
||||
* @param $contents
|
||||
*/
|
||||
public function writeToFile($filename, $contents)
|
||||
{
|
||||
$this->_writeToFile($this->absolutizePath($filename), $contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directory on the server
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->makeDir('vendor');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $dirname
|
||||
*/
|
||||
public function makeDir($dirname)
|
||||
{
|
||||
$this->makeDirectory($this->absolutizePath($dirname));
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently not supported in this module, overwrite inherited method
|
||||
*
|
||||
* @param $src
|
||||
* @param $dst
|
||||
*/
|
||||
public function copyDir($src, $dst)
|
||||
{
|
||||
$this->fail('copyDir() currently unsupported by FTP module');
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename/Move file on the FTP/SFTP server
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->renameFile('composer.lock', 'composer_old.lock');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $filename
|
||||
* @param $rename
|
||||
*/
|
||||
public function renameFile($filename, $rename)
|
||||
{
|
||||
$this->renameDirectory($this->absolutizePath($filename), $this->absolutizePath($rename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename/Move directory on the FTP/SFTP server
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->renameDir('vendor', 'vendor_old');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $dirname
|
||||
* @param $rename
|
||||
*/
|
||||
public function renameDir($dirname, $rename)
|
||||
{
|
||||
$this->renameDirectory($this->absolutizePath($dirname), $this->absolutizePath($rename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file on the remote FTP/SFTP system
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->deleteFile('composer.lock');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $filename
|
||||
*/
|
||||
public function deleteFile($filename)
|
||||
{
|
||||
$this->delete($this->absolutizePath($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes directory with all subdirectories on the remote FTP/SFTP server
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->deleteDir('vendor');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $dirname
|
||||
*/
|
||||
public function deleteDir($dirname)
|
||||
{
|
||||
$this->delete($this->absolutizePath($dirname));
|
||||
}
|
||||
|
||||
/**
|
||||
* Erases directory contents on the FTP/SFTP server
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->cleanDir('logs');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $dirname
|
||||
*/
|
||||
public function cleanDir($dirname)
|
||||
{
|
||||
$this->clearDirectory($this->absolutizePath($dirname));
|
||||
}
|
||||
|
||||
// ----------- GRABBER METHODS BELOW HERE -----------------------//
|
||||
|
||||
|
||||
/**
|
||||
* Grabber method for returning file/folders listing in an array
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $files = $I->grabFileList();
|
||||
* $count = $I->grabFileList('TEST', false); // Include . .. .thumbs.db
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $path
|
||||
* @param bool $ignore - suppress '.', '..' and '.thumbs.db'
|
||||
* @return array
|
||||
*/
|
||||
public function grabFileList($path = '', $ignore = true)
|
||||
{
|
||||
$absolutize_path = $this->absolutizePath($path)
|
||||
. ($path != '' && substr($path, -1) != '/' ? DIRECTORY_SEPARATOR : '');
|
||||
$files = $this->_listFiles($absolutize_path);
|
||||
|
||||
$display_files = [];
|
||||
if (is_array($files) && !empty($files)) {
|
||||
$this->debug('File List:');
|
||||
foreach ($files as &$file) {
|
||||
if (strtolower($file) != '.' &&
|
||||
strtolower($file) != '..' &&
|
||||
strtolower($file) != 'thumbs.db'
|
||||
) { // Ignore '.', '..' and 'thumbs.db'
|
||||
// Replace full path from file listings if returned in listing
|
||||
$file = str_replace(
|
||||
$absolutize_path,
|
||||
'',
|
||||
$file
|
||||
);
|
||||
$display_files[] = $file;
|
||||
$this->debug(' - ' . $file);
|
||||
}
|
||||
}
|
||||
return $ignore ? $display_files : $files;
|
||||
}
|
||||
$this->debug("File List: <empty>");
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabber method for returning file/folders count in directory
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $count = $I->grabFileCount();
|
||||
* $count = $I->grabFileCount('TEST', false); // Include . .. .thumbs.db
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $path
|
||||
* @param bool $ignore - suppress '.', '..' and '.thumbs.db'
|
||||
* @return int
|
||||
*/
|
||||
public function grabFileCount($path = '', $ignore = true)
|
||||
{
|
||||
$count = count($this->grabFileList($path, $ignore));
|
||||
$this->debug("File Count: {$count}");
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabber method to return file size
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $size = $I->grabFileSize('test.txt');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $filename
|
||||
* @return bool
|
||||
*/
|
||||
public function grabFileSize($filename)
|
||||
{
|
||||
$fileSize = $this->size($filename);
|
||||
$this->debug("{$filename} has a file size of {$fileSize}");
|
||||
return $fileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabber method to return last modified timestamp
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $time = $I->grabFileModified('test.txt');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $filename
|
||||
* @return bool
|
||||
*/
|
||||
public function grabFileModified($filename)
|
||||
{
|
||||
$time = $this->modified($filename);
|
||||
$this->debug("{$filename} was last modified at {$time}");
|
||||
return $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabber method to return current working directory
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $pwd = $I->grabDirectory();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function grabDirectory()
|
||||
{
|
||||
$pwd = $this->_directory();
|
||||
$this->debug("PWD: {$pwd}");
|
||||
return $pwd;
|
||||
}
|
||||
|
||||
// ----------- SERVER CONNECTION METHODS BELOW HERE -------------//
|
||||
|
||||
/**
|
||||
* Open a new FTP/SFTP connection and authenticate user.
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $password
|
||||
*/
|
||||
private function _openConnection($user = 'anonymous', $password = '')
|
||||
{
|
||||
$this->_closeConnection(); // Close connection if already open
|
||||
if ($this->isSFTP()) {
|
||||
$this->sftpConnect($user, $password);
|
||||
} else {
|
||||
$this->ftpConnect($user, $password);
|
||||
}
|
||||
$pwd = $this->grabDirectory();
|
||||
$this->path = $pwd . ($pwd == '/' ? '' : DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close open FTP/SFTP connection
|
||||
*/
|
||||
private function _closeConnection()
|
||||
{
|
||||
if (!$this->ftp) {
|
||||
return;
|
||||
}
|
||||
if (!$this->isSFTP()) {
|
||||
ftp_close($this->ftp);
|
||||
$this->ftp = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file listing for FTP/SFTP connection
|
||||
*
|
||||
* @param String $path
|
||||
* @return array
|
||||
*/
|
||||
private function _listFiles($path)
|
||||
{
|
||||
if ($this->isSFTP()) {
|
||||
$files = @$this->ftp->nlist($path);
|
||||
} else {
|
||||
$files = @ftp_nlist($this->ftp, $path);
|
||||
}
|
||||
if ($files === false) {
|
||||
$this->fail("couldn't list files");
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current directory for the FTP/SFTP connection
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function _directory()
|
||||
{
|
||||
if ($this->isSFTP()) {
|
||||
// == DIRECTORY_SEPARATOR ? '' : $pwd;
|
||||
$pwd = @$this->ftp->pwd();
|
||||
} else {
|
||||
$pwd = @ftp_pwd($this->ftp);
|
||||
}
|
||||
if (!$pwd) {
|
||||
$this->fail("couldn't get current directory");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the working directory on the FTP/SFTP server
|
||||
*
|
||||
* @param $path
|
||||
*/
|
||||
private function _changeDirectory($path)
|
||||
{
|
||||
if ($this->isSFTP()) {
|
||||
$changed = @$this->ftp->chdir($path);
|
||||
} else {
|
||||
$changed = @ftp_chdir($this->ftp, $path);
|
||||
}
|
||||
if (!$changed) {
|
||||
$this->fail("couldn't change directory {$path}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download remote file to local tmp directory and open contents.
|
||||
*
|
||||
* @param $filename
|
||||
*/
|
||||
private function _openFile($filename)
|
||||
{
|
||||
// Check local tmp directory
|
||||
if (!is_dir($this->config['tmp']) || !is_writeable($this->config['tmp'])) {
|
||||
$this->fail('tmp directory not found or is not writable');
|
||||
}
|
||||
|
||||
// Download file to local tmp directory
|
||||
$tmp_file = $this->config['tmp'] . "/ftp_data_file.tmp";
|
||||
|
||||
if ($this->isSFTP()) {
|
||||
$downloaded = @$this->ftp->get($filename, $tmp_file);
|
||||
} else {
|
||||
$downloaded = @ftp_get($this->ftp, $tmp_file, $filename, FTP_BINARY);
|
||||
}
|
||||
if (!$downloaded) {
|
||||
$this->fail('failed to download file to tmp directory');
|
||||
}
|
||||
|
||||
// Open file content to variable
|
||||
if ($this->file = file_get_contents($tmp_file)) {
|
||||
$this->filepath = $filename;
|
||||
} else {
|
||||
$this->fail('failed to open tmp file');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to local tmp file and upload to server
|
||||
*
|
||||
* @param $filename
|
||||
* @param $contents
|
||||
*/
|
||||
private function _writeToFile($filename, $contents)
|
||||
{
|
||||
// Check local tmp directory
|
||||
if (!is_dir($this->config['tmp']) || !is_writeable($this->config['tmp'])) {
|
||||
$this->fail('tmp directory not found or is not writable');
|
||||
}
|
||||
|
||||
// Build temp file
|
||||
$tmp_file = $this->config['tmp'] . "/ftp_data_file.tmp";
|
||||
file_put_contents($tmp_file, $contents);
|
||||
|
||||
// Update variables
|
||||
$this->filepath = $tmp_file;
|
||||
$this->file = $contents;
|
||||
|
||||
// Upload the file to server
|
||||
if ($this->isSFTP()) {
|
||||
$uploaded = @$this->ftp->put($filename, $tmp_file, NET_SFTP_LOCAL_FILE);
|
||||
} else {
|
||||
$uploaded = ftp_put($this->ftp, $filename, $tmp_file, FTP_BINARY);
|
||||
}
|
||||
if (!$uploaded) {
|
||||
$this->fail('failed to upload file to server');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make new directory on server
|
||||
*
|
||||
* @param $path
|
||||
*/
|
||||
private function makeDirectory($path)
|
||||
{
|
||||
if ($this->isSFTP()) {
|
||||
$created = @$this->ftp->mkdir($path, true);
|
||||
} else {
|
||||
$created = @ftp_mkdir($this->ftp, $path);
|
||||
}
|
||||
if (!$created) {
|
||||
$this->fail("couldn't make directory {$path}");
|
||||
}
|
||||
$this->debug("Make directory: {$path}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename/Move directory/file on server
|
||||
*
|
||||
* @param $path
|
||||
* @param $rename
|
||||
*/
|
||||
private function renameDirectory($path, $rename)
|
||||
{
|
||||
if ($this->isSFTP()) {
|
||||
$renamed = @$this->ftp->rename($path, $rename);
|
||||
} else {
|
||||
$renamed = @ftp_rename($this->ftp, $path, $rename);
|
||||
}
|
||||
if (!$renamed) {
|
||||
$this->fail("couldn't rename directory {$path} to {$rename}");
|
||||
}
|
||||
$this->debug("Renamed directory: {$path} to {$rename}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete file on server
|
||||
*
|
||||
* @param $filename
|
||||
*/
|
||||
private function delete($filename, $isDir = false)
|
||||
{
|
||||
if ($this->isSFTP()) {
|
||||
$deleted = @$this->ftp->delete($filename, $isDir);
|
||||
} else {
|
||||
$deleted = @$this->ftpDelete($filename);
|
||||
}
|
||||
if (!$deleted) {
|
||||
$this->fail("couldn't delete {$filename}");
|
||||
}
|
||||
$this->debug("Deleted: {$filename}");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to recursively delete folder, used for PHP FTP build in client.
|
||||
*
|
||||
* @param $directory
|
||||
* @return bool
|
||||
*/
|
||||
private function ftpDelete($directory)
|
||||
{
|
||||
// here we attempt to delete the file/directory
|
||||
if (!(@ftp_rmdir($this->ftp, $directory) || @ftp_delete($this->ftp, $directory))) {
|
||||
// if the attempt to delete fails, get the file listing
|
||||
$filelist = @ftp_nlist($this->ftp, $directory);
|
||||
|
||||
// loop through the file list and recursively delete the FILE in the list
|
||||
foreach ($filelist as $file) {
|
||||
$this->ftpDelete($file);
|
||||
}
|
||||
|
||||
// if the file list is empty, delete the DIRECTORY we passed
|
||||
$this->ftpDelete($directory);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear directory on server of all content
|
||||
*
|
||||
* @param $path
|
||||
*/
|
||||
private function clearDirectory($path)
|
||||
{
|
||||
$this->debug("Clear directory: {$path}");
|
||||
$this->delete($path);
|
||||
$this->makeDirectory($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of a given file
|
||||
*
|
||||
* @param $filename
|
||||
* @return bool
|
||||
*/
|
||||
private function size($filename)
|
||||
{
|
||||
if ($this->isSFTP()) {
|
||||
$size = (int)@$this->ftp->size($filename);
|
||||
} else {
|
||||
$size = @ftp_size($this->ftp, $filename);
|
||||
}
|
||||
if ($size > 0) {
|
||||
return $size;
|
||||
}
|
||||
$this->fail("couldn't get the file size for {$filename}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last modified time of a given file
|
||||
*
|
||||
* @param $filename
|
||||
* @return bool
|
||||
*/
|
||||
private function modified($filename)
|
||||
{
|
||||
if ($this->isSFTP()) {
|
||||
$info = @$this->ftp->lstat($filename);
|
||||
if ($info) {
|
||||
return $info['mtime'];
|
||||
}
|
||||
} else {
|
||||
if ($time = @ftp_mdtm($this->ftp, $filename)) {
|
||||
return $time;
|
||||
}
|
||||
}
|
||||
$this->fail("couldn't get the file size for {$filename}");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $user
|
||||
* @param $password
|
||||
*/
|
||||
protected function sftpConnect($user, $password)
|
||||
{
|
||||
$this->ftp = new \Net_SFTP($this->config['host'], $this->config['port'], $this->config['timeout']);
|
||||
if ($this->ftp === false) {
|
||||
$this->ftp = null;
|
||||
$this->fail('failed to connect to ftp server');
|
||||
}
|
||||
|
||||
if (isset($this->config['key'])) {
|
||||
$keyFile = file_get_contents($this->config['key']);
|
||||
$password = new \Crypt_RSA();
|
||||
$password->loadKey($keyFile);
|
||||
}
|
||||
|
||||
if (!$this->ftp->login($user, $password)) {
|
||||
$this->fail('failed to authenticate user');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $user
|
||||
* @param $password
|
||||
*/
|
||||
protected function ftpConnect($user, $password)
|
||||
{
|
||||
$this->ftp = ftp_connect($this->config['host'], $this->config['port'], $this->config['timeout']);
|
||||
if ($this->ftp === false) {
|
||||
$this->ftp = null;
|
||||
$this->fail('failed to connect to ftp server');
|
||||
}
|
||||
|
||||
// Login using given access details
|
||||
if (!@ftp_login($this->ftp, $user, $password)) {
|
||||
$this->fail('failed to authenticate user');
|
||||
}
|
||||
|
||||
// Set passive mode option (ftp only option)
|
||||
if (isset($this->config['passive'])) {
|
||||
ftp_pasv($this->ftp, $this->config['passive']);
|
||||
}
|
||||
}
|
||||
|
||||
protected function isSFTP()
|
||||
{
|
||||
return strtolower($this->config['type']) == 'sftp';
|
||||
}
|
||||
}
|
||||
325
vendor/codeception/base/src/Codeception/Module/Facebook.php
vendored
Normal file
325
vendor/codeception/base/src/Codeception/Module/Facebook.php
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Exception\ModuleException as ModuleException;
|
||||
use Codeception\Exception\ModuleConfigException as ModuleConfigException;
|
||||
use Codeception\Lib\Driver\Facebook as FacebookDriver;
|
||||
use Codeception\Lib\Interfaces\DependsOnModule;
|
||||
use Codeception\Lib\Interfaces\RequiresPackage;
|
||||
use Codeception\Lib\Notification;
|
||||
use Codeception\Module as BaseModule;
|
||||
|
||||
/**
|
||||
* Provides testing for projects integrated with Facebook API.
|
||||
* Relies on Facebook's tool Test User API.
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* To use this module with Composer you need <em>"facebook/php-sdk4": "5.*"</em> package.
|
||||
* </div>
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* [ ](https://codeship.com/projects/160201)
|
||||
*
|
||||
* * Stability: **beta**
|
||||
* * Maintainer: **tiger-seo**
|
||||
* * Contact: tiger.seo@codeception.com
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * app_id *required* - Facebook application ID
|
||||
* * secret *required* - Facebook application secret
|
||||
* * test_user - Facebook test user parameters:
|
||||
* * name - You can specify a name for the test user you create. The specified name will also be used in the email address assigned to the test user.
|
||||
* * locale - You can specify a locale for the test user you create, the default is en_US. The list of supported locales is available at https://www.facebook.com/translations/FacebookLocales.xml
|
||||
* * permissions - An array of permissions. Your app is granted these permissions for the new test user. The full list of permissions is available at https://developers.facebook.com/docs/authentication/permissions
|
||||
*
|
||||
* ### Config example
|
||||
*
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Facebook:
|
||||
* depends: PhpBrowser
|
||||
* app_id: 412345678901234
|
||||
* secret: ccb79c1b0fdff54e4f7c928bf233aea5
|
||||
* test_user:
|
||||
* name: FacebookGuy
|
||||
* locale: uk_UA
|
||||
* permissions: [email, publish_stream]
|
||||
*
|
||||
* ### Test example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I = new ApiGuy($scenario);
|
||||
* $I->am('Guest');
|
||||
* $I->wantToTest('check-in to a place be published on the Facebook using API');
|
||||
* $I->haveFacebookTestUserAccount();
|
||||
* $accessToken = $I->grabFacebookTestUserAccessToken();
|
||||
* $I->haveHttpHeader('Auth', 'FacebookToken ' . $accessToken);
|
||||
* $I->amGoingTo('send request to the backend, so that it will publish on user\'s wall on Facebook');
|
||||
* $I->sendPOST('/api/v1/some-api-endpoint');
|
||||
* $I->seePostOnFacebookWithAttachedPlace('167724369950862');
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I = new WebGuy($scenario);
|
||||
* $I->am('Guest');
|
||||
* $I->wantToTest('log in to site using Facebook');
|
||||
* $I->haveFacebookTestUserAccount(); // create facebook test user
|
||||
* $I->haveTestUserLoggedInOnFacebook(); // so that facebook will not ask us for login and password
|
||||
* $fbUserFirstName = $I->grabFacebookTestUserFirstName();
|
||||
* $I->amOnPage('/welcome');
|
||||
* $I->see('Welcome, Guest');
|
||||
* $I->click('Login with Facebook');
|
||||
* $I->see('Welcome, ' . $fbUserFirstName);
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* @since 1.6.3
|
||||
* @author tiger.seo@gmail.com
|
||||
*/
|
||||
class Facebook extends BaseModule implements DependsOnModule, RequiresPackage
|
||||
{
|
||||
protected $requiredFields = ['app_id', 'secret'];
|
||||
|
||||
/**
|
||||
* @var FacebookDriver
|
||||
*/
|
||||
protected $facebook;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $testUser = [];
|
||||
|
||||
/**
|
||||
* @var PhpBrowser
|
||||
*/
|
||||
protected $browserModule;
|
||||
|
||||
protected $dependencyMessage = <<<EOF
|
||||
Example configuring PhpBrowser
|
||||
--
|
||||
modules
|
||||
enabled:
|
||||
- Facebook:
|
||||
depends: PhpBrowser
|
||||
app_id: 412345678901234
|
||||
secret: ccb79c1b0fdff54e4f7c928bf233aea5
|
||||
test_user:
|
||||
name: FacebookGuy
|
||||
locale: uk_UA
|
||||
permissions: [email, publish_stream]
|
||||
EOF;
|
||||
|
||||
public function _requires()
|
||||
{
|
||||
return ['Facebook\Facebook' => '"facebook/graph-sdk": "~5.3"'];
|
||||
}
|
||||
|
||||
public function _depends()
|
||||
{
|
||||
return ['Codeception\Module\PhpBrowser' => $this->dependencyMessage];
|
||||
}
|
||||
|
||||
public function _inject(PhpBrowser $browserModule)
|
||||
{
|
||||
$this->browserModule = $browserModule;
|
||||
}
|
||||
|
||||
protected function deleteTestUser()
|
||||
{
|
||||
if (array_key_exists('id', $this->testUser)) {
|
||||
// make api-call for test user deletion
|
||||
$this->facebook->deleteTestUser($this->testUser['id']);
|
||||
$this->testUser = [];
|
||||
}
|
||||
}
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
Notification::deprecate('Facebook module is not maintained and will be deprecated. Contact Codeception team if you are interested in maintaining it');
|
||||
if (!array_key_exists('test_user', $this->config)) {
|
||||
$this->config['test_user'] = [
|
||||
'permissions' => [],
|
||||
'name' => 'Codeception Testuser'
|
||||
];
|
||||
} elseif (!array_key_exists('permissions', $this->config['test_user'])) {
|
||||
$this->config['test_user']['permissions'] = [];
|
||||
} elseif (!array_key_exists('name', $this->config['test_user'])) {
|
||||
$this->config['test_user']['name'] = "codeception testuser";
|
||||
}
|
||||
|
||||
$this->facebook = new FacebookDriver(
|
||||
[
|
||||
'app_id' => $this->config['app_id'],
|
||||
'secret' => $this->config['secret'],
|
||||
],
|
||||
function ($title, $message) {
|
||||
if (version_compare(PHP_VERSION, '5.4', '>=')) {
|
||||
$this->debugSection($title, $message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function _afterSuite()
|
||||
{
|
||||
$this->deleteTestUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get facebook test user be created.
|
||||
*
|
||||
* *Please, note that the test user is created only at first invoke, unless $renew arguments is true.*
|
||||
*
|
||||
* @param bool $renew true if the test user should be recreated
|
||||
*/
|
||||
public function haveFacebookTestUserAccount($renew = false)
|
||||
{
|
||||
if ($renew) {
|
||||
$this->deleteTestUser();
|
||||
}
|
||||
|
||||
// make api-call for test user creation only if it's not yet created
|
||||
if (!array_key_exists('id', $this->testUser)) {
|
||||
$this->testUser = $this->facebook->createTestUser(
|
||||
$this->config['test_user']['name'],
|
||||
$this->config['test_user']['permissions']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get facebook test user be logged in on facebook.
|
||||
* This is done by going to facebook.com
|
||||
*
|
||||
* @throws ModuleConfigException
|
||||
*/
|
||||
public function haveTestUserLoggedInOnFacebook()
|
||||
{
|
||||
if (!array_key_exists('id', $this->testUser)) {
|
||||
throw new ModuleException(
|
||||
__CLASS__,
|
||||
'Facebook test user was not found. Did you forget to create one?'
|
||||
);
|
||||
}
|
||||
|
||||
$callbackUrl = $this->browserModule->_getUrl();
|
||||
$this->browserModule->amOnUrl('https://facebook.com/login');
|
||||
$this->browserModule->submitForm('#login_form', [
|
||||
'email' => $this->grabFacebookTestUserEmail(),
|
||||
'pass' => $this->grabFacebookTestUserPassword()
|
||||
]);
|
||||
// if login in successful we are back on login screen:
|
||||
$this->browserModule->dontSeeInCurrentUrl('/login');
|
||||
$this->browserModule->amOnUrl($callbackUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the test user access token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function grabFacebookTestUserAccessToken()
|
||||
{
|
||||
return $this->testUser['access_token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the test user id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function grabFacebookTestUserId()
|
||||
{
|
||||
return $this->testUser['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the test user email.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function grabFacebookTestUserEmail()
|
||||
{
|
||||
return $this->testUser['email'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns URL for test user auto-login.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function grabFacebookTestUserLoginUrl()
|
||||
{
|
||||
return $this->testUser['login_url'];
|
||||
}
|
||||
|
||||
public function grabFacebookTestUserPassword()
|
||||
{
|
||||
return $this->testUser['password'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the test user name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function grabFacebookTestUserName()
|
||||
{
|
||||
if (!array_key_exists('profile', $this->testUser)) {
|
||||
$this->testUser['profile'] = $this->facebook->getTestUserInfo($this->grabFacebookTestUserAccessToken());
|
||||
}
|
||||
|
||||
return $this->testUser['profile']['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Please, note that you must have publish_actions permission to be able to publish to user's feed.
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
public function postToFacebookAsTestUser($params)
|
||||
{
|
||||
$this->facebook->sendPostToFacebook($this->grabFacebookTestUserAccessToken(), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Please, note that you must have publish_actions permission to be able to publish to user's feed.
|
||||
*
|
||||
* @param string $placeId Place identifier to be verified against user published posts
|
||||
*/
|
||||
public function seePostOnFacebookWithAttachedPlace($placeId)
|
||||
{
|
||||
$token = $this->grabFacebookTestUserAccessToken();
|
||||
$this->debugSection('Access Token', $token);
|
||||
$place = $this->facebook->getVisitedPlaceTagForTestUser($placeId, $token);
|
||||
$this->assertEquals($placeId, $place['id'], "The place was not found on facebook page");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Please, note that you must have publish_actions permission to be able to publish to user's feed.
|
||||
*
|
||||
* @param string $message published post to be verified against the actual post on facebook
|
||||
*/
|
||||
public function seePostOnFacebookWithMessage($message)
|
||||
{
|
||||
$posts = $this->facebook->getLastPostsForTestUser($this->grabFacebookTestUserAccessToken());
|
||||
$facebook_post_message = '';
|
||||
$this->assertNotEquals($message, $facebook_post_message, "You can not test for an empty message post");
|
||||
if ($posts['data']) {
|
||||
foreach ($posts['data'] as $post) {
|
||||
if (array_key_exists('message', $post) && ($post['message'] == $message)) {
|
||||
$facebook_post_message = $post['message'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->assertEquals($message, $facebook_post_message, "The post message was not found on facebook page");
|
||||
}
|
||||
}
|
||||
343
vendor/codeception/base/src/Codeception/Module/Filesystem.php
vendored
Normal file
343
vendor/codeception/base/src/Codeception/Module/Filesystem.php
vendored
Normal file
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Util\FileSystem as Util;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Configuration;
|
||||
|
||||
/**
|
||||
* Module for testing local filesystem.
|
||||
* Fork it to extend the module for FTP, Amazon S3, others.
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **davert**
|
||||
* * Stability: **stable**
|
||||
* * Contact: codecept@davert.mail.ua
|
||||
*
|
||||
* Module was developed to test Codeception itself.
|
||||
*/
|
||||
class Filesystem extends CodeceptionModule
|
||||
{
|
||||
protected $file = null;
|
||||
protected $filepath = null;
|
||||
|
||||
protected $path = '';
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->path = Configuration::projectDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters a directory In local filesystem.
|
||||
* Project root directory is used by default
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function amInPath($path)
|
||||
{
|
||||
chdir($this->path = $this->absolutizePath($path) . DIRECTORY_SEPARATOR);
|
||||
$this->debug('Moved to ' . getcwd());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
protected function absolutizePath($path)
|
||||
{
|
||||
// *nix way
|
||||
if (strpos($path, '/') === 0) {
|
||||
return $path;
|
||||
}
|
||||
// windows
|
||||
if (strpos($path, ':\\') === 1) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
return $this->path . $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file and stores it's content.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->openFile('composer.json');
|
||||
* $I->seeInThisFile('codeception/codeception');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $filename
|
||||
*/
|
||||
public function openFile($filename)
|
||||
{
|
||||
$this->file = file_get_contents($this->absolutizePath($filename));
|
||||
$this->filepath = $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->deleteFile('composer.lock');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $filename
|
||||
*/
|
||||
public function deleteFile($filename)
|
||||
{
|
||||
if (!file_exists($this->absolutizePath($filename))) {
|
||||
\PHPUnit\Framework\Assert::fail('file not found');
|
||||
}
|
||||
unlink($this->absolutizePath($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes directory with all subdirectories
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->deleteDir('vendor');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $dirname
|
||||
*/
|
||||
public function deleteDir($dirname)
|
||||
{
|
||||
$dir = $this->absolutizePath($dirname);
|
||||
Util::deleteDir($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies directory with all contents
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->copyDir('vendor','old_vendor');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $src
|
||||
* @param string $dst
|
||||
*/
|
||||
public function copyDir($src, $dst)
|
||||
{
|
||||
Util::copyDir($src, $dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks If opened file has `text` in it.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->openFile('composer.json');
|
||||
* $I->seeInThisFile('codeception/codeception');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $text
|
||||
*/
|
||||
public function seeInThisFile($text)
|
||||
{
|
||||
$this->assertContains($text, $this->file, "No text '$text' in currently opened file");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks If opened file has the `number` of new lines.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->openFile('composer.json');
|
||||
* $I->seeNumberNewLines(5);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param int $number New lines
|
||||
*/
|
||||
public function seeNumberNewLines($number)
|
||||
{
|
||||
$lines = preg_split('/\n|\r/', $this->file);
|
||||
|
||||
$this->assertTrue(
|
||||
(int) $number === count($lines),
|
||||
"The number of new lines does not match with $number"
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Checks that contents of currently opened file matches $regex
|
||||
*
|
||||
* @param string $regex
|
||||
*/
|
||||
public function seeThisFileMatches($regex)
|
||||
{
|
||||
$this->assertRegExp($regex, $this->file, "Contents of currently opened file does not match '$regex'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the strict matching of file contents.
|
||||
* Unlike `seeInThisFile` will fail if file has something more than expected lines.
|
||||
* Better to use with HEREDOC strings.
|
||||
* Matching is done after removing "\r" chars from file content.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->openFile('process.pid');
|
||||
* $I->seeFileContentsEqual('3192');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $text
|
||||
*/
|
||||
public function seeFileContentsEqual($text)
|
||||
{
|
||||
$file = str_replace("\r", '', $this->file);
|
||||
\PHPUnit\Framework\Assert::assertEquals($text, $file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks If opened file doesn't contain `text` in it
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->openFile('composer.json');
|
||||
* $I->dontSeeInThisFile('codeception/codeception');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $text
|
||||
*/
|
||||
public function dontSeeInThisFile($text)
|
||||
{
|
||||
$this->assertNotContains($text, $this->file, "Found text '$text' in currently opened file");
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file
|
||||
*/
|
||||
public function deleteThisFile()
|
||||
{
|
||||
$this->deleteFile($this->filepath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if file exists in path.
|
||||
* Opens a file when it's exists
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeFileFound('UserModel.php','app/models');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $path
|
||||
*/
|
||||
public function seeFileFound($filename, $path = '')
|
||||
{
|
||||
if ($path === '' && file_exists($filename)) {
|
||||
$this->openFile($filename);
|
||||
\PHPUnit\Framework\Assert::assertFileExists($filename);
|
||||
return;
|
||||
}
|
||||
|
||||
$found = $this->findFileInPath($filename, $path);
|
||||
|
||||
if ($found === false) {
|
||||
$this->fail("File \"$filename\" not found at \"$path\"");
|
||||
}
|
||||
|
||||
$this->openFile($found);
|
||||
\PHPUnit\Framework\Assert::assertFileExists($found);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if file does not exist in path
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $path
|
||||
*/
|
||||
public function dontSeeFileFound($filename, $path = '')
|
||||
{
|
||||
if ($path === '') {
|
||||
\PHPUnit\Framework\Assert::assertFileNotExists($filename);
|
||||
return;
|
||||
}
|
||||
|
||||
$found = $this->findFileInPath($filename, $path);
|
||||
|
||||
if ($found === false) {
|
||||
//this line keeps a count of assertions correct
|
||||
\PHPUnit\Framework\Assert::assertTrue(true);
|
||||
return;
|
||||
}
|
||||
|
||||
\PHPUnit\Framework\Assert::assertFileNotExists($found);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first matching file
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $path
|
||||
* @throws \PHPUnit\Framework\AssertionFailedError When path does not exist
|
||||
* @return string|false Path to the first matching file
|
||||
*/
|
||||
private function findFileInPath($filename, $path)
|
||||
{
|
||||
$path = $this->absolutizePath($path);
|
||||
if (!file_exists($path)) {
|
||||
$this->fail("Directory does not exist: $path");
|
||||
}
|
||||
|
||||
$files = Finder::create()->files()->name($filename)->in($path);
|
||||
if ($files->count() === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
return $file->getRealPath();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Erases directory contents
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->cleanDir('logs');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $dirname
|
||||
*/
|
||||
public function cleanDir($dirname)
|
||||
{
|
||||
$path = $this->absolutizePath($dirname);
|
||||
Util::doEmptyDir($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves contents to file
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $contents
|
||||
*/
|
||||
public function writeToFile($filename, $contents)
|
||||
{
|
||||
file_put_contents($filename, $contents);
|
||||
}
|
||||
}
|
||||
1246
vendor/codeception/base/src/Codeception/Module/Laravel5.php
vendored
Normal file
1246
vendor/codeception/base/src/Codeception/Module/Laravel5.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
575
vendor/codeception/base/src/Codeception/Module/Lumen.php
vendored
Normal file
575
vendor/codeception/base/src/Codeception/Module/Lumen.php
vendored
Normal file
@@ -0,0 +1,575 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Lib\Connector\Lumen as LumenConnector;
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\Lib\Interfaces\ActiveRecord;
|
||||
use Codeception\Lib\Interfaces\PartedModule;
|
||||
use Codeception\Lib\Shared\LaravelCommon;
|
||||
use Codeception\Lib\ModuleContainer;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Util\ReflectionHelper;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Database\Eloquent\Model as EloquentModel;
|
||||
|
||||
/**
|
||||
*
|
||||
* This module allows you to run functional tests for Lumen.
|
||||
* Please try it and leave your feedback.
|
||||
*
|
||||
* ## Demo project
|
||||
* <https://github.com/janhenkgerritsen/codeception-lumen-sample>
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **Jan-Henk Gerritsen**
|
||||
* * Stability: **dev**
|
||||
* * Contact: janhenkgerritsen@gmail.com
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * cleanup: `boolean`, default `true` - all database queries will be run in a transaction,
|
||||
* which will be rolled back at the end of each test.
|
||||
* * bootstrap: `string`, default `bootstrap/app.php` - relative path to app.php config file.
|
||||
* * root: `string`, default `` - root path of the application.
|
||||
* * packages: `string`, default `workbench` - root path of application packages (if any).
|
||||
* * url: `string`, default `http://localhost` - the application URL
|
||||
*
|
||||
* ## API
|
||||
*
|
||||
* * app - `\Laravel\Lumen\Application`
|
||||
* * config - `array`
|
||||
*
|
||||
* ## Parts
|
||||
*
|
||||
* * ORM - only include the database methods of this module:
|
||||
* * have
|
||||
* * haveMultiple
|
||||
* * haveRecord
|
||||
* * grabRecord
|
||||
* * seeRecord
|
||||
* * dontSeeRecord
|
||||
*/
|
||||
class Lumen extends Framework implements ActiveRecord, PartedModule
|
||||
{
|
||||
use LaravelCommon;
|
||||
|
||||
/**
|
||||
* @var \Laravel\Lumen\Application
|
||||
*/
|
||||
public $app;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $config = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ModuleContainer $container
|
||||
* @param array|null $config
|
||||
*/
|
||||
public function __construct(ModuleContainer $container, $config = null)
|
||||
{
|
||||
$this->config = array_merge(
|
||||
[
|
||||
'cleanup' => true,
|
||||
'bootstrap' => 'bootstrap' . DIRECTORY_SEPARATOR . 'app.php',
|
||||
'root' => '',
|
||||
'packages' => 'workbench',
|
||||
'url' => 'http://localhost',
|
||||
],
|
||||
(array)$config
|
||||
);
|
||||
|
||||
$projectDir = explode($this->config['packages'], Configuration::projectDir())[0];
|
||||
$projectDir .= $this->config['root'];
|
||||
|
||||
$this->config['project_dir'] = $projectDir;
|
||||
$this->config['bootstrap_file'] = $projectDir . $this->config['bootstrap'];
|
||||
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function _parts()
|
||||
{
|
||||
return ['orm'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize hook.
|
||||
*/
|
||||
public function _initialize()
|
||||
{
|
||||
$this->checkBootstrapFileExists();
|
||||
$this->registerAutoloaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* Before hook.
|
||||
*
|
||||
* @param \Codeception\TestInterface $test
|
||||
* @throws ModuleConfigException
|
||||
*/
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->client = new LumenConnector($this);
|
||||
|
||||
if ($this->app['db'] && $this->config['cleanup']) {
|
||||
$this->app['db']->beginTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After hook.
|
||||
*
|
||||
* @param \Codeception\TestInterface $test
|
||||
*/
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
if ($this->app['db'] && $this->config['cleanup']) {
|
||||
$this->app['db']->rollback();
|
||||
}
|
||||
|
||||
// disconnect from DB to prevent "Too many connections" issue
|
||||
if ($this->app['db']) {
|
||||
$this->app['db']->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the Lumen bootstrap file exists.
|
||||
*
|
||||
* @throws ModuleConfigException
|
||||
*/
|
||||
protected function checkBootstrapFileExists()
|
||||
{
|
||||
$bootstrapFile = $this->config['bootstrap_file'];
|
||||
|
||||
if (!file_exists($bootstrapFile)) {
|
||||
throw new ModuleConfigException(
|
||||
$this,
|
||||
"Lumen bootstrap file not found in $bootstrapFile.\n"
|
||||
. "Please provide a valid path using the 'bootstrap' config param. "
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register autoloaders.
|
||||
*/
|
||||
protected function registerAutoloaders()
|
||||
{
|
||||
require $this->config['project_dir'] . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access the Lumen application object.
|
||||
*
|
||||
* @return \Laravel\Lumen\Application
|
||||
*/
|
||||
public function getApplication()
|
||||
{
|
||||
return $this->app;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Laravel\Lumen\Application $app
|
||||
*/
|
||||
public function setApplication($app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens web page using route name and parameters.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->amOnRoute('homepage');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $routeName
|
||||
* @param array $params
|
||||
*/
|
||||
public function amOnRoute($routeName, $params = [])
|
||||
{
|
||||
$route = $this->getRouteByName($routeName);
|
||||
|
||||
if (!$route) {
|
||||
$this->fail("Could not find route with name '$routeName'");
|
||||
}
|
||||
|
||||
$url = $this->generateUrlForRoute($route, $params);
|
||||
$this->amOnPage($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the route for a route name.
|
||||
*
|
||||
* @param string $routeName
|
||||
* @return array|null
|
||||
*/
|
||||
private function getRouteByName($routeName)
|
||||
{
|
||||
foreach ($this->app->getRoutes() as $route) {
|
||||
if ($route['method'] != 'GET') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($route['action']['as']) && $route['action']['as'] == $routeName) {
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the URL for a route specification.
|
||||
* Replaces the route parameters from left to right with the parameters
|
||||
* passed in the $params array.
|
||||
*
|
||||
* @param array $route
|
||||
* @param array $params
|
||||
* @return string
|
||||
*/
|
||||
private function generateUrlForRoute($route, $params)
|
||||
{
|
||||
$url = $route['uri'];
|
||||
|
||||
while (count($params) > 0) {
|
||||
$param = array_shift($params);
|
||||
$url = preg_replace('/{.+?}/', $param, $url, 1);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the authenticated user for the next request.
|
||||
* This will not persist between multiple requests.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable
|
||||
* @param string|null $driver The authentication driver for Lumen <= 5.1.*, guard name for Lumen >= 5.2
|
||||
* @return void
|
||||
*/
|
||||
public function amLoggedAs($user, $driver = null)
|
||||
{
|
||||
if (!$user instanceof Authenticatable) {
|
||||
$this->fail(
|
||||
'The user passed to amLoggedAs() should be an instance of \\Illuminate\\Contracts\\Auth\\Authenticatable'
|
||||
);
|
||||
}
|
||||
|
||||
$guard = $auth = $this->app['auth'];
|
||||
|
||||
if (method_exists($auth, 'driver')) {
|
||||
$guard = $auth->driver($driver);
|
||||
}
|
||||
|
||||
if (method_exists($auth, 'guard')) {
|
||||
$guard = $auth->guard($driver);
|
||||
}
|
||||
|
||||
$guard->setUser($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that user is authenticated.
|
||||
*/
|
||||
public function seeAuthentication()
|
||||
{
|
||||
$this->assertTrue($this->app['auth']->check(), 'User is not logged in');
|
||||
}
|
||||
/**
|
||||
* Check that user is not authenticated.
|
||||
*/
|
||||
public function dontSeeAuthentication()
|
||||
{
|
||||
$this->assertFalse($this->app['auth']->check(), 'User is logged in');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of a class from the IoC Container.
|
||||
*
|
||||
* Example
|
||||
* ``` php
|
||||
* <?php
|
||||
* // In Lumen
|
||||
* App::bind('foo', function($app)
|
||||
* {
|
||||
* return new FooBar;
|
||||
* });
|
||||
*
|
||||
* // Then in test
|
||||
* $service = $I->grabService('foo');
|
||||
*
|
||||
* // Will return an instance of FooBar, also works for singletons.
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $class
|
||||
* @return mixed
|
||||
*/
|
||||
public function grabService($class)
|
||||
{
|
||||
return $this->app[$class];
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts record into the database.
|
||||
* If you pass the name of a database table as the first argument, this method returns an integer ID.
|
||||
* You can also pass the class name of an Eloquent model, in that case this method returns an Eloquent model.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $user_id = $I->haveRecord('users', array('name' => 'Davert')); // returns integer
|
||||
* $user = $I->haveRecord('App\User', array('name' => 'Davert')); // returns Eloquent model
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $attributes
|
||||
* @return integer|EloquentModel
|
||||
* @part orm
|
||||
*/
|
||||
public function haveRecord($table, $attributes = [])
|
||||
{
|
||||
if (class_exists($table)) {
|
||||
$model = new $table;
|
||||
|
||||
if (!$model instanceof EloquentModel) {
|
||||
throw new \RuntimeException("Class $table is not an Eloquent model");
|
||||
}
|
||||
|
||||
$model->fill($attributes)->save();
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->app['db']->table($table)->insertGetId($attributes);
|
||||
} catch (\Exception $e) {
|
||||
$this->fail("Could not insert record into table '$table':\n\n" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that record exists in database.
|
||||
* You can pass the name of a database table or the class name of an Eloquent model as the first argument.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeRecord('users', array('name' => 'davert'));
|
||||
* $I->seeRecord('App\User', array('name' => 'davert'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $attributes
|
||||
* @part orm
|
||||
*/
|
||||
public function seeRecord($table, $attributes = [])
|
||||
{
|
||||
if (class_exists($table)) {
|
||||
if (!$this->findModel($table, $attributes)) {
|
||||
$this->fail("Could not find $table with " . json_encode($attributes));
|
||||
}
|
||||
} elseif (!$this->findRecord($table, $attributes)) {
|
||||
$this->fail("Could not find matching record in table '$table'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that record does not exist in database.
|
||||
* You can pass the name of a database table or the class name of an Eloquent model as the first argument.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeRecord('users', array('name' => 'davert'));
|
||||
* $I->dontSeeRecord('App\User', array('name' => 'davert'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $attributes
|
||||
* @part orm
|
||||
*/
|
||||
public function dontSeeRecord($table, $attributes = [])
|
||||
{
|
||||
if (class_exists($table)) {
|
||||
if ($this->findModel($table, $attributes)) {
|
||||
$this->fail("Unexpectedly found matching $table with " . json_encode($attributes));
|
||||
}
|
||||
} elseif ($this->findRecord($table, $attributes)) {
|
||||
$this->fail("Unexpectedly found matching record in table '$table'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves record from database
|
||||
* If you pass the name of a database table as the first argument, this method returns an array.
|
||||
* You can also pass the class name of an Eloquent model, in that case this method returns an Eloquent model.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $record = $I->grabRecord('users', array('name' => 'davert')); // returns array
|
||||
* $record = $I->grabRecord('App\User', array('name' => 'davert')); // returns Eloquent model
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $attributes
|
||||
* @return array|EloquentModel
|
||||
* @part orm
|
||||
*/
|
||||
public function grabRecord($table, $attributes = [])
|
||||
{
|
||||
if (class_exists($table)) {
|
||||
if (!$model = $this->findModel($table, $attributes)) {
|
||||
$this->fail("Could not find $table with " . json_encode($attributes));
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
if (!$record = $this->findRecord($table, $attributes)) {
|
||||
$this->fail("Could not find matching record in table '$table'");
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $modelClass
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return EloquentModel
|
||||
*/
|
||||
protected function findModel($modelClass, $attributes = [])
|
||||
{
|
||||
$model = new $modelClass;
|
||||
|
||||
if (!$model instanceof EloquentModel) {
|
||||
throw new \RuntimeException("Class $modelClass is not an Eloquent model");
|
||||
}
|
||||
|
||||
$query = $model->newQuery();
|
||||
foreach ($attributes as $key => $value) {
|
||||
$query->where($key, $value);
|
||||
}
|
||||
|
||||
return $query->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param array $attributes
|
||||
* @return array
|
||||
*/
|
||||
protected function findRecord($table, $attributes = [])
|
||||
{
|
||||
$query = $this->app['db']->table($table);
|
||||
foreach ($attributes as $key => $value) {
|
||||
$query->where($key, $value);
|
||||
}
|
||||
|
||||
return (array)$query->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use Lumen's model factory to create a model.
|
||||
* Can only be used with Lumen 5.1 and later.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->have('App\User');
|
||||
* $I->have('App\User', ['name' => 'John Doe']);
|
||||
* $I->have('App\User', [], 'admin');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @see https://lumen.laravel.com/docs/master/testing#model-factories
|
||||
* @param string $model
|
||||
* @param array $attributes
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @part orm
|
||||
*/
|
||||
public function have($model, $attributes = [], $name = 'default')
|
||||
{
|
||||
try {
|
||||
return $this->modelFactory($model, $name)->create($attributes);
|
||||
} catch (\Exception $e) {
|
||||
$this->fail("Could not create model: \n\n" . get_class($e) . "\n\n" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use Laravel's model factory to create multiple models.
|
||||
* Can only be used with Lumen 5.1 and later.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->haveMultiple('App\User', 10);
|
||||
* $I->haveMultiple('App\User', 10, ['name' => 'John Doe']);
|
||||
* $I->haveMultiple('App\User', 10, [], 'admin');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @see https://lumen.laravel.com/docs/master/testing#model-factories
|
||||
* @param string $model
|
||||
* @param int $times
|
||||
* @param array $attributes
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @part orm
|
||||
*/
|
||||
public function haveMultiple($model, $times, $attributes = [], $name = 'default')
|
||||
{
|
||||
try {
|
||||
return $this->modelFactory($model, $name, $times)->create($attributes);
|
||||
} catch (\Exception $e) {
|
||||
$this->fail("Could not create model: \n\n" . get_class($e) . "\n\n" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $model
|
||||
* @param string $name
|
||||
* @param int $times
|
||||
* @return \Illuminate\Database\Eloquent\FactoryBuilder
|
||||
* @throws ModuleException
|
||||
*/
|
||||
protected function modelFactory($model, $name, $times = 1)
|
||||
{
|
||||
if (!function_exists('factory')) {
|
||||
throw new ModuleException($this, 'The factory() method does not exist. ' .
|
||||
'This functionality relies on Lumen model factories, which were introduced in Lumen 5.1.');
|
||||
}
|
||||
|
||||
return factory($model, $name, $times);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of recognized domain names.
|
||||
* This elements of this list are regular expressions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getInternalDomains()
|
||||
{
|
||||
$server = ReflectionHelper::readPrivateProperty($this->client, 'server');
|
||||
|
||||
return ['/^' . str_replace('.', '\.', $server['HTTP_HOST']) . '$/'];
|
||||
}
|
||||
}
|
||||
206
vendor/codeception/base/src/Codeception/Module/Memcache.php
vendored
Normal file
206
vendor/codeception/base/src/Codeception/Module/Memcache.php
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
|
||||
/**
|
||||
* Connects to [memcached](http://www.memcached.org/) using either _Memcache_ or _Memcached_ extension.
|
||||
*
|
||||
* Performs a cleanup by flushing all values after each test run.
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **davert**
|
||||
* * Stability: **beta**
|
||||
* * Contact: davert@codeception.com
|
||||
*
|
||||
* ## Configuration
|
||||
*
|
||||
* * **`host`** (`string`, default `'localhost'`) - The memcached host
|
||||
* * **`port`** (`int`, default `11211`) - The memcached port
|
||||
*
|
||||
* ### Example (`unit.suite.yml`)
|
||||
*
|
||||
* ```yaml
|
||||
* modules:
|
||||
* - Memcache:
|
||||
* host: 'localhost'
|
||||
* port: 11211
|
||||
* ```
|
||||
*
|
||||
* Be sure you don't use the production server to connect.
|
||||
*
|
||||
* ## Public Properties
|
||||
*
|
||||
* * **memcache** - instance of _Memcache_ or _Memcached_ object
|
||||
*
|
||||
*/
|
||||
class Memcache extends CodeceptionModule
|
||||
{
|
||||
/**
|
||||
* @var \Memcache|\Memcached
|
||||
*/
|
||||
public $memcache = null;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $config = [
|
||||
'host' => 'localhost',
|
||||
'port' => 11211
|
||||
];
|
||||
|
||||
/**
|
||||
* Code to run before each test.
|
||||
*
|
||||
* @param TestInterface $test
|
||||
* @throws ModuleConfigException
|
||||
*/
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
if (class_exists('\Memcache')) {
|
||||
$this->memcache = new \Memcache;
|
||||
$this->memcache->connect($this->config['host'], $this->config['port']);
|
||||
} elseif (class_exists('\Memcached')) {
|
||||
$this->memcache = new \Memcached;
|
||||
$this->memcache->addServer($this->config['host'], $this->config['port']);
|
||||
} else {
|
||||
throw new ModuleConfigException(__CLASS__, 'Memcache classes not loaded');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Code to run after each test.
|
||||
*
|
||||
* @param TestInterface $test
|
||||
*/
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
if (empty($this->memcache)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->memcache->flush();
|
||||
switch (get_class($this->memcache)) {
|
||||
case 'Memcache':
|
||||
$this->memcache->close();
|
||||
break;
|
||||
case 'Memcached':
|
||||
$this->memcache->quit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs value from memcached by key.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $users_count = $I->grabValueFromMemcached('users_count');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $key
|
||||
* @return array|string
|
||||
*/
|
||||
public function grabValueFromMemcached($key)
|
||||
{
|
||||
$value = $this->memcache->get($key);
|
||||
$this->debugSection("Value", $value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks item in Memcached exists and the same as expected.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // With only one argument, only checks the key exists
|
||||
* $I->seeInMemcached('users_count');
|
||||
*
|
||||
* // Checks a 'users_count' exists and has the value 200
|
||||
* $I->seeInMemcached('users_count', 200);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $key
|
||||
* @param $value
|
||||
*/
|
||||
public function seeInMemcached($key, $value = null)
|
||||
{
|
||||
$actual = $this->memcache->get($key);
|
||||
$this->debugSection("Value", $actual);
|
||||
|
||||
if (null === $value) {
|
||||
$this->assertNotFalse($actual, "Cannot find key '$key' in Memcached");
|
||||
} else {
|
||||
$this->assertEquals($value, $actual, "Cannot find key '$key' in Memcached with the provided value");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks item in Memcached doesn't exist or is the same as expected.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // With only one argument, only checks the key does not exist
|
||||
* $I->dontSeeInMemcached('users_count');
|
||||
*
|
||||
* // Checks a 'users_count' exists does not exist or its value is not the one provided
|
||||
* $I->dontSeeInMemcached('users_count', 200);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $key
|
||||
* @param $value
|
||||
*/
|
||||
public function dontSeeInMemcached($key, $value = null)
|
||||
{
|
||||
$actual = $this->memcache->get($key);
|
||||
$this->debugSection("Value", $actual);
|
||||
|
||||
if (null === $value) {
|
||||
$this->assertFalse($actual, "The key '$key' exists in Memcached");
|
||||
} else {
|
||||
if (false !== $actual) {
|
||||
$this->assertEquals($value, $actual, "The key '$key' exists in Memcached with the provided value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores an item `$value` with `$key` on the Memcached server.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $expiration
|
||||
*/
|
||||
public function haveInMemcached($key, $value, $expiration = null)
|
||||
{
|
||||
switch (get_class($this->memcache)) {
|
||||
case 'Memcache':
|
||||
$this->assertTrue($this->memcache->set($key, $value, null, $expiration));
|
||||
break;
|
||||
case 'Memcached':
|
||||
$this->assertTrue($this->memcache->set($key, $value, $expiration));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes all Memcached data.
|
||||
*/
|
||||
public function clearMemcache()
|
||||
{
|
||||
$this->memcache->flush();
|
||||
}
|
||||
}
|
||||
441
vendor/codeception/base/src/Codeception/Module/MongoDb.php
vendored
Normal file
441
vendor/codeception/base/src/Codeception/Module/MongoDb.php
vendored
Normal file
@@ -0,0 +1,441 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Lib\Interfaces\RequiresPackage;
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\Configuration as Configuration;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Lib\Driver\MongoDb as MongoDbDriver;
|
||||
use Codeception\TestInterface;
|
||||
|
||||
/**
|
||||
* Works with MongoDb database.
|
||||
*
|
||||
* The most important function of this module is cleaning database before each test.
|
||||
* To have your database properly cleaned you should configure it to access the database.
|
||||
*
|
||||
* In order to have your database populated with data you need a valid js file with data (of the same style which can be fed up to mongo binary)
|
||||
* File can be generated by RockMongo export command
|
||||
* You can also use directory, generated by ```mongodump``` tool or it's ```.tar.gz``` archive (not available for Windows systems), generated by ```tar -czf <archive_file_name>.tar.gz <path_to dump directory>```.
|
||||
* Just put it in ``` tests/_data ``` dir (by default) and specify path to it in config.
|
||||
* Next time after database is cleared all your data will be restored from dump.
|
||||
* The DB preparation should as following:
|
||||
* - clean database
|
||||
* - system collection system.users should contain the user which will be authenticated while script performs DB operations
|
||||
*
|
||||
* Connection is done by MongoDb driver, which is stored in Codeception\Lib\Driver namespace.
|
||||
* Check out the driver if you get problems loading dumps and cleaning databases.
|
||||
*
|
||||
* HINT: This module can be used with [Mongofill](https://github.com/mongofill/mongofill) library which is Mongo client written in PHP without extension.
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **judgedim**, **davert**
|
||||
* * Stability: **beta**
|
||||
* * Contact: davert@codeception.com
|
||||
*
|
||||
* *Please review the code of non-stable modules and provide patches if you have issues.*
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * dsn *required* - MongoDb DSN with the db name specified at the end of the host after slash
|
||||
* * user *required* - user to access database
|
||||
* * password *required* - password
|
||||
* * dump_type *required* - type of dump.
|
||||
* One of 'js' (MongoDb::DUMP_TYPE_JS), 'mongodump' (MongoDb::DUMP_TYPE_MONGODUMP) or 'mongodump-tar-gz' (MongoDb::DUMP_TYPE_MONGODUMP_TAR_GZ).
|
||||
* default: MongoDb::DUMP_TYPE_JS).
|
||||
* * dump - path to database dump
|
||||
* * populate: true - should the dump be loaded before test suite is started.
|
||||
* * cleanup: true - should the dump be reloaded after each test
|
||||
*
|
||||
*/
|
||||
class MongoDb extends CodeceptionModule implements RequiresPackage
|
||||
{
|
||||
const DUMP_TYPE_JS = 'js';
|
||||
const DUMP_TYPE_MONGODUMP = 'mongodump';
|
||||
const DUMP_TYPE_MONGODUMP_TAR_GZ = 'mongodump-tar-gz';
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @var
|
||||
*/
|
||||
public $dbh;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
|
||||
protected $dumpFile;
|
||||
protected $isDumpFileEmpty = true;
|
||||
|
||||
protected $config = [
|
||||
'populate' => true,
|
||||
'cleanup' => true,
|
||||
'dump' => null,
|
||||
'dump_type' => self::DUMP_TYPE_JS,
|
||||
'user' => null,
|
||||
'password' => null,
|
||||
'quiet' => false,
|
||||
];
|
||||
|
||||
protected $populated = false;
|
||||
|
||||
/**
|
||||
* @var \Codeception\Lib\Driver\MongoDb
|
||||
*/
|
||||
public $driver;
|
||||
|
||||
protected $requiredFields = ['dsn'];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
|
||||
try {
|
||||
$this->driver = MongoDbDriver::create(
|
||||
$this->config['dsn'],
|
||||
$this->config['user'],
|
||||
$this->config['password']
|
||||
);
|
||||
} catch (\MongoConnectionException $e) {
|
||||
throw new ModuleException(__CLASS__, $e->getMessage() . ' while creating Mongo connection');
|
||||
}
|
||||
|
||||
// starting with loading dump
|
||||
if ($this->config['populate']) {
|
||||
$this->cleanup();
|
||||
$this->loadDump();
|
||||
$this->populated = true;
|
||||
}
|
||||
}
|
||||
|
||||
private function validateDump()
|
||||
{
|
||||
if ($this->config['dump'] && ($this->config['cleanup'] or ($this->config['populate']))) {
|
||||
if (!file_exists(Configuration::projectDir() . $this->config['dump'])) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"File with dump doesn't exist.\n
|
||||
Please, check path for dump file: " . $this->config['dump']
|
||||
);
|
||||
}
|
||||
$this->dumpFile = Configuration::projectDir() . $this->config['dump'];
|
||||
$this->isDumpFileEmpty = false;
|
||||
|
||||
if ($this->config['dump_type'] === self::DUMP_TYPE_JS) {
|
||||
$content = file_get_contents($this->dumpFile);
|
||||
$content = trim(preg_replace('%/\*(?:(?!\*/).)*\*/%s', "", $content));
|
||||
if (!sizeof(explode("\n", $content))) {
|
||||
$this->isDumpFileEmpty = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->config['dump_type'] === self::DUMP_TYPE_MONGODUMP) {
|
||||
if (!is_dir($this->dumpFile)) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"Dump must be a directory.\n
|
||||
Please, check dump: " . $this->config['dump']
|
||||
);
|
||||
}
|
||||
$this->isDumpFileEmpty = true;
|
||||
$dumpDir = dir($this->dumpFile);
|
||||
while (false !== ($entry = $dumpDir->read())) {
|
||||
if ($entry !== '..' && $entry !== '.') {
|
||||
$this->isDumpFileEmpty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$dumpDir->close();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->config['dump_type'] === self::DUMP_TYPE_MONGODUMP_TAR_GZ) {
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"Tar gunzip archives are not supported for Windows systems"
|
||||
);
|
||||
}
|
||||
if (!preg_match('/(\.tar\.gz|\.tgz)$/', $this->dumpFile)) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"Dump file must be a valid tar gunzip archive.\n
|
||||
Please, check dump file: " . $this->config['dump']
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
'\"dump_type\" must be one of ["'
|
||||
. self::DUMP_TYPE_JS . '", "'
|
||||
. self::DUMP_TYPE_MONGODUMP . '", "'
|
||||
. self::DUMP_TYPE_MONGODUMP_TAR_GZ . '"].'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
if ($this->config['cleanup'] && !$this->populated) {
|
||||
$this->cleanup();
|
||||
$this->loadDump();
|
||||
}
|
||||
}
|
||||
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
$this->populated = false;
|
||||
}
|
||||
|
||||
protected function cleanup()
|
||||
{
|
||||
$dbh = $this->driver->getDbh();
|
||||
if (!$dbh) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"No connection to database. Remove this module from config if you don't need database repopulation"
|
||||
);
|
||||
}
|
||||
try {
|
||||
$this->driver->cleanup();
|
||||
} catch (\Exception $e) {
|
||||
throw new ModuleException(__CLASS__, $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadDump()
|
||||
{
|
||||
$this->validateDump();
|
||||
|
||||
if ($this->isDumpFileEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->config['dump_type'] === self::DUMP_TYPE_JS) {
|
||||
$this->driver->load($this->dumpFile);
|
||||
}
|
||||
if ($this->config['dump_type'] === self::DUMP_TYPE_MONGODUMP) {
|
||||
$this->driver->setQuiet($this->config['quiet']);
|
||||
$this->driver->loadFromMongoDump($this->dumpFile);
|
||||
}
|
||||
if ($this->config['dump_type'] === self::DUMP_TYPE_MONGODUMP_TAR_GZ) {
|
||||
$this->driver->setQuiet($this->config['quiet']);
|
||||
$this->driver->loadFromTarGzMongoDump($this->dumpFile);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new ModuleException(__CLASS__, $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the database to use
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->useDatabase('db_1');
|
||||
* ```
|
||||
*
|
||||
* @param $dbName
|
||||
*/
|
||||
public function useDatabase($dbName)
|
||||
{
|
||||
$this->driver->setDatabase($dbName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts data into collection
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->haveInCollection('users', array('name' => 'John', 'email' => 'john@coltrane.com'));
|
||||
* $user_id = $I->haveInCollection('users', array('email' => 'john@coltrane.com'));
|
||||
* ```
|
||||
*
|
||||
* @param $collection
|
||||
* @param array $data
|
||||
*/
|
||||
public function haveInCollection($collection, array $data)
|
||||
{
|
||||
$collection = $this->driver->getDbh()->selectCollection($collection);
|
||||
if ($this->driver->isLegacy()) {
|
||||
$collection->insert($data);
|
||||
return $data['_id'];
|
||||
}
|
||||
|
||||
$response = $collection->insertOne($data);
|
||||
return (string) $response->getInsertedId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if collection contains an item.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeInCollection('users', array('name' => 'miles'));
|
||||
* ```
|
||||
*
|
||||
* @param $collection
|
||||
* @param array $criteria
|
||||
*/
|
||||
public function seeInCollection($collection, $criteria = [])
|
||||
{
|
||||
$collection = $this->driver->getDbh()->selectCollection($collection);
|
||||
$res = $collection->count($criteria);
|
||||
\PHPUnit\Framework\Assert::assertGreaterThan(0, $res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if collection doesn't contain an item.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeInCollection('users', array('name' => 'miles'));
|
||||
* ```
|
||||
*
|
||||
* @param $collection
|
||||
* @param array $criteria
|
||||
*/
|
||||
public function dontSeeInCollection($collection, $criteria = [])
|
||||
{
|
||||
$collection = $this->driver->getDbh()->selectCollection($collection);
|
||||
$res = $collection->count($criteria);
|
||||
\PHPUnit\Framework\Assert::assertLessThan(1, $res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs a data from collection
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $user = $I->grabFromCollection('users', array('name' => 'miles'));
|
||||
* ```
|
||||
*
|
||||
* @param $collection
|
||||
* @param array $criteria
|
||||
* @return array
|
||||
*/
|
||||
public function grabFromCollection($collection, $criteria = [])
|
||||
{
|
||||
$collection = $this->driver->getDbh()->selectCollection($collection);
|
||||
return $collection->findOne($criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs the documents count from a collection
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $count = $I->grabCollectionCount('users');
|
||||
* // or
|
||||
* $count = $I->grabCollectionCount('users', array('isAdmin' => true));
|
||||
* ```
|
||||
*
|
||||
* @param $collection
|
||||
* @param array $criteria
|
||||
* @return integer
|
||||
*/
|
||||
public function grabCollectionCount($collection, $criteria = [])
|
||||
{
|
||||
$collection = $this->driver->getDbh()->selectCollection($collection);
|
||||
return $collection->count($criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that an element in a collection exists and is an Array
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeElementIsArray('users', array('name' => 'John Doe') , 'data.skills');
|
||||
* ```
|
||||
*
|
||||
* @param String $collection
|
||||
* @param Array $criteria
|
||||
* @param String $elementToCheck
|
||||
*/
|
||||
public function seeElementIsArray($collection, $criteria = [], $elementToCheck = null)
|
||||
{
|
||||
$collection = $this->driver->getDbh()->selectCollection($collection);
|
||||
|
||||
$res = $collection->count(
|
||||
array_merge(
|
||||
$criteria,
|
||||
[
|
||||
$elementToCheck => ['$exists' => true],
|
||||
'$where' => "Array.isArray(this.{$elementToCheck})"
|
||||
]
|
||||
)
|
||||
);
|
||||
if ($res > 1) {
|
||||
throw new \PHPUnit\Framework\ExpectationFailedException(
|
||||
'Error: you should test against a single element criteria when asserting that elementIsArray'
|
||||
);
|
||||
}
|
||||
\PHPUnit\Framework\Assert::assertEquals(1, $res, 'Specified element is not a Mongo Object');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that an element in a collection exists and is an Object
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeElementIsObject('users', array('name' => 'John Doe') , 'data');
|
||||
* ```
|
||||
*
|
||||
* @param String $collection
|
||||
* @param Array $criteria
|
||||
* @param String $elementToCheck
|
||||
*/
|
||||
public function seeElementIsObject($collection, $criteria = [], $elementToCheck = null)
|
||||
{
|
||||
$collection = $this->driver->getDbh()->selectCollection($collection);
|
||||
|
||||
$res = $collection->count(
|
||||
array_merge(
|
||||
$criteria,
|
||||
[
|
||||
$elementToCheck => ['$exists' => true],
|
||||
'$where' => "! Array.isArray(this.{$elementToCheck}) && isObject(this.{$elementToCheck})"
|
||||
]
|
||||
)
|
||||
);
|
||||
if ($res > 1) {
|
||||
throw new \PHPUnit\Framework\ExpectationFailedException(
|
||||
'Error: you should test against a single element criteria when asserting that elementIsObject'
|
||||
);
|
||||
}
|
||||
\PHPUnit\Framework\Assert::assertEquals(1, $res, 'Specified element is not a Mongo Object');
|
||||
}
|
||||
|
||||
/**
|
||||
* Count number of records in a collection
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeNumElementsInCollection('users', 2);
|
||||
* $I->seeNumElementsInCollection('users', 1, array('name' => 'miles'));
|
||||
* ```
|
||||
*
|
||||
* @param $collection
|
||||
* @param integer $expected
|
||||
* @param array $criteria
|
||||
*/
|
||||
public function seeNumElementsInCollection($collection, $expected, $criteria = [])
|
||||
{
|
||||
$collection = $this->driver->getDbh()->selectCollection($collection);
|
||||
$res = $collection->count($criteria);
|
||||
\PHPUnit\Framework\Assert::assertSame($expected, $res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of classes and corresponding packages required for this module
|
||||
*/
|
||||
public function _requires()
|
||||
{
|
||||
return ['MongoDB\Client' => '"mongodb/mongodb": "^1.0"'];
|
||||
}
|
||||
}
|
||||
662
vendor/codeception/base/src/Codeception/Module/Phalcon.php
vendored
Normal file
662
vendor/codeception/base/src/Codeception/Module/Phalcon.php
vendored
Normal file
@@ -0,0 +1,662 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Phalcon\Di;
|
||||
use PDOException;
|
||||
use Phalcon\Mvc\Url;
|
||||
use Phalcon\DiInterface;
|
||||
use Phalcon\Di\Injectable;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Framework;
|
||||
use Phalcon\Mvc\RouterInterface;
|
||||
use Phalcon\Mvc\Model as PhalconModel;
|
||||
use Phalcon\Mvc\Router\RouteInterface;
|
||||
use Codeception\Util\ReflectionHelper;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Lib\Interfaces\ActiveRecord;
|
||||
use Codeception\Lib\Interfaces\PartedModule;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Lib\Connector\Phalcon as PhalconConnector;
|
||||
|
||||
/**
|
||||
* This module provides integration with [Phalcon framework](http://www.phalconphp.com/) (3.x).
|
||||
* Please try it and leave your feedback.
|
||||
*
|
||||
* ## Demo Project
|
||||
*
|
||||
* <https://github.com/Codeception/phalcon-demo>
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **Serghei Iakovlev**
|
||||
* * Stability: **stable**
|
||||
* * Contact: serghei@phalconphp.com
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* The following configurations are required for this module:
|
||||
*
|
||||
* * bootstrap: `string`, default `app/config/bootstrap.php` - relative path to app.php config file
|
||||
* * cleanup: `boolean`, default `true` - all database queries will be run in a transaction,
|
||||
* which will be rolled back at the end of each test
|
||||
* * savepoints: `boolean`, default `true` - use savepoints to emulate nested transactions
|
||||
*
|
||||
* The application bootstrap file must return Application object but not call its handle() method.
|
||||
*
|
||||
* ## API
|
||||
*
|
||||
* * di - `Phalcon\Di\Injectable` instance
|
||||
* * client - `BrowserKit` client
|
||||
*
|
||||
* ## Parts
|
||||
*
|
||||
* By default all available methods are loaded, but you can specify parts to select only needed
|
||||
* actions and avoid conflicts.
|
||||
*
|
||||
* * `orm` - include only `haveRecord/grabRecord/seeRecord/dontSeeRecord` actions.
|
||||
* * `services` - allows to use `grabServiceFromContainer` and `addServiceToContainer`.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* Sample bootstrap (`app/config/bootstrap.php`):
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $config = include __DIR__ . "/config.php";
|
||||
* include __DIR__ . "/loader.php";
|
||||
* $di = new \Phalcon\DI\FactoryDefault();
|
||||
* include __DIR__ . "/services.php";
|
||||
* return new \Phalcon\Mvc\Application($di);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* ```yaml
|
||||
* actor: AcceptanceTester
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Phalcon:
|
||||
* part: services
|
||||
* bootstrap: 'app/config/bootstrap.php'
|
||||
* cleanup: true
|
||||
* savepoints: true
|
||||
* - WebDriver:
|
||||
* url: http://your-url.com
|
||||
* browser: phantomjs
|
||||
* ```
|
||||
*/
|
||||
class Phalcon extends Framework implements ActiveRecord, PartedModule
|
||||
{
|
||||
protected $config = [
|
||||
'bootstrap' => 'app/config/bootstrap.php',
|
||||
'cleanup' => true,
|
||||
'savepoints' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Phalcon bootstrap file path
|
||||
*/
|
||||
protected $bootstrapFile = null;
|
||||
|
||||
/**
|
||||
* Dependency injection container
|
||||
* @var DiInterface
|
||||
*/
|
||||
public $di = null;
|
||||
|
||||
/**
|
||||
* Phalcon Connector
|
||||
* @var PhalconConnector
|
||||
*/
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* HOOK: used after configuration is loaded
|
||||
*
|
||||
* @throws ModuleConfigException
|
||||
*/
|
||||
public function _initialize()
|
||||
{
|
||||
$this->bootstrapFile = Configuration::projectDir() . $this->config['bootstrap'];
|
||||
|
||||
if (!file_exists($this->bootstrapFile)) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"Bootstrap file does not exist in " . $this->config['bootstrap'] . "\n"
|
||||
. "Please create the bootstrap file that returns Application object\n"
|
||||
. "And specify path to it with 'bootstrap' config\n\n"
|
||||
. "Sample bootstrap: \n\n<?php\n"
|
||||
. '$config = include __DIR__ . "/config.php";' . "\n"
|
||||
. 'include __DIR__ . "/loader.php";' . "\n"
|
||||
. '$di = new \Phalcon\DI\FactoryDefault();' . "\n"
|
||||
. 'include __DIR__ . "/services.php";' . "\n"
|
||||
. 'return new \Phalcon\Mvc\Application($di);'
|
||||
);
|
||||
}
|
||||
|
||||
$this->client = new PhalconConnector();
|
||||
}
|
||||
|
||||
/**
|
||||
* HOOK: before scenario
|
||||
*
|
||||
* @param TestInterface $test
|
||||
* @throws ModuleException
|
||||
*/
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
$application = require $this->bootstrapFile;
|
||||
if (!$application instanceof Injectable) {
|
||||
throw new ModuleException(__CLASS__, 'Bootstrap must return \Phalcon\Di\Injectable object');
|
||||
}
|
||||
|
||||
$this->di = $application->getDI();
|
||||
|
||||
Di::reset();
|
||||
Di::setDefault($this->di);
|
||||
|
||||
if ($this->di->has('session')) {
|
||||
// Destroy existing sessions of previous tests
|
||||
$this->di['session'] = new PhalconConnector\MemorySession();
|
||||
}
|
||||
|
||||
if ($this->di->has('cookies')) {
|
||||
$this->di['cookies']->useEncryption(false);
|
||||
}
|
||||
|
||||
if ($this->config['cleanup'] && $this->di->has('db')) {
|
||||
if ($this->config['savepoints']) {
|
||||
$this->di['db']->setNestedTransactionsWithSavepoints(true);
|
||||
}
|
||||
$this->di['db']->begin();
|
||||
$this->debugSection('Database', 'Transaction started');
|
||||
}
|
||||
|
||||
// localize
|
||||
$bootstrap = $this->bootstrapFile;
|
||||
$this->client->setApplication(function () use ($bootstrap) {
|
||||
$currentDi = Di::getDefault();
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
$application = require $bootstrap;
|
||||
$di = $application->getDI();
|
||||
if ($currentDi->has('db')) {
|
||||
$di['db'] = $currentDi['db'];
|
||||
}
|
||||
if ($currentDi->has('session')) {
|
||||
$di['session'] = $currentDi['session'];
|
||||
}
|
||||
if ($di->has('cookies')) {
|
||||
$di['cookies']->useEncryption(false);
|
||||
}
|
||||
return $application;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* HOOK: after scenario
|
||||
*
|
||||
* @param TestInterface $test
|
||||
*/
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
if ($this->config['cleanup'] && isset($this->di['db'])) {
|
||||
while ($this->di['db']->isUnderTransaction()) {
|
||||
$level = $this->di['db']->getTransactionLevel();
|
||||
try {
|
||||
$this->di['db']->rollback(true);
|
||||
$this->debugSection('Database', 'Transaction cancelled; all changes reverted.');
|
||||
} catch (PDOException $e) {
|
||||
}
|
||||
if ($level == $this->di['db']->getTransactionLevel()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->di['db']->close();
|
||||
}
|
||||
$this->di = null;
|
||||
Di::reset();
|
||||
|
||||
$_SESSION = $_FILES = $_GET = $_POST = $_COOKIE = $_REQUEST = [];
|
||||
}
|
||||
|
||||
public function _parts()
|
||||
{
|
||||
return ['orm', 'services'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access the Phalcon application object.
|
||||
*
|
||||
* @see \Codeception\Lib\Connector\Phalcon::getApplication
|
||||
* @return \Phalcon\Application|\Phalcon\Mvc\Micro
|
||||
*/
|
||||
public function getApplication()
|
||||
{
|
||||
return $this->client->getApplication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value to session. Use for authorization.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $val
|
||||
*/
|
||||
public function haveInSession($key, $val)
|
||||
{
|
||||
$this->di->get('session')->set($key, $val);
|
||||
$this->debugSection('Session', json_encode($this->di['session']->toArray()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that session contains value.
|
||||
* If value is `null` checks that session has key.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeInSession('key');
|
||||
* $I->seeInSession('key', 'value');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function seeInSession($key, $value = null)
|
||||
{
|
||||
$this->debugSection('Session', json_encode($this->di['session']->toArray()));
|
||||
|
||||
if (is_array($key)) {
|
||||
$this->seeSessionHasValues($key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->di['session']->has($key)) {
|
||||
$this->fail("No session variable with key '$key'");
|
||||
}
|
||||
|
||||
if (is_null($value)) {
|
||||
$this->assertTrue($this->di['session']->has($key));
|
||||
} else {
|
||||
$this->assertEquals($value, $this->di['session']->get($key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the session has a given list of values.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeSessionHasValues(['key1', 'key2']);
|
||||
* $I->seeSessionHasValues(['key1' => 'value1', 'key2' => 'value2']);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param array $bindings
|
||||
* @return void
|
||||
*/
|
||||
public function seeSessionHasValues(array $bindings)
|
||||
{
|
||||
foreach ($bindings as $key => $value) {
|
||||
if (is_int($key)) {
|
||||
$this->seeInSession($value);
|
||||
} else {
|
||||
$this->seeInSession($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts record into the database.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $user_id = $I->haveRecord('App\Models\Users', ['name' => 'Phalcon']);
|
||||
* $I->haveRecord('App\Models\Categories', ['name' => 'Testing']');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $model Model name
|
||||
* @param array $attributes Model attributes
|
||||
* @return mixed
|
||||
* @part orm
|
||||
*/
|
||||
public function haveRecord($model, $attributes = [])
|
||||
{
|
||||
$record = $this->getModelRecord($model);
|
||||
$res = $record->save($attributes);
|
||||
$field = function ($field) {
|
||||
if (is_array($field)) {
|
||||
return implode(', ', $field);
|
||||
}
|
||||
|
||||
return $field;
|
||||
};
|
||||
|
||||
if (!$res) {
|
||||
$messages = $record->getMessages();
|
||||
$errors = [];
|
||||
foreach ($messages as $message) {
|
||||
/** @var \Phalcon\Mvc\Model\MessageInterface $message */
|
||||
$errors[] = sprintf(
|
||||
'[%s] %s: %s',
|
||||
$message->getType(),
|
||||
$field($message->getField()),
|
||||
$message->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
$this->fail(sprintf("Record %s was not saved. Messages: \n%s", $model, implode(PHP_EOL, $errors)));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->debugSection($model, json_encode($record));
|
||||
|
||||
return $this->getModelIdentity($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that record exists in database.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeRecord('App\Models\Categories', ['name' => 'Testing']);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $model Model name
|
||||
* @param array $attributes Model attributes
|
||||
* @part orm
|
||||
*/
|
||||
public function seeRecord($model, $attributes = [])
|
||||
{
|
||||
$record = $this->findRecord($model, $attributes);
|
||||
if (!$record) {
|
||||
$this->fail("Couldn't find $model with " . json_encode($attributes));
|
||||
}
|
||||
$this->debugSection($model, json_encode($record));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that record does not exist in database.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeRecord('App\Models\Categories', ['name' => 'Testing']);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $model Model name
|
||||
* @param array $attributes Model attributes
|
||||
* @part orm
|
||||
*/
|
||||
public function dontSeeRecord($model, $attributes = [])
|
||||
{
|
||||
$record = $this->findRecord($model, $attributes);
|
||||
$this->debugSection($model, json_encode($record));
|
||||
if ($record) {
|
||||
$this->fail("Unexpectedly managed to find $model with " . json_encode($attributes));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves record from database
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $category = $I->grabRecord('App\Models\Categories', ['name' => 'Testing']);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $model Model name
|
||||
* @param array $attributes Model attributes
|
||||
* @return mixed
|
||||
* @part orm
|
||||
*/
|
||||
public function grabRecord($model, $attributes = [])
|
||||
{
|
||||
return $this->findRecord($model, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the service based on its configuration from Phalcon's DI container
|
||||
* Recommended to use for unit testing.
|
||||
*
|
||||
* @param string $service Service name
|
||||
* @param array $parameters Parameters [Optional]
|
||||
* @return mixed
|
||||
* @part services
|
||||
*/
|
||||
public function grabServiceFromContainer($service, array $parameters = [])
|
||||
{
|
||||
if (!$this->di->has($service)) {
|
||||
$this->fail("Service $service is not available in container");
|
||||
}
|
||||
|
||||
return $this->di->get($service, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for `grabServiceFromContainer`.
|
||||
*
|
||||
* Note: Deprecated. Will be removed in Codeception 2.3.
|
||||
*
|
||||
* @param string $service Service name
|
||||
* @param array $parameters Parameters [Optional]
|
||||
* @return mixed
|
||||
* @part services
|
||||
*/
|
||||
public function grabServiceFromDi($service, array $parameters = [])
|
||||
{
|
||||
return $this->grabServiceFromContainer($service, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a service in the services container and resolve it. This record will be erased after the test.
|
||||
* Recommended to use for unit testing.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $filter = $I->addServiceToContainer('filter', ['className' => '\Phalcon\Filter']);
|
||||
* $filter = $I->addServiceToContainer('answer', function () {
|
||||
* return rand(0, 1) ? 'Yes' : 'No';
|
||||
* }, true);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $definition
|
||||
* @param boolean $shared
|
||||
* @return mixed|null
|
||||
* @part services
|
||||
*/
|
||||
public function addServiceToContainer($name, $definition, $shared = false)
|
||||
{
|
||||
try {
|
||||
$service = $this->di->set($name, $definition, $shared);
|
||||
return $service->resolve();
|
||||
} catch (\Exception $e) {
|
||||
$this->fail($e->getMessage());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for `addServiceToContainer`.
|
||||
*
|
||||
* Note: Deprecated. Will be removed in Codeception 2.3.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $definition
|
||||
* @param boolean $shared
|
||||
* @return mixed|null
|
||||
* @part services
|
||||
*/
|
||||
public function haveServiceInDi($name, $definition, $shared = false)
|
||||
{
|
||||
return $this->addServiceToContainer($name, $definition, $shared);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens web page using route name and parameters.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->amOnRoute('posts.create');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $routeName
|
||||
* @param array $params
|
||||
*/
|
||||
public function amOnRoute($routeName, array $params = [])
|
||||
{
|
||||
if (!$this->di->has('url')) {
|
||||
$this->fail('Unable to resolve "url" service.');
|
||||
}
|
||||
|
||||
/** @var Url $url */
|
||||
$url = $this->di->getShared('url');
|
||||
|
||||
$urlParams = ['for' => $routeName];
|
||||
|
||||
if ($params) {
|
||||
$urlParams += $params;
|
||||
}
|
||||
|
||||
$this->amOnPage($url->get($urlParams, null, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that current url matches route
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeCurrentRouteIs('posts.index');
|
||||
* ?>
|
||||
* ```
|
||||
* @param string $routeName
|
||||
*/
|
||||
public function seeCurrentRouteIs($routeName)
|
||||
{
|
||||
if (!$this->di->has('url')) {
|
||||
$this->fail('Unable to resolve "url" service.');
|
||||
}
|
||||
|
||||
/** @var Url $url */
|
||||
$url = $this->di->getShared('url');
|
||||
$this->seeCurrentUrlEquals($url->get(['for' => $routeName], null, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to query the first record that match the specified conditions
|
||||
*
|
||||
* @param string $model Model name
|
||||
* @param array $attributes Model attributes
|
||||
*
|
||||
* @return \Phalcon\Mvc\Model
|
||||
*/
|
||||
protected function findRecord($model, $attributes = [])
|
||||
{
|
||||
$this->getModelRecord($model);
|
||||
$query = [];
|
||||
foreach ($attributes as $key => $value) {
|
||||
$query[] = "$key = '$value'";
|
||||
}
|
||||
$squery = implode(' AND ', $query);
|
||||
$this->debugSection('Query', $squery);
|
||||
return call_user_func_array([$model, 'findFirst'], [$squery]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Model Record
|
||||
*
|
||||
* @param $model
|
||||
*
|
||||
* @return \Phalcon\Mvc\Model
|
||||
* @throws ModuleException
|
||||
*/
|
||||
protected function getModelRecord($model)
|
||||
{
|
||||
if (!class_exists($model)) {
|
||||
throw new ModuleException(__CLASS__, "Model $model does not exist");
|
||||
}
|
||||
|
||||
$record = new $model;
|
||||
if (!$record instanceof PhalconModel) {
|
||||
throw new ModuleException(__CLASS__, "Model $model is not instance of \\Phalcon\\Mvc\\Model");
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get identity.
|
||||
*
|
||||
* @param \Phalcon\Mvc\Model $model
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getModelIdentity(PhalconModel $model)
|
||||
{
|
||||
if (property_exists($model, 'id')) {
|
||||
return $model->id;
|
||||
}
|
||||
|
||||
if (!$this->di->has('modelsMetadata')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$primaryKeys = $this->di->get('modelsMetadata')->getPrimaryKeyAttributes($model);
|
||||
|
||||
switch (count($primaryKeys)) {
|
||||
case 0:
|
||||
return null;
|
||||
case 1:
|
||||
return $model->{$primaryKeys[0]};
|
||||
default:
|
||||
return array_intersect_key(get_object_vars($model), array_flip($primaryKeys));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of recognized domain names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getInternalDomains()
|
||||
{
|
||||
$internalDomains = [$this->getApplicationDomainRegex()];
|
||||
|
||||
/** @var RouterInterface $router */
|
||||
$router = $this->di->get('router');
|
||||
|
||||
if ($router instanceof RouterInterface) {
|
||||
/** @var RouteInterface[] $routes */
|
||||
$routes = $router->getRoutes();
|
||||
|
||||
foreach ($routes as $route) {
|
||||
if ($route instanceof RouteInterface) {
|
||||
$hostName = $route->getHostname();
|
||||
if (!empty($hostName)) {
|
||||
$internalDomains[] = '/^' . str_replace('.', '\.', $route->getHostname()) . '$/';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($internalDomains);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getApplicationDomainRegex()
|
||||
{
|
||||
$server = ReflectionHelper::readPrivateProperty($this->client, 'server');
|
||||
$domain = $server['HTTP_HOST'];
|
||||
|
||||
return '/^' . str_replace('.', '\.', $domain) . '$/';
|
||||
}
|
||||
}
|
||||
290
vendor/codeception/base/src/Codeception/Module/PhpBrowser.php
vendored
Normal file
290
vendor/codeception/base/src/Codeception/Module/PhpBrowser.php
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Lib\Connector\Guzzle6;
|
||||
use Codeception\Lib\InnerBrowser;
|
||||
use Codeception\Lib\Interfaces\MultiSession;
|
||||
use Codeception\Lib\Interfaces\Remote;
|
||||
use Codeception\Lib\Interfaces\RequiresPackage;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Util\Uri;
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
|
||||
/**
|
||||
* Uses [Guzzle](http://guzzlephp.org/) to interact with your application over CURL.
|
||||
* Module works over CURL and requires **PHP CURL extension** to be enabled.
|
||||
*
|
||||
* Use to perform web acceptance tests with non-javascript browser.
|
||||
*
|
||||
* If test fails stores last shown page in 'output' dir.
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **davert**
|
||||
* * Stability: **stable**
|
||||
* * Contact: codeception@codeception.com
|
||||
*
|
||||
*
|
||||
* ## Configuration
|
||||
*
|
||||
* * url *required* - start url of your app
|
||||
* * headers - default headers are set before each test.
|
||||
* * handler (default: curl) - Guzzle handler to use. By default curl is used, also possible to pass `stream`, or any valid class name as [Handler](http://docs.guzzlephp.org/en/latest/handlers-and-middleware.html#handlers).
|
||||
* * middleware - Guzzle middlewares to add. An array of valid callables is required.
|
||||
* * curl - curl options
|
||||
* * cookies - ...
|
||||
* * auth - ...
|
||||
* * verify - ...
|
||||
* * .. those and other [Guzzle Request options](http://docs.guzzlephp.org/en/latest/request-options.html)
|
||||
*
|
||||
*
|
||||
* ### Example (`acceptance.suite.yml`)
|
||||
*
|
||||
* modules:
|
||||
* enabled:
|
||||
* - PhpBrowser:
|
||||
* url: 'http://localhost'
|
||||
* auth: ['admin', '123345']
|
||||
* curl:
|
||||
* CURLOPT_RETURNTRANSFER: true
|
||||
* cookies:
|
||||
* cookie-1:
|
||||
* Name: userName
|
||||
* Value: john.doe
|
||||
* cookie-2:
|
||||
* Name: authToken
|
||||
* Value: 1abcd2345
|
||||
* Domain: subdomain.domain.com
|
||||
* Path: /admin/
|
||||
* Expires: 1292177455
|
||||
* Secure: true
|
||||
* HttpOnly: false
|
||||
*
|
||||
*
|
||||
* All SSL certification checks are disabled by default.
|
||||
* Use Guzzle request options to configure certifications and others.
|
||||
*
|
||||
* ## Public API
|
||||
*
|
||||
* Those properties and methods are expected to be used in Helper classes:
|
||||
*
|
||||
* Properties:
|
||||
*
|
||||
* * `guzzle` - contains [Guzzle](http://guzzlephp.org/) client instance: `\GuzzleHttp\Client`
|
||||
* * `client` - Symfony BrowserKit instance.
|
||||
*
|
||||
*/
|
||||
class PhpBrowser extends InnerBrowser implements Remote, MultiSession, RequiresPackage
|
||||
{
|
||||
|
||||
private $isGuzzlePsr7;
|
||||
protected $requiredFields = ['url'];
|
||||
|
||||
protected $config = [
|
||||
'headers' => [],
|
||||
'verify' => false,
|
||||
'expect' => false,
|
||||
'timeout' => 30,
|
||||
'curl' => [],
|
||||
'refresh_max_interval' => 10,
|
||||
'handler' => 'curl',
|
||||
'middleware' => null,
|
||||
|
||||
// required defaults (not recommended to change)
|
||||
'allow_redirects' => false,
|
||||
'http_errors' => false,
|
||||
'cookies' => true,
|
||||
];
|
||||
|
||||
protected $guzzleConfigFields = [
|
||||
'auth',
|
||||
'proxy',
|
||||
'verify',
|
||||
'cert',
|
||||
'query',
|
||||
'ssl_key',
|
||||
'proxy',
|
||||
'expect',
|
||||
'version',
|
||||
'timeout',
|
||||
'connect_timeout'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Codeception\Lib\Connector\Guzzle6
|
||||
*/
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* @var GuzzleClient
|
||||
*/
|
||||
public $guzzle;
|
||||
|
||||
public function _requires()
|
||||
{
|
||||
return ['GuzzleHttp\Client' => '"guzzlehttp/guzzle": ">=4.1.4 <7.0"'];
|
||||
}
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$this->_initializeSession();
|
||||
}
|
||||
|
||||
protected function guessGuzzleConnector()
|
||||
{
|
||||
if (class_exists('GuzzleHttp\Url')) {
|
||||
$this->isGuzzlePsr7 = false;
|
||||
return new \Codeception\Lib\Connector\Guzzle();
|
||||
}
|
||||
$this->isGuzzlePsr7 = true;
|
||||
return new \Codeception\Lib\Connector\Guzzle6();
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
if (!$this->client) {
|
||||
$this->client = $this->guessGuzzleConnector();
|
||||
}
|
||||
$this->_prepareSession();
|
||||
}
|
||||
|
||||
public function _getUrl()
|
||||
{
|
||||
return $this->config['url'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias to `haveHttpHeader`
|
||||
*
|
||||
* @param $name
|
||||
* @param $value
|
||||
*/
|
||||
public function setHeader($name, $value)
|
||||
{
|
||||
$this->haveHttpHeader($name, $value);
|
||||
}
|
||||
|
||||
public function amHttpAuthenticated($username, $password)
|
||||
{
|
||||
$this->client->setAuth($username, $password);
|
||||
}
|
||||
|
||||
public function amOnUrl($url)
|
||||
{
|
||||
$host = Uri::retrieveHost($url);
|
||||
$this->_reconfigure(['url' => $host]);
|
||||
$page = substr($url, strlen($host));
|
||||
if ($page === '') {
|
||||
$page = '/';
|
||||
}
|
||||
$this->debugSection('Host', $host);
|
||||
$this->amOnPage($page);
|
||||
}
|
||||
|
||||
public function amOnSubdomain($subdomain)
|
||||
{
|
||||
$url = $this->config['url'];
|
||||
$url = preg_replace('~(https?:\/\/)(.*\.)(.*\.)~', "$1$3", $url); // removing current subdomain
|
||||
$url = preg_replace('~(https?:\/\/)(.*)~', "$1$subdomain.$2", $url); // inserting new
|
||||
$this->_reconfigure(['url' => $url]);
|
||||
}
|
||||
|
||||
protected function onReconfigure()
|
||||
{
|
||||
$this->_prepareSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Low-level API method.
|
||||
* If Codeception commands are not enough, use [Guzzle HTTP Client](http://guzzlephp.org/) methods directly
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->executeInGuzzle(function (\GuzzleHttp\Client $client) {
|
||||
* $client->get('/get', ['query' => ['foo' => 'bar']]);
|
||||
* });
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* It is not recommended to use this command on a regular basis.
|
||||
* If Codeception lacks important Guzzle Client methods, implement them and submit patches.
|
||||
*
|
||||
* @param callable $function
|
||||
*/
|
||||
public function executeInGuzzle(\Closure $function)
|
||||
{
|
||||
return $function($this->guzzle);
|
||||
}
|
||||
|
||||
|
||||
public function _getResponseCode()
|
||||
{
|
||||
return $this->getResponseStatusCode();
|
||||
}
|
||||
|
||||
public function _initializeSession()
|
||||
{
|
||||
// independent sessions need independent cookies
|
||||
$this->client = $this->guessGuzzleConnector();
|
||||
$this->_prepareSession();
|
||||
}
|
||||
|
||||
public function _prepareSession()
|
||||
{
|
||||
$defaults = array_intersect_key($this->config, array_flip($this->guzzleConfigFields));
|
||||
$curlOptions = [];
|
||||
|
||||
foreach ($this->config['curl'] as $key => $val) {
|
||||
if (defined($key)) {
|
||||
$curlOptions[constant($key)] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
$this->headers = $this->config['headers'];
|
||||
$this->setCookiesFromOptions();
|
||||
|
||||
if ($this->isGuzzlePsr7) {
|
||||
$defaults['base_uri'] = $this->config['url'];
|
||||
$defaults['curl'] = $curlOptions;
|
||||
$handler = Guzzle6::createHandler($this->config['handler']);
|
||||
if ($handler && is_array($this->config['middleware'])) {
|
||||
foreach ($this->config['middleware'] as $middleware) {
|
||||
$handler->push($middleware);
|
||||
}
|
||||
}
|
||||
$defaults['handler'] = $handler;
|
||||
$this->guzzle = new GuzzleClient($defaults);
|
||||
} else {
|
||||
$defaults['config']['curl'] = $curlOptions;
|
||||
$this->guzzle = new GuzzleClient(['base_url' => $this->config['url'], 'defaults' => $defaults]);
|
||||
$this->client->setBaseUri($this->config['url']);
|
||||
}
|
||||
|
||||
$this->client->setRefreshMaxInterval($this->config['refresh_max_interval']);
|
||||
$this->client->setClient($this->guzzle);
|
||||
}
|
||||
|
||||
public function _backupSession()
|
||||
{
|
||||
return [
|
||||
'client' => $this->client,
|
||||
'guzzle' => $this->guzzle,
|
||||
'crawler' => $this->crawler,
|
||||
'headers' => $this->headers,
|
||||
];
|
||||
}
|
||||
|
||||
public function _loadSession($session)
|
||||
{
|
||||
foreach ($session as $key => $val) {
|
||||
$this->$key = $val;
|
||||
}
|
||||
}
|
||||
|
||||
public function _closeSession($session = null)
|
||||
{
|
||||
unset($session);
|
||||
}
|
||||
}
|
||||
402
vendor/codeception/base/src/Codeception/Module/Queue.php
vendored
Normal file
402
vendor/codeception/base/src/Codeception/Module/Queue.php
vendored
Normal file
@@ -0,0 +1,402 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Lib\Driver\AmazonSQS;
|
||||
use Codeception\Lib\Driver\Beanstalk;
|
||||
use Codeception\Lib\Driver\Iron;
|
||||
|
||||
/**
|
||||
*
|
||||
* Works with Queue servers.
|
||||
*
|
||||
* Testing with a selection of remote/local queueing services, including Amazon's SQS service
|
||||
* Iron.io service and beanstalkd service.
|
||||
*
|
||||
* Supported and tested queue types are:
|
||||
*
|
||||
* * [Iron.io](http://iron.io/)
|
||||
* * [Beanstalkd](http://kr.github.io/beanstalkd/)
|
||||
* * [Amazon SQS](http://aws.amazon.com/sqs/)
|
||||
*
|
||||
* The following dependencies are needed for the listed queue servers:
|
||||
*
|
||||
* * Beanstalkd: pda/pheanstalk ~3.0
|
||||
* * Amazon SQS: aws/aws-sdk-php
|
||||
* * IronMQ: iron-io/iron_mq
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **nathanmac**
|
||||
* * Stability:
|
||||
* - Iron.io: **stable**
|
||||
* - Beanstalkd: **stable**
|
||||
* - Amazon SQS: **stable**
|
||||
* * Contact: nathan.macnamara@outlook.com
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* The configuration settings depending on which queueing service is being used, all the options are listed
|
||||
* here. Refer to the configuration examples below to identify the configuration options required for your chosen
|
||||
* service.
|
||||
*
|
||||
* * type - type of queueing server (defaults to beanstalkd).
|
||||
* * host - hostname/ip address of the queue server or the host for the iron.io when using iron.io service.
|
||||
* * port: 11300 - port number for the queue server.
|
||||
* * timeout: 90 - timeout settings for connecting the queue server.
|
||||
* * token - Iron.io access token.
|
||||
* * project - Iron.io project ID.
|
||||
* * key - AWS access key ID.
|
||||
* * version - AWS version (e.g. latest)
|
||||
* * endpoint - The full URI of the webservice. This is only required when connecting to a custom endpoint (e.g., a local version of SQS).
|
||||
* * secret - AWS secret access key.
|
||||
* Warning:
|
||||
* Hard-coding your credentials can be dangerous, because it is easy to accidentally commit your credentials
|
||||
* into an SCM repository, potentially exposing your credentials to more people than intended.
|
||||
* It can also make it difficult to rotate credentials in the future.
|
||||
* * profile - AWS credential profile
|
||||
* - it should be located in ~/.aws/credentials file
|
||||
* - eg: [default]
|
||||
* aws_access_key_id = YOUR_AWS_ACCESS_KEY_ID
|
||||
* aws_secret_access_key = YOUR_AWS_SECRET_ACCESS_KEY
|
||||
* [project1]
|
||||
* aws_access_key_id = YOUR_AWS_ACCESS_KEY_ID
|
||||
* aws_secret_access_key = YOUR_AWS_SECRET_ACCESS_KEY
|
||||
* - Note: Using IAM roles is the preferred technique for providing credentials
|
||||
* to applications running on Amazon EC2
|
||||
* http://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/credentials.html?highlight=credentials
|
||||
*
|
||||
* * region - A region parameter is also required for AWS, refer to the AWS documentation for possible values list.
|
||||
*
|
||||
* ### Example
|
||||
* #### Example (beanstalkd)
|
||||
*
|
||||
* modules:
|
||||
* enabled: [Queue]
|
||||
* config:
|
||||
* Queue:
|
||||
* type: 'beanstalkd'
|
||||
* host: '127.0.0.1'
|
||||
* port: 11300
|
||||
* timeout: 120
|
||||
*
|
||||
* #### Example (Iron.io)
|
||||
*
|
||||
* modules:
|
||||
* enabled: [Queue]
|
||||
* config:
|
||||
* Queue:
|
||||
* 'type': 'iron',
|
||||
* 'host': 'mq-aws-us-east-1.iron.io',
|
||||
* 'token': 'your-token',
|
||||
* 'project': 'your-project-id'
|
||||
*
|
||||
* #### Example (AWS SQS)
|
||||
*
|
||||
* modules:
|
||||
* enabled: [Queue]
|
||||
* config:
|
||||
* Queue:
|
||||
* 'type': 'aws',
|
||||
* 'key': 'your-public-key',
|
||||
* 'secret': 'your-secret-key',
|
||||
* 'region': 'us-west-2'
|
||||
*
|
||||
* #### Example AWS SQS using profile credentials
|
||||
*
|
||||
* modules:
|
||||
* enabled: [Queue]
|
||||
* config:
|
||||
* Queue:
|
||||
* 'type': 'aws',
|
||||
* 'profile': 'project1', //see documentation
|
||||
* 'region': 'us-west-2'
|
||||
*
|
||||
* #### Example AWS SQS running on Amazon EC2 instance
|
||||
*
|
||||
* modules:
|
||||
* enabled: [Queue]
|
||||
* config:
|
||||
* Queue:
|
||||
* 'type': 'aws',
|
||||
* 'region': 'us-west-2'
|
||||
*
|
||||
*/
|
||||
class Queue extends CodeceptionModule
|
||||
{
|
||||
/**
|
||||
* @var \Codeception\Lib\Interfaces\Queue
|
||||
*/
|
||||
public $queueDriver;
|
||||
|
||||
/**
|
||||
* Setup connection and open/setup the connection with config settings
|
||||
*
|
||||
* @param \Codeception\TestInterface $test
|
||||
*/
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->queueDriver->openConnection($this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide and override for the config settings and allow custom settings depending on the service being used.
|
||||
*/
|
||||
protected function validateConfig()
|
||||
{
|
||||
$this->queueDriver = $this->createQueueDriver();
|
||||
$this->requiredFields = $this->queueDriver->getRequiredConfig();
|
||||
$this->config = array_merge($this->queueDriver->getDefaultConfig(), $this->config);
|
||||
parent::validateConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Codeception\Lib\Interfaces\Queue
|
||||
* @throws ModuleConfigException
|
||||
*/
|
||||
protected function createQueueDriver()
|
||||
{
|
||||
switch ($this->config['type']) {
|
||||
case 'aws':
|
||||
case 'sqs':
|
||||
case 'aws_sqs':
|
||||
return new AmazonSQS();
|
||||
case 'iron':
|
||||
case 'iron_mq':
|
||||
return new Iron();
|
||||
case 'beanstalk':
|
||||
case 'beanstalkd':
|
||||
case 'beanstalkq':
|
||||
return new Beanstalk();
|
||||
default:
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"Unknown queue type {$this->config}; Supported queue types are: aws, iron, beanstalk"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------- SEARCH METHODS BELOW HERE ------------------------//
|
||||
|
||||
/**
|
||||
* Check if a queue/tube exists on the queueing server.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeQueueExists('default');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue Queue Name
|
||||
*/
|
||||
public function seeQueueExists($queue)
|
||||
{
|
||||
$this->assertContains($queue, $this->queueDriver->getQueues());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a queue/tube does NOT exist on the queueing server.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->dontSeeQueueExists('default');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue Queue Name
|
||||
*/
|
||||
public function dontSeeQueueExists($queue)
|
||||
{
|
||||
$this->assertNotContains($queue, $this->queueDriver->getQueues());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a queue/tube is empty of all messages
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeEmptyQueue('default');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue Queue Name
|
||||
*/
|
||||
public function seeEmptyQueue($queue)
|
||||
{
|
||||
$this->assertEquals(0, $this->queueDriver->getMessagesCurrentCountOnQueue($queue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a queue/tube is NOT empty of all messages
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->dontSeeEmptyQueue('default');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue Queue Name
|
||||
*/
|
||||
public function dontSeeEmptyQueue($queue)
|
||||
{
|
||||
$this->assertNotEquals(0, $this->queueDriver->getMessagesCurrentCountOnQueue($queue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a queue/tube has a given current number of messages
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeQueueHasCurrentCount('default', 10);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue Queue Name
|
||||
* @param int $expected Number of messages expected
|
||||
*/
|
||||
public function seeQueueHasCurrentCount($queue, $expected)
|
||||
{
|
||||
$this->assertEquals($expected, $this->queueDriver->getMessagesCurrentCountOnQueue($queue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a queue/tube does NOT have a given current number of messages
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->dontSeeQueueHasCurrentCount('default', 10);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue Queue Name
|
||||
* @param int $expected Number of messages expected
|
||||
*/
|
||||
public function dontSeeQueueHasCurrentCount($queue, $expected)
|
||||
{
|
||||
$this->assertNotEquals($expected, $this->queueDriver->getMessagesCurrentCountOnQueue($queue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a queue/tube has a given total number of messages
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeQueueHasTotalCount('default', 10);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue Queue Name
|
||||
* @param int $expected Number of messages expected
|
||||
*/
|
||||
public function seeQueueHasTotalCount($queue, $expected)
|
||||
{
|
||||
$this->assertEquals($expected, $this->queueDriver->getMessagesTotalCountOnQueue($queue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a queue/tube does NOT have a given total number of messages
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->dontSeeQueueHasTotalCount('default', 10);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue Queue Name
|
||||
* @param int $expected Number of messages expected
|
||||
*/
|
||||
public function dontSeeQueueHasTotalCount($queue, $expected)
|
||||
{
|
||||
$this->assertNotEquals($expected, $this->queueDriver->getMessagesTotalCountOnQueue($queue));
|
||||
}
|
||||
|
||||
// ----------- UTILITY METHODS BELOW HERE -------------------------//
|
||||
|
||||
/**
|
||||
* Add a message to a queue/tube
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->addMessageToQueue('this is a messages', 'default');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $message Message Body
|
||||
* @param string $queue Queue Name
|
||||
*/
|
||||
public function addMessageToQueue($message, $queue)
|
||||
{
|
||||
$this->queueDriver->addMessageToQueue($message, $queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all messages of the queue/tube
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->clearQueue('default');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $queue Queue Name
|
||||
*/
|
||||
public function clearQueue($queue)
|
||||
{
|
||||
$this->queueDriver->clearQueue($queue);
|
||||
}
|
||||
|
||||
// ----------- GRABBER METHODS BELOW HERE -----------------------//
|
||||
|
||||
/**
|
||||
* Grabber method to get the list of queues/tubes on the server
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $queues = $I->grabQueues();
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @return array List of Queues/Tubes
|
||||
*/
|
||||
public function grabQueues()
|
||||
{
|
||||
return $this->queueDriver->getQueues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabber method to get the current number of messages on the queue/tube (pending/ready)
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->grabQueueCurrentCount('default');
|
||||
* ?>
|
||||
* ```
|
||||
* @param string $queue Queue Name
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function grabQueueCurrentCount($queue)
|
||||
{
|
||||
return $this->queueDriver->getMessagesCurrentCountOnQueue($queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabber method to get the total number of messages on the queue/tube
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->grabQueueTotalCount('default');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $queue Queue Name
|
||||
*
|
||||
* @return int Count
|
||||
*/
|
||||
public function grabQueueTotalCount($queue)
|
||||
{
|
||||
return $this->queueDriver->getMessagesTotalCountOnQueue($queue);
|
||||
}
|
||||
}
|
||||
72
vendor/codeception/base/src/Codeception/Module/README.md
vendored
Normal file
72
vendor/codeception/base/src/Codeception/Module/README.md
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
# Modules
|
||||
|
||||
Modules are high-level extensions that are used in tests. Modules are created for each test suites (according to suite configuration) and can be accessed directly from unit tests:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$this->getModule('PhpBrowser')->client;
|
||||
?>
|
||||
```
|
||||
|
||||
or used inside scenario-driven tests, where `$I` acts as an wrapper to different modules
|
||||
|
||||
```php
|
||||
<?php
|
||||
$I->click(); // => PhpBrowser
|
||||
$I->seeInDatabase(); // => Db
|
||||
?>
|
||||
```
|
||||
|
||||
Each module is extending `Codeception\Module` class and defined in `Codeception\Module` namespace. All Codeception modules are autoloaded by searching in this particular namespace: `PhpBrowser` => `Codeception\Module\PhpBrowser`.
|
||||
|
||||
## What you should know before developing a module
|
||||
|
||||
The core principles:
|
||||
|
||||
1. Public methods of modules are actions of an actor inside a test. That's why they should be named in proper format:
|
||||
|
||||
```
|
||||
doSomeStuff() => $I->doSomeStuff() => I do some stuff
|
||||
doSomeStuffWith($a, $b) => $I->doSomeStuffWith("vodka", "gin"); => I do some stuff with "vodka", "gin"
|
||||
seeIsGreat() => $I->seeIsGreat() => I see is great
|
||||
```
|
||||
|
||||
* Each method that define environment should start with `am` or `have`
|
||||
* Each assertion should start with `see` prefix
|
||||
* Each method that returns values should start with `grab` (grabbers) or `have` (definitions)
|
||||
|
||||
Example:
|
||||
|
||||
```php
|
||||
$I->amSeller();
|
||||
$I->haveProducts(['vodka', 'gin']);
|
||||
$I->haveDiscount('0.1');
|
||||
$I->setPrice('gin', '10$');
|
||||
$I->seePrice('gin', '9.9');
|
||||
$price = $I->grabPriceFor('gin');
|
||||
```
|
||||
|
||||
2. Configuration parameters are set in `.suite.yml` config and stored in `config` property array of a module. All default values can be set there as well. Required parameters should be set in `requiredFields` property.
|
||||
|
||||
```php
|
||||
<?php
|
||||
protected $config = ['browser' => 'firefox'];
|
||||
protected $requiredFields = ['url'];
|
||||
?>
|
||||
```
|
||||
|
||||
You should not perform validation if `url` was set. Module would perform it for you, so you could access `$this->config['url']` inside a module.
|
||||
|
||||
3. If you use low-level clients in your module (PDO driver, framework client, selenium client) you should allow developers to access them. That's why you should define their instances as `public` properties of method.
|
||||
|
||||
Also you *may* provide a closure method to access low-level API
|
||||
|
||||
```php
|
||||
<?php
|
||||
$I->executeInSelenium(function(\WebDriverClient $wb) {
|
||||
$wd->manage()->addCookie(['name' => 'verified']);
|
||||
});
|
||||
?>
|
||||
```
|
||||
|
||||
4. Modules can be added to official repo, or published standalone. In any case module should be defined in `Codeception\Module` namespace. If you develop a module and you think it might be useful to others, please ask in Github Issues, maybe we would like to include it into the official repo.
|
||||
1470
vendor/codeception/base/src/Codeception/Module/REST.php
vendored
Normal file
1470
vendor/codeception/base/src/Codeception/Module/REST.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
695
vendor/codeception/base/src/Codeception/Module/Redis.php
vendored
Normal file
695
vendor/codeception/base/src/Codeception/Module/Redis.php
vendored
Normal file
@@ -0,0 +1,695 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Lib\Interfaces\RequiresPackage;
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\TestInterface;
|
||||
use Predis\Client as RedisDriver;
|
||||
|
||||
/**
|
||||
* This module uses the [Predis](https://github.com/nrk/predis) library
|
||||
* to interact with a Redis server.
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Stability: **beta**
|
||||
*
|
||||
* ## Configuration
|
||||
*
|
||||
* * **`host`** (`string`, default `'127.0.0.1'`) - The Redis host
|
||||
* * **`port`** (`int`, default `6379`) - The Redis port
|
||||
* * **`database`** (`int`, no default) - The Redis database. Needs to be specified.
|
||||
* * **`cleanupBefore`**: (`string`, default `'never'`) - Whether/when to flush the database:
|
||||
* * `suite`: at the beginning of every suite
|
||||
* * `test`: at the beginning of every test
|
||||
* * Any other value: never
|
||||
*
|
||||
* ### Example (`unit.suite.yml`)
|
||||
*
|
||||
* ```yaml
|
||||
* modules:
|
||||
* - Redis:
|
||||
* host: '127.0.0.1'
|
||||
* port: 6379
|
||||
* database: 0
|
||||
* cleanupBefore: 'never'
|
||||
* ```
|
||||
*
|
||||
* ## Public Properties
|
||||
*
|
||||
* * **driver** - Contains the Predis client/driver
|
||||
*
|
||||
* @author Marc Verney <marc@marcverney.net>
|
||||
*/
|
||||
class Redis extends CodeceptionModule implements RequiresPackage
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* No default value is set for the database, using this parameter.
|
||||
*/
|
||||
protected $config = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'cleanupBefore' => 'never'
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $requiredFields = [
|
||||
'database'
|
||||
];
|
||||
|
||||
/**
|
||||
* The Redis driver
|
||||
*
|
||||
* @var RedisDriver
|
||||
*/
|
||||
public $driver;
|
||||
|
||||
public function _requires()
|
||||
{
|
||||
return ['Predis\Client' => '"predis/predis": "^1.0"'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions to run after configuration is loaded
|
||||
*
|
||||
* @throws ModuleException
|
||||
*/
|
||||
public function _initialize()
|
||||
{
|
||||
try {
|
||||
$this->driver = new RedisDriver([
|
||||
'host' => $this->config['host'],
|
||||
'port' => $this->config['port'],
|
||||
'database' => $this->config['database']
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
throw new ModuleException(
|
||||
__CLASS__,
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Code to run before each suite
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
public function _beforeSuite($settings = [])
|
||||
{
|
||||
if ($this->config['cleanupBefore'] === 'suite') {
|
||||
$this->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Code to run before each test
|
||||
*
|
||||
* @param TestInterface $test
|
||||
*/
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
if ($this->config['cleanupBefore'] === 'test') {
|
||||
$this->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the keys in the Redis database
|
||||
*
|
||||
* @throws ModuleException
|
||||
*/
|
||||
public function cleanup()
|
||||
{
|
||||
try {
|
||||
$this->driver->flushdb();
|
||||
} catch (\Exception $e) {
|
||||
throw new ModuleException(
|
||||
__CLASS__,
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a given key
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // Strings
|
||||
* $I->grabFromRedis('string');
|
||||
*
|
||||
* // Lists: get all members
|
||||
* $I->grabFromRedis('example:list');
|
||||
*
|
||||
* // Lists: get a specific member
|
||||
* $I->grabFromRedis('example:list', 2);
|
||||
*
|
||||
* // Lists: get a range of elements
|
||||
* $I->grabFromRedis('example:list', 2, 4);
|
||||
*
|
||||
* // Sets: get all members
|
||||
* $I->grabFromRedis('example:set');
|
||||
*
|
||||
* // ZSets: get all members
|
||||
* $I->grabFromRedis('example:zset');
|
||||
*
|
||||
* // ZSets: get a range of members
|
||||
* $I->grabFromRedis('example:zset', 3, 12);
|
||||
*
|
||||
* // Hashes: get all fields of a key
|
||||
* $I->grabFromRedis('example:hash');
|
||||
*
|
||||
* // Hashes: get a specific field of a key
|
||||
* $I->grabFromRedis('example:hash', 'foo');
|
||||
* ```
|
||||
*
|
||||
* @param string $key The key name
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws ModuleException if the key does not exist
|
||||
*/
|
||||
public function grabFromRedis($key)
|
||||
{
|
||||
$args = func_get_args();
|
||||
|
||||
switch ($this->driver->type($key)) {
|
||||
case 'none':
|
||||
throw new ModuleException(
|
||||
$this,
|
||||
"Cannot grab key \"$key\" as it does not exist"
|
||||
);
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
$reply = $this->driver->get($key);
|
||||
break;
|
||||
|
||||
case 'list':
|
||||
if (count($args) === 2) {
|
||||
$reply = $this->driver->lindex($key, $args[1]);
|
||||
} else {
|
||||
$reply = $this->driver->lrange(
|
||||
$key,
|
||||
isset($args[1]) ? $args[1] : 0,
|
||||
isset($args[2]) ? $args[2] : -1
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'set':
|
||||
$reply = $this->driver->smembers($key);
|
||||
break;
|
||||
|
||||
case 'zset':
|
||||
if (count($args) === 2) {
|
||||
throw new ModuleException(
|
||||
$this,
|
||||
"The method grabFromRedis(), when used with sorted "
|
||||
. "sets, expects either one argument or three"
|
||||
);
|
||||
}
|
||||
$reply = $this->driver->zrange(
|
||||
$key,
|
||||
isset($args[2]) ? $args[1] : 0,
|
||||
isset($args[2]) ? $args[2] : -1,
|
||||
'WITHSCORES'
|
||||
);
|
||||
break;
|
||||
|
||||
case 'hash':
|
||||
$reply = isset($args[1])
|
||||
? $this->driver->hget($key, $args[1])
|
||||
: $this->driver->hgetall($key);
|
||||
break;
|
||||
|
||||
default:
|
||||
$reply = null;
|
||||
}
|
||||
|
||||
return $reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or modifies keys
|
||||
*
|
||||
* If $key already exists:
|
||||
*
|
||||
* - Strings: its value will be overwritten with $value
|
||||
* - Other types: $value items will be appended to its value
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // Strings: $value must be a scalar
|
||||
* $I->haveInRedis('string', 'Obladi Oblada');
|
||||
*
|
||||
* // Lists: $value can be a scalar or an array
|
||||
* $I->haveInRedis('list', ['riri', 'fifi', 'loulou']);
|
||||
*
|
||||
* // Sets: $value can be a scalar or an array
|
||||
* $I->haveInRedis('set', ['riri', 'fifi', 'loulou']);
|
||||
*
|
||||
* // ZSets: $value must be an associative array with scores
|
||||
* $I->haveInRedis('zset', ['riri' => 1, 'fifi' => 2, 'loulou' => 3]);
|
||||
*
|
||||
* // Hashes: $value must be an associative array
|
||||
* $I->haveInRedis('hash', ['obladi' => 'oblada']);
|
||||
* ```
|
||||
*
|
||||
* @param string $type The type of the key
|
||||
* @param string $key The key name
|
||||
* @param mixed $value The value
|
||||
*
|
||||
* @throws ModuleException
|
||||
*/
|
||||
public function haveInRedis($type, $key, $value)
|
||||
{
|
||||
switch (strtolower($type)) {
|
||||
case 'string':
|
||||
if (!is_scalar($value)) {
|
||||
throw new ModuleException(
|
||||
$this,
|
||||
'If second argument of haveInRedis() method is "string", '
|
||||
. 'third argument must be a scalar'
|
||||
);
|
||||
}
|
||||
$this->driver->set($key, $value);
|
||||
break;
|
||||
|
||||
case 'list':
|
||||
$this->driver->rpush($key, $value);
|
||||
break;
|
||||
|
||||
case 'set':
|
||||
$this->driver->sadd($key, $value);
|
||||
break;
|
||||
|
||||
case 'zset':
|
||||
if (!is_array($value)) {
|
||||
throw new ModuleException(
|
||||
$this,
|
||||
'If second argument of haveInRedis() method is "zset", '
|
||||
. 'third argument must be an (associative) array'
|
||||
);
|
||||
}
|
||||
$this->driver->zadd($key, $value);
|
||||
break;
|
||||
|
||||
case 'hash':
|
||||
if (!is_array($value)) {
|
||||
throw new ModuleException(
|
||||
$this,
|
||||
'If second argument of haveInRedis() method is "hash", '
|
||||
. 'third argument must be an array'
|
||||
);
|
||||
}
|
||||
$this->driver->hmset($key, $value);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ModuleException(
|
||||
$this,
|
||||
"Unknown type \"$type\" for key \"$key\". Allowed types are "
|
||||
. '"string", "list", "set", "zset", "hash"'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a key does not exist or, optionally, that it doesn't have the
|
||||
* provided $value
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // With only one argument, only checks the key does not exist
|
||||
* $I->dontSeeInRedis('example:string');
|
||||
*
|
||||
* // Checks a String does not exist or its value is not the one provided
|
||||
* $I->dontSeeInRedis('example:string', 'life');
|
||||
*
|
||||
* // Checks a List does not exist or its value is not the one provided (order of elements is compared).
|
||||
* $I->dontSeeInRedis('example:list', ['riri', 'fifi', 'loulou']);
|
||||
*
|
||||
* // Checks a Set does not exist or its value is not the one provided (order of members is ignored).
|
||||
* $I->dontSeeInRedis('example:set', ['riri', 'fifi', 'loulou']);
|
||||
*
|
||||
* // Checks a ZSet does not exist or its value is not the one provided (scores are required, order of members is compared)
|
||||
* $I->dontSeeInRedis('example:zset', ['riri' => 1, 'fifi' => 2, 'loulou' => 3]);
|
||||
*
|
||||
* // Checks a Hash does not exist or its value is not the one provided (order of members is ignored).
|
||||
* $I->dontSeeInRedis('example:hash', ['riri' => true, 'fifi' => 'Dewey', 'loulou' => 2]);
|
||||
* ```
|
||||
*
|
||||
* @param string $key The key name
|
||||
* @param mixed $value Optional. If specified, also checks the key has this
|
||||
* value. Booleans will be converted to 1 and 0 (even inside arrays)
|
||||
*/
|
||||
public function dontSeeInRedis($key, $value = null)
|
||||
{
|
||||
$this->assertFalse(
|
||||
(bool) $this->checkKeyExists($key, $value),
|
||||
"The key \"$key\" exists" . ($value ? ' and its value matches the one provided' : '')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a given key does not contain a given item
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // Strings: performs a substring search
|
||||
* $I->dontSeeRedisKeyContains('string', 'bar');
|
||||
*
|
||||
* // Lists
|
||||
* $I->dontSeeRedisKeyContains('example:list', 'poney');
|
||||
*
|
||||
* // Sets
|
||||
* $I->dontSeeRedisKeyContains('example:set', 'cat');
|
||||
*
|
||||
* // ZSets: check whether the zset has this member
|
||||
* $I->dontSeeRedisKeyContains('example:zset', 'jordan');
|
||||
*
|
||||
* // ZSets: check whether the zset has this member with this score
|
||||
* $I->dontSeeRedisKeyContains('example:zset', 'jordan', 23);
|
||||
*
|
||||
* // Hashes: check whether the hash has this field
|
||||
* $I->dontSeeRedisKeyContains('example:hash', 'magic');
|
||||
*
|
||||
* // Hashes: check whether the hash has this field with this value
|
||||
* $I->dontSeeRedisKeyContains('example:hash', 'magic', 32);
|
||||
* ```
|
||||
*
|
||||
* @param string $key The key
|
||||
* @param mixed $item The item
|
||||
* @param null $itemValue Optional and only used for zsets and hashes. If
|
||||
* specified, the method will also check that the $item has this value/score
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function dontSeeRedisKeyContains($key, $item, $itemValue = null)
|
||||
{
|
||||
$this->assertFalse(
|
||||
(bool) $this->checkKeyContains($key, $item, $itemValue),
|
||||
"The key \"$key\" contains " . (
|
||||
is_null($itemValue)
|
||||
? "\"$item\""
|
||||
: "[\"$item\" => \"$itemValue\"]"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a key exists, and optionally that it has the provided $value
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // With only one argument, only checks the key exists
|
||||
* $I->seeInRedis('example:string');
|
||||
*
|
||||
* // Checks a String exists and has the value "life"
|
||||
* $I->seeInRedis('example:string', 'life');
|
||||
*
|
||||
* // Checks the value of a List. Order of elements is compared.
|
||||
* $I->seeInRedis('example:list', ['riri', 'fifi', 'loulou']);
|
||||
*
|
||||
* // Checks the value of a Set. Order of members is ignored.
|
||||
* $I->seeInRedis('example:set', ['riri', 'fifi', 'loulou']);
|
||||
*
|
||||
* // Checks the value of a ZSet. Scores are required. Order of members is compared.
|
||||
* $I->seeInRedis('example:zset', ['riri' => 1, 'fifi' => 2, 'loulou' => 3]);
|
||||
*
|
||||
* // Checks the value of a Hash. Order of members is ignored.
|
||||
* $I->seeInRedis('example:hash', ['riri' => true, 'fifi' => 'Dewey', 'loulou' => 2]);
|
||||
* ```
|
||||
*
|
||||
* @param string $key The key name
|
||||
* @param mixed $value Optional. If specified, also checks the key has this
|
||||
* value. Booleans will be converted to 1 and 0 (even inside arrays)
|
||||
*/
|
||||
public function seeInRedis($key, $value = null)
|
||||
{
|
||||
$this->assertTrue(
|
||||
(bool) $this->checkKeyExists($key, $value),
|
||||
"Cannot find key \"$key\"" . ($value ? ' with the provided value' : '')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command directly to the Redis driver. See documentation at
|
||||
* https://github.com/nrk/predis
|
||||
* Every argument that follows the $command name will be passed to it.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->sendCommandToRedis('incr', 'example:string');
|
||||
* $I->sendCommandToRedis('strLen', 'example:string');
|
||||
* $I->sendCommandToRedis('lPop', 'example:list');
|
||||
* $I->sendCommandToRedis('zRangeByScore', 'example:set', '-inf', '+inf', ['withscores' => true, 'limit' => [1, 2]]);
|
||||
* $I->sendCommandToRedis('flushdb');
|
||||
* ```
|
||||
*
|
||||
* @param string $command The command name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function sendCommandToRedis($command)
|
||||
{
|
||||
return call_user_func_array(
|
||||
[$this->driver, $command],
|
||||
array_slice(func_get_args(), 1)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a given key contains a given item
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* // Strings: performs a substring search
|
||||
* $I->seeRedisKeyContains('example:string', 'bar');
|
||||
*
|
||||
* // Lists
|
||||
* $I->seeRedisKeyContains('example:list', 'poney');
|
||||
*
|
||||
* // Sets
|
||||
* $I->seeRedisKeyContains('example:set', 'cat');
|
||||
*
|
||||
* // ZSets: check whether the zset has this member
|
||||
* $I->seeRedisKeyContains('example:zset', 'jordan');
|
||||
*
|
||||
* // ZSets: check whether the zset has this member with this score
|
||||
* $I->seeRedisKeyContains('example:zset', 'jordan', 23);
|
||||
*
|
||||
* // Hashes: check whether the hash has this field
|
||||
* $I->seeRedisKeyContains('example:hash', 'magic');
|
||||
*
|
||||
* // Hashes: check whether the hash has this field with this value
|
||||
* $I->seeRedisKeyContains('example:hash', 'magic', 32);
|
||||
* ```
|
||||
*
|
||||
* @param string $key The key
|
||||
* @param mixed $item The item
|
||||
* @param null $itemValue Optional and only used for zsets and hashes. If
|
||||
* specified, the method will also check that the $item has this value/score
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function seeRedisKeyContains($key, $item, $itemValue = null)
|
||||
{
|
||||
$this->assertTrue(
|
||||
(bool) $this->checkKeyContains($key, $item, $itemValue),
|
||||
"The key \"$key\" does not contain " . (
|
||||
is_null($itemValue)
|
||||
? "\"$item\""
|
||||
: "[\"$item\" => \"$itemValue\"]"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts boolean values to "0" and "1"
|
||||
*
|
||||
* @param mixed $var The variable
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function boolToString($var)
|
||||
{
|
||||
$copy = is_array($var) ? $var : [$var];
|
||||
|
||||
foreach ($copy as $key => $value) {
|
||||
if (is_bool($value)) {
|
||||
$copy[$key] = $value ? '1' : '0';
|
||||
}
|
||||
}
|
||||
|
||||
return is_array($var) ? $copy : $copy[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a key contains a given item
|
||||
*
|
||||
* @param string $key The key
|
||||
* @param mixed $item The item
|
||||
* @param null $itemValue Optional and only used for zsets and hashes. If
|
||||
* specified, the method will also check that the $item has this value/score
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws ModuleException
|
||||
*/
|
||||
private function checkKeyContains($key, $item, $itemValue = null)
|
||||
{
|
||||
$result = null;
|
||||
|
||||
if (!is_scalar($item)) {
|
||||
throw new ModuleException(
|
||||
$this,
|
||||
"All arguments of [dont]seeRedisKeyContains() must be scalars"
|
||||
);
|
||||
}
|
||||
|
||||
switch ($this->driver->type($key)) {
|
||||
case 'string':
|
||||
$reply = $this->driver->get($key);
|
||||
$result = strpos($reply, $item) !== false;
|
||||
break;
|
||||
|
||||
case 'list':
|
||||
$reply = $this->driver->lrange($key, 0, -1);
|
||||
$result = in_array($item, $reply);
|
||||
break;
|
||||
|
||||
case 'set':
|
||||
$result = $this->driver->sismember($key, $item);
|
||||
break;
|
||||
|
||||
case 'zset':
|
||||
$reply = $this->driver->zscore($key, $item);
|
||||
|
||||
if (is_null($reply)) {
|
||||
$result = false;
|
||||
} elseif (!is_null($itemValue)) {
|
||||
$result = (float) $reply === (float) $itemValue;
|
||||
} else {
|
||||
$result = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'hash':
|
||||
$reply = $this->driver->hget($key, $item);
|
||||
|
||||
$result = is_null($itemValue)
|
||||
? !is_null($reply)
|
||||
: (string) $reply === (string) $itemValue;
|
||||
break;
|
||||
|
||||
case 'none':
|
||||
throw new ModuleException(
|
||||
$this,
|
||||
"Key \"$key\" does not exist"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a key exists and, optionally, whether it has a given $value
|
||||
*
|
||||
* @param string $key The key name
|
||||
* @param mixed $value Optional. If specified, also checks the key has this
|
||||
* value. Booleans will be converted to 1 and 0 (even inside arrays)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function checkKeyExists($key, $value = null)
|
||||
{
|
||||
$type = $this->driver->type($key);
|
||||
|
||||
if (is_null($value)) {
|
||||
return $type != 'none';
|
||||
}
|
||||
|
||||
$value = $this->boolToString($value);
|
||||
|
||||
switch ($type) {
|
||||
case 'string':
|
||||
$reply = $this->driver->get($key);
|
||||
// Allow non strict equality (2 equals '2')
|
||||
$result = $reply == $value;
|
||||
break;
|
||||
|
||||
case 'list':
|
||||
$reply = $this->driver->lrange($key, 0, -1);
|
||||
// Check both arrays have the same key/value pairs + same order
|
||||
$result = $reply === $value;
|
||||
break;
|
||||
|
||||
case 'set':
|
||||
$reply = $this->driver->smembers($key);
|
||||
// Only check both arrays have the same values
|
||||
sort($reply);
|
||||
sort($value);
|
||||
$result = $reply === $value;
|
||||
break;
|
||||
|
||||
case 'zset':
|
||||
$reply = $this->driver->zrange($key, 0, -1, 'WITHSCORES');
|
||||
// Check both arrays have the same key/value pairs + same order
|
||||
$reply = $this->scoresToFloat($reply);
|
||||
$value = $this->scoresToFloat($value);
|
||||
$result = $reply === $value;
|
||||
break;
|
||||
|
||||
case 'hash':
|
||||
$reply = $this->driver->hgetall($key);
|
||||
// Only check both arrays have the same key/value pairs (==)
|
||||
$result = $reply == $value;
|
||||
break;
|
||||
|
||||
default:
|
||||
$result = false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly cast the scores of a Zset associative array as float/double
|
||||
*
|
||||
* @param array $arr The ZSet associative array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function scoresToFloat(array $arr)
|
||||
{
|
||||
foreach ($arr as $member => $score) {
|
||||
$arr[$member] = (float) $score;
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
512
vendor/codeception/base/src/Codeception/Module/SOAP.php
vendored
Normal file
512
vendor/codeception/base/src/Codeception/Module/SOAP.php
vendored
Normal file
@@ -0,0 +1,512 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Lib\Interfaces\API;
|
||||
use Codeception\Lib\Interfaces\DependsOnModule;
|
||||
use Codeception\Lib\Notification;
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Exception\ModuleRequireException;
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\Lib\InnerBrowser;
|
||||
use Codeception\Util\Soap as SoapUtils;
|
||||
use Codeception\Util\XmlStructure;
|
||||
|
||||
/**
|
||||
* Module for testing SOAP WSDL web services.
|
||||
* Send requests and check if response matches the pattern.
|
||||
*
|
||||
* This module can be used either with frameworks or PHPBrowser.
|
||||
* It tries to guess the framework is is attached to.
|
||||
* If a endpoint is a full url then it uses PHPBrowser.
|
||||
*
|
||||
* ### Using Inside Framework
|
||||
*
|
||||
* Please note, that PHP SoapServer::handle method sends additional headers.
|
||||
* This may trigger warning: "Cannot modify header information"
|
||||
* If you use PHP SoapServer with framework, try to block call to this method in testing environment.
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **davert**
|
||||
* * Stability: **stable**
|
||||
* * Contact: codecept@davert.mail.ua
|
||||
*
|
||||
* ## Configuration
|
||||
*
|
||||
* * endpoint *required* - soap wsdl endpoint
|
||||
* * SOAPAction - replace SOAPAction HTTP header (Set to '' to SOAP 1.2)
|
||||
*
|
||||
* ## Public Properties
|
||||
*
|
||||
* * xmlRequest - last SOAP request (DOMDocument)
|
||||
* * xmlResponse - last SOAP response (DOMDocument)
|
||||
*
|
||||
*/
|
||||
class SOAP extends CodeceptionModule implements DependsOnModule
|
||||
{
|
||||
protected $config = [
|
||||
'schema' => "",
|
||||
'schema_url' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'framework_collect_buffer' => true
|
||||
];
|
||||
|
||||
protected $requiredFields = ['endpoint'];
|
||||
|
||||
protected $dependencyMessage = <<<EOF
|
||||
Example using PhpBrowser as backend for SOAP module.
|
||||
--
|
||||
modules:
|
||||
enabled:
|
||||
- SOAP:
|
||||
depends: PhpBrowser
|
||||
--
|
||||
Framework modules can be used as well for functional testing of SOAP API.
|
||||
EOF;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\BrowserKit\Client
|
||||
*/
|
||||
public $client = null;
|
||||
public $isFunctional = false;
|
||||
|
||||
/**
|
||||
* @var \DOMDocument
|
||||
*/
|
||||
public $xmlRequest = null;
|
||||
/**
|
||||
* @var \DOMDocument
|
||||
*/
|
||||
public $xmlResponse = null;
|
||||
|
||||
/**
|
||||
* @var XmlStructure
|
||||
*/
|
||||
protected $xmlStructure = null;
|
||||
|
||||
/**
|
||||
* @var InnerBrowser
|
||||
*/
|
||||
protected $connectionModule;
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->client = &$this->connectionModule->client;
|
||||
$this->buildRequest();
|
||||
$this->xmlResponse = null;
|
||||
$this->xmlStructure = null;
|
||||
}
|
||||
|
||||
protected function onReconfigure()
|
||||
{
|
||||
$this->buildRequest();
|
||||
$this->xmlResponse = null;
|
||||
$this->xmlStructure = null;
|
||||
}
|
||||
|
||||
public function _depends()
|
||||
{
|
||||
return ['Codeception\Lib\InnerBrowser' => $this->dependencyMessage];
|
||||
}
|
||||
|
||||
public function _inject(InnerBrowser $connectionModule)
|
||||
{
|
||||
$this->connectionModule = $connectionModule;
|
||||
if ($connectionModule instanceof Framework) {
|
||||
$this->isFunctional = true;
|
||||
}
|
||||
}
|
||||
|
||||
private function getClient()
|
||||
{
|
||||
if (!$this->client) {
|
||||
throw new ModuleRequireException($this, "Connection client is not available.");
|
||||
}
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
private function getXmlResponse()
|
||||
{
|
||||
if (!$this->xmlResponse) {
|
||||
throw new ModuleException($this, "No XML response, use `\$I->sendSoapRequest` to receive it");
|
||||
}
|
||||
return $this->xmlResponse;
|
||||
}
|
||||
|
||||
private function getXmlStructure()
|
||||
{
|
||||
if (!$this->xmlStructure) {
|
||||
$this->xmlStructure = new XmlStructure($this->getXmlResponse());
|
||||
}
|
||||
return $this->xmlStructure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare SOAP header.
|
||||
* Receives header name and parameters as array.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->haveSoapHeader('AuthHeader', array('username' => 'davert', 'password' => '123345'));
|
||||
* ```
|
||||
*
|
||||
* Will produce header:
|
||||
*
|
||||
* ```
|
||||
* <soapenv:Header>
|
||||
* <SessionHeader>
|
||||
* <AuthHeader>
|
||||
* <username>davert</username>
|
||||
* <password>12345</password>
|
||||
* </AuthHeader>
|
||||
* </soapenv:Header>
|
||||
* ```
|
||||
*
|
||||
* @param $header
|
||||
* @param array $params
|
||||
*/
|
||||
public function haveSoapHeader($header, $params = [])
|
||||
{
|
||||
$soap_schema_url = $this->config['schema_url'];
|
||||
$xml = $this->xmlRequest;
|
||||
$xmlHeader = $xml->documentElement->getElementsByTagNameNS($soap_schema_url, 'Header')->item(0);
|
||||
$headerEl = $xml->createElement($header);
|
||||
SoapUtils::arrayToXml($xml, $headerEl, $params);
|
||||
$xmlHeader->appendChild($headerEl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits request to endpoint.
|
||||
*
|
||||
* Requires of api function name and parameters.
|
||||
* Parameters can be passed either as DOMDocument, DOMNode, XML string, or array (if no attributes).
|
||||
*
|
||||
* You are allowed to execute as much requests as you need inside test.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* $I->sendSoapRequest('UpdateUser', '<user><id>1</id><name>notdavert</name></user>');
|
||||
* $I->sendSoapRequest('UpdateUser', \Codeception\Utils\Soap::request()->user
|
||||
* ->id->val(1)->parent()
|
||||
* ->name->val('notdavert');
|
||||
* ```
|
||||
*
|
||||
* @param $request
|
||||
* @param $body
|
||||
*/
|
||||
public function sendSoapRequest($action, $body = "")
|
||||
{
|
||||
$soap_schema_url = $this->config['schema_url'];
|
||||
$xml = $this->xmlRequest;
|
||||
$call = $xml->createElement('ns:' . $action);
|
||||
if ($body) {
|
||||
$bodyXml = SoapUtils::toXml($body);
|
||||
if ($bodyXml->hasChildNodes()) {
|
||||
foreach ($bodyXml->childNodes as $bodyChildNode) {
|
||||
$bodyNode = $xml->importNode($bodyChildNode, true);
|
||||
$call->appendChild($bodyNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$xmlBody = $xml->getElementsByTagNameNS($soap_schema_url, 'Body')->item(0);
|
||||
|
||||
// cleanup if body already set
|
||||
foreach ($xmlBody->childNodes as $node) {
|
||||
$xmlBody->removeChild($node);
|
||||
}
|
||||
|
||||
$xmlBody->appendChild($call);
|
||||
$this->debugSection("Request", $req = $xml->C14N());
|
||||
|
||||
if ($this->isFunctional && $this->config['framework_collect_buffer']) {
|
||||
$response = $this->processInternalRequest($action, $req);
|
||||
} else {
|
||||
$response = $this->processExternalRequest($action, $req);
|
||||
}
|
||||
|
||||
$this->debugSection("Response", (string) $response);
|
||||
$this->xmlResponse = SoapUtils::toXml($response);
|
||||
$this->xmlStructure = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks XML response equals provided XML.
|
||||
* Comparison is done by canonicalizing both xml`s.
|
||||
*
|
||||
* Parameters can be passed either as DOMDocument, DOMNode, XML string, or array (if no attributes).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeSoapResponseEquals("<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope><SOAP-ENV:Body><result>1</result></SOAP-ENV:Envelope>");
|
||||
*
|
||||
* $dom = new \DOMDocument();
|
||||
* $dom->load($file);
|
||||
* $I->seeSoapRequestIncludes($dom);
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* @param $xml
|
||||
*/
|
||||
public function seeSoapResponseEquals($xml)
|
||||
{
|
||||
$xml = SoapUtils::toXml($xml);
|
||||
$this->assertEquals($xml->C14N(), $this->getXmlResponse()->C14N());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks XML response includes provided XML.
|
||||
* Comparison is done by canonicalizing both xml`s.
|
||||
* Parameter can be passed either as XmlBuilder, DOMDocument, DOMNode, XML string, or array (if no attributes).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeSoapResponseIncludes("<result>1</result>");
|
||||
* $I->seeSoapRequestIncludes(\Codeception\Utils\Soap::response()->result->val(1));
|
||||
*
|
||||
* $dom = new \DDOMDocument();
|
||||
* $dom->load('template.xml');
|
||||
* $I->seeSoapRequestIncludes($dom);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $xml
|
||||
*/
|
||||
public function seeSoapResponseIncludes($xml)
|
||||
{
|
||||
$xml = $this->canonicalize($xml);
|
||||
$this->assertContains($xml, $this->getXmlResponse()->C14N(), "found in XML Response");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks XML response equals provided XML.
|
||||
* Comparison is done by canonicalizing both xml`s.
|
||||
*
|
||||
* Parameter can be passed either as XmlBuilder, DOMDocument, DOMNode, XML string, or array (if no attributes).
|
||||
*
|
||||
* @param $xml
|
||||
*/
|
||||
public function dontSeeSoapResponseEquals($xml)
|
||||
{
|
||||
$xml = SoapUtils::toXml($xml);
|
||||
\PHPUnit\Framework\Assert::assertXmlStringNotEqualsXmlString($xml->C14N(), $this->getXmlResponse()->C14N());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks XML response does not include provided XML.
|
||||
* Comparison is done by canonicalizing both xml`s.
|
||||
* Parameter can be passed either as XmlBuilder, DOMDocument, DOMNode, XML string, or array (if no attributes).
|
||||
*
|
||||
* @param $xml
|
||||
*/
|
||||
public function dontSeeSoapResponseIncludes($xml)
|
||||
{
|
||||
$xml = $this->canonicalize($xml);
|
||||
$this->assertNotContains($xml, $this->getXmlResponse()->C14N(), "found in XML Response");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks XML response contains provided structure.
|
||||
* Response elements will be compared with XML provided.
|
||||
* Only nodeNames are checked to see elements match.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
*
|
||||
* $I->seeSoapResponseContainsStructure("<query><name></name></query>");
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Use this method to check XML of valid structure is returned.
|
||||
* This method does not use schema for validation.
|
||||
* This method does not require path from root to match the structure.
|
||||
*
|
||||
* @param $xml
|
||||
*/
|
||||
public function seeSoapResponseContainsStructure($xml)
|
||||
{
|
||||
$xml = SoapUtils::toXml($xml);
|
||||
$this->debugSection("Structure", $xml->saveXML());
|
||||
$this->assertTrue((bool)$this->getXmlStructure()->matchXmlStructure($xml), "this structure is in response");
|
||||
}
|
||||
|
||||
/**
|
||||
* Opposite to `seeSoapResponseContainsStructure`
|
||||
* @param $xml
|
||||
*/
|
||||
public function dontSeeSoapResponseContainsStructure($xml)
|
||||
{
|
||||
$xml = SoapUtils::toXml($xml);
|
||||
$this->debugSection("Structure", $xml->saveXML());
|
||||
$this->assertFalse((bool)$this->getXmlStructure()->matchXmlStructure($xml), "this structure is in response");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks XML response with XPath locator
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeSoapResponseContainsXPath('//root/user[@id=1]');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $xpath
|
||||
*/
|
||||
public function seeSoapResponseContainsXPath($xpath)
|
||||
{
|
||||
$this->assertTrue($this->getXmlStructure()->matchesXpath($xpath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks XML response doesn't contain XPath locator
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->dontSeeSoapResponseContainsXPath('//root/user[@id=1]');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $xpath
|
||||
*/
|
||||
public function dontSeeSoapResponseContainsXPath($xpath)
|
||||
{
|
||||
$this->assertFalse($this->getXmlStructure()->matchesXpath($xpath));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks response code from server.
|
||||
*
|
||||
* @param $code
|
||||
*/
|
||||
public function seeSoapResponseCodeIs($code)
|
||||
{
|
||||
$this->assertEquals(
|
||||
$code,
|
||||
$this->client->getInternalResponse()->getStatus(),
|
||||
"soap response code matches expected"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use seeSoapResponseCodeIs instead
|
||||
*/
|
||||
public function seeResponseCodeIs($code)
|
||||
{
|
||||
Notification::deprecate('SOAP::seeResponseCodeIs deprecated in favor of seeSoapResponseCodeIs', 'SOAP Module');
|
||||
$this->seeSoapResponseCodeIs($code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns text contents of element.
|
||||
* Element is matched by either CSS or XPath
|
||||
*
|
||||
* @version 1.1
|
||||
* @param $cssOrXPath
|
||||
* @return string
|
||||
*/
|
||||
public function grabTextContentFrom($cssOrXPath)
|
||||
{
|
||||
$el = $this->getXmlStructure()->matchElement($cssOrXPath);
|
||||
return $el->textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns attribute of element.
|
||||
* Element is matched by either CSS or XPath
|
||||
*
|
||||
* @version 1.1
|
||||
* @param $cssOrXPath
|
||||
* @param $attribute
|
||||
* @return string
|
||||
*/
|
||||
public function grabAttributeFrom($cssOrXPath, $attribute)
|
||||
{
|
||||
$el = $this->getXmlStructure()->matchElement($cssOrXPath);
|
||||
if (!$el->hasAttribute($attribute)) {
|
||||
$this->fail("Attribute not found in element matched by '$cssOrXPath'");
|
||||
}
|
||||
return $el->getAttribute($attribute);
|
||||
}
|
||||
|
||||
protected function getSchema()
|
||||
{
|
||||
return $this->config['schema'];
|
||||
}
|
||||
|
||||
protected function canonicalize($xml)
|
||||
{
|
||||
return SoapUtils::toXml($xml)->C14N();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DOMDocument
|
||||
*/
|
||||
protected function buildRequest()
|
||||
{
|
||||
$soap_schema_url = $this->config['schema_url'];
|
||||
$xml = new \DOMDocument();
|
||||
$root = $xml->createElement('soapenv:Envelope');
|
||||
$xml->appendChild($root);
|
||||
$root->setAttribute('xmlns:ns', $this->getSchema());
|
||||
$root->setAttribute('xmlns:soapenv', $soap_schema_url);
|
||||
$body = $xml->createElementNS($soap_schema_url, 'soapenv:Body');
|
||||
$header = $xml->createElementNS($soap_schema_url, 'soapenv:Header');
|
||||
$root->appendChild($header);
|
||||
$root->appendChild($body);
|
||||
$this->xmlRequest = $xml;
|
||||
return $xml;
|
||||
}
|
||||
|
||||
protected function processRequest($action, $body)
|
||||
{
|
||||
$this->getClient()->request(
|
||||
'POST',
|
||||
$this->config['endpoint'],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'HTTP_Content-Type' => 'text/xml; charset=UTF-8',
|
||||
'HTTP_Content-Length' => strlen($body),
|
||||
'HTTP_SOAPAction' => isset($this->config['SOAPAction']) ? $this->config['SOAPAction'] : $action
|
||||
],
|
||||
$body
|
||||
);
|
||||
}
|
||||
|
||||
protected function processInternalRequest($action, $body)
|
||||
{
|
||||
ob_start();
|
||||
try {
|
||||
$this->getClient()->setServerParameter('HTTP_HOST', 'localhost');
|
||||
$this->processRequest($action, $body);
|
||||
} catch (\ErrorException $e) {
|
||||
// Zend_Soap outputs warning as an exception
|
||||
if (strpos($e->getMessage(), 'Warning: Cannot modify header information') === false) {
|
||||
ob_end_clean();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
$response = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function processExternalRequest($action, $body)
|
||||
{
|
||||
$this->processRequest($action, $body);
|
||||
return $this->client->getInternalResponse()->getContent();
|
||||
}
|
||||
}
|
||||
128
vendor/codeception/base/src/Codeception/Module/Sequence.php
vendored
Normal file
128
vendor/codeception/base/src/Codeception/Module/Sequence.php
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\TestInterface;
|
||||
|
||||
/**
|
||||
* Sequence solves data cleanup issue in alternative way.
|
||||
* Instead cleaning up the database between tests,
|
||||
* you can use generated unique names, that should not conflict.
|
||||
* When you create article on a site, for instance, you can assign it a unique name and then check it.
|
||||
*
|
||||
* This module has no actions, but introduces a function `sq` for generating unique sequences within test and
|
||||
* `sqs` for generating unique sequences across suite.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* Function `sq` generates sequence, the only parameter it takes, is id.
|
||||
* You can get back to previously generated sequence using that id:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* sq('post1'); // post1_521fbc63021eb
|
||||
* sq('post2'); // post2_521fbc6302266
|
||||
* sq('post1'); // post1_521fbc63021eb
|
||||
* ```
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->wantTo('create article');
|
||||
* $I->click('New Article');
|
||||
* $I->fillField('Title', sq('Article'));
|
||||
* $I->fillField('Body', 'Demo article with Lorem Ipsum');
|
||||
* $I->click('save');
|
||||
* $I->see(sq('Article') ,'#articles')
|
||||
* ```
|
||||
*
|
||||
* Populating Database:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
*
|
||||
* for ($i = 0; $i<10; $i++) {
|
||||
* $I->haveInDatabase('users', array('login' => sq("user$i"), 'email' => sq("user$i").'@email.com');
|
||||
* }
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* Cest Suite tests:
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* class UserTest
|
||||
* {
|
||||
* public function createUser(AcceptanceTester $I)
|
||||
* {
|
||||
* $I->createUser(sqs('user') . '@mailserver.com', sqs('login'), sqs('pwd'));
|
||||
* }
|
||||
*
|
||||
* public function checkEmail(AcceptanceTester $I)
|
||||
* {
|
||||
* $I->seeInEmailTo(sqs('user') . '@mailserver.com', sqs('login'));
|
||||
* }
|
||||
*
|
||||
* public function removeUser(AcceptanceTester $I)
|
||||
* {
|
||||
* $I->removeUser(sqs('user') . '@mailserver.com');
|
||||
* }
|
||||
* }
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* ### Config
|
||||
*
|
||||
* By default produces unique string with param as a prefix:
|
||||
*
|
||||
* ```
|
||||
* sq('user') => 'user_876asd8as87a'
|
||||
* ```
|
||||
*
|
||||
* This behavior can be configured using `prefix` config param.
|
||||
*
|
||||
* Old style sequences:
|
||||
*
|
||||
* ```yaml
|
||||
* Sequence:
|
||||
* prefix: '_'
|
||||
* ```
|
||||
*
|
||||
* Using id param inside prefix:
|
||||
*
|
||||
* ```yaml
|
||||
* Sequence:
|
||||
* prefix: '{id}.'
|
||||
* ```
|
||||
*/
|
||||
class Sequence extends CodeceptionModule
|
||||
{
|
||||
public static $hash = [];
|
||||
public static $suiteHash = [];
|
||||
public static $prefix = '';
|
||||
|
||||
protected $config = ['prefix' => '{id}_'];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
static::$prefix = $this->config['prefix'];
|
||||
}
|
||||
|
||||
public function _after(TestInterface $t)
|
||||
{
|
||||
self::$hash = [];
|
||||
}
|
||||
|
||||
public function _afterSuite()
|
||||
{
|
||||
self::$suiteHash = [];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('sq') && !function_exists('sqs')) {
|
||||
require_once __DIR__ . '/../Util/sq.php';
|
||||
} else {
|
||||
throw new ModuleException('Codeception\Module\Sequence', "function 'sq' and 'sqs' already defined");
|
||||
}
|
||||
150
vendor/codeception/base/src/Codeception/Module/Silex.php
vendored
Normal file
150
vendor/codeception/base/src/Codeception/Module/Silex.php
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\Lib\Interfaces\DoctrineProvider;
|
||||
use Codeception\TestInterface;
|
||||
use Symfony\Component\HttpKernel\Client;
|
||||
|
||||
/**
|
||||
* Module for testing Silex applications like you would regularly do with Silex\WebTestCase.
|
||||
* This module uses Symfony2 Crawler and HttpKernel to emulate requests and get response.
|
||||
*
|
||||
* This module may be considered experimental and require feedback and pull requests from you.
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **davert**
|
||||
* * Stability: **alpha**
|
||||
* * Contact: davert.codecept@resend.cc
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * app: **required** - path to Silex bootstrap file.
|
||||
* * em_service: 'db.orm.em' - use the stated EntityManager to pair with Doctrine Module.
|
||||
*
|
||||
* ### Bootstrap File
|
||||
*
|
||||
* Bootstrap is the same as [WebTestCase.createApplication](http://silex.sensiolabs.org/doc/testing.html#webtestcase).
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $app = require __DIR__.'/path/to/app.php';
|
||||
* $app['debug'] = true;
|
||||
* unset($app['exception_handler']);
|
||||
*
|
||||
* return $app; // optionally
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* ### Example (`functional.suite.yml`)
|
||||
*
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Silex:
|
||||
* app: 'app/bootstrap.php'
|
||||
*
|
||||
* ## Public Properties
|
||||
*
|
||||
* * app - `Silex\Application` instance received from bootstrap file
|
||||
*
|
||||
* Class Silex
|
||||
* @package Codeception\Module
|
||||
*/
|
||||
class Silex extends Framework implements DoctrineProvider
|
||||
{
|
||||
/**
|
||||
* @var \Silex\Application
|
||||
*/
|
||||
public $app;
|
||||
|
||||
protected $requiredFields = ['app'];
|
||||
protected $config = [
|
||||
'em_service' => 'db.orm.em'
|
||||
];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
if (!file_exists(Configuration::projectDir() . $this->config['app'])) {
|
||||
throw new ModuleConfigException(__CLASS__, "Bootstrap file {$this->config['app']} not found");
|
||||
}
|
||||
|
||||
$this->loadApp();
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->loadApp();
|
||||
$this->client = new Client($this->app);
|
||||
}
|
||||
|
||||
public function _getEntityManager()
|
||||
{
|
||||
if (!isset($this->app[$this->config['em_service']])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->app[$this->config['em_service']];
|
||||
}
|
||||
|
||||
protected function loadApp()
|
||||
{
|
||||
$this->app = require Configuration::projectDir() . $this->config['app'];
|
||||
// if $app is not returned but exists
|
||||
if (isset($app)) {
|
||||
$this->app = $app;
|
||||
}
|
||||
if (!isset($this->app)) {
|
||||
throw new ModuleConfigException(__CLASS__, "\$app instance was not received from bootstrap file");
|
||||
}
|
||||
|
||||
// make doctrine persistent
|
||||
$db_orm_em = $this->_getEntityManager();
|
||||
if ($db_orm_em) {
|
||||
$this->app->extend($this->config['em_service'], function () use ($db_orm_em) {
|
||||
return $db_orm_em;
|
||||
});
|
||||
}
|
||||
|
||||
// some Silex apps (like Bolt) may rely on global $app variable
|
||||
$GLOBALS['app'] = $this->app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of a class from the Container.
|
||||
*
|
||||
* Example
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->grabService('session');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $service
|
||||
* @return mixed
|
||||
*/
|
||||
public function grabService($service)
|
||||
{
|
||||
return $this->app[$service];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of recognized domain names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getInternalDomains()
|
||||
{
|
||||
$internalDomains = [];
|
||||
|
||||
foreach ($this->app['routes'] as $route) {
|
||||
if ($domain = $route->getHost()) {
|
||||
$internalDomains[] = '/^' . preg_quote($domain, '/') . '$/';
|
||||
}
|
||||
}
|
||||
|
||||
return $internalDomains;
|
||||
}
|
||||
}
|
||||
697
vendor/codeception/base/src/Codeception/Module/Symfony.php
vendored
Normal file
697
vendor/codeception/base/src/Codeception/Module/Symfony.php
vendored
Normal file
@@ -0,0 +1,697 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\Exception\ModuleRequireException;
|
||||
use Codeception\Lib\Connector\Symfony as SymfonyConnector;
|
||||
use Codeception\Lib\Interfaces\DoctrineProvider;
|
||||
use Codeception\Lib\Interfaces\PartedModule;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
use Symfony\Component\VarDumper\Cloner\Data;
|
||||
|
||||
/**
|
||||
* This module uses Symfony Crawler and HttpKernel to emulate requests and test response.
|
||||
*
|
||||
* ## Demo Project
|
||||
*
|
||||
* <https://github.com/Codeception/symfony-demo>
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* ### Symfony 4.x
|
||||
*
|
||||
* * app_path: 'src' - in Symfony 4 Kernel is located inside `src`
|
||||
* * environment: 'local' - environment used for load kernel
|
||||
* * kernel_class: 'App\Kernel' - kernel class name
|
||||
* * em_service: 'doctrine.orm.entity_manager' - use the stated EntityManager to pair with Doctrine Module.
|
||||
* * debug: true - turn on/off debug mode
|
||||
* * cache_router: 'false' - enable router caching between tests in order to [increase performance](http://lakion.com/blog/how-did-we-speed-up-sylius-behat-suite-with-blackfire)
|
||||
* * rebootable_client: 'true' - reboot client's kernel before each request
|
||||
*
|
||||
* #### Example (`functional.suite.yml`) - Symfony 4 Directory Structure
|
||||
*
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Symfony:
|
||||
* app_path: 'src'
|
||||
* environment: 'test'
|
||||
*
|
||||
*
|
||||
* ### Symfony 3.x
|
||||
*
|
||||
* * app_path: 'app' - specify custom path to your app dir, where the kernel interface is located.
|
||||
* * var_path: 'var' - specify custom path to your var dir, where bootstrap cache is located.
|
||||
* * environment: 'local' - environment used for load kernel
|
||||
* * kernel_class: 'AppKernel' - kernel class name
|
||||
* * em_service: 'doctrine.orm.entity_manager' - use the stated EntityManager to pair with Doctrine Module.
|
||||
* * debug: true - turn on/off debug mode
|
||||
* * cache_router: 'false' - enable router caching between tests in order to [increase performance](http://lakion.com/blog/how-did-we-speed-up-sylius-behat-suite-with-blackfire)
|
||||
* * rebootable_client: 'true' - reboot client's kernel before each request
|
||||
*
|
||||
* #### Example (`functional.suite.yml`) - Symfony 3 Directory Structure
|
||||
*
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Symfony:
|
||||
* app_path: 'app/front'
|
||||
* var_path: 'var'
|
||||
* environment: 'local_test'
|
||||
*
|
||||
*
|
||||
* ### Symfony 2.x
|
||||
*
|
||||
* * app_path: 'app' - specify custom path to your app dir, where bootstrap cache and kernel interface is located.
|
||||
* * environment: 'local' - environment used for load kernel
|
||||
* * kernel_class: 'AppKernel' - kernel class name
|
||||
* * debug: true - turn on/off debug mode
|
||||
* * em_service: 'doctrine.orm.entity_manager' - use the stated EntityManager to pair with Doctrine Module.
|
||||
* * cache_router: 'false' - enable router caching between tests in order to [increase performance](http://lakion.com/blog/how-did-we-speed-up-sylius-behat-suite-with-blackfire)
|
||||
* * rebootable_client: 'true' - reboot client's kernel before each request
|
||||
*
|
||||
* ### Example (`functional.suite.yml`) - Symfony 2.x Directory Structure
|
||||
*
|
||||
* ```
|
||||
* modules:
|
||||
* - Symfony:
|
||||
* app_path: 'app/front'
|
||||
* environment: 'local_test'
|
||||
* ```
|
||||
*
|
||||
* ## Public Properties
|
||||
*
|
||||
* * kernel - HttpKernel instance
|
||||
* * client - current Crawler instance
|
||||
*
|
||||
* ## Parts
|
||||
*
|
||||
* * services - allows to use Symfony DIC only with WebDriver or PhpBrowser modules.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```yaml
|
||||
* actor: AcceptanceTester
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Symfony:
|
||||
* part: SERVICES
|
||||
* - Doctrine2:
|
||||
* depends: Symfony
|
||||
* - WebDriver:
|
||||
* url: http://your-url.com
|
||||
* browser: phantomjs
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
class Symfony extends Framework implements DoctrineProvider, PartedModule
|
||||
{
|
||||
private static $possibleKernelClasses = [
|
||||
'AppKernel', // Symfony Standard
|
||||
'App\Kernel', // Symfony Flex
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\HttpKernel\Kernel
|
||||
*/
|
||||
public $kernel;
|
||||
|
||||
public $config = [
|
||||
'app_path' => 'app',
|
||||
'var_path' => 'app',
|
||||
'kernel_class' => null,
|
||||
'environment' => 'test',
|
||||
'debug' => true,
|
||||
'cache_router' => false,
|
||||
'em_service' => 'doctrine.orm.entity_manager',
|
||||
'rebootable_client' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function _parts()
|
||||
{
|
||||
return ['services'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $kernelClass;
|
||||
|
||||
/**
|
||||
* Services that should be persistent permanently for all tests
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $permanentServices = [];
|
||||
|
||||
/**
|
||||
* Services that should be persistent during test execution between kernel reboots
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $persistentServices = [];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
|
||||
$this->initializeSymfonyCache();
|
||||
$this->kernelClass = $this->getKernelClass();
|
||||
$maxNestingLevel = 200; // Symfony may have very long nesting level
|
||||
$xdebugMaxLevelKey = 'xdebug.max_nesting_level';
|
||||
if (ini_get($xdebugMaxLevelKey) < $maxNestingLevel) {
|
||||
ini_set($xdebugMaxLevelKey, $maxNestingLevel);
|
||||
}
|
||||
|
||||
$this->kernel = new $this->kernelClass($this->config['environment'], $this->config['debug']);
|
||||
$this->kernel->boot();
|
||||
|
||||
if ($this->config['cache_router'] === true) {
|
||||
$this->persistService('router', true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Require Symfonys bootstrap.php.cache only for PHP Version < 7
|
||||
*
|
||||
* @throws ModuleRequireException
|
||||
*/
|
||||
private function initializeSymfonyCache()
|
||||
{
|
||||
$cache = Configuration::projectDir() . $this->config['var_path'] . DIRECTORY_SEPARATOR . 'bootstrap.php.cache';
|
||||
if (PHP_VERSION_ID < 70000 && !file_exists($cache)) {
|
||||
throw new ModuleRequireException(
|
||||
__CLASS__,
|
||||
"Symfony bootstrap file not found in $cache\n \n" .
|
||||
"Please specify path to bootstrap file using `var_path` config option\n \n" .
|
||||
"If you are trying to load bootstrap from a Bundle provide path like:\n \n" .
|
||||
"modules:\n enabled:\n" .
|
||||
" - Symfony:\n" .
|
||||
" var_path: '../../app'\n" .
|
||||
" app_path: '../../app'"
|
||||
);
|
||||
}
|
||||
if (file_exists($cache)) {
|
||||
require_once $cache;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize new client instance before each test
|
||||
*/
|
||||
public function _before(\Codeception\TestInterface $test)
|
||||
{
|
||||
$this->persistentServices = array_merge($this->persistentServices, $this->permanentServices);
|
||||
$this->client = new SymfonyConnector($this->kernel, $this->persistentServices, $this->config['rebootable_client']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update permanent services after each test
|
||||
*/
|
||||
public function _after(\Codeception\TestInterface $test)
|
||||
{
|
||||
foreach ($this->permanentServices as $serviceName => $service) {
|
||||
$this->permanentServices[$serviceName] = $this->grabService($serviceName);
|
||||
}
|
||||
parent::_after($test);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve Entity Manager.
|
||||
*
|
||||
* EM service is retrieved once and then that instance returned on each call
|
||||
*/
|
||||
public function _getEntityManager()
|
||||
{
|
||||
if ($this->kernel === null) {
|
||||
$this->fail('Symfony2 platform module is not loaded');
|
||||
}
|
||||
if (!isset($this->permanentServices[$this->config['em_service']])) {
|
||||
// try to persist configured EM
|
||||
$this->persistService($this->config['em_service'], true);
|
||||
|
||||
if ($this->_getContainer()->has('doctrine')) {
|
||||
$this->persistService('doctrine', true);
|
||||
}
|
||||
if ($this->_getContainer()->has('doctrine.orm.default_entity_manager')) {
|
||||
$this->persistService('doctrine.orm.default_entity_manager', true);
|
||||
}
|
||||
if ($this->_getContainer()->has('doctrine.dbal.backend_connection')) {
|
||||
$this->persistService('doctrine.dbal.backend_connection', true);
|
||||
}
|
||||
}
|
||||
return $this->permanentServices[$this->config['em_service']];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return container.
|
||||
*
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public function _getContainer()
|
||||
{
|
||||
return $this->kernel->getContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to guess the kernel location.
|
||||
*
|
||||
* When the Kernel is located, the file is required.
|
||||
*
|
||||
* @return string The Kernel class name
|
||||
*/
|
||||
protected function getKernelClass()
|
||||
{
|
||||
$path = codecept_root_dir() . $this->config['app_path'];
|
||||
if (!file_exists(codecept_root_dir() . $this->config['app_path'])) {
|
||||
throw new ModuleRequireException(
|
||||
__CLASS__,
|
||||
"Can't load Kernel from $path.\n"
|
||||
. "Directory does not exists. Use `app_path` parameter to provide valid application path"
|
||||
);
|
||||
}
|
||||
|
||||
$finder = new Finder();
|
||||
$finder->name('*Kernel.php')->depth('0')->in($path);
|
||||
$results = iterator_to_array($finder);
|
||||
if (!count($results)) {
|
||||
throw new ModuleRequireException(
|
||||
__CLASS__,
|
||||
"File with Kernel class was not found at $path. "
|
||||
. "Specify directory where file with Kernel class for your application is located with `app_path` parameter."
|
||||
);
|
||||
}
|
||||
|
||||
if (file_exists(codecept_root_dir() . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php')) {
|
||||
// ensure autoloader from this dir is loaded
|
||||
require_once codecept_root_dir() . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
|
||||
}
|
||||
|
||||
$filesRealPath = array_map(function ($file) {
|
||||
require_once $file;
|
||||
return $file->getRealPath();
|
||||
}, $results);
|
||||
|
||||
$possibleKernelClasses = $this->getPossibleKernelClasses();
|
||||
|
||||
foreach ($possibleKernelClasses as $class) {
|
||||
if (class_exists($class)) {
|
||||
$refClass = new \ReflectionClass($class);
|
||||
if ($file = array_search($refClass->getFileName(), $filesRealPath)) {
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new ModuleRequireException(
|
||||
__CLASS__,
|
||||
"Kernel class was not found in $file. "
|
||||
. "Specify directory where file with Kernel class for your application is located with `app_path` parameter."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get service $serviceName and add it to the lists of persistent services.
|
||||
* If $isPermanent then service becomes persistent between tests
|
||||
*
|
||||
* @param string $serviceName
|
||||
* @param boolean $isPermanent
|
||||
*/
|
||||
public function persistService($serviceName, $isPermanent = false)
|
||||
{
|
||||
$service = $this->grabService($serviceName);
|
||||
$this->persistentServices[$serviceName] = $service;
|
||||
if ($isPermanent) {
|
||||
$this->permanentServices[$serviceName] = $service;
|
||||
}
|
||||
if ($this->client) {
|
||||
$this->client->persistentServices[$serviceName] = $service;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove service $serviceName from the lists of persistent services.
|
||||
*
|
||||
* @param string $serviceName
|
||||
*/
|
||||
public function unpersistService($serviceName)
|
||||
{
|
||||
if (isset($this->persistentServices[$serviceName])) {
|
||||
unset($this->persistentServices[$serviceName]);
|
||||
}
|
||||
if (isset($this->permanentServices[$serviceName])) {
|
||||
unset($this->permanentServices[$serviceName]);
|
||||
}
|
||||
if ($this->client && isset($this->client->persistentServices[$serviceName])) {
|
||||
unset($this->client->persistentServices[$serviceName]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate previously cached routes.
|
||||
*/
|
||||
public function invalidateCachedRouter()
|
||||
{
|
||||
$this->unpersistService('router');
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens web page using route name and parameters.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->amOnRoute('posts.create');
|
||||
* $I->amOnRoute('posts.show', array('id' => 34));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $routeName
|
||||
* @param array $params
|
||||
*/
|
||||
public function amOnRoute($routeName, array $params = [])
|
||||
{
|
||||
$router = $this->grabService('router');
|
||||
if (!$router->getRouteCollection()->get($routeName)) {
|
||||
$this->fail(sprintf('Route with name "%s" does not exists.', $routeName));
|
||||
}
|
||||
$url = $router->generate($routeName, $params);
|
||||
$this->amOnPage($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that current url matches route.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeCurrentRouteIs('posts.index');
|
||||
* $I->seeCurrentRouteIs('posts.show', array('id' => 8));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $routeName
|
||||
* @param array $params
|
||||
*/
|
||||
public function seeCurrentRouteIs($routeName, array $params = [])
|
||||
{
|
||||
$router = $this->grabService('router');
|
||||
if (!$router->getRouteCollection()->get($routeName)) {
|
||||
$this->fail(sprintf('Route with name "%s" does not exists.', $routeName));
|
||||
}
|
||||
|
||||
$uri = explode('?', $this->grabFromCurrentUrl())[0];
|
||||
try {
|
||||
$match = $router->match($uri);
|
||||
} catch (\Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
|
||||
$this->fail(sprintf('The "%s" url does not match with any route', $uri));
|
||||
}
|
||||
$expected = array_merge(['_route' => $routeName], $params);
|
||||
$intersection = array_intersect_assoc($expected, $match);
|
||||
|
||||
$this->assertEquals($expected, $intersection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that current url matches route.
|
||||
* Unlike seeCurrentRouteIs, this can matches without exact route parameters
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeCurrentRouteMatches('my_blog_pages');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $routeName
|
||||
*/
|
||||
public function seeInCurrentRoute($routeName)
|
||||
{
|
||||
$router = $this->grabService('router');
|
||||
if (!$router->getRouteCollection()->get($routeName)) {
|
||||
$this->fail(sprintf('Route with name "%s" does not exists.', $routeName));
|
||||
}
|
||||
|
||||
$uri = explode('?', $this->grabFromCurrentUrl())[0];
|
||||
try {
|
||||
$matchedRouteName = $router->match($uri)['_route'];
|
||||
} catch (\Symfony\Component\Routing\Exception\ResourceNotFoundException $e) {
|
||||
$this->fail(sprintf('The "%s" url does not match with any route', $uri));
|
||||
}
|
||||
|
||||
$this->assertEquals($matchedRouteName, $routeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the desired number of emails was sent.
|
||||
* If no argument is provided then at least one email must be sent to satisfy the check.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeEmailIsSent(2);
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param null|int $expectedCount
|
||||
*/
|
||||
public function seeEmailIsSent($expectedCount = null)
|
||||
{
|
||||
$profile = $this->getProfile();
|
||||
if (!$profile) {
|
||||
$this->fail('Emails can\'t be tested without Profiler');
|
||||
}
|
||||
if (!$profile->hasCollector('swiftmailer')) {
|
||||
$this->fail('Emails can\'t be tested without SwiftMailer connector');
|
||||
}
|
||||
|
||||
if (!is_int($expectedCount) && !is_null($expectedCount)) {
|
||||
$this->fail(sprintf(
|
||||
'The required number of emails must be either an integer or null. "%s" was provided.',
|
||||
print_r($expectedCount, true)
|
||||
));
|
||||
}
|
||||
|
||||
$realCount = $profile->getCollector('swiftmailer')->getMessageCount();
|
||||
if ($expectedCount === null) {
|
||||
$this->assertGreaterThan(0, $realCount);
|
||||
} else {
|
||||
$this->assertEquals(
|
||||
$expectedCount,
|
||||
$realCount,
|
||||
sprintf(
|
||||
'Expected number of sent emails was %d, but in reality %d %s sent.',
|
||||
$expectedCount,
|
||||
$realCount,
|
||||
$realCount === 2 ? 'was' : 'were'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that no email was sent. This is an alias for seeEmailIsSent(0).
|
||||
*
|
||||
* @part email
|
||||
*/
|
||||
public function dontSeeEmailIsSent()
|
||||
{
|
||||
$this->seeEmailIsSent(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs a service from Symfony DIC container.
|
||||
* Recommended to use for unit testing.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $em = $I->grabServiceFromContainer('doctrine');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $service
|
||||
* @return mixed
|
||||
* @part services
|
||||
* @deprecated Use grabService instead
|
||||
*/
|
||||
public function grabServiceFromContainer($service)
|
||||
{
|
||||
return $this->grabService($service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs a service from Symfony DIC container.
|
||||
* Recommended to use for unit testing.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $em = $I->grabService('doctrine');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $service
|
||||
* @return mixed
|
||||
* @part services
|
||||
*/
|
||||
public function grabService($service)
|
||||
{
|
||||
$container = $this->_getContainer();
|
||||
if (!$container->has($service)) {
|
||||
$this->fail("Service $service is not available in container");
|
||||
}
|
||||
return $container->get($service);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\HttpKernel\Profiler\Profile
|
||||
*/
|
||||
protected function getProfile()
|
||||
{
|
||||
$container = $this->_getContainer();
|
||||
if (!$container->has('profiler')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$profiler = $this->grabService('profiler');
|
||||
$response = $this->client->getResponse();
|
||||
if (null === $response) {
|
||||
$this->fail("You must perform a request before using this method.");
|
||||
}
|
||||
return $profiler->loadProfileFromResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
*/
|
||||
protected function debugResponse($url)
|
||||
{
|
||||
parent::debugResponse($url);
|
||||
|
||||
if ($profile = $this->getProfile()) {
|
||||
if ($profile->hasCollector('security')) {
|
||||
if ($profile->getCollector('security')->isAuthenticated()) {
|
||||
$roles = $profile->getCollector('security')->getRoles();
|
||||
|
||||
if ($roles instanceof Data) {
|
||||
$roles = $this->extractRawRoles($roles);
|
||||
}
|
||||
|
||||
$this->debugSection(
|
||||
'User',
|
||||
$profile->getCollector('security')->getUser()
|
||||
. ' [' . implode(',', $roles) . ']'
|
||||
);
|
||||
} else {
|
||||
$this->debugSection('User', 'Anonymous');
|
||||
}
|
||||
}
|
||||
if ($profile->hasCollector('swiftmailer')) {
|
||||
$messages = $profile->getCollector('swiftmailer')->getMessageCount();
|
||||
if ($messages) {
|
||||
$this->debugSection('Emails', $messages . ' sent');
|
||||
}
|
||||
}
|
||||
if ($profile->hasCollector('timer')) {
|
||||
$this->debugSection('Time', $profile->getCollector('timer')->getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Data $data
|
||||
* @return array
|
||||
*/
|
||||
private function extractRawRoles(Data $data)
|
||||
{
|
||||
if ($this->dataRevealsValue($data)) {
|
||||
$roles = $data->getValue();
|
||||
} else {
|
||||
$raw = $data->getRawData();
|
||||
$roles = isset($raw[1]) ? $raw[1] : [];
|
||||
}
|
||||
|
||||
return $roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of recognized domain names.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getInternalDomains()
|
||||
{
|
||||
$internalDomains = [];
|
||||
|
||||
$routes = $this->grabService('router')->getRouteCollection();
|
||||
/* @var \Symfony\Component\Routing\Route $route */
|
||||
foreach ($routes as $route) {
|
||||
if (!is_null($route->getHost())) {
|
||||
$compiled = $route->compile();
|
||||
if (!is_null($compiled->getHostRegex())) {
|
||||
$internalDomains[] = $compiled->getHostRegex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($internalDomains);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reboot client's kernel.
|
||||
* Can be used to manually reboot kernel when 'rebootable_client' => false
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* ...
|
||||
* perform some requests
|
||||
* ...
|
||||
* $I->rebootClientKernel();
|
||||
* ...
|
||||
* perform other requests
|
||||
* ...
|
||||
*
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
public function rebootClientKernel()
|
||||
{
|
||||
if ($this->client) {
|
||||
$this->client->rebootKernel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public API from Data changed from Symfony 3.2 to 3.3.
|
||||
*
|
||||
* @param \Symfony\Component\VarDumper\Cloner\Data $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function dataRevealsValue(Data $data)
|
||||
{
|
||||
return method_exists($data, 'getValue');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of the possible kernel classes based on the module configuration
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getPossibleKernelClasses()
|
||||
{
|
||||
if (empty($this->config['kernel_class'])) {
|
||||
return self::$possibleKernelClasses;
|
||||
}
|
||||
|
||||
if (!is_string($this->config['kernel_class'])) {
|
||||
throw new ModuleException(
|
||||
__CLASS__,
|
||||
"Parameter 'kernel_class' must have 'string' type.\n"
|
||||
);
|
||||
}
|
||||
|
||||
return [$this->config['kernel_class']];
|
||||
}
|
||||
}
|
||||
3303
vendor/codeception/base/src/Codeception/Module/WebDriver.php
vendored
Normal file
3303
vendor/codeception/base/src/Codeception/Module/WebDriver.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
165
vendor/codeception/base/src/Codeception/Module/XMLRPC.php
vendored
Normal file
165
vendor/codeception/base/src/Codeception/Module/XMLRPC.php
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Lib\Interfaces\API;
|
||||
use Codeception\Module as CodeceptionModule;
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Exception\ModuleRequireException;
|
||||
use Codeception\TestInterface;
|
||||
|
||||
/**
|
||||
* Module for testing XMLRPC WebService.
|
||||
*
|
||||
* This module can be used either with frameworks or PHPBrowser.
|
||||
* It tries to guess the framework is is attached to.
|
||||
*
|
||||
* Whether framework is used it operates via standard framework modules.
|
||||
* Otherwise sends raw HTTP requests to url via PHPBrowser.
|
||||
*
|
||||
* ## Requirements
|
||||
*
|
||||
* * Module requires installed php_xmlrpc extension
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **tiger-seo**
|
||||
* * Stability: **beta**
|
||||
* * Contact: tiger.seo@gmail.com
|
||||
*
|
||||
* ## Configuration
|
||||
*
|
||||
* * url *optional* - the url of api
|
||||
*
|
||||
* ## Public Properties
|
||||
*
|
||||
* * headers - array of headers going to be sent.
|
||||
* * params - array of sent data
|
||||
* * response - last response (string)
|
||||
*
|
||||
* @since 1.1.5
|
||||
* @author tiger.seo@gmail.com
|
||||
*/
|
||||
class XMLRPC extends CodeceptionModule implements API
|
||||
{
|
||||
protected $config = ['url' => ""];
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\BrowserKit\Client
|
||||
*/
|
||||
public $client = null;
|
||||
public $is_functional = false;
|
||||
|
||||
public $headers = [];
|
||||
public $params = [];
|
||||
public $response = "";
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
if (!function_exists('xmlrpc_encode_request')) {
|
||||
throw new ModuleRequireException(__CLASS__, "XMLRPC module requires installed php_xmlrpc extension");
|
||||
}
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
if (!$this->client) {
|
||||
if (!strpos($this->config['url'], '://')) {
|
||||
// not valid url
|
||||
foreach ($this->getModules() as $module) {
|
||||
if ($module instanceof Framework) {
|
||||
$this->client = $module->client;
|
||||
$this->is_functional = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!$this->hasModule('PhpBrowser')) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"For XMLRPC testing via HTTP please enable PhpBrowser module"
|
||||
);
|
||||
}
|
||||
$this->client = $this->getModule('PhpBrowser')->client;
|
||||
}
|
||||
if (!$this->client) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"Client for XMLRPC requests not initialized.\n"
|
||||
. "Provide either PhpBrowser module, or a framework module which shares FrameworkInterface"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->headers = [];
|
||||
$this->params = [];
|
||||
$this->response = '';
|
||||
|
||||
$this->client->setServerParameters([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets HTTP header
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*/
|
||||
public function haveHttpHeader($name, $value)
|
||||
{
|
||||
$this->headers[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks response code.
|
||||
*
|
||||
* @param $num
|
||||
*/
|
||||
public function seeResponseCodeIs($num)
|
||||
{
|
||||
\PHPUnit\Framework\Assert::assertEquals($num, $this->client->getInternalResponse()->getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks weather last response was valid XMLRPC.
|
||||
* This is done with xmlrpc_decode function.
|
||||
*
|
||||
*/
|
||||
public function seeResponseIsXMLRPC()
|
||||
{
|
||||
$result = xmlrpc_decode($this->response);
|
||||
\PHPUnit\Framework\Assert::assertNotNull($result, 'Invalid response document returned from XmlRpc server');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a XMLRPC method call to remote XMLRPC-server.
|
||||
*
|
||||
* @param string $methodName
|
||||
* @param array $parameters
|
||||
*/
|
||||
public function sendXMLRPCMethodCall($methodName, $parameters = [])
|
||||
{
|
||||
if (!array_key_exists('Content-Type', $this->headers)) {
|
||||
$this->headers['Content-Type'] = 'text/xml';
|
||||
}
|
||||
|
||||
foreach ($this->headers as $header => $val) {
|
||||
$this->client->setServerParameter("HTTP_$header", $val);
|
||||
}
|
||||
|
||||
$url = $this->config['url'];
|
||||
|
||||
if (is_array($parameters)) {
|
||||
$parameters = $this->scalarizeArray($parameters);
|
||||
}
|
||||
|
||||
$requestBody = xmlrpc_encode_request($methodName, array_values($parameters));
|
||||
|
||||
$this->debugSection('Request', $url . PHP_EOL . $requestBody);
|
||||
$this->client->request('POST', $url, [], [], [], $requestBody);
|
||||
|
||||
$this->response = $this->client->getInternalResponse()->getContent();
|
||||
$this->debugSection('Response', $this->response);
|
||||
}
|
||||
}
|
||||
265
vendor/codeception/base/src/Codeception/Module/Yii1.php
vendored
Normal file
265
vendor/codeception/base/src/Codeception/Module/Yii1.php
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Lib\Interfaces\PartedModule;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Lib\Connector\Yii1 as Yii1Connector;
|
||||
use Codeception\Util\ReflectionHelper;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* This module provides integration with [Yii Framework 1.1](http://www.yiiframework.com/doc/guide/).
|
||||
*
|
||||
* The following configurations are available for this module:
|
||||
*
|
||||
* * `appPath` - full path to the application, include index.php</li>
|
||||
* * `url` - full url to the index.php entry script</li>
|
||||
*
|
||||
* In your index.php you must return an array with correct configuration for the application:
|
||||
*
|
||||
* For the simple created yii application index.php will be like this:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* // change the following paths if necessary
|
||||
* $yii=dirname(__FILE__).'/../yii/framework/yii.php';
|
||||
* $config=dirname(__FILE__).'/protected/config/main.php';
|
||||
*
|
||||
* // remove the following lines when in production mode
|
||||
* defined('YII_DEBUG') or define('YII_DEBUG',true);
|
||||
* // specify how many levels of call stack should be shown in each log message
|
||||
* defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
|
||||
* require_once($yii);
|
||||
* return array(
|
||||
* 'class' => 'CWebApplication',
|
||||
* 'config' => $config,
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* You can use this module by setting params in your `functional.suite.yml`:
|
||||
*
|
||||
* ```yaml
|
||||
* actor: FunctionalTester
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Yii1:
|
||||
* appPath: '/path/to/index.php'
|
||||
* url: 'http://localhost/path/to/index.php'
|
||||
* - \Helper\Functional
|
||||
* ```
|
||||
*
|
||||
* You will also need to install [Codeception-Yii Bridge](https://github.com/Codeception/YiiBridge)
|
||||
* which include component wrappers for testing.
|
||||
*
|
||||
* When you are done, you can test this module by creating new empty Yii application and creating this Cept scenario:
|
||||
*
|
||||
* ```
|
||||
* php codecept.phar g:cept functional IndexCept
|
||||
* ```
|
||||
*
|
||||
* and write it as in example:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I = new FunctionalTester($scenario);
|
||||
* $I->wantTo('Test index page');
|
||||
* $I->amOnPage('/index.php');
|
||||
* $I->see('My Web Application','#header #logo');
|
||||
* $I->click('Login');
|
||||
* $I->see('Login','h1');
|
||||
* $I->see('Username');
|
||||
* $I->fillField('#LoginForm_username','demo');
|
||||
* $I->fillField('#LoginForm_password','demo');
|
||||
* $I->click('#login-form input[type="submit"]');
|
||||
* $I->seeLink('Logout (demo)');
|
||||
* $I->click('Logout (demo)');
|
||||
* $I->seeLink('Login');
|
||||
* ```
|
||||
*
|
||||
* Then run codeception: php codecept.phar --steps run functional
|
||||
* You must see "OK" and that all steps are marked with asterisk (*).
|
||||
* Do not forget that after adding module in your functional.suite.yml you must run codeception "build" command.
|
||||
*
|
||||
* ### Public Properties
|
||||
*
|
||||
* `client`: instance of `\Codeception\Lib\Connector\Yii1`
|
||||
*
|
||||
* ### Parts
|
||||
*
|
||||
* If you ever encounter error message:
|
||||
*
|
||||
* ```
|
||||
* Yii1 module conflicts with WebDriver
|
||||
* ```
|
||||
*
|
||||
* you should include Yii module partially, with `init` part only
|
||||
*
|
||||
* * `init`: only initializes module and not provides any actions from it. Can be used for unit/acceptance tests to avoid conflicts.
|
||||
*
|
||||
* ### Acceptance Testing Example:
|
||||
*
|
||||
* In `acceptance.suite.yml`:
|
||||
*
|
||||
* ```yaml
|
||||
* class_name: AcceptanceTester
|
||||
* modules:
|
||||
* enabled:
|
||||
* - WebDriver:
|
||||
* browser: firefox
|
||||
* url: http://localhost
|
||||
* - Yii1:
|
||||
* appPath: '/path/to/index.php'
|
||||
* url: 'http://localhost/path/to/index.php'
|
||||
* part: init # to not conflict with WebDriver
|
||||
* - \Helper\Acceptance
|
||||
* ```
|
||||
*/
|
||||
class Yii1 extends Framework implements PartedModule
|
||||
{
|
||||
|
||||
/**
|
||||
* Application path and url must be set always
|
||||
* @var array
|
||||
*/
|
||||
protected $requiredFields = ['appPath', 'url'];
|
||||
|
||||
/**
|
||||
* Application settings array('class'=>'YourAppClass','config'=>'YourAppArrayConfig');
|
||||
* @var array
|
||||
*/
|
||||
private $appSettings;
|
||||
|
||||
private $_appConfig;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
if (!file_exists($this->config['appPath'])) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"Couldn't load application config file {$this->config['appPath']}\n" .
|
||||
"Please provide application bootstrap file configured for testing"
|
||||
);
|
||||
}
|
||||
|
||||
$this->appSettings = include($this->config['appPath']); //get application settings in the entry script
|
||||
|
||||
// get configuration from array or file
|
||||
if (is_array($this->appSettings['config'])) {
|
||||
$this->_appConfig = $this->appSettings['config'];
|
||||
} else {
|
||||
if (!file_exists($this->appSettings['config'])) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"Couldn't load configuration file from Yii app file: {$this->appSettings['config']}\n" .
|
||||
"Please provide valid 'config' parameter"
|
||||
);
|
||||
}
|
||||
$this->_appConfig = include($this->appSettings['config']);
|
||||
}
|
||||
|
||||
if (!defined('YII_ENABLE_EXCEPTION_HANDLER')) {
|
||||
define('YII_ENABLE_EXCEPTION_HANDLER', false);
|
||||
}
|
||||
if (!defined('YII_ENABLE_ERROR_HANDLER')) {
|
||||
define('YII_ENABLE_ERROR_HANDLER', false);
|
||||
}
|
||||
|
||||
$_SERVER['SCRIPT_NAME'] = parse_url($this->config['url'], PHP_URL_PATH);
|
||||
$_SERVER['SCRIPT_FILENAME'] = $this->config['appPath'];
|
||||
|
||||
if (!function_exists('launch_codeception_yii_bridge')) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"Codeception-Yii Bridge is not launched. In order to run tests you need to install "
|
||||
. "https://github.com/Codeception/YiiBridge Implement function 'launch_codeception_yii_bridge' to "
|
||||
. "load all Codeception overrides"
|
||||
);
|
||||
}
|
||||
launch_codeception_yii_bridge();
|
||||
|
||||
Yii::$enableIncludePath = false;
|
||||
Yii::setApplication(null);
|
||||
Yii::createApplication($this->appSettings['class'], $this->_appConfig);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the client connector. Called before each test
|
||||
*/
|
||||
public function _createClient()
|
||||
{
|
||||
$this->client = new Yii1Connector();
|
||||
$this->client->setServerParameter("HTTP_HOST", parse_url($this->config['url'], PHP_URL_HOST));
|
||||
$this->client->appPath = $this->config['appPath'];
|
||||
$this->client->url = $this->config['url'];
|
||||
$this->client->appSettings = [
|
||||
'class' => $this->appSettings['class'],
|
||||
'config' => $this->_appConfig,
|
||||
];
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->_createClient();
|
||||
}
|
||||
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
$_SESSION = [];
|
||||
$_GET = [];
|
||||
$_POST = [];
|
||||
$_COOKIE = [];
|
||||
$_REQUEST = [];
|
||||
Yii::app()->session->close();
|
||||
parent::_after($test);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting domain regex from rule template and parameters
|
||||
*
|
||||
* @param string $template
|
||||
* @param array $parameters
|
||||
* @return string
|
||||
*/
|
||||
private function getDomainRegex($template, $parameters = [])
|
||||
{
|
||||
if ($host = parse_url($template, PHP_URL_HOST)) {
|
||||
$template = $host;
|
||||
}
|
||||
if (strpos($template, '<') !== false) {
|
||||
$template = str_replace(['<', '>'], '#', $template);
|
||||
}
|
||||
$template = preg_quote($template);
|
||||
foreach ($parameters as $name => $value) {
|
||||
$template = str_replace("#$name#", $value, $template);
|
||||
}
|
||||
return '/^' . $template . '$/u';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of regex patterns for recognized domain names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getInternalDomains()
|
||||
{
|
||||
$domains = [$this->getDomainRegex(Yii::app()->request->getHostInfo())];
|
||||
if (Yii::app()->urlManager->urlFormat === 'path') {
|
||||
$parent = Yii::app()->urlManager instanceof \CUrlManager ? '\CUrlManager' : null;
|
||||
$rules = ReflectionHelper::readPrivateProperty(Yii::app()->urlManager, '_rules', $parent);
|
||||
foreach ($rules as $rule) {
|
||||
if ($rule->hasHostInfo === true) {
|
||||
$domains[] = $this->getDomainRegex($rule->template, $rule->params);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_unique($domains);
|
||||
}
|
||||
|
||||
public function _parts()
|
||||
{
|
||||
return ['init', 'initialize'];
|
||||
}
|
||||
}
|
||||
855
vendor/codeception/base/src/Codeception/Module/Yii2.php
vendored
Normal file
855
vendor/codeception/base/src/Codeception/Module/Yii2.php
vendored
Normal file
@@ -0,0 +1,855 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Exception\ModuleConfigException;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Lib\Connector\Yii2 as Yii2Connector;
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\Lib\Interfaces\ActiveRecord;
|
||||
use Codeception\Lib\Interfaces\PartedModule;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Util\Debug;
|
||||
use Yii;
|
||||
use yii\base\Event;
|
||||
use yii\db\ActiveRecordInterface;
|
||||
use yii\db\Connection;
|
||||
use yii\db\QueryInterface;
|
||||
use yii\db\Transaction;
|
||||
|
||||
/**
|
||||
* This module provides integration with [Yii framework](http://www.yiiframework.com/) (2.0).
|
||||
* It initializes Yii framework in test environment and provides actions for functional testing.
|
||||
* ## Application state during testing
|
||||
* This section details what you can expect when using this module.
|
||||
* * You will get a fresh application in `\Yii::$app` at the start of each test (available in the test and in `_before()`).
|
||||
* * Inside your test you may change application state; however these changes will be lost when doing a request if you have enabled `recreateApplication`.
|
||||
* * When executing a request via one of the request functions the `request` and `response` component are both recreated.
|
||||
* * After a request the whole application is available for inspection / interaction.
|
||||
* * You may use multiple database connections, each will use a separate transaction; to prevent accidental mistakes we
|
||||
* will warn you if you try to connect to the same database twice but we cannot reuse the same connection.
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * `configFile` *required* - the path to the application config file. File should be configured for test environment and return configuration array.
|
||||
* * `entryUrl` - initial application url (default: http://localhost/index-test.php).
|
||||
* * `entryScript` - front script title (like: index-test.php). If not set - taken from entryUrl.
|
||||
* * `transaction` - (default: true) wrap all database connection inside a transaction and roll it back after the test. Should be disabled for acceptance testing..
|
||||
* * `cleanup` - (default: true) cleanup fixtures after the test
|
||||
* * `ignoreCollidingDSN` - (default: false) When 2 database connections use the same DSN but different settings an exception will be thrown, set this to true to disable this behavior.
|
||||
* * `fixturesMethod` - (default: _fixtures) Name of the method used for creating fixtures.
|
||||
* * `responseCleanMethod` - (default: clear) Method for cleaning the response object. Note that this is only for multiple requests inside a single test case.
|
||||
* Between test casesthe whole application is always recreated
|
||||
* * `requestCleanMethod` - (default: recreate) Method for cleaning the request object. Note that this is only for multiple requests inside a single test case.
|
||||
* Between test cases the whole application is always recreated
|
||||
* * `recreateComponents` - (default: []) Some components change their state making them unsuitable for processing multiple requests. In production this is usually
|
||||
* not a problem since web apps tend to die and start over after each request. This allows you to list application components that need to be recreated before each request.
|
||||
* As a consequence, any components specified here should not be changed inside a test since those changes will get regarded.
|
||||
* You can use this module by setting params in your functional.suite.yml:
|
||||
* * `recreateApplication` - (default: false) whether to recreate the whole application before each request
|
||||
* You can use this module by setting params in your functional.suite.yml:
|
||||
* ```yaml
|
||||
* actor: FunctionalTester
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Yii2:
|
||||
* configFile: 'path/to/config.php'
|
||||
* ```
|
||||
*
|
||||
* ### Parts
|
||||
*
|
||||
* By default all available methods are loaded, but you can specify parts to select only needed actions and avoid conflicts.
|
||||
*
|
||||
* * `init` - use module only for initialization (for acceptance tests).
|
||||
* * `orm` - include only `haveRecord/grabRecord/seeRecord/dontSeeRecord` actions.
|
||||
* * `fixtures` - use fixtures inside tests with `haveFixtures/grabFixture/grabFixtures` actions.
|
||||
* * `email` - include email actions `seeEmailsIsSent/grabLastSentEmail/...`
|
||||
*
|
||||
* ### Example (`functional.suite.yml`)
|
||||
*
|
||||
* ```yaml
|
||||
* actor: FunctionalTester
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Yii2:
|
||||
* configFile: 'config/test.php'
|
||||
* ```
|
||||
*
|
||||
* ### Example (`unit.suite.yml`)
|
||||
*
|
||||
* ```yaml
|
||||
* actor: UnitTester
|
||||
* modules:
|
||||
* enabled:
|
||||
* - Asserts
|
||||
* - Yii2:
|
||||
* configFile: 'config/test.php'
|
||||
* part: init
|
||||
* ```
|
||||
*
|
||||
* ### Example (`acceptance.suite.yml`)
|
||||
*
|
||||
* ```yaml
|
||||
* actor: AcceptanceTester
|
||||
* modules:
|
||||
* enabled:
|
||||
* - WebDriver:
|
||||
* url: http://127.0.0.1:8080/
|
||||
* browser: firefox
|
||||
* - Yii2:
|
||||
* configFile: 'config/test.php'
|
||||
* part: ORM # allow to use AR methods
|
||||
* transaction: false # don't wrap test in transaction
|
||||
* cleanup: false # don't cleanup the fixtures
|
||||
* entryScript: index-test.php
|
||||
* ```
|
||||
*
|
||||
* ## Fixtures
|
||||
*
|
||||
* This module allows to use [fixtures](http://www.yiiframework.com/doc-2.0/guide-test-fixtures.html) inside a test. There are two options for that.
|
||||
* Fixtures can be loaded using [haveFixtures](#haveFixtures) method inside a test:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->haveFixtures(['posts' => PostsFixture::className()]);
|
||||
* ```
|
||||
*
|
||||
* or, if you need to load fixtures before the test, you
|
||||
* can specify fixtures with `_fixtures` method of a testcase:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* // inside Cest file or Codeception\TestCase\Unit
|
||||
* public function _fixtures()
|
||||
* {
|
||||
* return ['posts' => PostsFixture::className()]
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* ## URL
|
||||
* This module provide to use native URL formats of Yii2 for all codeception commands that use url for work.
|
||||
* This commands allows input like:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->amOnPage(['site/view','page'=>'about']);
|
||||
* $I->amOnPage('index-test.php?site/index');
|
||||
* $I->amOnPage('http://localhost/index-test.php?site/index');
|
||||
* $I->sendAjaxPostRequest(['/user/update', 'id' => 1], ['UserForm[name]' => 'G.Hopper');
|
||||
* ```
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* Maintainer: **samdark**
|
||||
* Stability: **stable**
|
||||
*
|
||||
* @property \Codeception\Lib\Connector\Yii2 $client
|
||||
*/
|
||||
class Yii2 extends Framework implements ActiveRecord, PartedModule
|
||||
{
|
||||
/**
|
||||
* Application config file must be set.
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [
|
||||
'fixturesMethod' => '_fixtures',
|
||||
'cleanup' => true,
|
||||
'ignoreCollidingDSN' => false,
|
||||
'transaction' => null,
|
||||
'entryScript' => '',
|
||||
'entryUrl' => 'http://localhost/index-test.php',
|
||||
'responseCleanMethod' => Yii2Connector::CLEAN_CLEAR,
|
||||
'requestCleanMethod' => Yii2Connector::CLEAN_RECREATE,
|
||||
'recreateComponents' => [],
|
||||
'recreateApplication' => false
|
||||
];
|
||||
|
||||
protected $requiredFields = ['configFile'];
|
||||
|
||||
/**
|
||||
* @var Yii2Connector\FixturesStore[]
|
||||
*/
|
||||
public $loadedFixtures = [];
|
||||
|
||||
/**
|
||||
* Helper to manage database connections
|
||||
* @var Yii2Connector\ConnectionWatcher
|
||||
*/
|
||||
private $connectionWatcher;
|
||||
|
||||
/**
|
||||
* Helper to force database transaction
|
||||
* @var Yii2Connector\TransactionForcer
|
||||
*/
|
||||
private $transactionForcer;
|
||||
|
||||
/**
|
||||
* @var array The contents of $_SERVER upon initialization of this object.
|
||||
* This is only used to restore it upon object destruction.
|
||||
* It MUST not be used anywhere else.
|
||||
*/
|
||||
private $server;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
if ($this->config['transaction'] === null) {
|
||||
$this->config['transaction'] = $this->backupConfig['transaction'] = $this->config['cleanup'];
|
||||
}
|
||||
|
||||
$this->defineConstants();
|
||||
$this->server = $_SERVER;
|
||||
$this->initServerGlobal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Module configuration changed inside a test.
|
||||
* We always re-create the application.
|
||||
*/
|
||||
protected function onReconfigure()
|
||||
{
|
||||
parent::onReconfigure();
|
||||
$this->client->resetApplication();
|
||||
$this->configureClient($this->config);
|
||||
$this->client->startApp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the required server params.
|
||||
* Note this is done separately from the request cycle since someone might call
|
||||
* `Url::to` before doing a request, which would instantiate the request component with incorrect server params.
|
||||
*/
|
||||
private function initServerGlobal()
|
||||
{
|
||||
|
||||
$entryUrl = $this->config['entryUrl'];
|
||||
$entryFile = $this->config['entryScript'] ?: basename($entryUrl);
|
||||
$entryScript = $this->config['entryScript'] ?: parse_url($entryUrl, PHP_URL_PATH);
|
||||
$_SERVER = array_merge($_SERVER, [
|
||||
'SCRIPT_FILENAME' => $entryFile,
|
||||
'SCRIPT_NAME' => $entryScript,
|
||||
'SERVER_NAME' => parse_url($entryUrl, PHP_URL_HOST),
|
||||
'SERVER_PORT' => parse_url($entryUrl, PHP_URL_PORT) ?: '80',
|
||||
'HTTPS' => parse_url($entryUrl, PHP_URL_SCHEME) === 'https'
|
||||
]);
|
||||
}
|
||||
|
||||
protected function validateConfig()
|
||||
{
|
||||
parent::validateConfig();
|
||||
|
||||
$pathToConfig = codecept_absolute_path($this->config['configFile']);
|
||||
if (!is_file($pathToConfig)) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"The application config file does not exist: " . $pathToConfig
|
||||
);
|
||||
}
|
||||
|
||||
if (!in_array($this->config['responseCleanMethod'], Yii2Connector::CLEAN_METHODS)) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"The response clean method must be one of: " . implode(", ", Yii2Connector::CLEAN_METHODS)
|
||||
);
|
||||
}
|
||||
|
||||
if (!in_array($this->config['requestCleanMethod'], Yii2Connector::CLEAN_METHODS)) {
|
||||
throw new ModuleConfigException(
|
||||
__CLASS__,
|
||||
"The response clean method must be one of: " . implode(", ", Yii2Connector::CLEAN_METHODS)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function configureClient(array $settings)
|
||||
{
|
||||
$settings['configFile'] = codecept_absolute_path($settings['configFile']);
|
||||
|
||||
foreach ($settings as $key => $value) {
|
||||
if (property_exists($this->client, $key)) {
|
||||
$this->client->$key = $value;
|
||||
}
|
||||
}
|
||||
$this->client->resetApplication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates the client based on module configuration
|
||||
*/
|
||||
protected function recreateClient()
|
||||
{
|
||||
$entryUrl = $this->config['entryUrl'];
|
||||
$entryFile = $this->config['entryScript'] ?: basename($entryUrl);
|
||||
$entryScript = $this->config['entryScript'] ?: parse_url($entryUrl, PHP_URL_PATH);
|
||||
|
||||
$this->client = new Yii2Connector([
|
||||
'SCRIPT_FILENAME' => $entryFile,
|
||||
'SCRIPT_NAME' => $entryScript,
|
||||
'SERVER_NAME' => parse_url($entryUrl, PHP_URL_HOST),
|
||||
'SERVER_PORT' => parse_url($entryUrl, PHP_URL_PORT) ?: '80',
|
||||
'HTTPS' => parse_url($entryUrl, PHP_URL_SCHEME) === 'https'
|
||||
]);
|
||||
|
||||
$this->configureClient($this->config);
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->recreateClient();
|
||||
$this->client->startApp();
|
||||
|
||||
$this->connectionWatcher = new Yii2Connector\ConnectionWatcher();
|
||||
$this->connectionWatcher->start();
|
||||
|
||||
// load fixtures before db transaction
|
||||
if ($test instanceof \Codeception\Test\Cest) {
|
||||
$this->loadFixtures($test->getTestClass());
|
||||
} else {
|
||||
$this->loadFixtures($test);
|
||||
}
|
||||
|
||||
|
||||
$this->startTransactions();
|
||||
}
|
||||
|
||||
/**
|
||||
* load fixtures before db transaction
|
||||
*
|
||||
* @param mixed $test instance of test class
|
||||
*/
|
||||
private function loadFixtures($test)
|
||||
{
|
||||
$this->debugSection('Fixtures', 'Loading fixtures');
|
||||
if (empty($this->loadedFixtures)
|
||||
&& method_exists($test, $this->_getConfig('fixturesMethod'))
|
||||
) {
|
||||
$connectionWatcher = new Yii2Connector\ConnectionWatcher();
|
||||
$connectionWatcher->start();
|
||||
$this->haveFixtures(call_user_func([$test, $this->_getConfig('fixturesMethod')]));
|
||||
$connectionWatcher->stop();
|
||||
$connectionWatcher->closeAll();
|
||||
}
|
||||
$this->debugSection('Fixtures', 'Done');
|
||||
}
|
||||
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
$_SESSION = [];
|
||||
$_FILES = [];
|
||||
$_GET = [];
|
||||
$_POST = [];
|
||||
$_COOKIE = [];
|
||||
$_REQUEST = [];
|
||||
|
||||
$this->rollbackTransactions();
|
||||
|
||||
$this->connectionWatcher->stop();
|
||||
$this->connectionWatcher->closeAll();
|
||||
unset($this->connectionWatcher);
|
||||
|
||||
if ($this->config['cleanup']) {
|
||||
foreach ($this->loadedFixtures as $fixture) {
|
||||
$fixture->unloadFixtures();
|
||||
}
|
||||
$this->loadedFixtures = [];
|
||||
}
|
||||
|
||||
if ($this->client !== null && $this->client->getApplication()->has('session', true)) {
|
||||
$this->client->getApplication()->session->close();
|
||||
}
|
||||
|
||||
$this->client->resetApplication();
|
||||
parent::_after($test);
|
||||
}
|
||||
|
||||
protected function startTransactions()
|
||||
{
|
||||
if ($this->config['transaction']) {
|
||||
$this->transactionForcer = new Yii2Connector\TransactionForcer($this->config['ignoreCollidingDSN']);
|
||||
$this->transactionForcer->start();
|
||||
}
|
||||
}
|
||||
|
||||
protected function rollbackTransactions()
|
||||
{
|
||||
if (isset($this->transactionForcer)) {
|
||||
$this->transactionForcer->rollbackAll();
|
||||
$this->transactionForcer->stop();
|
||||
unset($this->transactionForcer);
|
||||
}
|
||||
}
|
||||
|
||||
public function _parts()
|
||||
{
|
||||
return ['orm', 'init', 'fixtures', 'email'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorizes user on a site without submitting login form.
|
||||
* Use it for fast pragmatic authorization in functional tests.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* // User is found by id
|
||||
* $I->amLoggedInAs(1);
|
||||
*
|
||||
* // User object is passed as parameter
|
||||
* $admin = \app\models\User::findByUsername('admin');
|
||||
* $I->amLoggedInAs($admin);
|
||||
* ```
|
||||
* Requires `user` component to be enabled and configured.
|
||||
*
|
||||
* @param $user
|
||||
* @throws ModuleException
|
||||
*/
|
||||
public function amLoggedInAs($user)
|
||||
{
|
||||
if (!$this->client->getApplication()->has('user')) {
|
||||
throw new ModuleException($this, 'User component is not loaded');
|
||||
}
|
||||
if ($user instanceof \yii\web\IdentityInterface) {
|
||||
$identity = $user;
|
||||
} else {
|
||||
// class name implementing IdentityInterface
|
||||
$identityClass = $this->client->getApplication()->user->identityClass;
|
||||
$identity = call_user_func([$identityClass, 'findIdentity'], $user);
|
||||
}
|
||||
$this->client->getApplication()->user->login($identity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and loads fixtures from a config.
|
||||
* Signature is the same as for `fixtures()` method of `yii\test\FixtureTrait`
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->haveFixtures([
|
||||
* 'posts' => PostsFixture::className(),
|
||||
* 'user' => [
|
||||
* 'class' => UserFixture::className(),
|
||||
* 'dataFile' => '@tests/_data/models/user.php',
|
||||
* ],
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* Note: if you need to load fixtures before the test (probably before the cleanup transaction is started;
|
||||
* `cleanup` options is `true` by default), you can specify fixtures with _fixtures method of a testcase
|
||||
* ```php
|
||||
* <?php
|
||||
* // inside Cest file or Codeception\TestCase\Unit
|
||||
* public function _fixtures(){
|
||||
* return [
|
||||
* 'user' => [
|
||||
* 'class' => UserFixture::className(),
|
||||
* 'dataFile' => codecept_data_dir() . 'user.php'
|
||||
* ]
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
* instead of defining `haveFixtures` in Cest `_before`
|
||||
*
|
||||
* @param $fixtures
|
||||
* @part fixtures
|
||||
*/
|
||||
public function haveFixtures($fixtures)
|
||||
{
|
||||
if (empty($fixtures)) {
|
||||
return;
|
||||
}
|
||||
$fixturesStore = new Yii2Connector\FixturesStore($fixtures);
|
||||
$fixturesStore->unloadFixtures();
|
||||
$fixturesStore->loadFixtures();
|
||||
$this->loadedFixtures[] = $fixturesStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all loaded fixtures.
|
||||
* Array of fixture instances
|
||||
*
|
||||
* @part fixtures
|
||||
* @return array
|
||||
*/
|
||||
public function grabFixtures()
|
||||
{
|
||||
return call_user_func_array(
|
||||
'array_merge',
|
||||
array_map( // merge all fixtures from all fixture stores
|
||||
function ($fixturesStore) {
|
||||
return $fixturesStore->getFixtures();
|
||||
},
|
||||
$this->loadedFixtures
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a fixture by name.
|
||||
* Returns a Fixture instance. If a fixture is an instance of `\yii\test\BaseActiveFixture` a second parameter
|
||||
* can be used to return a specific model:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->haveFixtures(['users' => UserFixture::className()]);
|
||||
*
|
||||
* $users = $I->grabFixture('users');
|
||||
*
|
||||
* // get first user by key, if a fixture is instance of ActiveFixture
|
||||
* $user = $I->grabFixture('users', 'user1');
|
||||
* ```
|
||||
*
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws ModuleException if a fixture is not found
|
||||
* @part fixtures
|
||||
*/
|
||||
public function grabFixture($name, $index = null)
|
||||
{
|
||||
$fixtures = $this->grabFixtures();
|
||||
if (!isset($fixtures[$name])) {
|
||||
throw new ModuleException($this, "Fixture $name is not loaded");
|
||||
}
|
||||
$fixture = $fixtures[$name];
|
||||
if ($index === null) {
|
||||
return $fixture;
|
||||
}
|
||||
if ($fixture instanceof \yii\test\BaseActiveFixture) {
|
||||
return $fixture->getModel($index);
|
||||
}
|
||||
throw new ModuleException($this, "Fixture $name is not an instance of ActiveFixture and can't be loaded with second parameter");
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts record into the database.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $user_id = $I->haveRecord('app\models\User', array('name' => 'Davert'));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $model
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
* @part orm
|
||||
*/
|
||||
public function haveRecord($model, $attributes = [])
|
||||
{
|
||||
/** @var $record \yii\db\ActiveRecord * */
|
||||
$record = \Yii::createObject($model);
|
||||
$record->setAttributes($attributes, false);
|
||||
$res = $record->save(false);
|
||||
if (!$res) {
|
||||
$this->fail("Record $model was not saved");
|
||||
}
|
||||
return $record->primaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that record exists in database.
|
||||
*
|
||||
* ``` php
|
||||
* $I->seeRecord('app\models\User', array('name' => 'davert'));
|
||||
* ```
|
||||
*
|
||||
* @param $model
|
||||
* @param array $attributes
|
||||
* @part orm
|
||||
*/
|
||||
public function seeRecord($model, $attributes = [])
|
||||
{
|
||||
$record = $this->findRecord($model, $attributes);
|
||||
if (!$record) {
|
||||
$this->fail("Couldn't find $model with " . json_encode($attributes));
|
||||
}
|
||||
$this->debugSection($model, json_encode($record));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that record does not exist in database.
|
||||
*
|
||||
* ``` php
|
||||
* $I->dontSeeRecord('app\models\User', array('name' => 'davert'));
|
||||
* ```
|
||||
*
|
||||
* @param $model
|
||||
* @param array $attributes
|
||||
* @part orm
|
||||
*/
|
||||
public function dontSeeRecord($model, $attributes = [])
|
||||
{
|
||||
$record = $this->findRecord($model, $attributes);
|
||||
$this->debugSection($model, json_encode($record));
|
||||
if ($record) {
|
||||
$this->fail("Unexpectedly managed to find $model with " . json_encode($attributes));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves record from database
|
||||
*
|
||||
* ``` php
|
||||
* $category = $I->grabRecord('app\models\User', array('name' => 'davert'));
|
||||
* ```
|
||||
*
|
||||
* @param $model
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
* @part orm
|
||||
*/
|
||||
public function grabRecord($model, $attributes = [])
|
||||
{
|
||||
return $this->findRecord($model, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $model Class name
|
||||
* @param array $attributes
|
||||
* @return mixed
|
||||
*/
|
||||
protected function findRecord($model, $attributes = [])
|
||||
{
|
||||
if (!class_exists($model)) {
|
||||
throw new \RuntimeException("Class $model does not exist");
|
||||
}
|
||||
$rc = new \ReflectionClass($model);
|
||||
if ($rc->hasMethod('find')
|
||||
&& ($findMethod = $rc->getMethod('find'))
|
||||
&& $findMethod->isStatic()
|
||||
&& $findMethod->isPublic()
|
||||
&& $findMethod->getNumberOfRequiredParameters() === 0
|
||||
) {
|
||||
$activeQuery = $findMethod->invoke(null);
|
||||
if ($activeQuery instanceof QueryInterface) {
|
||||
return $activeQuery->andWhere($attributes)->one();
|
||||
}
|
||||
|
||||
throw new \RuntimeException("$model::find() must return an instance of yii\db\QueryInterface");
|
||||
|
||||
}
|
||||
throw new \RuntimeException("Class $model does not have a public static find() method without required parameters");
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to amOnPage but accepts route as first argument and params as second
|
||||
*
|
||||
* ```
|
||||
* $I->amOnRoute('site/view', ['page' => 'about']);
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
public function amOnRoute($route, array $params = [])
|
||||
{
|
||||
array_unshift($params, $route);
|
||||
$this->amOnPage($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* To support to use the behavior of urlManager component
|
||||
* for the methods like this: amOnPage(), sendAjaxRequest() and etc.
|
||||
* @param $method
|
||||
* @param $uri
|
||||
* @param array $parameters
|
||||
* @param array $files
|
||||
* @param array $server
|
||||
* @param null $content
|
||||
* @param bool $changeHistory
|
||||
* @return mixed
|
||||
*/
|
||||
protected function clientRequest($method, $uri, array $parameters = [], array $files = [], array $server = [], $content = null, $changeHistory = true)
|
||||
{
|
||||
if (is_array($uri)) {
|
||||
$uri = $this->client->getApplication()->getUrlManager()->createUrl($uri);
|
||||
}
|
||||
return parent::clientRequest($method, $uri, $parameters, $files, $server, $content, $changeHistory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a component from Yii container. Throws exception if component is not available
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $mailer = $I->grabComponent('mailer');
|
||||
* ```
|
||||
*
|
||||
* @param $component
|
||||
* @return mixed
|
||||
* @throws ModuleException
|
||||
*/
|
||||
public function grabComponent($component)
|
||||
{
|
||||
if (!$this->client->getApplication()->has($component)) {
|
||||
throw new ModuleException($this, "Component $component is not available in current application");
|
||||
}
|
||||
return $this->client->getApplication()->get($component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that email is sent.
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* // check that at least 1 email was sent
|
||||
* $I->seeEmailIsSent();
|
||||
*
|
||||
* // check that only 3 emails were sent
|
||||
* $I->seeEmailIsSent(3);
|
||||
* ```
|
||||
*
|
||||
* @param int $num
|
||||
* @throws ModuleException
|
||||
* @part email
|
||||
*/
|
||||
public function seeEmailIsSent($num = null)
|
||||
{
|
||||
if ($num === null) {
|
||||
$this->assertNotEmpty($this->grabSentEmails(), 'emails were sent');
|
||||
return;
|
||||
}
|
||||
$this->assertEquals($num, count($this->grabSentEmails()), 'number of sent emails is equal to ' . $num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that no email was sent
|
||||
*
|
||||
* @part email
|
||||
*/
|
||||
public function dontSeeEmailIsSent()
|
||||
{
|
||||
$this->seeEmailIsSent(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of all sent email messages.
|
||||
* Each message implements `yii\mail\MessageInterface` interface.
|
||||
* Useful to perform additional checks using `Asserts` module:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeEmailIsSent();
|
||||
* $messages = $I->grabSentEmails();
|
||||
* $I->assertEquals('admin@site,com', $messages[0]->getTo());
|
||||
* ```
|
||||
*
|
||||
* @part email
|
||||
* @return array
|
||||
* @throws ModuleException
|
||||
*/
|
||||
public function grabSentEmails()
|
||||
{
|
||||
$mailer = $this->grabComponent('mailer');
|
||||
if (!$mailer instanceof Yii2Connector\TestMailer) {
|
||||
throw new ModuleException($this, "Mailer module is not mocked, can't test emails");
|
||||
}
|
||||
return $mailer->getSentMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last sent email:
|
||||
*
|
||||
* ```php
|
||||
* <?php
|
||||
* $I->seeEmailIsSent();
|
||||
* $message = $I->grabLastSentEmail();
|
||||
* $I->assertEquals('admin@site,com', $message->getTo());
|
||||
* ```
|
||||
* @part email
|
||||
*/
|
||||
public function grabLastSentEmail()
|
||||
{
|
||||
$this->seeEmailIsSent();
|
||||
$messages = $this->grabSentEmails();
|
||||
return end($messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting domain regex from rule host template
|
||||
*
|
||||
* @param string $template
|
||||
* @return string
|
||||
*/
|
||||
private function getDomainRegex($template)
|
||||
{
|
||||
if (preg_match('#https?://(.*)#', $template, $matches)) {
|
||||
$template = $matches[1];
|
||||
}
|
||||
$parameters = [];
|
||||
if (strpos($template, '<') !== false) {
|
||||
$template = preg_replace_callback(
|
||||
'/<(?:\w+):?([^>]+)?>/u',
|
||||
function ($matches) use (&$parameters) {
|
||||
$key = '#' . count($parameters) . '#';
|
||||
$parameters[$key] = isset($matches[1]) ? $matches[1] : '\w+';
|
||||
return $key;
|
||||
},
|
||||
$template
|
||||
);
|
||||
}
|
||||
$template = preg_quote($template);
|
||||
$template = strtr($template, $parameters);
|
||||
return '/^' . $template . '$/u';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of regex patterns for recognized domain names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getInternalDomains()
|
||||
{
|
||||
$domains = [$this->getDomainRegex($this->client->getApplication()->urlManager->hostInfo)];
|
||||
|
||||
if ($this->client->getApplication()->urlManager->enablePrettyUrl) {
|
||||
foreach ($this->client->getApplication()->urlManager->rules as $rule) {
|
||||
/** @var \yii\web\UrlRule $rule */
|
||||
if (isset($rule->host)) {
|
||||
$domains[] = $this->getDomainRegex($rule->host);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_unique($domains);
|
||||
}
|
||||
|
||||
private function defineConstants()
|
||||
{
|
||||
defined('YII_DEBUG') or define('YII_DEBUG', true);
|
||||
defined('YII_ENV') or define('YII_ENV', 'test');
|
||||
defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a cookie and, if validation is enabled, signs it.
|
||||
* @param string $name The name of the cookie
|
||||
* @param string $value The value of the cookie
|
||||
* @param array $params Additional cookie params like `domain`, `path`, `expires` and `secure`.
|
||||
*/
|
||||
public function setCookie($name, $val, array $params = [])
|
||||
{
|
||||
// Sign the cookie.
|
||||
if ($this->client->getApplication()->request->enableCookieValidation) {
|
||||
$val = $this->client->getApplication()->security->hashData(serialize([$name, $val]), $this->client->getApplication()->request->cookieValidationKey);
|
||||
}
|
||||
parent::setCookie($name, $val, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function creates the CSRF Cookie.
|
||||
* @param string $val The value of the CSRF token
|
||||
* @return string[] Returns an array containing the name of the CSRF param and the masked CSRF token.
|
||||
*/
|
||||
public function createAndSetCsrfCookie($val)
|
||||
{
|
||||
$masked = $this->client->getApplication()->security->maskToken($val);
|
||||
$name = $this->client->getApplication()->request->csrfParam;
|
||||
$this->setCookie($name, $val);
|
||||
return [$name, $masked];
|
||||
}
|
||||
|
||||
public function _afterSuite()
|
||||
{
|
||||
parent::_afterSuite();
|
||||
codecept_debug('Suite done, restoring $_SERVER to original');
|
||||
|
||||
$_SERVER = $this->server;
|
||||
}
|
||||
|
||||
}
|
||||
266
vendor/codeception/base/src/Codeception/Module/ZF1.php
vendored
Normal file
266
vendor/codeception/base/src/Codeception/Module/ZF1.php
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Exception\ModuleException;
|
||||
use Codeception\Util\ReflectionHelper;
|
||||
use Codeception\Lib\Connector\ZF1 as ZF1Connector;
|
||||
use Zend_Controller_Router_Route_Hostname;
|
||||
use Zend_Controller_Router_Route_Chain;
|
||||
|
||||
/**
|
||||
* This module allows you to run tests inside Zend Framework.
|
||||
* It acts just like ControllerTestCase, but with usage of Codeception syntax.
|
||||
*
|
||||
* It assumes, you have standard structure with __APPLICATION_PATH__ set to './application'
|
||||
* and LIBRARY_PATH set to './library'. If it's not then set the appropriate path in the Config.
|
||||
*
|
||||
* [Tutorial](http://codeception.com/01-27-2012/bdd-with-zend-framework.html)
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **davert**
|
||||
* * Stability: **stable**
|
||||
* * Contact: codecept@davert.mail.ua
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * env - environment used for testing ('testing' by default).
|
||||
* * config - relative path to your application config ('application/configs/application.ini' by default).
|
||||
* * app_path - relative path to your application folder ('application' by default).
|
||||
* * lib_path - relative path to your library folder ('library' by default).
|
||||
*
|
||||
* ## API
|
||||
*
|
||||
* * client - BrowserKit client
|
||||
* * db - current instance of Zend_Db_Adapter
|
||||
* * bootstrap - current bootstrap file.
|
||||
*
|
||||
* ## Cleaning up
|
||||
*
|
||||
* Unfortunately Zend_Db doesn't support nested transactions,
|
||||
* thus, for cleaning your database you should either use standard Db module or
|
||||
* [implement nested transactions yourself](http://blog.ekini.net/2010/03/05/zend-framework-how-to-use-nested-transactions-with-zend_db-and-mysql/).
|
||||
*
|
||||
* If your database supports nested transactions (MySQL doesn't)
|
||||
* or you implemented them you can put all your code inside a transaction.
|
||||
* Use a generated helper TestHelper. Use this code inside of it.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* namespace Codeception\Module;
|
||||
* class TestHelper extends \Codeception\Module {
|
||||
* function _before($test) {
|
||||
* $this->getModule('ZF1')->db->beginTransaction();
|
||||
* }
|
||||
*
|
||||
* function _after($test) {
|
||||
* $this->getModule('ZF1')->db->rollback();
|
||||
* }
|
||||
* }
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* This will make your functional tests run super-fast.
|
||||
*
|
||||
*/
|
||||
class ZF1 extends Framework
|
||||
{
|
||||
protected $config = [
|
||||
'env' => 'testing',
|
||||
'config' => 'application/configs/application.ini',
|
||||
'app_path' => 'application',
|
||||
'lib_path' => 'library'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Zend_Application
|
||||
*/
|
||||
public $bootstrap;
|
||||
|
||||
/**
|
||||
* @var \Zend_Db_Adapter_Abstract
|
||||
*/
|
||||
public $db;
|
||||
|
||||
/**
|
||||
* @var \Codeception\Lib\Connector\ZF1
|
||||
*/
|
||||
public $client;
|
||||
|
||||
protected $queries = 0;
|
||||
protected $time = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @var array Used to collect domains while recursively traversing route tree
|
||||
*/
|
||||
private $domainCollector = [];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
defined('APPLICATION_ENV') || define('APPLICATION_ENV', $this->config['env']);
|
||||
defined('APPLICATION_PATH') || define(
|
||||
'APPLICATION_PATH',
|
||||
Configuration::projectDir() . $this->config['app_path']
|
||||
);
|
||||
defined('LIBRARY_PATH') || define('LIBRARY_PATH', Configuration::projectDir() . $this->config['lib_path']);
|
||||
|
||||
// Ensure library/ is on include_path
|
||||
set_include_path(
|
||||
implode(
|
||||
PATH_SEPARATOR,
|
||||
[
|
||||
LIBRARY_PATH,
|
||||
get_include_path(),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
require_once 'Zend/Loader/Autoloader.php';
|
||||
\Zend_Loader_Autoloader::getInstance();
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->client = new ZF1Connector();
|
||||
|
||||
\Zend_Session::$_unitTestEnabled = true;
|
||||
try {
|
||||
$this->bootstrap = new \Zend_Application(
|
||||
$this->config['env'],
|
||||
Configuration::projectDir() . $this->config['config']
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
throw new ModuleException(__CLASS__, $e->getMessage());
|
||||
}
|
||||
$this->bootstrap->bootstrap();
|
||||
$this->client->setBootstrap($this->bootstrap);
|
||||
|
||||
$db = $this->bootstrap->getBootstrap()->getResource('db');
|
||||
if ($db instanceof \Zend_Db_Adapter_Abstract) {
|
||||
$this->db = $db;
|
||||
$this->db->getProfiler()->setEnabled(true);
|
||||
$this->db->getProfiler()->clear();
|
||||
}
|
||||
}
|
||||
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
$_SESSION = [];
|
||||
$_GET = [];
|
||||
$_POST = [];
|
||||
$_COOKIE = [];
|
||||
if ($this->bootstrap) {
|
||||
$fc = $this->bootstrap->getBootstrap()->getResource('frontcontroller');
|
||||
if ($fc) {
|
||||
$fc->resetInstance();
|
||||
}
|
||||
}
|
||||
\Zend_Layout::resetMvcInstance();
|
||||
\Zend_Controller_Action_HelperBroker::resetHelpers();
|
||||
\Zend_Session::$_unitTestEnabled = true;
|
||||
\Zend_Registry::_unsetInstance();
|
||||
$this->queries = 0;
|
||||
$this->time = 0;
|
||||
|
||||
parent::_after($test);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
*/
|
||||
protected function debugResponse($url)
|
||||
{
|
||||
parent::debugResponse($url);
|
||||
|
||||
$this->debugSection('Session', json_encode($_COOKIE));
|
||||
if ($this->db) {
|
||||
$profiler = $this->db->getProfiler();
|
||||
$queries = $profiler->getTotalNumQueries() - $this->queries;
|
||||
$time = $profiler->getTotalElapsedSecs() - $this->time;
|
||||
$this->debugSection('Db', $queries . ' queries');
|
||||
$this->debugSection('Time', round($time, 2) . ' secs taken');
|
||||
$this->time = $profiler->getTotalElapsedSecs();
|
||||
$this->queries = $profiler->getTotalNumQueries();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens web page using route name and parameters.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->amOnRoute('posts.create');
|
||||
* $I->amOnRoute('posts.show', array('id' => 34));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $routeName
|
||||
* @param array $params
|
||||
*/
|
||||
public function amOnRoute($routeName, array $params = [])
|
||||
{
|
||||
$router = $this->bootstrap->getBootstrap()->getResource('frontcontroller')->getRouter();
|
||||
$url = $router->assemble($params, $routeName);
|
||||
$this->amOnPage($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that current url matches route.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeCurrentRouteIs('posts.index');
|
||||
* $I->seeCurrentRouteIs('posts.show', ['id' => 8]));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $routeName
|
||||
* @param array $params
|
||||
*/
|
||||
public function seeCurrentRouteIs($routeName, array $params = [])
|
||||
{
|
||||
$router = $this->bootstrap->getBootstrap()->getResource('frontcontroller')->getRouter();
|
||||
$url = $router->assemble($params, $routeName);
|
||||
$this->seeCurrentUrlEquals($url);
|
||||
}
|
||||
|
||||
protected function getInternalDomains()
|
||||
{
|
||||
$router = $this->bootstrap->getBootstrap()->getResource('frontcontroller')->getRouter();
|
||||
$this->domainCollector = [];
|
||||
$this->addInternalDomainsFromRoutes($router->getRoutes());
|
||||
return array_unique($this->domainCollector);
|
||||
}
|
||||
|
||||
private function addInternalDomainsFromRoutes($routes)
|
||||
{
|
||||
foreach ($routes as $name => $route) {
|
||||
try {
|
||||
$route->assemble([]);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
if ($route instanceof Zend_Controller_Router_Route_Hostname) {
|
||||
$this->addInternalDomain($route);
|
||||
} elseif ($route instanceof Zend_Controller_Router_Route_Chain) {
|
||||
$chainRoutes = ReflectionHelper::readPrivateProperty($route, '_routes');
|
||||
$this->addInternalDomainsFromRoutes($chainRoutes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function addInternalDomain(Zend_Controller_Router_Route_Hostname $route)
|
||||
{
|
||||
$parts = ReflectionHelper::readPrivateProperty($route, '_parts');
|
||||
foreach ($parts as &$part) {
|
||||
if ($part === null) {
|
||||
$part = '[^.]+';
|
||||
}
|
||||
}
|
||||
$regex = implode('\.', $parts);
|
||||
$this->domainCollector []= '/^' . $regex . '$/iu';
|
||||
}
|
||||
}
|
||||
256
vendor/codeception/base/src/Codeception/Module/ZF2.php
vendored
Normal file
256
vendor/codeception/base/src/Codeception/Module/ZF2.php
vendored
Normal file
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Interfaces\DoctrineProvider;
|
||||
use Codeception\Lib\Interfaces\PartedModule;
|
||||
use Codeception\Util\ReflectionHelper;
|
||||
use Zend\Console\Console;
|
||||
use Zend\EventManager\StaticEventManager;
|
||||
use Codeception\Lib\Connector\ZF2 as ZF2Connector;
|
||||
|
||||
/**
|
||||
* This module allows you to run tests inside Zend Framework 2 and Zend Framework 3.
|
||||
*
|
||||
* File `init_autoloader` in project's root is required by Zend Framework 2.
|
||||
* Uses `tests/application.config.php` config file by default.
|
||||
*
|
||||
* Note: services part and Doctrine integration is not compatible with ZF3 yet
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **Naktibalda**
|
||||
* * Stability: **stable**
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * config: relative path to config file (default: `tests/application.config.php`)
|
||||
*
|
||||
* ## Public Properties
|
||||
*
|
||||
* * application - instance of `\Zend\Mvc\ApplicationInterface`
|
||||
* * db - instance of `\Zend\Db\Adapter\AdapterInterface`
|
||||
* * client - BrowserKit client
|
||||
*
|
||||
* ## Parts
|
||||
*
|
||||
* * services - allows to use grabServiceFromContainer and addServiceToContainer with WebDriver or PhpBrowser modules.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```yaml
|
||||
* actor: AcceptanceTester
|
||||
* modules:
|
||||
* enabled:
|
||||
* - ZF2:
|
||||
* part: services
|
||||
* - Doctrine2:
|
||||
* depends: ZF2
|
||||
* - WebDriver:
|
||||
* url: http://your-url.com
|
||||
* browser: phantomjs
|
||||
* ```
|
||||
*/
|
||||
class ZF2 extends Framework implements DoctrineProvider, PartedModule
|
||||
{
|
||||
protected $config = [
|
||||
'config' => 'tests/application.config.php',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Zend\Mvc\ApplicationInterface
|
||||
*/
|
||||
public $application;
|
||||
|
||||
/**
|
||||
* @var \Zend\Db\Adapter\AdapterInterface
|
||||
*/
|
||||
public $db;
|
||||
|
||||
/**
|
||||
* @var \Codeception\Lib\Connector\ZF2
|
||||
*/
|
||||
public $client;
|
||||
|
||||
protected $applicationConfig;
|
||||
|
||||
protected $queries = 0;
|
||||
protected $time = 0;
|
||||
|
||||
/**
|
||||
* @var array Used to collect domains while recursively traversing route tree
|
||||
*/
|
||||
private $domainCollector = [];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$initAutoloaderFile = Configuration::projectDir() . 'init_autoloader.php';
|
||||
if (file_exists($initAutoloaderFile)) {
|
||||
require $initAutoloaderFile;
|
||||
}
|
||||
|
||||
$this->applicationConfig = require Configuration::projectDir() . $this->config['config'];
|
||||
if (isset($this->applicationConfig['module_listener_options']['config_cache_enabled'])) {
|
||||
$this->applicationConfig['module_listener_options']['config_cache_enabled'] = false;
|
||||
}
|
||||
Console::overrideIsConsole(false);
|
||||
|
||||
//grabServiceFromContainer may need client in beforeClass hooks of modules or helpers
|
||||
$this->client = new ZF2Connector();
|
||||
$this->client->setApplicationConfig($this->applicationConfig);
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->client = new ZF2Connector();
|
||||
$this->client->setApplicationConfig($this->applicationConfig);
|
||||
$_SERVER['REQUEST_URI'] = '';
|
||||
}
|
||||
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
$_SESSION = [];
|
||||
$_GET = [];
|
||||
$_POST = [];
|
||||
$_COOKIE = [];
|
||||
|
||||
if (class_exists('Zend\EventManager\StaticEventManager')) {
|
||||
// reset singleton (ZF2)
|
||||
StaticEventManager::resetInstance();
|
||||
}
|
||||
|
||||
$this->queries = 0;
|
||||
$this->time = 0;
|
||||
|
||||
parent::_after($test);
|
||||
}
|
||||
|
||||
public function _afterSuite()
|
||||
{
|
||||
unset($this->client);
|
||||
}
|
||||
|
||||
public function _getEntityManager()
|
||||
{
|
||||
if (!$this->client) {
|
||||
$this->client = new ZF2Connector();
|
||||
$this->client->setApplicationConfig($this->applicationConfig);
|
||||
}
|
||||
|
||||
return $this->grabServiceFromContainer('Doctrine\ORM\EntityManager');
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs a service from ZF2 container.
|
||||
* Recommended to use for unit testing.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $em = $I->grabServiceFromContainer('Doctrine\ORM\EntityManager');
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $service
|
||||
* @return mixed
|
||||
* @part services
|
||||
*/
|
||||
public function grabServiceFromContainer($service)
|
||||
{
|
||||
return $this->client->grabServiceFromContainer($service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds service to ZF2 container
|
||||
* @param string $name
|
||||
* @param object $service
|
||||
* @part services
|
||||
*/
|
||||
public function addServiceToContainer($name, $service)
|
||||
{
|
||||
$this->client->addServiceToContainer($name, $service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens web page using route name and parameters.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->amOnRoute('posts.create');
|
||||
* $I->amOnRoute('posts.show', array('id' => 34));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $routeName
|
||||
* @param array $params
|
||||
*/
|
||||
public function amOnRoute($routeName, array $params = [])
|
||||
{
|
||||
$router = $this->client->grabServiceFromContainer('router');
|
||||
$url = $router->assemble($params, ['name' => $routeName]);
|
||||
$this->amOnPage($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that current url matches route.
|
||||
*
|
||||
* ``` php
|
||||
* <?php
|
||||
* $I->seeCurrentRouteIs('posts.index');
|
||||
* $I->seeCurrentRouteIs('posts.show', ['id' => 8]));
|
||||
* ?>
|
||||
* ```
|
||||
*
|
||||
* @param $routeName
|
||||
* @param array $params
|
||||
*/
|
||||
public function seeCurrentRouteIs($routeName, array $params = [])
|
||||
{
|
||||
$router = $this->client->grabServiceFromContainer('router');
|
||||
$url = $router->assemble($params, ['name' => $routeName]);
|
||||
$this->seeCurrentUrlEquals($url);
|
||||
}
|
||||
|
||||
protected function getInternalDomains()
|
||||
{
|
||||
/**
|
||||
* @var Zend\Mvc\Router\Http\TreeRouteStack
|
||||
*/
|
||||
$router = $this->client->grabServiceFromContainer('router');
|
||||
$this->domainCollector = [];
|
||||
$this->addInternalDomainsFromRoutes($router->getRoutes());
|
||||
return array_unique($this->domainCollector);
|
||||
}
|
||||
|
||||
private function addInternalDomainsFromRoutes($routes)
|
||||
{
|
||||
foreach ($routes as $name => $route) {
|
||||
if ($route instanceof \Zend\Mvc\Router\Http\Hostname || $route instanceof \Zend\Router\Http\Hostname) {
|
||||
$this->addInternalDomain($route);
|
||||
} elseif ($route instanceof \Zend\Mvc\Router\Http\Part || $route instanceof \Zend\Router\Http\Part) {
|
||||
$parentRoute = ReflectionHelper::readPrivateProperty($route, 'route');
|
||||
if ($parentRoute instanceof \Zend\Mvc\Router\Http\Hostname || $parentRoute instanceof \Zend\Mvc\Router\Http\Hostname) {
|
||||
$this->addInternalDomain($parentRoute);
|
||||
}
|
||||
// this is necessary to instantiate child routes
|
||||
try {
|
||||
$route->assemble([], []);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
$this->addInternalDomainsFromRoutes($route->getRoutes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function addInternalDomain($route)
|
||||
{
|
||||
$regex = ReflectionHelper::readPrivateProperty($route, 'regex');
|
||||
$this->domainCollector []= '/^' . $regex . '$/';
|
||||
}
|
||||
|
||||
public function _parts()
|
||||
{
|
||||
return ['services'];
|
||||
}
|
||||
}
|
||||
116
vendor/codeception/base/src/Codeception/Module/ZendExpressive.php
vendored
Normal file
116
vendor/codeception/base/src/Codeception/Module/ZendExpressive.php
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
namespace Codeception\Module;
|
||||
|
||||
use Codeception\Lib\Framework;
|
||||
use Codeception\TestInterface;
|
||||
use Codeception\Configuration;
|
||||
use Codeception\Lib\Connector\ZendExpressive as ZendExpressiveConnector;
|
||||
use Codeception\Lib\Interfaces\DoctrineProvider;
|
||||
|
||||
/**
|
||||
* This module allows you to run tests inside Zend Expressive.
|
||||
*
|
||||
* Uses `config/container.php` file by default.
|
||||
*
|
||||
* ## Status
|
||||
*
|
||||
* * Maintainer: **Naktibalda**
|
||||
* * Stability: **alpha**
|
||||
*
|
||||
* ## Config
|
||||
*
|
||||
* * container: relative path to file which returns Container (default: `config/container.php`)
|
||||
*
|
||||
* ## API
|
||||
*
|
||||
* * application - instance of `\Zend\Expressive\Application`
|
||||
* * container - instance of `\Interop\Container\ContainerInterface`
|
||||
* * client - BrowserKit client
|
||||
*
|
||||
*/
|
||||
class ZendExpressive extends Framework implements DoctrineProvider
|
||||
{
|
||||
protected $config = [
|
||||
'container' => 'config/container.php',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Codeception\Lib\Connector\ZendExpressive
|
||||
*/
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* @var \Interop\Container\ContainerInterface
|
||||
*/
|
||||
public $container;
|
||||
|
||||
/**
|
||||
* @var \Zend\Expressive\Application
|
||||
*/
|
||||
public $application;
|
||||
|
||||
protected $responseCollector;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
$cwd = getcwd();
|
||||
$projectDir = Configuration::projectDir();
|
||||
chdir($projectDir);
|
||||
$this->container = require $projectDir . $this->config['container'];
|
||||
$app = $this->container->get('Zend\Expressive\Application');
|
||||
|
||||
$pipelineFile = $projectDir . 'config/pipeline.php';
|
||||
if (file_exists($pipelineFile)) {
|
||||
require $pipelineFile;
|
||||
}
|
||||
$routesFile = $projectDir . 'config/routes.php';
|
||||
if (file_exists($routesFile)) {
|
||||
require $routesFile;
|
||||
}
|
||||
chdir($cwd);
|
||||
|
||||
$this->application = $app;
|
||||
$this->initResponseCollector();
|
||||
}
|
||||
|
||||
public function _before(TestInterface $test)
|
||||
{
|
||||
$this->client = new ZendExpressiveConnector();
|
||||
$this->client->setApplication($this->application);
|
||||
$this->client->setResponseCollector($this->responseCollector);
|
||||
}
|
||||
|
||||
public function _after(TestInterface $test)
|
||||
{
|
||||
//Close the session, if any are open
|
||||
if (session_status() == PHP_SESSION_ACTIVE) {
|
||||
session_write_close();
|
||||
}
|
||||
|
||||
parent::_after($test);
|
||||
}
|
||||
|
||||
private function initResponseCollector()
|
||||
{
|
||||
/**
|
||||
* @var Zend\Expressive\Emitter\EmitterStack
|
||||
*/
|
||||
$emitterStack = $this->application->getEmitter();
|
||||
while (!$emitterStack->isEmpty()) {
|
||||
$emitterStack->pop();
|
||||
}
|
||||
|
||||
$this->responseCollector = new ZendExpressiveConnector\ResponseCollector;
|
||||
$emitterStack->unshift($this->responseCollector);
|
||||
}
|
||||
|
||||
public function _getEntityManager()
|
||||
{
|
||||
$service = 'Doctrine\ORM\EntityManager';
|
||||
if (!$this->container->has($service)) {
|
||||
throw new \PHPUnit\Framework\AssertionFailedError("Service $service is not available in container");
|
||||
}
|
||||
|
||||
return $this->container->get('Doctrine\ORM\EntityManager');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user