Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests/e2e - Isolate each call to civix. More representative of real usage #359

Merged
merged 1 commit into from
Jun 27, 2024
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
34 changes: 34 additions & 0 deletions src/CRM/CivixBundle/Test/CommandTester.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace CRM\CivixBundle\Test;

interface CommandTester {

/**
* Executes the command.
*
* Available execution options:
*
* * interactive: Sets the input interactive flag
* * decorated: Sets the output decorated flag
* * verbosity: Sets the output verbosity flag
* * capture_stderr_separately: Make output of stdOut and stdErr separately available
*
* @param array $input An array of command arguments and options
* @param array $options An array of execution options
*
* @return int The command exit code
*/
public function execute(array $input, array $options = []);

/**
* @return string
*/
public function getDisplay(bool $normalize = FALSE);

/**
* @return int
*/
public function getStatusCode();

}
88 changes: 88 additions & 0 deletions src/CRM/CivixBundle/Test/SubProcessCommandTester.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

namespace CRM\CivixBundle\Test;

use Symfony\Component\Process\Process;

class SubProcessCommandTester implements CommandTester {

/**
* @var array
*/
protected $baseCommand;

/**
* @var string|null
*/
protected $display;

/**
* @var int|null
*/
protected $statusCode;

/**
* @param array $baseCommand
*/
public function __construct(array $baseCommand) {
$this->baseCommand = $baseCommand;
}

/**
* Executes the command.
*
* @param array $input An array of command arguments and options
* @param array $options An array of execution options
* Ignored
* @return int The command exit code
*/
public function execute(array $input, array $options = []) {
if (!empty($options)) {
throw new \LogicException(__CLASS__ . " does not implement support for execute() options");
}

$command = $this->baseCommand;
foreach ($input as $key => $value) {
if (substr($key, 0, 2) === '--') {
if ($value === TRUE) {
$command[] = $key;
}
else {
$command[] = "$key=$value";
}
}
else {
$command[] = $value;
}
}

$buffer = fopen('php://memory', 'w+');

$p = new Process($command);
$p->run(function ($type, $data) use ($buffer) {
// Default policy - combine STDOUT and STDIN into one continuous stream.
fwrite($buffer, $data);
});
$this->statusCode = $p->getExitCode();

rewind($buffer);
$this->display = stream_get_contents($buffer);
fclose($buffer);

return $this->statusCode;
}

public function getDisplay(bool $normalize = FALSE) {
if ($normalize) {
return str_replace(\PHP_EOL, "\n", $this->display);
}
else {
return $this->display;
}
}

public function getStatusCode(): int {
return $this->statusCode;
}

}
35 changes: 28 additions & 7 deletions tests/e2e/CivixProjectTestTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

namespace E2E;

use CRM\CivixBundle\Application;
use CRM\CivixBundle\Generator;
use CRM\CivixBundle\Test\CommandTester;
use CRM\CivixBundle\Test\SubProcessCommandTester;
use CRM\CivixBundle\Utils\Files;
use CRM\CivixBundle\Utils\Path;
use ProcessHelper\ProcessHelper as PH;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Tester\CommandTester;

/**
* Add this to a test-class to define an E2E test with a new civix-style extension/project.
Expand Down Expand Up @@ -71,11 +71,32 @@ public static function getExtPath(...$subpath): Path {
return static::getWorkspacePath(...$subpath);
}

public static function civix(string $command): CommandTester {
public static function civix(string $subCommand): CommandTester {
\Civix::reset();
$application = new Application();
$command = $application->find($command);
return new CommandTester($command);

$isolation = getenv('CIVIX_TEST_ISOLATION') ?: 'on';

switch ($isolation) {
case 'on':
if (getenv('CIVIX_TEST_BINARY')) {
$baseCommand = [getenv('CIVIX_TEST_BINARY')];
}
else {
$baseCommand = ['php', (dirname(__DIR__, 2) . '/bin/civix')];
}
$baseCommand[] = $subCommand;
return new SubProcessCommandTester($baseCommand);

case 'off':
$application = new \CRM\CivixBundle\Application();
$command = $application->find($subCommand);
return new class ($command) extends \Symfony\Component\Console\Tester\CommandTester implements CommandTester {

};

default:
throw new \RuntimeException("Unrecognized value of CIVIX_TEST_BINARY. Specify on|off.");
}
}

public function civixGenerateModule(string $key, array $options = []): CommandTester {
Expand All @@ -85,7 +106,7 @@ public function civixGenerateModule(string $key, array $options = []): CommandTe
'--enable' => 'false',
]);
if ($tester->getStatusCode() !== 0) {
throw new \RuntimeException(sprintf("Failed to generate module (%s)", $key));
throw new \RuntimeException(sprintf("Failed to generate module (%s):\n%s", $key, $tester->getDisplay(TRUE)));
}
return $tester;
}
Expand Down