<?php declare(strict_types=1); namespace SimpleSAML\Test\Module\accounting; use PHPUnit\Framework\TestCase; use SimpleSAML\Configuration; use SimpleSAML\Module\accounting\Data\Providers\Activity\DoctrineDbal\VersionedDataProvider; use SimpleSAML\Module\accounting\Data\Stores; use SimpleSAML\Module\accounting\Data\Stores\Interfaces\JobsStoreInterface; use SimpleSAML\Module\accounting\Data\Stores\Jobs\DoctrineDbal\Store; use SimpleSAML\Module\accounting\Data\Trackers; use SimpleSAML\Module\accounting\Exceptions\InvalidConfigurationException; use SimpleSAML\Module\accounting\ModuleConfiguration; use stdClass; /** * @covers \SimpleSAML\Module\accounting\ModuleConfiguration */ class ModuleConfigurationTest extends TestCase { protected ModuleConfiguration $moduleConfiguration; protected function setUp(): void { parent::setUp(); // Configuration directory is set by phpunit using php ENV setting feature (check phpunit.xml). $this->moduleConfiguration = new ModuleConfiguration('module_accounting.php'); } public function testCanGetUnderlyingConfigurationInstance(): void { $this->assertInstanceOf(Configuration::class, $this->moduleConfiguration->getConfiguration()); } public function testThrowExceptionsIfInvalidOptionIsSupplied(): void { $this->expectException(InvalidConfigurationException::class); $this->moduleConfiguration->get('invalid'); } public function testCanGetValidOption(): void { $this->assertIsString($this->moduleConfiguration->get(ModuleConfiguration::OPTION_USER_ID_ATTRIBUTE_NAME)); } public function testCanGetUserIdAttributeName(): void { $this->assertIsString($this->moduleConfiguration->getUserIdAttributeName()); } public function testCanGetDefaultAuthenticationSource(): void { $this->assertIsString($this->moduleConfiguration->getDefaultAuthenticationSource()); } public function testCanGetJobsStoreClass(): void { $this->assertTrue( is_subclass_of($this->moduleConfiguration->getJobsStoreClass(), JobsStoreInterface::class) ); } /** * @throws \Exception */ public function testThrowsForInvalidConfig(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_ACCOUNTING_PROCESSING_TYPE => 'invalid', ] ); } /** * @throws \Exception */ public function testThrowsForInvalidJobsStore(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_ACCOUNTING_PROCESSING_TYPE => ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS, ModuleConfiguration::OPTION_JOBS_STORE => 'invalid', ] ); } public function testProperConnectionKeyIsReturned(): void { $this->assertSame( 'doctrine_dbal_pdo_sqlite', $this->moduleConfiguration->getClassConnectionKey( Store::class ) ); } public function testCanGetSlaveConnectionKey(): void { $this->assertSame( 'doctrine_dbal_pdo_sqlite_slave', $this->moduleConfiguration->getClassConnectionKey( VersionedDataProvider::class, ModuleConfiguration\ConnectionType::SLAVE ) ); } /** * @throws \Exception */ public function testThrowsForNonStringAndNonArrayConnectionKey(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_CLASS_TO_CONNECTION_MAP => [ 'invalid-object-value' => new stdClass(), ] ] ); } /** * @throws \Exception */ public function testThrowsForNonMasterInArrayConnection(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_CLASS_TO_CONNECTION_MAP => [ 'invalid-array-value' => [ 'no-master-key' => 'invalid', ], ] ] ); } public function testThrowsForInvalidConnectionType(): void { $this->expectException(InvalidConfigurationException::class); $this->moduleConfiguration->getClassConnectionKey( Store::class, 'invalid' ); } public function testThrowsIfConnectionForClassNotSet(): void { $this->expectException(InvalidConfigurationException::class); $this->moduleConfiguration->getClassConnectionKey('invalid'); } public function testCanGetDefinedConnections(): void { $this->assertArrayHasKey( 'doctrine_dbal_pdo_sqlite', $this->moduleConfiguration->getConnectionsAndParameters() ); } public function testCanGetParametersForSpecificConnection(): void { $this->assertIsArray($this->moduleConfiguration->getConnectionParameters('doctrine_dbal_pdo_sqlite')); } public function testGettingSettingsForInvalidConnectionThrows(): void { $this->expectException(InvalidConfigurationException::class); $this->moduleConfiguration->getConnectionParameters('invalid'); } public function testCanGetModuleSourceDirectory(): void { $this->assertSame( dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'src', $this->moduleConfiguration->getModuleSourceDirectory() ); } public function testCanGetModuleRootDirectory(): void { $this->assertSame( dirname(__DIR__, 2), $this->moduleConfiguration->getModuleRootDirectory() ); } public function testCanGetCronTagForJobRunner(): void { $this->assertSame( 'accounting_job_runner', $this->moduleConfiguration->getCronTagForJobRunner() ); } public function testCanGetJobRunnerMaximumExecutionTime(): void { $this->assertNull($this->moduleConfiguration->getJobRunnerMaximumExecutionTime()); } /** * @throws \Exception */ public function testThrowsForNonStringJobRunnerMaximumExecutionTime(): void { $moduleConfiguration = new ModuleConfiguration( null, [ModuleConfiguration::OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME => []] ); $this->expectException(InvalidConfigurationException::class); $moduleConfiguration->getJobRunnerMaximumExecutionTime(); } /** * @throws \Exception */ public function testThrowsForInvalidStringJobRunnerMaximumExecutionTime(): void { $moduleConfiguration = new ModuleConfiguration( null, [ModuleConfiguration::OPTION_JOB_RUNNER_MAXIMUM_EXECUTION_TIME => 'invalid'] ); $this->expectException(InvalidConfigurationException::class); $moduleConfiguration->getJobRunnerMaximumExecutionTime(); } public function testCanGetJobRunnerShouldPauseAfterNumberOfJobsProcessed(): void { $this->assertSame(10, $this->moduleConfiguration->getJobRunnerShouldPauseAfterNumberOfJobsProcessed()); } /** * @throws \Exception */ public function testCanGetNullForJobRunnerShouldPauseAfterNumberOfJobsProcessed(): void { $moduleConfiguration = new ModuleConfiguration( null, [ModuleConfiguration::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED => false] ); $this->assertNull($moduleConfiguration->getJobRunnerShouldPauseAfterNumberOfJobsProcessed()); } /** * @throws \Exception */ public function testThrowsForNonIntegerJobRunnerShouldPauseAfterNumberOfJobsProcessed(): void { $moduleConfiguration = new ModuleConfiguration( null, [ModuleConfiguration::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED => []] ); $this->expectException(InvalidConfigurationException::class); $moduleConfiguration->getJobRunnerShouldPauseAfterNumberOfJobsProcessed(); } /** * @throws \Exception */ public function testThrowsForNegativeIntegerJobRunnerShouldPauseAfterNumberOfJobsProcessed(): void { $moduleConfiguration = new ModuleConfiguration( null, [ModuleConfiguration::OPTION_JOB_RUNNER_SHOULD_PAUSE_AFTER_NUMBER_OF_JOBS_PROCESSED => -1] ); $this->expectException(InvalidConfigurationException::class); $moduleConfiguration->getJobRunnerShouldPauseAfterNumberOfJobsProcessed(); } /** * @throws \Exception */ public function testThrowsOnInvalidCronTag(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_ACCOUNTING_PROCESSING_TYPE => ModuleConfiguration\AccountingProcessingType::VALUE_ASYNCHRONOUS, ModuleConfiguration::OPTION_CRON_TAG_FOR_JOB_RUNNER => -1 ] ); } /** * @throws \Exception */ public function testThrowsOnInvalidDataProvider(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_PROVIDER_FOR_ACTIVITY => 'invalid' ] ); } /** * @throws \Exception */ public function testThrowsOnInvalidAdditionalTrackers(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_ADDITIONAL_TRACKERS => ['invalid'] ] ); } /** * @throws \Exception */ public function testThrowsOnNonStringAdditionalTracker(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_ADDITIONAL_TRACKERS => [-1] ] ); } /** * @throws \Exception */ public function testThrowsWhenClassHasNoConnectionParametersSet(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_CONNECTIONS_AND_PARAMETERS => [] ] ); } /** * @throws \Exception */ public function testThrowsForInvalidTrackerDataRetentionPolicy(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_TRACKER_DATA_RETENTION_POLICY => 'invalid' ] ); } /** * @throws \Exception */ public function testThrowsForInvalidCronTagForTrackerDataRetentionPolicy(): void { $this->expectException(InvalidConfigurationException::class); new ModuleConfiguration( null, [ ModuleConfiguration::OPTION_TRACKER_DATA_RETENTION_POLICY => 'P1D', ModuleConfiguration::OPTION_CRON_TAG_FOR_TRACKER_DATA_RETENTION_POLICY => false, ] ); } public function testCanGetActionButtonsEnabled(): void { $moduleConfiguration = new ModuleConfiguration(); $this->assertTrue($moduleConfiguration->getActionButtonsEnabled()); $moduleConfiguration = new ModuleConfiguration( null, [ModuleConfiguration::OPTION_ACTION_BUTTONS_ENABLED => false] ); $this->assertFalse($moduleConfiguration->getActionButtonsEnabled()); } }