diff --git a/app/config/schema.json b/app/config/schema.json index ef55d6f7..1b4873f6 100644 --- a/app/config/schema.json +++ b/app/config/schema.json @@ -28,17 +28,21 @@ "faker": { "$ref": "#/definitions/faker" }, - "variables": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, "tables": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/table" - } + "oneOf": [ + { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/table" + } + }, + { + "type": "array", + "items": { + "maxLength": 0 + } + } + ] }, "tables_whitelist": { "type": "array", @@ -53,6 +57,22 @@ "type": "string", "minLength": 1 } + }, + "variables": { + "oneOf": [ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "maxLength": 0 + } + } + ] } }, "additionalProperties": false, diff --git a/app/config/services.yaml b/app/config/services.yaml index bb913370..3bc7ccf4 100644 --- a/app/config/services.yaml +++ b/app/config/services.yaml @@ -69,12 +69,18 @@ services: arguments: - !tagged_iterator config.compiler_processor - config.compiler.dump_output: + config.compiler.processor.default_settings: + class: 'Smile\GdprDump\Config\Compiler\Processor\DefaultSettingsProcessor' + + config.compiler.processor.dump_output: class: 'Smile\GdprDump\Config\Compiler\Processor\DumpOutputProcessor' config.compiler.processor.env_var: class: 'Smile\GdprDump\Config\Compiler\Processor\EnvVarProcessor' + config.compiler.processor.query_validation: + class: 'Smile\GdprDump\Config\Compiler\Processor\QueryValidationProcessor' + config.compiler.processor.version: class: 'Smile\GdprDump\Config\Compiler\Processor\VersionProcessor' diff --git a/app/config/templates/sylius.yaml b/app/config/templates/sylius.yaml new file mode 100644 index 00000000..44309e8b --- /dev/null +++ b/app/config/templates/sylius.yaml @@ -0,0 +1,77 @@ +--- +tables: + sylius_address_log_entries: + truncate: true + + sylius_address: + converters: + first_name: + converter: 'randomizeText' + last_name: + converter: 'randomizeText' + phone_number: + converter: 'randomizeNumber' + street: + converter: 'randomizeText' + company: + converter: 'randomizeText' + city: + converter: 'randomizeText' + postcode: + converter: 'randomizeNumber' + + sylius_admin_user: + converters: + username: + converter: 'randomizeText' + unique: true + username_canonical: + converter: 'fromContext' + parameters: + key: 'processed_data.username' + email: + converter: 'randomizeEmail' + unique: true + email_canonical: + converter: 'fromContext' + parameters: + key: 'processed_data.email' + first_name: + converter: 'randomizeText' + last_name: + converter: 'randomizeText' + + sylius_customer: + converters: + email: + converter: 'randomizeEmail' + unique: true + email_canonical: + converter: 'fromContext' + parameters: + key: 'processed_data.email' + first_name: + converter: 'randomizeText' + last_name: + converter: 'randomizeText' + birthday: + converter: 'anonymizeDateTime' + phone_number: + converter: 'randomizeNumber' + + sylius_shop_user: + converters: + username: + converter: 'randomizeText' + unique: true + username_canonical: + converter: 'fromContext' + parameters: + key: 'processed_data.username' + email: + converter: 'randomizeEmail' + unique: true + email_canonical: + converter: 'fromContext' + parameters: + key: 'processed_data.email' diff --git a/composer.json b/composer.json index 63e4967f..c71705e5 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "doctrine/dbal": "^3.1", "druidfi/mysqldump-php": "^1.1", "fakerphp/faker": "^1.17", - "justinrainbow/json-schema": "^5.2", + "justinrainbow/json-schema": "^5.3", "symfony/config": "^6.1", "symfony/console": "^6.1", "symfony/dependency-injection": "^6.1", diff --git a/src/Config/Compiler/Processor/DefaultSettingsProcessor.php b/src/Config/Compiler/Processor/DefaultSettingsProcessor.php new file mode 100644 index 00000000..25ccb4e5 --- /dev/null +++ b/src/Config/Compiler/Processor/DefaultSettingsProcessor.php @@ -0,0 +1,74 @@ +toArray(); + $data += [ + 'database' => [], + 'dump' => [], + 'faker' => [], + 'filter_propagation' => [], + 'tables_whitelist' => [], + 'tables_blacklist' => [], + 'tables' => [], + 'variables' => [], + ]; + + foreach ($this->getDefaultSettings() as $key => $value) { + $data[$key] += $value; + } + + $config->reset($data); + } + + /** + * Get default settings. + */ + private function getDefaultSettings(): array + { + return [ + 'dump' => [ + 'output' => 'php://stdout', + 'add_drop_database' => false, + 'add_drop_table' => true, // false in MySQLDump-PHP + 'add_drop_trigger' => true, + 'add_locks' => true, + 'complete_insert' => false, + 'compress' => 'none', + 'default_character_set' => 'utf8', + 'disable_keys' => true, + 'events' => false, + 'extended_insert' => true, + 'hex_blob' => false, // true in MySQLDump-PHP + 'init_commands' => [], + 'insert_ignore' => false, + 'lock_tables' => false, // true in MySQLDump-PHP + 'net_buffer_length' => 1000000, + 'no_autocommit' => true, + 'no_create_info' => false, + 'routines' => false, + 'single_transaction' => true, + 'skip_comments' => false, + 'skip_definer' => false, + 'skip_dump_date' => false, + 'skip_triggers' => false, + 'skip_tz_utc' => false, + ], + 'filter_propagation' => [ + 'enabled' => true, + 'ignored_foreign_keys' => [], + ], + 'faker' => [ + 'locale' => '', + ], + ]; + } +} diff --git a/src/Config/Compiler/Processor/DumpOutputProcessor.php b/src/Config/Compiler/Processor/DumpOutputProcessor.php index e8a059b2..a68fd6c3 100644 --- a/src/Config/Compiler/Processor/DumpOutputProcessor.php +++ b/src/Config/Compiler/Processor/DumpOutputProcessor.php @@ -4,26 +4,38 @@ namespace Smile\GdprDump\Config\Compiler\Processor; +use Smile\GdprDump\Config\ConfigException; use Smile\GdprDump\Config\ConfigInterface; final class DumpOutputProcessor implements ProcessorInterface { /** - * Process date placeholders in dump output (e.g. "dump-{Y-m-d-H.i.s}.sql"). + * Process placeholders in the dump output setting. */ public function process(ConfigInterface $config): void { - $dumpSettings = (array) $config->get('dump', []); - if (!array_key_exists('output', $dumpSettings)) { - return; - } + $dumpSettings = (array) $config->get('dump'); + $dumpSettings['output'] = $this->processDatePlaceholder((string) $dumpSettings['output']); + $config->set('dump', $dumpSettings); + } - $dumpSettings['output'] = preg_replace_callback( + /** + * Replace date placeholders. + * + * @throws ConfigException + */ + private function processDatePlaceholder(string $input): string + { + $input = preg_replace_callback( '/{([^}]+)}/', fn (array $matches) => date($matches[1]), - $dumpSettings['output'] + $input ); - $config->set('dump', $dumpSettings); + if ($input === null) { + throw new ConfigException('Failed to replace placeholders in value "%s".', $input); + } + + return $input; } } diff --git a/src/Config/Compiler/Processor/QueryValidationProcessor.php b/src/Config/Compiler/Processor/QueryValidationProcessor.php new file mode 100644 index 00000000..b65c30ea --- /dev/null +++ b/src/Config/Compiler/Processor/QueryValidationProcessor.php @@ -0,0 +1,52 @@ +validateVarQueries($config); + $this->validateInitCommands($config); + } catch (Exception $e) { + throw new ConfigException($e->getMessage(), $e); + } + } + + /** + * Validate SQL queries found in the "variables" section of the config. + */ + private function validateVarQueries(ConfigInterface $config): void + { + $selectQueryValidator = new QueryValidator(['select']); + $varQueries = (array) $config->get('variables'); + + foreach ($varQueries as $query) { + $selectQueryValidator->validate($query); + } + } + + /** + * Validate SQL queries found in the "dump.init_commands" section of the config. + */ + private function validateInitCommands(ConfigInterface $config): void + { + $selectQueryValidator = new QueryValidator(['set']); + $dumpSettings = (array) $config->get('dump'); + + foreach ($dumpSettings['init_commands'] as $query) { + $selectQueryValidator->validate($query); + } + } +} diff --git a/src/Dumper/Config/ConfigProcessor.php b/src/Dumper/Config/ConfigProcessor.php index e08c93e3..711d77f4 100644 --- a/src/Dumper/Config/ConfigProcessor.php +++ b/src/Dumper/Config/ConfigProcessor.php @@ -4,9 +4,9 @@ namespace Smile\GdprDump\Dumper\Config; +use RuntimeException; use Smile\GdprDump\Config\ConfigInterface; use Smile\GdprDump\Database\Metadata\MetadataInterface; -use Smile\GdprDump\Dumper\Config\Validation\ValidationException; final class ConfigProcessor { @@ -31,7 +31,7 @@ public function process(ConfigInterface $config): DumperConfig } /** - * Remote tables that don't exist and resolve patterns (e.g. "log_*") for included/excluded tables. + * Remove tables that don't exist and resolve patterns (e.g. "log_*") for included/excluded tables. */ private function processTableLists(ConfigInterface $config): void { @@ -127,6 +127,8 @@ private function findTablesByName(string $pattern): array /** * Raise an exception if the table data contains a converter that references an undefined column. + * + * @throws RuntimeException */ private function validateTableColumns(string $tableName, array $tableData): void { @@ -141,7 +143,7 @@ private function validateTableColumns(string $tableName, array $tableData): void if (!$disabled && !in_array($columnName, $columns)) { $message = 'The table "%s" uses a converter on an undefined column "%s".'; - throw new ValidationException(sprintf($message, $tableName, $columnName)); + throw new RuntimeException(sprintf($message, $tableName, $columnName)); } } } diff --git a/src/Dumper/Config/Definition/TableConfig.php b/src/Dumper/Config/Definition/TableConfig.php index 8340d7f1..e674bc79 100644 --- a/src/Dumper/Config/Definition/TableConfig.php +++ b/src/Dumper/Config/Definition/TableConfig.php @@ -5,7 +5,6 @@ namespace Smile\GdprDump\Dumper\Config\Definition; use Smile\GdprDump\Dumper\Config\Definition\Table\SortOrder; -use Smile\GdprDump\Dumper\Config\Validation\ValidationException; use Smile\GdprDump\Dumper\Config\Validation\WhereExprValidator; use UnexpectedValueException; @@ -117,12 +116,12 @@ private function prepareConfig(array $tableData): void /** * Prepare the table filters. * - * @throws ValidationException + * @throws UnexpectedValueException */ private function prepareFilters(array $tableData): void { if (array_key_exists('filters', $tableData)) { - throw new ValidationException( + throw new UnexpectedValueException( 'The property "filters" is no longer supported. Use "where" instead.' ); } diff --git a/src/Dumper/Config/DumperConfig.php b/src/Dumper/Config/DumperConfig.php index b9068ca6..8c75e37c 100644 --- a/src/Dumper/Config/DumperConfig.php +++ b/src/Dumper/Config/DumperConfig.php @@ -4,63 +4,33 @@ namespace Smile\GdprDump\Dumper\Config; -use Druidfi\Mysqldump\Compress\CompressManagerFactory; -use Druidfi\Mysqldump\DumpSettings; use Smile\GdprDump\Config\ConfigInterface; use Smile\GdprDump\Dumper\Config\Definition\FakerSettings; use Smile\GdprDump\Dumper\Config\Definition\FilterPropagationSettings; use Smile\GdprDump\Dumper\Config\Definition\TableConfig; use Smile\GdprDump\Dumper\Config\Definition\TableConfigCollection; -use Smile\GdprDump\Dumper\Config\Validation\QueryValidator; -use Smile\GdprDump\Dumper\Config\Validation\ValidationException; final class DumperConfig implements DumperConfigInterface { private FakerSettings $fakerSettings; private FilterPropagationSettings $filterPropagationSettings; private TableConfigCollection $tablesConfig; - private array $dumpSettings = [ - 'output' => 'php://stdout', - 'add_drop_database' => false, - 'add_drop_table' => true, // false in MySQLDump-PHP - 'add_drop_trigger' => true, - 'add_locks' => true, - 'complete_insert' => false, - 'compress' => CompressManagerFactory::NONE, - 'default_character_set' => DumpSettings::UTF8, - 'disable_keys' => true, - 'events' => false, - 'extended_insert' => true, - 'hex_blob' => false, // true in MySQLDump-PHP - 'init_commands' => [], - 'insert_ignore' => false, - 'lock_tables' => false, // true in MySQLDump-PHP - 'net_buffer_length' => 1000000, - 'no_autocommit' => true, - 'no_create_info' => false, - 'routines' => false, - 'single_transaction' => true, - 'skip_comments' => false, - 'skip_definer' => false, - 'skip_dump_date' => false, - 'skip_triggers' => false, - 'skip_tz_utc' => false, - ]; + private array $dumpSettings; /** * @var string[] */ - private array $includedTables = []; + private array $varQueries; /** * @var string[] */ - private array $excludedTables = []; + private array $includedTables = []; /** * @var string[] */ - private array $varQueries = []; + private array $excludedTables = []; /** * @var string[] @@ -77,13 +47,10 @@ final class DumperConfig implements DumperConfigInterface */ private array $tablesToSort = []; - /** - * @throws ValidationException - */ public function __construct(ConfigInterface $config) { - $this->prepareVarQueries($config); - $this->prepareDumpSettings($config); + $this->varQueries = (array) $config->get('variables', []); + $this->dumpSettings = (array) $config->get('dump', []); $this->prepareFakerSettings($config); $this->prepareFilterPropagationSettings($config); $this->prepareTableSettings($config); @@ -177,46 +144,6 @@ public function getTablesToSort(): array return $this->tablesToSort; } - /** - * Prepare SQL variable queries. - * - * @throws ValidationException - */ - private function prepareVarQueries(ConfigInterface $config): void - { - $this->varQueries = (array) $config->get('variables', []); - - // Allow only "select" statements in queries - $selectQueryValidator = new QueryValidator(['select']); - foreach ($this->varQueries as $query) { - $selectQueryValidator->validate($query); - } - } - - /** - * Prepare dump settings. - * - * @throws ValidationException - */ - private function prepareDumpSettings(ConfigInterface $config): void - { - $settings = (array) $config->get('dump', []); - - foreach ($settings as $param => $value) { - if (!array_key_exists($param, $this->dumpSettings)) { - throw new ValidationException(sprintf('Invalid dump setting "%s".', $param)); - } - - $this->dumpSettings[$param] = $value; - } - - // Allow only "set" statements in init commands - $initCommandQueryValidator = new QueryValidator(['set']); - foreach ($this->dumpSettings['init_commands'] as $query) { - $initCommandQueryValidator->validate($query); - } - } - /** * Prepare faker settings. */ @@ -232,10 +159,9 @@ private function prepareFakerSettings(ConfigInterface $config): void private function prepareFilterPropagationSettings(ConfigInterface $config): void { $settings = (array) $config->get('filter_propagation', []); - $this->filterPropagationSettings = new FilterPropagationSettings( - $settings['enabled'] ?? true, - $settings['ignored_foreign_keys'] ?? [] + (bool) ($settings['enabled'] ?? true), + (array) ($settings['ignored_foreign_keys'] ?? []) ); } diff --git a/src/Dumper/Config/Validation/WhereExprValidator.php b/src/Dumper/Config/Validation/WhereExprValidator.php index e44459e6..63551352 100644 --- a/src/Dumper/Config/Validation/WhereExprValidator.php +++ b/src/Dumper/Config/Validation/WhereExprValidator.php @@ -4,7 +4,9 @@ namespace Smile\GdprDump\Dumper\Config\Validation; +use Smile\GdprDump\Util\QueryValidator; use TheSeer\Tokenizer\Token; +use UnexpectedValueException; final class WhereExprValidator { @@ -31,7 +33,9 @@ public function validate(string $expr): void if ($token->getName() === 'T_CLOSE_BRACKET') { if ($openedBrackets === 0) { - throw new ValidationException(sprintf('Unmatched closing bracket found in query "%s".', $expr)); + throw new UnexpectedValueException( + sprintf('Unmatched closing bracket found in query "%s".', $expr) + ); } --$openedBrackets; diff --git a/src/Dumper/MysqlDumper.php b/src/Dumper/MysqlDumper.php index 448573ec..72f9f373 100644 --- a/src/Dumper/MysqlDumper.php +++ b/src/Dumper/MysqlDumper.php @@ -87,6 +87,11 @@ private function getDumpSettings(DumperConfigInterface $config): array } } + if (array_key_exists('compress', $settings)) { + // e.g. "gzip" -> "Gzip" + $settings['compress'] = strtoupper($settings['compress']); + } + // Tables to include/exclude/truncate $settings['include-tables'] = $config->getIncludedTables(); $settings['exclude-tables'] = $config->getExcludedTables(); diff --git a/src/Dumper/Config/Validation/QueryValidator.php b/src/Util/QueryValidator.php similarity index 86% rename from src/Dumper/Config/Validation/QueryValidator.php rename to src/Util/QueryValidator.php index b4e55286..ccd21428 100644 --- a/src/Dumper/Config/Validation/QueryValidator.php +++ b/src/Util/QueryValidator.php @@ -2,10 +2,11 @@ declare(strict_types=1); -namespace Smile\GdprDump\Dumper\Config\Validation; +namespace Smile\GdprDump\Util; use TheSeer\Tokenizer\TokenCollection; use TheSeer\Tokenizer\Tokenizer; +use UnexpectedValueException; final class QueryValidator { @@ -42,6 +43,8 @@ public function __construct(array $allowedStatements) /** * Validate the query. An optional callback can be passed for additional validation. + * + * @throws UnexpectedValueException */ public function validate(string $query, ?callable $callback = null): void { @@ -52,11 +55,13 @@ public function validate(string $query, ?callable $callback = null): void $value = $token->getValue(); if ($name === 'T_DEC' || $name === 'T_COMMENT') { - throw new ValidationException(sprintf('Forbidden comment found in query "%s".', $query)); + throw new UnexpectedValueException(sprintf('Forbidden comment found in query "%s".', $query)); } if ($name === 'T_STRING' && !$this->isStatementAllowed($value)) { - throw new ValidationException(sprintf('Forbidden keyword "%s" found in query "%s".', $value, $query)); + throw new UnexpectedValueException( + sprintf('Forbidden keyword "%s" found in query "%s".', $value, $query) + ); } if ($callback !== null) { diff --git a/tests/unit/Config/Compiler/Processor/DefaultSettingsProcessorTest.php b/tests/unit/Config/Compiler/Processor/DefaultSettingsProcessorTest.php new file mode 100644 index 00000000..f37c3fa9 --- /dev/null +++ b/tests/unit/Config/Compiler/Processor/DefaultSettingsProcessorTest.php @@ -0,0 +1,109 @@ +process($config); + + $this->assertSame([], $config->get('database')); + $this->assertSame([], $config->get('tables_blacklist')); + $this->assertSame([], $config->get('tables_whitelist')); + $this->assertSame([], $config->get('tables')); + $this->assertSame([], $config->get('variables')); + + $fakerSettings = $config->get('faker'); + $this->assertIsArray($fakerSettings); + $this->assertArrayHasKey('locale', $fakerSettings); + $this->assertSame('', $fakerSettings['locale']); + + $filterPropagationSettings = $config->get('filter_propagation'); + $this->assertIsArray($filterPropagationSettings); + $this->assertArrayHasKey('enabled', $filterPropagationSettings); + $this->assertTrue($filterPropagationSettings['enabled']); + $this->assertArrayHasKey('ignored_foreign_keys', $filterPropagationSettings); + $this->assertSame([], $filterPropagationSettings['ignored_foreign_keys']); + + $dumpSettings = $config->get('dump'); + $this->assertIsArray($dumpSettings); + $this->assertArrayHasKey('output', $dumpSettings); + $this->assertArrayHasKey('add_drop_database', $dumpSettings); + $this->assertArrayHasKey('add_drop_table', $dumpSettings); + $this->assertArrayHasKey('add_drop_trigger', $dumpSettings); + $this->assertArrayHasKey('add_locks', $dumpSettings); + $this->assertArrayHasKey('complete_insert', $dumpSettings); + $this->assertArrayHasKey('compress', $dumpSettings); + $this->assertArrayHasKey('default_character_set', $dumpSettings); + $this->assertArrayHasKey('disable_keys', $dumpSettings); + $this->assertArrayHasKey('events', $dumpSettings); + $this->assertArrayHasKey('extended_insert', $dumpSettings); + $this->assertArrayHasKey('hex_blob', $dumpSettings); + $this->assertArrayHasKey('init_commands', $dumpSettings); + $this->assertArrayHasKey('insert_ignore', $dumpSettings); + $this->assertArrayHasKey('lock_tables', $dumpSettings); + $this->assertArrayHasKey('net_buffer_length', $dumpSettings); + $this->assertArrayHasKey('no_autocommit', $dumpSettings); + $this->assertArrayHasKey('no_create_info', $dumpSettings); + $this->assertArrayHasKey('routines', $dumpSettings); + $this->assertArrayHasKey('single_transaction', $dumpSettings); + $this->assertArrayHasKey('skip_comments', $dumpSettings); + $this->assertArrayHasKey('skip_definer', $dumpSettings); + $this->assertArrayHasKey('skip_dump_date', $dumpSettings); + $this->assertArrayHasKey('skip_triggers', $dumpSettings); + $this->assertArrayHasKey('skip_tz_utc', $dumpSettings); + } + + /** + * Assert that default values are existing merged with an existing config. + */ + public function testMergeValues(): void + { + $data = [ + 'dump' => ['output' => 'dump.sql'], + 'faker' => [ + 'locale' => 'en_US', + ], + 'filter_propagation' => [ + 'ignored_foreign_keys' => ['fk1', 'fk2'], + ], + 'tables_blacklist' => ['table1'], + ]; + + $config = new Config($data); + $processor = new DefaultSettingsProcessor(); + $processor->process($config); + + $dumpSettings = $config->get('dump'); + $this->assertIsArray($dumpSettings); + $this->assertArrayHasKey('output', $dumpSettings); + $this->assertSame('dump.sql', $dumpSettings['output']); + + $fakerSettings = $config->get('faker'); + $this->assertIsArray($fakerSettings); + $this->assertArrayHasKey('locale', $fakerSettings); + $this->assertSame('en_US', $fakerSettings['locale']); + + $filterPropagationSettings = $config->get('filter_propagation'); + $this->assertIsArray($filterPropagationSettings); + $this->assertArrayHasKey('enabled', $filterPropagationSettings); + $this->assertTrue($filterPropagationSettings['enabled']); + $this->assertArrayHasKey('ignored_foreign_keys', $filterPropagationSettings); + $this->assertSame( + $data['filter_propagation']['ignored_foreign_keys'], + $filterPropagationSettings['ignored_foreign_keys'] + ); + } +} diff --git a/tests/unit/Config/Compiler/Processor/DumpOutputProcessorTest.php b/tests/unit/Config/Compiler/Processor/DumpOutputProcessorTest.php new file mode 100644 index 00000000..f4eacbc5 --- /dev/null +++ b/tests/unit/Config/Compiler/Processor/DumpOutputProcessorTest.php @@ -0,0 +1,33 @@ + [ + 'output' => 'dump-{Ymd}.sql', + ], + ]); + + $processor = new DumpOutputProcessor(); + $processor->process($config); + + $dumpSettings = $config->get('dump'); + $this->assertIsArray($dumpSettings); + $this->assertArrayHasKey('output', $dumpSettings); + $this->assertSame('dump-' . (new DateTime())->format('Ymd') . '.sql', $dumpSettings['output']); + } +} diff --git a/tests/unit/Config/Compiler/Processor/QueryValidationProcessorTest.php b/tests/unit/Config/Compiler/Processor/QueryValidationProcessorTest.php new file mode 100644 index 00000000..f31e7117 --- /dev/null +++ b/tests/unit/Config/Compiler/Processor/QueryValidationProcessorTest.php @@ -0,0 +1,68 @@ +getData(); + $data['variables'][] = 'select `id` from `table1` where `value` = "bar"'; + $data['dump']['init_commands'][] = + 'SET SESSION SQL_MODE="STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER"'; + $config = new Config($data); + + $processor = new QueryValidationProcessor(); + $this->expectNotToPerformAssertions(); + $processor->process($config); + } + + /** + * Assert that an exception is thrown when the "variables" param contains an invalid SQL query. + */ + public function testInvalidVariableQuery(): void + { + $data = $this->getData(); + $data['variables'][] = 'update `table1` set `value` = "bar" where `id` = 1'; + $config = new Config($data); + + $processor = new QueryValidationProcessor(); + $this->expectException(ConfigException::class); + $processor->process($config); + } + + /** + * Assert that an exception is thrown when the "init_commands" param contains an invalid SQL query. + */ + public function testInvalidInitQuery(): void + { + $data = $this->getData(); + $data['dump']['init_commands'][] = 'update `table1` set `value` = "bar" where `id` = 1'; + $config = new Config($data); + + $processor = new QueryValidationProcessor(); + $this->expectException(ConfigException::class); + $processor->process($config); + } + + /** + * Get sample config data. + */ + private function getData(): array + { + return [ + 'dump' => ['init_commands' => []], + 'variables' => [], + ]; + } +} diff --git a/tests/unit/Config/Compiler/Processor/VersionProcessorTest.php b/tests/unit/Config/Compiler/Processor/VersionProcessorTest.php index a1af7675..6a65e284 100644 --- a/tests/unit/Config/Compiler/Processor/VersionProcessorTest.php +++ b/tests/unit/Config/Compiler/Processor/VersionProcessorTest.php @@ -29,8 +29,8 @@ public function testVersionProcessor(): void ], ]; - $processor = new VersionProcessor(); $config = new Config($data); + $processor = new VersionProcessor(); // Test with version "1.0.0" $config->set('version', '1.0.0'); diff --git a/tests/unit/Dumper/Config/Definition/TableConfigTest.php b/tests/unit/Dumper/Config/Definition/TableConfigTest.php index df67070c..7bbd8d50 100644 --- a/tests/unit/Dumper/Config/Definition/TableConfigTest.php +++ b/tests/unit/Dumper/Config/Definition/TableConfigTest.php @@ -5,7 +5,6 @@ namespace Smile\GdprDump\Tests\Unit\Dumper\Config\Definition; use Smile\GdprDump\Dumper\Config\Definition\TableConfig; -use Smile\GdprDump\Dumper\Config\Validation\ValidationException; use Smile\GdprDump\Tests\Unit\TestCase; use UnexpectedValueException; @@ -91,7 +90,7 @@ public function testWhereCondition(): void */ public function testWhereConditionWithDisallowedStatement(): void { - $this->expectException(ValidationException::class); + $this->expectException(UnexpectedValueException::class); new TableConfig('table1', [ 'where' => 'drop database example', ]); @@ -102,7 +101,7 @@ public function testWhereConditionWithDisallowedStatement(): void */ public function testWhereConditionWithUnmatchedClosingBracket(): void { - $this->expectException(ValidationException::class); + $this->expectException(UnexpectedValueException::class); new TableConfig('table1', [ 'where' => '1); select * from customer where (1', ]); diff --git a/tests/unit/Dumper/Config/DumperConfigTest.php b/tests/unit/Dumper/Config/DumperConfigTest.php index a14d15b5..225a0640 100644 --- a/tests/unit/Dumper/Config/DumperConfigTest.php +++ b/tests/unit/Dumper/Config/DumperConfigTest.php @@ -6,7 +6,6 @@ use Smile\GdprDump\Config\Config; use Smile\GdprDump\Dumper\Config\DumperConfig; -use Smile\GdprDump\Dumper\Config\Validation\ValidationException; use Smile\GdprDump\Tests\Unit\TestCase; final class DumperConfigTest extends TestCase @@ -120,46 +119,18 @@ public function testDefaultValues(): void { $config = $this->createConfig([]); + $this->assertSame([], $config->getDumpSettings()); $this->assertSame([], $config->getIncludedTables()); $this->assertSame([], $config->getExcludedTables()); $this->assertSame([], $config->getTablesToSort()); $this->assertSame([], $config->getTablesToFilter()); $this->assertSame([], $config->getTablesToTruncate()); $this->assertSame([], $config->getTablesConfig()->all()); - $this->assertSame('php://stdout', $config->getDumpOutput()); $this->assertTrue($config->getFilterPropagationSettings()->isEnabled()); $this->assertSame([], $config->getFilterPropagationSettings()->getIgnoredForeignKeys()); - - // Test these values because they differ from MySQLDump-PHP - $settings = $config->getDumpSettings(); - $this->assertArrayHasKey('add_drop_table', $settings); - $this->assertTrue($settings['add_drop_table']); - $this->assertArrayHasKey('hex_blob', $settings); - $this->assertFalse($settings['hex_blob']); - $this->assertArrayHasKey('lock_tables', $settings); - $this->assertFalse($settings['lock_tables']); - $this->assertSame('', $config->getFakerSettings()->getLocale()); } - /** - * Assert that an exception is thrown when an invalid parameter is used. - */ - public function testInvalidDumpParameter(): void - { - $this->expectException(ValidationException::class); - $this->createConfig(['dump' => ['not_exists' => true]]); - } - - /** - * Assert that an exception is thrown when a var query contains a forbidden statement. - */ - public function testInvalidStatementInQuery(): void - { - $this->expectException(ValidationException::class); - $this->createConfig(['variables' => ['my_var' => 'select my_col from my_table; delete from my_table']]); - } - /** * Create a dumper config object that stores the specified data. */ diff --git a/tests/unit/Dumper/Config/Validation/QueryValidatorTest.php b/tests/unit/Dumper/Config/Validation/QueryValidatorTest.php index b9744246..46c400c6 100644 --- a/tests/unit/Dumper/Config/Validation/QueryValidatorTest.php +++ b/tests/unit/Dumper/Config/Validation/QueryValidatorTest.php @@ -5,10 +5,10 @@ namespace Smile\GdprDump\Tests\Unit\Dumper\Config\Validation; use RuntimeException; -use Smile\GdprDump\Dumper\Config\Validation\QueryValidator; -use Smile\GdprDump\Dumper\Config\Validation\ValidationException; use Smile\GdprDump\Tests\Unit\TestCase; +use Smile\GdprDump\Util\QueryValidator; use TheSeer\Tokenizer\Token; +use UnexpectedValueException; final class QueryValidatorTest extends TestCase { @@ -27,7 +27,7 @@ public function testAllowedStatement(): void */ public function testForbiddenStatement(): void { - $this->expectException(ValidationException::class); + $this->expectException(UnexpectedValueException::class); $queryValidator = new QueryValidator(['set']); $queryValidator->validate('select * from my_table'); } diff --git a/tests/unit/Dumper/Config/Validation/WhereExprValidatorTest.php b/tests/unit/Dumper/Config/Validation/WhereExprValidatorTest.php index da9ddfcd..9391f122 100644 --- a/tests/unit/Dumper/Config/Validation/WhereExprValidatorTest.php +++ b/tests/unit/Dumper/Config/Validation/WhereExprValidatorTest.php @@ -4,9 +4,9 @@ namespace Smile\GdprDump\Tests\Unit\Dumper\Config\Validation; -use Smile\GdprDump\Dumper\Config\Validation\ValidationException; use Smile\GdprDump\Dumper\Config\Validation\WhereExprValidator; use Smile\GdprDump\Tests\Unit\TestCase; +use UnexpectedValueException; final class WhereExprValidatorTest extends TestCase { @@ -35,7 +35,7 @@ public function testSubSelectIsAllowed(): void */ public function testForbiddenStatement(): void { - $this->expectException(ValidationException::class); + $this->expectException(UnexpectedValueException::class); $queryValidator = new WhereExprValidator(); $queryValidator->validate('drop database example'); } @@ -45,7 +45,7 @@ public function testForbiddenStatement(): void */ public function testUnmatchedClosingBracket(): void { - $this->expectException(ValidationException::class); + $this->expectException(UnexpectedValueException::class); $queryValidator = new WhereExprValidator(); $queryValidator->validate('1); select * from customer where (1'); }