first commit
This commit is contained in:
143
bundles/KupShop/DevelopmentBundle/Util/Tests/CartTestTrait.php
Normal file
143
bundles/KupShop/DevelopmentBundle/Util/Tests/CartTestTrait.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: ondra
|
||||
* Date: 2.11.17
|
||||
* Time: 16:07.
|
||||
*/
|
||||
|
||||
namespace KupShop\DevelopmentBundle\Util\Tests;
|
||||
|
||||
use KupShop\OrderingBundle\Cart;
|
||||
|
||||
/**
|
||||
* Trait CartTestTrait.
|
||||
*/
|
||||
trait CartTestTrait
|
||||
{
|
||||
use OrderFromPStateToggleTrait;
|
||||
|
||||
/** @var \Cart */
|
||||
public $cart;
|
||||
|
||||
/** @var \Order */
|
||||
public $order;
|
||||
private $userKey = '123456test123456';
|
||||
|
||||
public function createCart()
|
||||
{
|
||||
$this->cart = $this->get(Cart::class);
|
||||
\Cart::setCartID($this->userKey);
|
||||
|
||||
$this->visitStep('delivery');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCartUserKey(string $userKey): void
|
||||
{
|
||||
$this->userKey = $userKey;
|
||||
}
|
||||
|
||||
public function prepareCart()
|
||||
{
|
||||
$this->createCart();
|
||||
$this->setDeliveryType();
|
||||
$this->setInvoice();
|
||||
|
||||
return $this->cart;
|
||||
}
|
||||
|
||||
public function setDeliveryType($id = 1)
|
||||
{
|
||||
$this->cart->setTransport($id);
|
||||
}
|
||||
|
||||
public function setInvoice()
|
||||
{
|
||||
$this->cart->updateAddresses([
|
||||
'email' => 'test@wpj.cz',
|
||||
'name' => 'Wpj',
|
||||
'surname' => 'Wpj',
|
||||
'street' => 'Wpj 123',
|
||||
'city' => 'Vrchlabi',
|
||||
'zip' => 12345,
|
||||
'country' => 'CZ',
|
||||
'phone' => '123456789',
|
||||
], null);
|
||||
}
|
||||
|
||||
public function insertProduct($id_product, $id_variation = null, $pieces = 1, $note = '')
|
||||
{
|
||||
$item = [
|
||||
'id_product' => $id_product,
|
||||
'id_variation' => $id_variation,
|
||||
'pieces' => $pieces,
|
||||
'note' => $note,
|
||||
];
|
||||
|
||||
$itemId = $this->cart->addItem($item);
|
||||
$this->assertGreaterThan(0, $itemId);
|
||||
|
||||
return $itemId;
|
||||
}
|
||||
|
||||
public function visitStep($name)
|
||||
{
|
||||
$this->cart->findNextStep($name);
|
||||
$this->cart->actualStep = $name;
|
||||
}
|
||||
|
||||
public function checkOrderPriceIsSameAsCart()
|
||||
{
|
||||
$this->order = $this->submitOrder();
|
||||
|
||||
$this->assertEquals($this->cart->totalPricePay->asFloat(), $this->order->total_price->asFloat(), '', 0.01);
|
||||
}
|
||||
|
||||
protected function loginUser($id_user)
|
||||
{
|
||||
$this->assertNull($this->cart, 'loginUser se musi volat jeste pred vytvorenim kosiku');
|
||||
|
||||
$user = \User::createFromId($id_user);
|
||||
$user->activateUser();
|
||||
}
|
||||
|
||||
public function saveCart()
|
||||
{
|
||||
$this->cart->save();
|
||||
}
|
||||
|
||||
public function submitOrder(): \Order
|
||||
{
|
||||
$this->recalculateCart();
|
||||
|
||||
$this->order = $this->cart->submitOrder();
|
||||
|
||||
$this->assertInstanceOf(\Order::class, $this->order);
|
||||
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
public function recalculateCart(): \Decimal
|
||||
{
|
||||
// je to fuj, ale je to kvuli spravnym cenam... aby se zapocitala i cena DeliveryType
|
||||
$this->cart->totalDiscountPrice = \DecimalConstants::zero();
|
||||
$this->cart->totalDiscountPriceNoVat = \DecimalConstants::zero();
|
||||
$this->cart->totalPricePay = \DecimalConstants::zero();
|
||||
$this->cart->totalPricePayNoVat = \DecimalConstants::zero();
|
||||
$this->cart->totalPriceNoVat = \DecimalConstants::zero();
|
||||
$this->cart->totalPriceWithVat = \DecimalConstants::zero();
|
||||
$this->cart->delivery_types = [];
|
||||
|
||||
// HACK: Donutit to znova spocitat
|
||||
$prop = new \ReflectionProperty(\CartBase::class, 'initialized');
|
||||
$prop->setAccessible(true);
|
||||
$prop->setValue($this->cart, false);
|
||||
$this->cart->only_virtual_products = null;
|
||||
$this->cart->createFromDB();
|
||||
|
||||
return $this->cart->totalPricePay;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\DevelopmentBundle\Util\Tests;
|
||||
|
||||
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
use Symfony\Contracts\Service\Attribute\Required;
|
||||
|
||||
trait ContainerAwareTestTrait
|
||||
{
|
||||
/**
|
||||
* @template T
|
||||
*
|
||||
* @param $service string|class-string<T>
|
||||
*
|
||||
* @return mixed|T
|
||||
*/
|
||||
public function get($service)
|
||||
{
|
||||
return ServiceContainer::getService($service);
|
||||
}
|
||||
|
||||
public function set($service, $instance, $container = null)
|
||||
{
|
||||
$container = $container ?: ServiceContainer::getContainer();
|
||||
|
||||
// osklivost, ale jinak to proste nejde :/ ten container pro testy umoznuje pouze pristupovat k private
|
||||
// servisam, ale setovani to uz nepodporuje a spadne to napr. na tom, ze se nemuze nasetovat private servica
|
||||
$refObject = new \ReflectionObject($container);
|
||||
$refMethod = $refObject->getMethod('getPublicContainer');
|
||||
$refMethod->setAccessible(true);
|
||||
$publicContainer = $refMethod->invoke($container);
|
||||
$refObject = new \ReflectionObject($publicContainer);
|
||||
|
||||
// povolim to v syntheticIds - to umozni nasetovat tu servisu do public containeru
|
||||
$refProperty = $refObject->getProperty('syntheticIds');
|
||||
$refProperty->setAccessible(true);
|
||||
$refProperty->setValue($publicContainer, array_merge($refProperty->getValue($publicContainer), [$service => $instance]));
|
||||
|
||||
// nasetuju tu servisu i do private containeru
|
||||
$refProperty = $refObject->getProperty('privates');
|
||||
$refProperty->setAccessible(true);
|
||||
$refProperty->setValue($publicContainer, array_merge($refProperty->getValue($publicContainer), [$service => $instance]));
|
||||
|
||||
return $publicContainer->set($service, $instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Client.
|
||||
*
|
||||
* @param array $options An array of options to pass to the createKernel class
|
||||
* @param array $server An array of server parameters
|
||||
*
|
||||
* @return KernelBrowser A Client instance
|
||||
*/
|
||||
protected function createClient(array $options = [], array $server = [])
|
||||
{
|
||||
$server = array_merge([
|
||||
'HTTPS' => true,
|
||||
'HTTP_HOST' => 'www.kupshop.local',
|
||||
], $server);
|
||||
|
||||
/** @var KernelBrowser $client */
|
||||
$client = $this->get('test.client');
|
||||
$client->setServerParameters($server);
|
||||
$client->disableReboot();
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
public function tearDownContainer()
|
||||
{
|
||||
// shutdown kernel before being destroyed - to be memory freed correctly
|
||||
ServiceContainer::getKernel()->shutdown();
|
||||
// destroy kernel
|
||||
ServiceContainer::destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a $class and autowire it with services from the Service Container.
|
||||
*
|
||||
* @template T
|
||||
*
|
||||
* @param class-string<T> $class
|
||||
*
|
||||
* @return T
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
protected function autowire(string $class)
|
||||
{
|
||||
$rc = new \ReflectionClass($class);
|
||||
$constructor = $rc->getConstructor();
|
||||
|
||||
// get constructor arguments from the container
|
||||
$constructorArgs = [];
|
||||
if ($constructor) {
|
||||
foreach ($constructor->getParameters() as $name => $param) {
|
||||
$classFqn = $param->getType()?->getName();
|
||||
$constructorArgs[$name] = $this->get($classFqn);
|
||||
}
|
||||
}
|
||||
|
||||
$instance = $rc->newInstanceArgs($constructorArgs);
|
||||
|
||||
// setter autowiring - public and has the `@required` annotation
|
||||
$setters = array_filter(
|
||||
$rc->getMethods(\ReflectionMethod::IS_PUBLIC),
|
||||
self::isRequired(...),
|
||||
);
|
||||
|
||||
foreach ($setters as $setter) {
|
||||
if ($setter->getNumberOfParameters() !== 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$param = $setter->getParameters()[0];
|
||||
$classFqn = $param->getType()?->getName();
|
||||
|
||||
$setter->invoke($instance, $this->get($classFqn));
|
||||
}
|
||||
|
||||
// autowire public properties with the `@required` annotation or Required attribute
|
||||
$requiredProperties = array_filter(
|
||||
$rc->getProperties(\ReflectionProperty::IS_PUBLIC),
|
||||
self::isRequired(...),
|
||||
);
|
||||
|
||||
foreach ($requiredProperties as $property) {
|
||||
$classFqn = $property->getType()?->getName();
|
||||
|
||||
$instance->{$property->getName()} = $this->get($classFqn);
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
protected function getRequiredProperties(object $class): array
|
||||
{
|
||||
$reflectionClass = new \ReflectionClass($class);
|
||||
|
||||
$requiredProperties = [];
|
||||
|
||||
// Check properties
|
||||
foreach ($reflectionClass->getProperties() as $property) {
|
||||
$attributes = $property->getAttributes(Required::class);
|
||||
$requireDoc = str_contains($property->getDocComment() ?? '', '@required');
|
||||
if (!empty($attributes) || !empty($requireDoc)) {
|
||||
$requiredProperties[] = $property->getName();
|
||||
}
|
||||
}
|
||||
|
||||
// Check methods
|
||||
foreach ($reflectionClass->getMethods() as $method) {
|
||||
$attributes = $method->getAttributes(Required::class);
|
||||
$requireDoc = str_contains($method->getDocComment() ?? '', '@required');
|
||||
if (!empty($attributes) || !empty($requireDoc)) {
|
||||
// Check if the method is a setter
|
||||
if (preg_match('/^set(.+)$/', $method->getName(), $matches)) {
|
||||
$propertyName = lcfirst($matches[1]);
|
||||
$requiredProperties[] = $propertyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $requiredProperties;
|
||||
}
|
||||
|
||||
private static function isRequired(\ReflectionMethod|\ReflectionProperty $prop): bool
|
||||
{
|
||||
$requireAttr = !empty($prop->getAttributes(Required::class));
|
||||
|
||||
$requireDoc = str_contains($prop->getDocComment() ?? '', '@required');
|
||||
|
||||
return $requireDoc || $requireAttr;
|
||||
}
|
||||
}
|
||||
157
bundles/KupShop/DevelopmentBundle/Util/Tests/DatabaseUtils.php
Normal file
157
bundles/KupShop/DevelopmentBundle/Util/Tests/DatabaseUtils.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\DevelopmentBundle\Util\Tests;
|
||||
|
||||
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
||||
use Upgrade;
|
||||
|
||||
class DatabaseUtils
|
||||
{
|
||||
private $databaseChecksum;
|
||||
|
||||
private $testDatabase = [
|
||||
'engine' => 'phpunit_test',
|
||||
'engine_units_float' => 'phpunit_test_units_float',
|
||||
'shop' => 'phpunit_test_shop',
|
||||
];
|
||||
|
||||
public function prepare()
|
||||
{
|
||||
$databaseName = $this->getDbName();
|
||||
|
||||
// Pass current database name to upgrade check_DBExists
|
||||
define('TEST_DB_NAME', $databaseName);
|
||||
|
||||
// Load stored checksum
|
||||
if (empty($this->databaseChecksum) && is_file('/tmp/kupshop_test_checksum')) {
|
||||
$this->databaseChecksum = file_get_contents('/tmp/kupshop_test_checksum');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->debugDatabaseChecksum();
|
||||
$this->createSchema();
|
||||
$this->debugDatabaseChecksum();
|
||||
} catch (\Exception $e) {
|
||||
echo "Error during database upgrade: {$e->getMessage()}\n{$e->getTraceAsString()}\n";
|
||||
}
|
||||
|
||||
if (TEST_SUITE == 'engine') {
|
||||
$this->checkDatabaseChecksum();
|
||||
} else {
|
||||
$this->databaseChecksum = $this->makeDatabaseChecksum();
|
||||
}
|
||||
|
||||
// Clear memcached
|
||||
getMemcached()->flush();
|
||||
}
|
||||
|
||||
public function createSchema()
|
||||
{
|
||||
global $cfg;
|
||||
/* @var \Doctrine\DBAL\Driver\PDOStatement $res */
|
||||
$cfg['Connection']['database'] = $this->getDbName();
|
||||
|
||||
$coverage = false;
|
||||
if (extension_loaded('xdebug')) {
|
||||
if ($coverage = xdebug_code_coverage_started()) {
|
||||
xdebug_stop_code_coverage(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Run migrations
|
||||
$upgrade = new \Upgrade(
|
||||
\Upgrade::VERBOSE_NO,
|
||||
TEST_SUITE === 'shop' ? \Upgrade::LOCAL_UPGRADES_YES : \Upgrade::LOCAL_UPGRADES_NO
|
||||
);
|
||||
$upgrade->run();
|
||||
$upgrade->run();
|
||||
|
||||
if ($coverage) {
|
||||
xdebug_start_code_coverage();
|
||||
}
|
||||
|
||||
ServiceContainer::destroy();
|
||||
}
|
||||
|
||||
private function debugDatabaseChecksum()
|
||||
{
|
||||
return;
|
||||
|
||||
try {
|
||||
echo "Database tables checksum:\n";
|
||||
$checksums = sqlFetchAll(sqlQuery(
|
||||
sprintf(
|
||||
'CHECKSUM TABLE %s',
|
||||
join(',', sqlGetConnection()->getSchemaManager()->listTableNames())
|
||||
)
|
||||
));
|
||||
array_map(function ($row) {
|
||||
echo "{$row['Table']}: {$row['Checksum']}\n";
|
||||
}, $checksums);
|
||||
echo "\n{$this->makeDatabaseChecksum()}\n";
|
||||
} catch (Exception $e) {
|
||||
echo "exception\n";
|
||||
}
|
||||
}
|
||||
|
||||
private function makeDatabaseChecksum()
|
||||
{
|
||||
$tables = sqlGetConnection()->getSchemaManager()->listTableNames();
|
||||
|
||||
if (!count($tables)) {
|
||||
return 'empty';
|
||||
}
|
||||
|
||||
return sha1(implode(array_column(sqlFetchAll(sqlQuery(
|
||||
sprintf(
|
||||
'CHECKSUM TABLE %s',
|
||||
join(',', $tables)
|
||||
)
|
||||
)), 'Checksum')));
|
||||
}
|
||||
|
||||
private function checkDatabaseChecksum()
|
||||
{
|
||||
$checksum = $this->makeDatabaseChecksum();
|
||||
if ($checksum != $this->databaseChecksum) {
|
||||
echo "Database checksum does not match!\n
|
||||
correct:".$this->databaseChecksum." current:{$checksum}\n";
|
||||
$this->debugDatabaseChecksum();
|
||||
|
||||
echo "Deleting database {$this->getDbName()}...\n";
|
||||
|
||||
sqlQuery('DROP DATABASE IF EXISTS '.$this->getDbName());
|
||||
sqlQuery('CREATE DATABASE '.$this->getDbName());
|
||||
sqlQuery('USE '.$this->getDbName());
|
||||
|
||||
echo "Running upgrade ...\n";
|
||||
$this->createSchema();
|
||||
|
||||
$this->databaseChecksum = $this->makeDatabaseChecksum();
|
||||
$this->debugDatabaseChecksum();
|
||||
|
||||
echo 'Database checksum does not match!
|
||||
Correct checksum: '.$this->databaseChecksum."\n\n";
|
||||
|
||||
echo "Storing checksum {$this->databaseChecksum} to /tmp/kupshop_test_checksum";
|
||||
$f = fopen('/tmp/kupshop_test_checksum', 'w');
|
||||
fwrite($f, $this->databaseChecksum);
|
||||
fclose($f);
|
||||
}
|
||||
}
|
||||
|
||||
public function getDatabaseChecksum(): string
|
||||
{
|
||||
return $this->databaseChecksum;
|
||||
}
|
||||
|
||||
public function getDbName()
|
||||
{
|
||||
return $this->testDatabase[TEST_SUITE].getenv('TEST_TOKEN');
|
||||
}
|
||||
|
||||
public function checkDatabaseNotChanged()
|
||||
{
|
||||
return $this->databaseChecksum === $this->makeDatabaseChecksum();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\DevelopmentBundle\Util\Tests;
|
||||
|
||||
use Monolog\Handler\TestHandler;
|
||||
use Symfony\Bridge\Monolog\Logger;
|
||||
|
||||
trait LoggerTestTrait
|
||||
{
|
||||
public function getLogger()
|
||||
{
|
||||
/** @var Logger $logger */
|
||||
$logger = $this->get('logger');
|
||||
$testHandler = new TestHandler('DEBUG');
|
||||
$logger->pushHandler($testHandler);
|
||||
}
|
||||
|
||||
public function getTestHandler()
|
||||
{
|
||||
$logger = $this->get('logger');
|
||||
$testHandler = null;
|
||||
foreach ($logger->getHandlers() as $handler) {
|
||||
if ($handler instanceof TestHandler) {
|
||||
$testHandler = $handler;
|
||||
}
|
||||
}
|
||||
|
||||
return $testHandler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\DevelopmentBundle\Util\Tests;
|
||||
|
||||
trait OrderFromPStateToggleTrait
|
||||
{
|
||||
public function data_purchaseStateProvider(): \Generator
|
||||
{
|
||||
yield 'Test with module create_orders_from_purchase_state' => [function () {
|
||||
$this->addModule(\Modules::ORDERS, \Modules::SUB_CREATE_ORDER_FROM_PURCHASE_STATE);
|
||||
}];
|
||||
|
||||
yield 'Test without module create_orders_from_purchase_state' => [function () {
|
||||
$this->removeModule(\Modules::ORDERS, \Modules::SUB_CREATE_ORDER_FROM_PURCHASE_STATE);
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\DevelopmentBundle\Util\Tests;
|
||||
|
||||
trait RequestCookiesTrait
|
||||
{
|
||||
/** Get request stack with cookies for functional testing */
|
||||
protected function getRequestStackWithCookies($cookieName, $cookieValue)
|
||||
{
|
||||
$requestStack = $this->get(\Symfony\Component\HttpFoundation\RequestStack::class);
|
||||
$request = new \Symfony\Component\HttpFoundation\Request();
|
||||
|
||||
$request->cookies->set($cookieName, $cookieValue);
|
||||
$request->setSession(
|
||||
$this->get('session.factory')->createSession()
|
||||
);
|
||||
|
||||
$requestStack->push($request);
|
||||
|
||||
return $requestStack;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\DevelopmentBundle\Util\Tests;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
trait RequestSessionTrait
|
||||
{
|
||||
/** Prepares request stack for functional testing */
|
||||
protected function prepareRequestStackSession(): void
|
||||
{
|
||||
$requestStack = $this->get(\Symfony\Component\HttpFoundation\RequestStack::class);
|
||||
$request = new \Symfony\Component\HttpFoundation\Request();
|
||||
|
||||
$request->setSession(
|
||||
$this->get(SessionInterface::class)
|
||||
);
|
||||
|
||||
$requestStack->push($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\DevelopmentBundle\Util\Tests;
|
||||
|
||||
use KupShop\KupShopBundle\KupShopAppKernel;
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Contracts\Service\ResetInterface;
|
||||
|
||||
class TestAppKernel extends KupShopAppKernel
|
||||
{
|
||||
protected static $connection;
|
||||
|
||||
public function registerContainerConfiguration(LoaderInterface $loader)
|
||||
{
|
||||
global $cfg;
|
||||
$loader->load(realpath($cfg['Path']['shared_version']).'/bundles/KupShop/KupShopBundle/Resources/config/config_'.$this->getEnvironment().'.yml');
|
||||
}
|
||||
|
||||
protected function initializeContainer()
|
||||
{
|
||||
parent::initializeContainer();
|
||||
|
||||
if (!self::$connection) {
|
||||
self::$connection = sqlGetConnection();
|
||||
} else {
|
||||
$this->getContainer()->set('doctrine.dbal.default_connection', self::$connection);
|
||||
}
|
||||
}
|
||||
|
||||
public function shutdown()
|
||||
{
|
||||
// call reset before shutdown to be memory freed correctly
|
||||
if ($this->getContainer() instanceof ResetInterface) {
|
||||
$this->getContainer()->reset();
|
||||
}
|
||||
|
||||
parent::shutdown();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user