Added bin/grav page-system-validator [-r|--record] [-c|--check] to test Flex Pages

This commit is contained in:
Matias Griese
2019-09-13 21:45:54 +03:00
parent e91ae5542d
commit ce2b80aeb9
3 changed files with 291 additions and 13 deletions

View File

@@ -5,6 +5,7 @@
* Added new `Security::sanitizeSVG()` function
1. [](#improved)
* Several FlexObject loading improvements
* Added `bin/grav page-system-validator [-r|--record] [-c|--check]` to test Flex Pages
1. [](#bugfix)
* Regression: Fixed language fallback
* Regression: Fixed translations when language code is used for non-language purposes

View File

@@ -3,7 +3,7 @@
use Grav\Common\Composer;
use Grav\Common\Grav;
use League\CLImate\CLImate;
use Grav\Console\Cli;
use Symfony\Component\Console\Application;
\define('GRAV_CLI', true);
@@ -52,17 +52,18 @@ if (!file_exists(GRAV_ROOT . '/index.php')) {
$app = new Application('Grav CLI Application', GRAV_VERSION);
$app->addCommands(array(
new \Grav\Console\Cli\InstallCommand(),
new \Grav\Console\Cli\ComposerCommand(),
new \Grav\Console\Cli\SandboxCommand(),
new \Grav\Console\Cli\CleanCommand(),
new \Grav\Console\Cli\ClearCacheCommand(),
new \Grav\Console\Cli\BackupCommand(),
new \Grav\Console\Cli\NewProjectCommand(),
new \Grav\Console\Cli\SchedulerCommand(),
new \Grav\Console\Cli\SecurityCommand(),
new \Grav\Console\Cli\LogViewerCommand(),
new \Grav\Console\Cli\YamlLinterCommand(),
new \Grav\Console\Cli\ServerCommand(),
new Cli\InstallCommand(),
new Cli\ComposerCommand(),
new Cli\SandboxCommand(),
new Cli\CleanCommand(),
new Cli\ClearCacheCommand(),
new Cli\BackupCommand(),
new Cli\NewProjectCommand(),
new Cli\SchedulerCommand(),
new Cli\SecurityCommand(),
new Cli\LogViewerCommand(),
new Cli\YamlLinterCommand(),
new Cli\ServerCommand(),
new Cli\PageSystemValidatorCommand(),
));
$app->run();

View File

@@ -0,0 +1,276 @@
<?php
/**
* @package Grav\Console\Cli
*
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Console\Cli;
use Grav\Common\Config\Config;
use Grav\Common\File\CompiledYamlFile;
use Grav\Common\Grav;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Uri;
use Grav\Console\ConsoleCommand;
use RocketTheme\Toolbox\Event\Event;
use Symfony\Component\Console\Input\InputOption;
class PageSystemValidatorCommand extends ConsoleCommand
{
protected $tests = [
// Content
'header' => [[]],
'summary' => [[], [200], [200, true]],
'content' => [[]],
'getRawContent' => [[]],
'rawMarkdown' => [[]],
'value' => [['content'], ['route'], ['order'], ['ordering'], ['folder'], ['slug'], ['name'], /*['frontmatter'],*/ ['header.menu'], ['header.slug']],
'title' => [[]],
'menu' => [[]],
'visible' => [[]],
'published' => [[]],
'publishDate' => [[]],
'unpublishDate' => [[]],
'process' => [[]],
'slug' => [[]],
'order' => [[]],
//'id' => [[]],
'modified' => [[]],
'lastModified' => [[]],
'folder' => [[]],
'date' => [[]],
'dateformat' => [[]],
'taxonomy' => [[]],
'shouldProcess' => [['twig'], ['markdown']],
'isPage' => [[]],
'isDir' => [[]],
'exists' => [[]],
// Forms
'forms' => [[]],
// Routing
'urlExtension' => [[]],
'routable' => [[]],
'link' => [[], [false], [true]],
'permalink' => [[]],
'canonical' => [[], [false], [true]],
'url' => [[], [true], [true, true], [true, true, false], [false, false, true, false]],
'route' => [[]],
'rawRoute' => [[]],
'routeAliases' => [[]],
'routeCanonical' => [[]],
'redirect' => [[]],
'relativePagePath' => [[]],
'path' => [[]],
//'folder' => [[]],
'parent' => [[]],
'topParent' => [[]],
'currentPosition' => [[]],
'active' => [[]],
'activeChild' => [[]],
'home' => [[]],
'root' => [[]],
// Translations
//'translatedLanguages' => [[], [false], [true]],
//'untranslatedLanguages' => [[], [false], [true]],
//'language' => [[]],
// Legacy
'raw' => [[]],
'frontmatter' => [[]],
'httpResponseCode' => [[]],
'httpHeaders' => [[]],
'blueprintName' => [[]],
'name' => [[]],
'childType' => [[]],
'template' => [[]],
'templateFormat' => [[]],
'extension' => [[]],
'expires' => [[]],
'cacheControl' => [[]],
'ssl' => [[]],
'metadata' => [[]],
'eTag' => [[]],
'filePath' => [[]],
'filePathClean' => [[]],
'orderDir' => [[]],
'orderBy' => [[]],
'orderManual' => [[]],
'maxCount' => [[]],
'modular' => [[]],
'modularTwig' => [[]],
//'children' => [[]],
'isFirst' => [[]],
'isLast' => [[]],
'prevSibling' => [[]],
'nextSibling' => [[]],
'adjacentSibling' => [[]],
'ancestor' => [[]],
//'inherited' => [[]],
//'inheritedField' => [[]],
'find' => [['/']],
//'collection' => [[]],
//'evaluate' => [[]],
'folderExists' => [[]],
//'getOriginal' => [[]],
//'getAction' => [[]],
];
protected function configure()
{
$this
->setName('page-system-validator')
->setDescription('Page validator can be used to compare site before/after update and when migrating to Flex Pages.')
->addOption('record', 'r', InputOption::VALUE_NONE, 'Record results')
->addOption('check', 'c', InputOption::VALUE_NONE, 'Compare site against previously recorded results')
->setHelp('The <info>page-system-validator</info> command can be used to test the pages before and after upgrade');
}
protected function serve()
{
$this->output->writeln('');
$this->grav = $grav = Grav::instance();
$grav->setup();
// Initialize
$grav['uri']->init();
/** @var Config $config */
$config = $grav['config'];
$config->init();
$grav['plugins']->setup();
$grav['debugger']->init();
// Initialize the timezone.
$timezone = $config->get('system.timezone');
if ($timezone) {
date_default_timezone_set($timezone);
}
/** @var Uri $uri */
$uri = $grav['uri'];
$uri->init();
$grav->setLocale();
$grav['language']->setActive('en');
// Plugins
$grav['accounts'];
$grav['plugins']->init();
$grav->fireEvent('onPluginsInitialized');
// Themes
$grav['themes']->init();
// Twig
$grav['twig']->init();
// Pages
$grav['pages']->init();
$grav->fireEvent('onPagesInitialized', new Event(['pages' => $grav['pages']]));
if ($this->input->getOption('record')) {
$this->output->writeln('Pages: ' . $config->get('system.pages.type', 'page'));
$this->output->writeln('<magenta>Record tests</magenta>');
$this->output->writeln('');
$results = $this->record();
$file = $this->getFile('pages-old');
$file->save($results);
$this->output->writeln('Recorded tests to ' . $file->filename());
} elseif ($this->input->getOption('check')) {
$this->output->writeln('Pages: ' . $config->get('system.pages.type', 'page'));
$this->output->writeln('<magenta>Run tests</magenta>');
$this->output->writeln('');
$new = $this->record();
$file = $this->getFile('pages-new');
$file->save($new);
$file = $this->getFile('pages-old');
$old = $file->content();
$results = $this->check($old, $new);
if (empty($results)) {
$this->output->writeln('<green>Success!</green>');
} else {
$file = $this->getFile('diff');
$file->save($results);
$this->output->writeln('Recorded results to ' . $file->filename());
}
} else {
$this->output->writeln('<green>page-system-validator [-r|--record] [-c|--check]</green>');
}
$this->output->writeln('');
}
private function record()
{
$pages = $this->grav['pages'];
$all = $pages->all();
$results = [];
foreach ($all as $page) {
foreach ($this->tests as $method => $params) {
$params = $params ?: [[]];
foreach ($params as $p) {
$result = $page->$method(...$p);
if (in_array($method, ['summary', 'content', 'getRawContent'], true)) {
$result = preg_replace('/name="(form-nonce|__unique_form_id__)" value="[^"]+"/', 'name="\\1" value="DYNAMIC"', $result);
$result = preg_replace('`src=("|\'|&quot;)/images/./././././[^"]+\\1`', 'src="\\1images/GENERATED\\1', $result);
$result = preg_replace('/\?\d{10}/', '?1234567890', $result);
} elseif ($method === 'httpHeaders' && isset($result['Expires'])) {
$result['Expires'] = 'Thu, 19 Sep 2019 13:10:24 GMT (REPLACED AS DYNAMIC)';
} elseif ($result instanceof PageInterface) {
$result = $result->rawRoute();
} elseif (is_object($result)) {
$result = json_decode(json_encode($result), true);
}
$ps = [];
foreach ($p as $val) {
$ps[] = (string)var_export($val, true);
}
$pstr = implode(', ', $ps);
$call = "->{$method}({$pstr})";
$results[$page->rawRoute()][$call] = $result;
}
}
}
return json_decode(json_encode($results), true);
}
private function check(array $old, array $new)
{
$errors = [];
foreach ($old as $path => $page) {
if (!isset($new[$path])) {
$errors[$path] = 'PAGE REMOVED';
continue;
}
foreach ($page as $method => $test) {
if (($new[$path][$method] ?? null) !== $test) {
$errors[$path][$method] = ['old' => $test, 'new' => $new[$path][$method]];
}
}
}
return $errors;
}
/**
* @param string $name
* @return CompiledYamlFile
*/
private function getFile(string $name)
{
return CompiledYamlFile::instance('cache://tests/' . $name . '.yaml');
}
}