Skip to content

Commit

Permalink
added AssetsInstallController tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kilip committed Oct 31, 2018
1 parent df9014c commit 1959330
Show file tree
Hide file tree
Showing 4 changed files with 362 additions and 1 deletion.
2 changes: 2 additions & 0 deletions module/Core/config/module.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@
'Core/File' => FileControllerFactory::class,
'Core/Content' => LazyControllerFactory::class,
Controller\Console\PurgeController::class => Controller\Console\PurgeControllerFactory::class,
AssetsInstallController::class => [AssetsInstallController::class,'factory']

],
),
// Configuration of the controller plugin service manager
Expand Down
261 changes: 261 additions & 0 deletions module/Core/src/Controller/Console/AssetsInstallController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
<?php

/*
* This file is part of the YAWIK project.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Core\Controller\Console;

use Interop\Container\ContainerInterface;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Zend\ModuleManager\ModuleManager;
use Zend\Mvc\Console\Controller\AbstractConsoleController;
use Zend\View\Stream;

/**
* Class AssetsInstallController
*
* @package Core\Controller\Console
* @author Anthonius Munthi <me@itstoni.com>
* @since 0.32.0
*/
class AssetsInstallController extends AbstractConsoleController
{
const METHOD_COPY = 'copy';
const METHOD_ABSOLUTE_SYMLINK = 'absolute symlink';
const METHOD_RELATIVE_SYMLINK = 'relative symlink';

/**
* @var Filesystem
*/
private $filesystem;

private $assets = [];

private $modules = [];

/**
* @var InputInterface
*/
private $input;

/**
* @var OutputInterface
*/
private $output;

public function __construct(array $modules = [])
{
$this->modules = $modules;
$this->filesystem = new Filesystem();
$this->input = new ArgvInput();
$this->output = new ConsoleOutput();
}

public static function factory(ContainerInterface $container)
{
static $stream;

/* @var ModuleManager $manager */
$manager = $container->get('ModuleManager');

$modules = $manager->getLoadedModules();
$config = $container->get('ApplicationConfig');
$ob = new static($modules);

if ($config['environment'] === 'test') {
if (is_null($stream)) {
$stream = fopen('php://memory', 'w');
}
$ob->setOutput(new StreamOutput(
$stream
));
}
return $ob;
}

/**
* @param InputInterface $input
* @return AssetsInstallController
*/
public function setInput($input)
{
$this->input = $input;
return $this;
}

/**
* @param OutputInterface $output
* @return AssetsInstallController
*/
public function setOutput($output)
{
$this->output = $output;
return $this;
}

public function getOutput()
{
return $this->output;
}

public function indexAction()
{
/* @var \Zend\Console\Request $request */


$modules = $this->modules;
foreach ($modules as $module) {
$this->processModule($module);
}

$io = new SymfonyStyle($this->input, $this->output);
$io->newLine();

$rows = [];
$exitCode = 0;
$copyUsed = false;

$request = $this->getRequest();
$publicDir = $request->getParam('target', getcwd().'/public/modules');
$symlink = $request->getParam('symlink');
$relative = $request->getParam('relative');

foreach ($this->assets as $name => $originDir) {
$targetDir = $publicDir.DIRECTORY_SEPARATOR.$name;
$message = $name;
try {
$this->filesystem->remove($targetDir);

if ($relative) {
$expectedMethod = self::METHOD_RELATIVE_SYMLINK;
$method = $this->relativeSymlinkWithFallback($originDir, $targetDir);
} elseif ($symlink) {
$expectedMethod = self::METHOD_ABSOLUTE_SYMLINK;
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
} else {
$expectedMethod = self::METHOD_COPY;
$method = $this->hardCopy($originDir, $targetDir);
}

if (self::METHOD_COPY === $method) {
$copyUsed = true;
}

if ($method === $expectedMethod) {
$rows[] = array(sprintf('<fg=green;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'OK' : "\xE2\x9C\x94" /* HEAVY CHECK MARK (U+2714) */), $message, $method);
} else {
$rows[] = array(sprintf('<fg=yellow;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'WARNING' : '!'), $message, $method);
}
} catch (\Exception $e) {
$exitCode = 1;
$rows[] = array(sprintf('<fg=red;options=bold>%s</>', '\\' === DIRECTORY_SEPARATOR ? 'ERROR' : "\xE2\x9C\x98" /* HEAVY BALLOT X (U+2718) */), $message, $e->getMessage());
}
}

if ($rows) {
$io->table(array('', 'Module', 'Method / Error'), $rows);
}

if (0 !== $exitCode) {
$io->error('Some errors occurred while installing assets.');
} else {
if ($copyUsed) {
$io->note('Some assets were installed via copy. If you make changes to these assets you have to run this command again.');
}
$io->success($rows ? 'All assets were successfully installed.' : 'No assets were provided by any bundle.');
}
}

private function processModule($module)
{
$r = new \ReflectionObject($module);
$file = $r->getFileName();
$baseDir = substr($file, 0, strpos($file, 'src'.DIRECTORY_SEPARATOR));
if (!is_dir($dir = $baseDir.'public')) {
return;
}

$className = get_class($module);
$moduleName = substr($className, 0, strpos($className, '\\'));
$this->assets[$moduleName] = $dir;
}

/**
* Try to create absolute symlink.
*
* Falling back to hard copy.
*/
private function absoluteSymlinkWithFallback($originDir, $targetDir)
{
try {
$this->symlink($originDir, $targetDir);
$method = self::METHOD_ABSOLUTE_SYMLINK;
} catch (\Exception $e) {
// fall back to copy
$method = $this->hardCopy($originDir, $targetDir);
}

return $method;
}

/**
* Try to create relative symlink.
*
* Falling back to absolute symlink and finally hard copy.
*/
private function relativeSymlinkWithFallback($originDir, $targetDir)
{
try {
$this->symlink($originDir, $targetDir, true);
$method = self::METHOD_RELATIVE_SYMLINK;
} catch (\Exception $e) {
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
}

return $method;
}

/**
* Creates symbolic link.
*
* @throws \Exception if link can not be created
*/
private function symlink($originDir, $targetDir, $relative = false)
{
if ($relative) {
$this->filesystem->mkdir(dirname($targetDir));
$originDir = $this->filesystem->makePathRelative($originDir, realpath(dirname($targetDir)));
}
$this->filesystem->symlink($originDir, $targetDir);
if (!file_exists($targetDir)) {
throw new \Exception(
sprintf('Symbolic link "%s" was created but appears to be broken.', $targetDir),
0,
null
);
}
}

/**
* Copies origin to target.
*/
private function hardCopy($originDir, $targetDir)
{
$this->filesystem->mkdir($targetDir, 0777);
// We use a custom iterator to ignore VCS files
$this->filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));

return self::METHOD_COPY;
}
}
4 changes: 3 additions & 1 deletion module/Core/test/CoreTest/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace CoreTest;

use Core\Yawik;
use Zend\Loader\AutoloaderFactory;
use Zend\Mvc\Service\ServiceManagerConfig;
use Zend\ServiceManager\ServiceManager;
Expand All @@ -23,7 +24,7 @@
* @package CoreTest
* @since 0.32
*/
class Bootstrap
class Bootstrap extends Yawik
{

/**
Expand Down Expand Up @@ -56,6 +57,7 @@ public static function init()
{
static $initialized = false;
if (!$initialized) {
parent::init();
//date_default_timezone_set('Europe/Berlin');
error_reporting(E_ALL | E_STRICT);
$testConfig = static::loadConfig();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

/*
* This file is part of the YAWIK project.
*
* (c) Anthonius Munthi <me@itstoni.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace CoreTest\Controller\Console;

use Core\Controller\Console\AssetsInstallController;
use CoreTest\Bootstrap;
use Interop\Container\ContainerInterface;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Tester\CommandTester;
use Zend\Stdlib\ArrayUtils;
use Zend\Test\PHPUnit\Controller\AbstractConsoleControllerTestCase;

class AssetsInstallControllerTest extends AbstractConsoleControllerTestCase
{
private $output;

public function setUp()
{
$this->setApplicationConfig(Bootstrap::getConfig());
parent::setUp();
$this->setUseConsoleRequest(true);
}

public function testSymlink()
{
$target = sys_get_temp_dir().'/yawik/assets-install';

$this->dispatch('assets-install --symlink '.$target);

$display = $this->getDisplay(true);

$this->assertRegExp('/absolute symlink/', $display);
$this->assertDirectoryExists($target.'/Core');
$this->assertDirectoryExists($target.'/Applications');
}

public function testRelative()
{
$target = sys_get_temp_dir().'/yawik/assets-install';

$this->dispatch('assets-install --relative '.$target);

$display = $this->getDisplay(true);

$this->assertRegExp('/relative symlink/', $display);
$this->assertRegExp('/All assets were successfully installed/', $display);
$this->assertDirectoryExists($target.'/Core');
$this->assertDirectoryExists($target.'/Applications');
}

public function testCopy()
{
$target = sys_get_temp_dir().'/yawik/assets-install';

$this->dispatch('assets-install '.$target);

$display = $this->getDisplay(true);

$this->assertRegExp('/Some assets were installed via copy/', $display);
$this->assertDirectoryExists($target.'/Core');
$this->assertDirectoryExists($target.'/Applications');
}

/**
* Gets the display returned by the last execution of the command.
*
* @param bool $normalize Whether to normalize end of lines to \n or not
*
* @return string The display
*/
public function getDisplay($normalize = false)
{
$sm = $this->getApplicationServiceLocator();
$controller = $sm->get(AssetsInstallController::class);
$output = $controller->getOutput();

rewind($output->getStream());

$display = stream_get_contents($output->getStream());

if ($normalize) {
$display = str_replace(PHP_EOL, "\n", $display);
}

return $display;
}
}

0 comments on commit 1959330

Please sign in to comment.