* @author Ivan Klimchuk */ namespace oat\taoQtiTest\scripts\cli; use common_exception_Error; use common_exception_InconsistentData; use common_ext_Extension; use common_ext_ExtensionException; use common_ext_ExtensionsManager; use common_report_Report as Report; use oat\oatbox\AbstractRegistry; use oat\oatbox\extension\script\ScriptAction; use oat\oatbox\extension\script\ScriptException; use oat\oatbox\service\ConfigurableService; use oat\oatbox\service\exception\InvalidServiceManagerException; use oat\taoTests\models\runner\plugins\PluginRegistry; use oat\taoTests\models\runner\providers\ProviderRegistry; use oat\taoTests\models\runner\providers\TestProvider; use oat\tao\model\modules\DynamicModule; /** * Class TestRunnerOfflineMode, replacement of old one SetOfflineTestRunnerConfig * @package oat\taoQtiTest\scripts\cli * * How to use: php index.php 'oat\taoQtiTest\scripts\cli\TestRunnerOfflineMode' --help * Set offline mode: php index.php 'oat\taoQtiTest\scripts\cli\TestRunnerOfflineMode' --mode offline * Return online mode: php index.php 'oat\taoQtiTest\scripts\cli\TestRunnerOfflineMode' --mode online */ class TestRunnerOfflineMode extends ScriptAction { public const OPTION_MODE = 'mode'; public const MODE_ONLINE = 'online'; public const MODE_OFFLINE = 'offline'; private const PERMITTED_MODES = [self::MODE_ONLINE, self::MODE_OFFLINE]; private const OFFLINE_TEST_RUNNER_CONFIG = [ 'allow-browse-next-item' => true, 'bootstrap' => [ 'serviceExtension' => 'taoQtiTest', 'serviceController' => 'OfflineRunner', 'communication' => [ 'enabled' => true, 'type' => 'request', 'extension' => 'taoQtiTest', 'controller' => 'OfflineRunner', 'action' => 'messages', 'syncActions' => [ 'move', 'skip', 'storeTraceData', 'timeout', 'exitTest', 'getNextItemData', ], ], ], ]; private const ONLINE_TEST_RUNNER_CONFIG = [ 'bootstrap' => [ 'serviceExtension' => 'taoQtiTest', 'serviceController' => 'Runner', 'communication' => [ 'type' => 'poll', 'extension' => null, 'controller' => null, 'action' => 'messages', 'syncActions' => [ 'move', 'skip', 'storeTraceData', 'timeout', 'exitTest', ], ], ], ]; private const UNSUPPORTED_PLUGINS = [ 'taoTestRunnerPlugins/runner/plugins/security/autoPause', 'taoTestRunnerPlugins/runner/plugins/connectivity/disconnectedTestSaver', ]; /** * @param array $configuration * * @throws InvalidServiceManagerException * @throws common_exception_Error * @throws common_ext_ExtensionException */ private function updateTestRunnerConfig($configuration = []) { /** @var common_ext_Extension $taoQtiTestExtension */ $taoQtiTestExtension = $this->getExtensionsManagerService()->getExtensionById('taoQtiTest'); $config = array_merge($taoQtiTestExtension->getConfig('testRunner'), $configuration); $taoQtiTestExtension->setConfig('testRunner', $config); } private function registerQtiServiceProxy() { $providerRegistry = $this->getProviderRegistry(); $providerRegistry->removeByCategory('proxy'); $providerRegistry->register( TestProvider::fromArray( [ 'id' => 'qtiServiceProxy', 'module' => 'taoQtiTest/runner/proxy/qtiServiceProxy', 'bundle' => 'taoQtiTest/loader/taoQtiTestRunner.min', 'category' => 'proxy', ] ) ); return $providerRegistry->isRegistered('taoQtiTest/runner/proxy/qtiServiceProxy'); } private function registerOfflineProxy() { $providerRegistry = $this->getProviderRegistry(); $providerRegistry->removeByCategory('proxy'); $providerRegistry->register( TestProvider::fromArray( [ 'id' => 'offlineProxy', 'module' => 'taoQtiTest/runner/proxy/offline/proxy', 'bundle' => 'taoQtiTest/loader/taoQtiTestRunner.min', 'category' => 'proxy', ] ) ); return $providerRegistry->isRegistered('taoQtiTest/runner/proxy/offline/proxy'); } /** * @param bool $active * * @throws common_exception_InconsistentData */ private function handleUnsupportedTestRunnerPlugins($active) { /** @var PluginRegistry $pluginRegistry */ $pluginRegistry = PluginRegistry::getRegistry(); foreach (self::UNSUPPORTED_PLUGINS as $pluginId) { if ($pluginRegistry->isRegistered($pluginId)) { /** @var array $plugin */ $plugin = $pluginRegistry->get($pluginId); $plugin['active'] = $active; $pluginRegistry->register(DynamicModule::fromArray($plugin)); } } } /** * @return ProviderRegistry|AbstractRegistry */ private function getProviderRegistry() { return ProviderRegistry::getRegistry(); } /** * @return common_ext_ExtensionsManager|ConfigurableService * @throws InvalidServiceManagerException */ private function getExtensionsManagerService() { return $this->getServiceManager()->get(common_ext_ExtensionsManager::SERVICE_ID); } /** * Turning on offline mode for test runner. It sets special proxy plugin that supports offline actions, * as well it deactivates plugins that unsupported in offline mode. Also, it adjusts test runner configuration. * * @return Report * @throws InvalidServiceManagerException * @throws common_exception_Error * @throws common_exception_InconsistentData * @throws common_ext_ExtensionException */ private function goOffline() { $this->updateTestRunnerConfig(self::OFFLINE_TEST_RUNNER_CONFIG); if (!$this->registerOfflineProxy()) { return new Report(Report::TYPE_ERROR, 'Unable to register the proxy.'); } // set unsupported plugins as inactive $this->handleUnsupportedTestRunnerPlugins(false); return new Report(Report::TYPE_SUCCESS, 'Offline Test Runner mode was set.'); } /** * Turning off the offline mode for test runner. It returns configuration to normal state, * as well returns disabled plugins to active state, if they were used. * * @return Report * @throws InvalidServiceManagerException * @throws common_exception_Error * @throws common_exception_InconsistentData * @throws common_ext_ExtensionException */ private function goOnline() { $this->updateTestRunnerConfig(self::ONLINE_TEST_RUNNER_CONFIG); $this->registerQtiServiceProxy(); // set unsupported plugins as active $this->handleUnsupportedTestRunnerPlugins(true); return new Report(Report::TYPE_SUCCESS, 'Offline Test Runner mode was unset.'); } protected function provideOptions() { return [ self::OPTION_MODE => [ 'prefix' => 'm', 'flag' => false, 'longPrefix' => 'mode', 'required' => true, 'description' => 'Sets online or offline mode for test runner' ] ]; } protected function provideDescription() { return 'Script for enabling/disabling offline mode for TestRunner. It registers or unregisters specific plugins and sets proper configuration.'; } protected function provideUsage() { return [ 'prefix' => 'h', 'longPrefix' => 'help', 'description' => 'Prints a help statement', ]; } /** * @return Report * @throws InvalidServiceManagerException * @throws ScriptException * @throws common_exception_Error * @throws common_exception_InconsistentData * @throws common_ext_ExtensionException */ protected function run() { $mode = $this->getOption(self::OPTION_MODE); if (!in_array($mode, self::PERMITTED_MODES, true)) { throw new ScriptException('The mode should be specified by "online" or "offline" value exactly.'); } switch ($mode) { case self::MODE_ONLINE: return $this->goOnline(); break; case self::MODE_OFFLINE: return $this->goOffline(); break; } } }