Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Monorepo/Benchmark/AsynchronousStackBenchmark.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
use Monorepo\ExampleApp\Common\Domain\Order\ShippingAddress;
use Monorepo\ExampleApp\Common\Infrastructure\Configuration;
use Monorepo\ExampleApp\ExampleAppCaseTrait;
use PHPUnit\Framework\Assert;
use Psr\Container\ContainerInterface;
use Ramsey\Uuid\Uuid;

#[Warmup(1), Revs(10), Iterations(5)]
final class AsynchronousStackBenchmark extends FullAppBenchmarkCase
final class AsynchronousStackBenchmark extends Assert
{
use FullAppBenchmarkCaseTrait;
use ExampleAppCaseTrait;

public function executeForSymfony(ContainerInterface $container, \Symfony\Component\HttpKernel\Kernel $kernel): void
Expand Down
4 changes: 3 additions & 1 deletion Monorepo/Benchmark/BootingEcotoneBenchmark.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
use PhpBench\Attributes\Iterations;
use PhpBench\Attributes\Revs;
use PhpBench\Attributes\Warmup;
use PHPUnit\Framework\Assert;
use Psr\Container\ContainerInterface;

#[Warmup(1), Revs(10), Iterations(5)]
class BootingEcotoneBenchmark extends FullAppBenchmarkCase
class BootingEcotoneBenchmark extends Assert
{
use FullAppBenchmarkCaseTrait;
use ExampleAppCaseTrait;

public function executeForSymfony(ContainerInterface $container, \Symfony\Component\HttpKernel\Kernel $kernel): void
Expand Down
3 changes: 2 additions & 1 deletion Monorepo/Benchmark/EventSourcingBenchmark.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
use Ramsey\Uuid\Uuid;

#[Warmup(1), Revs(10), Iterations(5)]
class EventSourcingBenchmark extends FullAppBenchmarkCase
class EventSourcingBenchmark extends Assert
{
use FullAppBenchmarkCaseTrait;
use ExampleAppEventSourcingCaseTrait;

public static function skippedPackages(): array
Expand Down
269 changes: 10 additions & 259 deletions Monorepo/Benchmark/FullAppBenchmarkCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,269 +2,20 @@

namespace Monorepo\Benchmark;

use Ecotone\Messaging\Config\ConfiguredMessagingSystem;
use Ecotone\Messaging\Config\ModulePackageList;
use Ecotone\Messaging\Endpoint\ExecutionPollingMetadata;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Http\Kernel as LaravelKernel;
use Illuminate\Support\Facades\Artisan;

use function json_encode;

use PHPUnit\Framework\Assert;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;

use function putenv;

use Symfony\Bundle\FrameworkBundle\Console\Application as SymfonyConsoleApplication;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\HttpKernel\Kernel as SymfonyKernel;

/**
* @BeforeClassMethods("clearAllCaches")
* Base for real PHPUnit test cases (run via `vendor/bin/phpunit`) that need the shared
* app-booting/cache-clearing/benchmark helpers in FullAppBenchmarkCaseTrait. PHPUnit
* constructs its TestCase subclasses itself (passing the test method name into
* TestCase::__construct(), which PHPUnit 12 made final), so extending TestCase here is safe.
*
* Pure PHPBench subjects (executed via `new $class()` with no constructor arguments,
* see phpbench's remote.template) must NOT extend this class — TestCase::__construct()
* requires a mandatory argument PHPBench never supplies. They should extend
* PHPUnit\Framework\Assert directly and `use FullAppBenchmarkCaseTrait;` instead.
*/
abstract class FullAppBenchmarkCase extends TestCase
{
public function __construct(?string $name = 'benchmark')
{
parent::__construct($name);
}
public function bench_symfony_prod()
{
self::productionEnvironments();
$kernel = self::bootSymfonyKernel(environment: 'prod', debug: false);
$container = $kernel->getContainer();

$this->executeForSymfony($container, $kernel);
}

public function bench_symfony_dev()
{
self::developmentEnvironments();
$kernel = self::bootSymfonyKernel(environment: 'dev', debug: true);
$container = $kernel->getContainer();

$this->executeForSymfony($container, $kernel);
}

public function bench_laravel_prod(): void
{
self::productionEnvironments();
$app = self::createLaravelApplication();

$this->executeForLaravel($app, $app->get(LaravelKernel::class));
}

public function bench_laravel_dev(): void
{
self::developmentEnvironments();
$app = self::createLaravelApplication();

$this->executeForLaravel($app, $app->get(LaravelKernel::class));
}

public function bench_lite_application_prod()
{
self::productionEnvironments();
$bootstrap = require static::getProjectDir() . '/LiteApplication/app.php';
$messagingSystem = $bootstrap(true);
$this->executeForLiteApplication(new LiteContainerAccessor($messagingSystem));
}

public function bench_lite_application_dev()
{
self::developmentEnvironments();
$bootstrap = require static::getProjectDir() . '/LiteApplication/app.php';
$messagingSystem = $bootstrap(false);
$this->executeForLiteApplication(new LiteContainerAccessor($messagingSystem));
}

public function bench_lite_prod()
{
self::productionEnvironments();
$bootstrap = require static::getProjectDir() . '/Lite/app.php';
$messagingSystem = $bootstrap(true);
$this->executeForLite($messagingSystem);
}

public function bench_lite_dev()
{
self::developmentEnvironments();
$bootstrap = require static::getProjectDir() . '/Lite/app.php';
$messagingSystem = $bootstrap(false);
$this->executeForLite($messagingSystem);
}

public static function clearAllCaches(): void
{
self::clearLaravelCache();
self::clearSymfonyCache();
self::clearLiteApplicationCache();
self::clearLiteCache();
}

public static function clearLiteCache(): void
{
self::deleteFiles(
static::getProjectDir() . '/Lite/var/cache',
false
);
}

public static function clearLiteApplicationCache(): void
{
self::deleteFiles(
static::getProjectDir() . '/LiteApplication/var/cache',
false
);
}

/**
* Calling config:cache always dumps the cache,
* this means we need to do it before the benchmark
*/
public function dumpLaravelCache(): void
{
self::productionEnvironments();
self::createLaravelApplication();
Artisan::call('route:cache');
Artisan::call('config:cache');
}

public static function clearLaravelCache(): void
{
self::deleteFiles(
static::getProjectDir() . '/Laravel/storage/framework/cache/data',
false
);
}

public static function clearSymfonyCache(): void
{
self::deleteFiles(
static::getProjectDir() . '/Symfony/var/cache',
false
);
}

private static function deleteFiles(string $target, bool $deleteDirectory): void
{
if (is_dir($target)) {
\Ecotone\Messaging\Support\Assert::isTrue(
is_writable($target),
"Not enough permissions to delete from cache directory {$target}"
);
$files = glob($target . '*', GLOB_MARK);

foreach ($files as $file) {
self::deleteFiles($file, true);
}

if ($deleteDirectory) {
rmdir($target);
}
} elseif (is_file($target)) {
Assert::isTrue(
is_writable($target),
"Not enough permissions to delete cache file {$target}"
);
unlink($target);
}
}

abstract public function executeForSymfony(
ContainerInterface $container,
SymfonyKernel $kernel
): void;

abstract public function executeForLaravel(
ContainerInterface $container,
LaravelKernel $kernel
): void;

abstract public function executeForLiteApplication(
ContainerInterface $container
): void;

abstract public function executeForLite(
ConfiguredMessagingSystem $messagingSystem
): void;

abstract protected static function getSymfonyKernelClass(): string;
abstract protected static function getProjectDir(): string;

private static function productionEnvironments(): void
{
putenv('APP_ENV=prod');
putenv('APP_DEBUG=false');
putenv(sprintf('APP_SKIPPED_PACKAGES=%s', json_encode(static::skippedPackages(), JSON_THROW_ON_ERROR)));
}

private static function developmentEnvironments(): void
{
putenv('APP_ENV=dev');
putenv('APP_DEBUG=true');
putenv(sprintf('APP_SKIPPED_PACKAGES=%s', json_encode(static::skippedPackages(), JSON_THROW_ON_ERROR)));
}

public static function skippedPackages(): array
{
return ModulePackageList::allPackagesExcept([ModulePackageList::ASYNCHRONOUS_PACKAGE]);
}

private static function createLaravelApplication(): Application
{
$app = require static::getProjectDir() . '/Laravel/bootstrap/app.php';

$app->make(LaravelKernel::class)->bootstrap();

return $app;
}

public static function bootSymfonyKernel(string $environment, bool $debug): SymfonyKernel
{
$kernelClass = static::getSymfonyKernelClass();
$kernel = new $kernelClass($environment, $debug);
$kernel->boot();
return $kernel;
}

public static function executeSymfonyConsoleCommand(SymfonyKernel $kernel, string $commandName, array $input): void
{
$application = new SymfonyConsoleApplication($kernel);
$result = $application->find($commandName)->run(
new ArrayInput($input),
new NullOutput()
);

Assert::assertSame(0, $result);
}

public static function runConsumerForSymfony(string $consumerName, SymfonyKernel $kernel, bool $stopOnFailure = true): void
{
self::executeSymfonyConsoleCommand(
$kernel,
'ecotone:run',
['consumerName' => $consumerName, '--stopOnFailure' => $stopOnFailure, '--executionTimeLimit' => 2000, '--finishWhenNoMessages' => true]
);
}

public static function runConsumerForLaravel(string $consumerName, bool $stopOnFailure = true): void
{
Artisan::call(
'ecotone:run',
['consumerName' => $consumerName, '--stopOnFailure' => $stopOnFailure, '--executionTimeLimit' => 2000, '--finishWhenNoMessages' => true]
);
}

public static function runConsumerForMessaging(string $consumerName, ConfiguredMessagingSystem $messagingSystem, bool $stopOnFailure = true): void
{
$messagingSystem->run(
$consumerName,
ExecutionPollingMetadata::createWithFinishWhenNoMessages($stopOnFailure)
->withExecutionTimeLimitInMilliseconds(2000)
);
}
use FullAppBenchmarkCaseTrait;
}
Loading
Loading