Skip to content

MQE-1257: MFTF Doctor command #500

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions dev/tests/functional/standalone_bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@

require_once realpath(PROJECT_ROOT . '/vendor/autoload.php');

$envFilePath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR;
defined('ENV_FILE_PATH') || define('ENV_FILE_PATH', $envFilePath);

//Load constants from .env file
$envFilePath = dirname(dirname(__DIR__));
if (file_exists($envFilePath . DIRECTORY_SEPARATOR . '.env')) {
$env = new \Dotenv\Loader($envFilePath . DIRECTORY_SEPARATOR . '.env');
if (file_exists(ENV_FILE_PATH . '.env')) {
$env = new \Dotenv\Loader(ENV_FILE_PATH . '.env');
$env->load();

foreach ($_ENV as $key => $var) {
Expand Down
18 changes: 18 additions & 0 deletions docs/commands/mftf.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,24 @@ You can include options to set configuration parameter values for your environme
vendor/bin/mftf build:project --MAGENTO_BASE_URL=http://magento.local/ --MAGENTO_BACKEND_NAME=admin214365
```

### `doctor`

#### Description

Diagnose MFTF configuration and setup. Currently this command will check the following:
- Verify admin credentials are valid. Allowing MFTF authenticates and runs API requests to Magento through cURL
- Verify that Selenium is up and running and available for MFTF
- Verify that new session of browser can open Magento admin and store front urls
- Verify that MFTF can run MagentoCLI commands

#### Usage

```bash
vendor/bin/mftf doctor
```

#### Options

### `generate:tests`

#### Description
Expand Down
27 changes: 14 additions & 13 deletions src/Magento/FunctionalTestingFramework/Console/CommandList.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,20 @@ class CommandList implements CommandListInterface
public function __construct(array $commands = [])
{
$this->commands = [
'build:project' => new BuildProjectCommand(),
'reset' => new CleanProjectCommand(),
'generate:urn-catalog' => new GenerateDevUrnCommand(),
'generate:suite' => new GenerateSuiteCommand(),
'generate:tests' => new GenerateTestsCommand(),
'run:test' => new RunTestCommand(),
'run:group' => new RunTestGroupCommand(),
'run:failed' => new RunTestFailedCommand(),
'run:manifest' => new RunManifestCommand(),
'setup:env' => new SetupEnvCommand(),
'upgrade:tests' => new UpgradeTestsCommand(),
'generate:docs' => new GenerateDocsCommand(),
'static-checks' => new StaticChecksCommand()
'build:project' => new BuildProjectCommand(),
'doctor' => new DoctorCommand(),
'generate:docs' => new GenerateDocsCommand(),
'generate:suite' => new GenerateSuiteCommand(),
'generate:tests' => new GenerateTestsCommand(),
'generate:urn-catalog' => new GenerateDevUrnCommand(),
'reset' => new CleanProjectCommand(),
'run:failed' => new RunTestFailedCommand(),
'run:group' => new RunTestGroupCommand(),
'run:manifest' => new RunManifestCommand(),
'run:test' => new RunTestCommand(),
'setup:env' => new SetupEnvCommand(),
'static-checks' => new StaticChecksCommand(),
'upgrade:tests' => new UpgradeTestsCommand(),
] + $commands;
}

Expand Down
204 changes: 204 additions & 0 deletions src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types = 1);

namespace Magento\FunctionalTestingFramework\Console;

use Codeception\Configuration;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Codeception\SuiteManager;
use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig;
use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Magento\FunctionalTestingFramework\Util\ModuleResolver;
use Magento\FunctionalTestingFramework\Module\MagentoWebDriver;
use Magento\FunctionalTestingFramework\Module\MagentoWebDriverDoctor;
use Symfony\Component\Console\Style\SymfonyStyle;

class DoctorCommand extends Command
{
const CODECEPTION_AUTOLOAD_FILE = PROJECT_ROOT . '/vendor/codeception/codeception/autoload.php';
const MFTF_CODECEPTION_CONFIG_FILE = ENV_FILE_PATH . 'codeception.yml';
const SUITE = 'functional';

/**
* Console output style
*
* @var SymfonyStyle
*/
private $ioStyle;

/**
* Exception Context
*
* @var array
*/
private $context = [];

/**
* Configures the current command.
*
* @return void
*/
protected function configure()
{
$this->setName('doctor')
->setDescription(
'This command checks environment readiness for generating and running MFTF tests.'
);
}

/**
* Executes the current command.
*
* @param InputInterface $input
* @param OutputInterface $output
* @return integer
* @throws TestFrameworkException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
// For output style
$this->ioStyle = new SymfonyStyle($input, $output);

$cmdStatus = true;

// Config application
$verbose = $output->isVerbose();
MftfApplicationConfig::create(
false,
MftfApplicationConfig::GENERATION_PHASE,
$verbose,
MftfApplicationConfig::LEVEL_DEVELOPER,
false
);

// Check authentication to Magento Admin
$status = $this->checkAuthenticationToMagentoAdmin();
$cmdStatus = $cmdStatus && !$status ? false : $cmdStatus;

// Check connection to Selenium
$status = $this->checkContextOnStep(
MagentoWebDriverDoctor::EXCEPTION_CONTEXT_SELENIUM,
'Connecting to Selenium Server'
);
$cmdStatus = $cmdStatus && !$status ? false : $cmdStatus;

// Check opening Magento Admin in web browser
$status = $this->checkContextOnStep(
MagentoWebDriverDoctor::EXCEPTION_CONTEXT_ADMIN,
'Loading Admin page'
);
$cmdStatus = $cmdStatus && !$status ? false : $cmdStatus;

// Check opening Magento Storefront in web browser
$status = $this->checkContextOnStep(
MagentoWebDriverDoctor::EXCEPTION_CONTEXT_STOREFRONT,
'Loading Storefront page'
);
$cmdStatus = $cmdStatus && !$status ? false : $cmdStatus;

// Check access to Magento CLI
$status = $this->checkContextOnStep(
MagentoWebDriverDoctor::EXCEPTION_CONTEXT_CLI,
'Running Magento CLI'
);
$cmdStatus = $cmdStatus && !$status ? false : $cmdStatus;

return $cmdStatus ? 0 : 1;
}

/**
* Check admin account authentication
*
* @return boolean
*/
private function checkAuthenticationToMagentoAdmin()
{
$result = false;
try {
$this->ioStyle->text("Requesting API token for admin user through cURL ...");
ModuleResolver::getInstance()->getAdminToken();
$this->ioStyle->success('Successful');
$result = true;
} catch (TestFrameworkException $e) {
$this->ioStyle->error(
$e->getMessage()
. "\nPlease verify MAGENTO_ADMIN_USERNAME and MAGENTO_ADMIN_PASSWORD in .env."
);
}
return $result;
}

/**
* Check exception context after runMagentoWebDriverDoctor
*
* @param string $exceptionType
* @param string $message
* @return boolean
* @throws TestFrameworkException
*/
private function checkContextOnStep($exceptionType, $message)
{
$this->ioStyle->text($message . ' ...');
$this->runMagentoWebDriverDoctor();

if (isset($this->context[$exceptionType])) {
$this->ioStyle->error($this->context[$exceptionType]);
return false;
} else {
$this->ioStyle->success('Successful');
return true;
}
}

/**
* Run diagnose through MagentoWebDriverDoctor
*
* @return void
* @throws TestFrameworkException
*/
private function runMagentoWebDriverDoctor()
{
if (!empty($this->context)) {
return;
}

$magentoWebDriver = '\\' . MagentoWebDriver::class;
$magentoWebDriverDoctor = '\\' . MagentoWebDriverDoctor::class;

require_once realpath(self::CODECEPTION_AUTOLOAD_FILE);

$config = Configuration::config(realpath(self::MFTF_CODECEPTION_CONFIG_FILE));
$settings = Configuration::suiteSettings(self::SUITE, $config);

// Enable MagentoWebDriverDoctor
$settings['modules']['enabled'][] = $magentoWebDriverDoctor;
$settings['modules']['config'][$magentoWebDriverDoctor] =
$settings['modules']['config'][$magentoWebDriver];

// Disable MagentoWebDriver to avoid conflicts
foreach ($settings['modules']['enabled'] as $index => $module) {
if ($module == $magentoWebDriver) {
unset($settings['modules']['enabled'][$index]);
break;
}
}
unset($settings['modules']['config'][$magentoWebDriver]);

$dispatcher = new EventDispatcher();
$suiteManager = new SuiteManager($dispatcher, self::SUITE, $settings);
try {
$suiteManager->initialize();
$this->context = ['Successful'];
} catch (TestFrameworkException $e) {
$this->context = $e->getContext();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
*/
class TestFrameworkException extends \Exception
{
/**
* Exception context
*
* @var array
*/
protected $context;

/**
* TestFrameworkException constructor.
* @param string $message
Expand All @@ -27,6 +34,17 @@ public function __construct($message, $context = [])
$context
);

$this->context = $context;
parent::__construct($message);
}

/**
* Return exception context
*
* @return array
*/
public function getContext()
{
return $this->context;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
use Symfony\Component\Process\Process;
use Yandex\Allure\Adapter\Support\AttachmentSupport;
use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException;
use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Exception\WebDriverCurlException;

/**
* MagentoWebDriver module provides common Magento web actions through Selenium WebDriver.
Expand Down
Loading