Skip to content

Commit

Permalink
Assert file downloaded
Browse files Browse the repository at this point in the history
  • Loading branch information
tienvx committed Jul 17, 2022
1 parent c0a830b commit 3c89217
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 12 deletions.
1 change: 1 addition & 0 deletions composer.json
Expand Up @@ -25,6 +25,7 @@
"symfony/config": "^6.1",
"symfony/dependency-injection": "^6.1",
"symfony/expression-language": "^6.1",
"symfony/http-client-contracts": "^3.1",
"symfony/http-kernel": "^6.1",
"symfony/messenger": "^6.1",
"symfony/validator": "^6.1",
Expand Down
47 changes: 45 additions & 2 deletions src/Command/Runner/CustomCommandRunner.php
Expand Up @@ -2,24 +2,43 @@

namespace Tienvx\Bundle\MbtBundle\Command\Runner;

use Exception;
use Facebook\WebDriver\Remote\LocalFileDetector;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Tienvx\Bundle\MbtBundle\Command\CommandRunner;
use Tienvx\Bundle\MbtBundle\Exception\RuntimeException;
use Tienvx\Bundle\MbtBundle\Model\Model\Revision\CommandInterface;
use Tienvx\Bundle\MbtBundle\Model\ValuesInterface;

class CustomCommandRunner extends CommandRunner
{
public const UPLOAD = 'upload';
public const ASSERT_FILE_DOWNLOADED = 'assertFileDownloaded';

public function __construct(protected string $uploadDir)
protected string $uploadDir;
protected string $webdriverUri;

public function __construct(protected HttpClientInterface $httpClient)
{
}

public function setUploadDir(string $uploadDir): void
{
$this->uploadDir = $uploadDir;
}

public function setWebdriverUri(string $webdriverUri): void
{
$this->webdriverUri = $webdriverUri;
}

public function getAllCommands(): array
{
return [
self::UPLOAD,
self::ASSERT_FILE_DOWNLOADED,
];
}

Expand All @@ -30,7 +49,9 @@ public function getCommandsRequireTarget(): array

public function getCommandsRequireValue(): array
{
return $this->getAllCommands();
return [
self::UPLOAD,
];
}

public function run(CommandInterface $command, ValuesInterface $values, RemoteWebDriver $driver): void
Expand All @@ -42,6 +63,28 @@ public function run(CommandInterface $command, ValuesInterface $values, RemoteWe
->setFileDetector(new LocalFileDetector())
->sendKeys($this->getFilePath($command));
break;
case self::ASSERT_FILE_DOWNLOADED:
try {
$code = $this->httpClient->request(
'GET',
sprintf(
'%s/download/%s/%s',
rtrim($this->webdriverUri, '/'),
$driver->getSessionID(),
$command->getTarget()
)
)->getStatusCode();
if (200 !== $code) {
throw new Exception(sprintf('File %s is not downloaded', $command->getTarget()));
}
} catch (ExceptionInterface $e) {
throw new RuntimeException(sprintf(
'Can not verify file %s is downloaded: %s',
$command->getTarget(),
$e->getMessage()
));
}
break;
default:
break;
}
Expand Down
10 changes: 10 additions & 0 deletions src/DependencyInjection/Configuration.php
Expand Up @@ -8,6 +8,7 @@
class Configuration implements ConfigurationInterface
{
public const WEBDRIVER_URI = 'webdriver_uri';
public const UPLOAD_DIR = 'upload_dir';

public function getConfigTreeBuilder(): TreeBuilder
{
Expand All @@ -24,6 +25,15 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
;

$rootNode
->children()
->scalarNode(static::UPLOAD_DIR)
->isRequired()
->cannotBeEmpty()
->end()
->end()
;

return $treeBuilder;
}
}
6 changes: 6 additions & 0 deletions src/DependencyInjection/TienvxMbtExtension.php
Expand Up @@ -8,6 +8,7 @@
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Tienvx\Bundle\MbtBundle\Command\CommandRunnerInterface;
use Tienvx\Bundle\MbtBundle\Command\Runner\CustomCommandRunner;
use Tienvx\Bundle\MbtBundle\Plugin\PluginInterface;
use Tienvx\Bundle\MbtBundle\Service\SelenoidHelperInterface;

Expand Down Expand Up @@ -35,6 +36,11 @@ public function load(array $configs, ContainerBuilder $container): void
->addMethodCall('setWebdriverUri', [$config[Configuration::WEBDRIVER_URI]])
;

$container->findDefinition(CustomCommandRunner::class)
->addMethodCall('setWebdriverUri', [$config[Configuration::WEBDRIVER_URI]])
->addMethodCall('setUploadDir', [$config[Configuration::UPLOAD_DIR]])
;

$this->registerForAutoconfiguration($container);
}

Expand Down
4 changes: 4 additions & 0 deletions src/Resources/config/services.php
Expand Up @@ -9,6 +9,7 @@
use SingleColorPetrinet\Service\GuardedTransitionService;
use SingleColorPetrinet\Service\GuardedTransitionServiceInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Tienvx\AssignmentsEvaluator\AssignmentsEvaluator;
use Tienvx\Bundle\MbtBundle\Channel\ChannelManager;
use Tienvx\Bundle\MbtBundle\Channel\ChannelManagerInterface;
Expand Down Expand Up @@ -199,6 +200,9 @@
->autoconfigure(true)
->set(CustomCommandRunner::class)
->autoconfigure(true)
->args([
service(HttpClientInterface::class),
])

// Repositories
->set(BugRepository::class)
Expand Down
86 changes: 78 additions & 8 deletions tests/Command/Runner/CustomCommandRunnerTest.php
Expand Up @@ -2,11 +2,16 @@

namespace Tienvx\Bundle\MbtBundle\Tests\Command\Runner;

use Exception;
use Facebook\WebDriver\Remote\LocalFileDetector;
use Facebook\WebDriver\Remote\RemoteWebElement;
use Facebook\WebDriver\WebDriverBy;
use Tienvx\Bundle\MbtBundle\Command\CommandRunner;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Tienvx\Bundle\MbtBundle\Command\Runner\CustomCommandRunner;
use Tienvx\Bundle\MbtBundle\Exception\RuntimeException;
use Tienvx\Bundle\MbtBundle\Tests\Fixtures\Exception\HttpClientException;
use Tienvx\Bundle\MbtBundle\ValueObject\Model\Command;

/**
Expand All @@ -17,9 +22,19 @@
*/
class CustomCommandRunnerTest extends RunnerTestCase
{
protected function createRunner(): CommandRunner
protected string $webdriverUri = 'http://localhost:4444';
protected string $uploadDir = '/path/to/upload-directory';
protected string $sessionId = 'abc123';
protected HttpClientInterface|MockObject $httpClient;

protected function createRunner(): CustomCommandRunner
{
return new CustomCommandRunner('/path/to/upload-directory');
$this->httpClient = $this->createMock(HttpClientInterface::class);
$runner = new CustomCommandRunner($this->httpClient);
$runner->setWebdriverUri($this->webdriverUri);
$runner->setUploadDir($this->uploadDir);

return $runner;
}

public function testUpload(): void
Expand All @@ -28,21 +43,75 @@ public function testUpload(): void
$command->setCommand(CustomCommandRunner::UPLOAD);
$command->setTarget('id=file_input');
$command->setValue('sub-directory/file.txt');
$element = $this->createMock(RemoteWebElement::class);
$element
$this->element = $this->createMock(RemoteWebElement::class);
$this->element
->expects($this->once())
->method('setFileDetector')
->with($this->isInstanceOf(LocalFileDetector::class))
->willReturnSelf();
$element
$this->element
->expects($this->once())
->method('sendKeys')
->with('/path/to/upload-directory/sub-directory/file.txt');
->with($this->uploadDir . '/sub-directory/file.txt');
$this->driver->expects($this->once())->method('findElement')->with($this->callback(function ($selector) {
return $selector instanceof WebDriverBy
&& 'id' === $selector->getMechanism()
&& 'file_input' === $selector->getValue();
}))->willReturn($element);
}))->willReturn($this->element);
$this->runner->run($command, $this->values, $this->driver);
}

/**
* @dataProvider statusCodeProvider
*/
public function testAssertFileDownloaded(int $code): void
{
$command = new Command();
$command->setCommand(CustomCommandRunner::ASSERT_FILE_DOWNLOADED);
$command->setTarget('file.txt');
$response = $this->createMock(ResponseInterface::class);
$response->expects($this->once())->method('getStatusCode')->willReturn($code);
$this->driver->expects($this->once())->method('getSessionID')->willReturn($this->sessionId);
$this->httpClient
->expects($this->once())
->method('request')
->with(
'GET',
$this->webdriverUri . '/download/' . $this->sessionId . '/file.txt'
)
->willReturn($response);
if (200 !== $code) {
$this->expectException(Exception::class);
$this->expectExceptionMessage('File file.txt is not downloaded');
}
$this->runner->run($command, $this->values, $this->driver);
}

public function statusCodeProvider(): array
{
return [
[200],
[404],
];
}

public function testAssertFileDownloadedThrowException(): void
{
$command = new Command();
$command->setCommand(CustomCommandRunner::ASSERT_FILE_DOWNLOADED);
$command->setTarget('file.txt');
$this->runner->setWebdriverUri($this->webdriverUri);
$this->driver->expects($this->once())->method('getSessionID')->willReturn($this->sessionId);
$this->httpClient
->expects($this->once())
->method('request')
->with(
'GET',
$this->webdriverUri . '/download/' . $this->sessionId . '/file.txt'
)
->willThrowException(new HttpClientException('Something wrong'));
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Can not verify file file.txt is downloaded: Something wrong');
$this->runner->run($command, $this->values, $this->driver);
}

Expand All @@ -59,6 +128,7 @@ public function commandsRequireTarget(): array
{
return [
CustomCommandRunner::UPLOAD,
CustomCommandRunner::ASSERT_FILE_DOWNLOADED,
];
}

Expand Down
8 changes: 6 additions & 2 deletions tests/Command/Runner/RunnerTestCase.php
Expand Up @@ -3,22 +3,26 @@
namespace Tienvx\Bundle\MbtBundle\Tests\Command\Runner;

use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverElement;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Tienvx\Bundle\MbtBundle\Command\CommandRunner;
use Tienvx\Bundle\MbtBundle\Model\ValuesInterface;
use Tienvx\Bundle\MbtBundle\ValueObject\Model\Command;

abstract class RunnerTestCase extends TestCase
{
protected RemoteWebDriver $driver;
protected RemoteWebDriver|MockObject $driver;
protected CommandRunner $runner;
protected ValuesInterface $values;
protected ValuesInterface|MockObject $values;
protected WebDriverElement|MockObject $element;

protected function setUp(): void
{
$this->driver = $this->createMock(RemoteWebDriver::class);
$this->runner = $this->createRunner();
$this->values = $this->createMock(ValuesInterface::class);
$this->element = $this->createMock(WebDriverElement::class);
}

abstract protected function createRunner(): CommandRunner;
Expand Down
6 changes: 6 additions & 0 deletions tests/DependencyInjection/TienvxMbtExtensionTest.php
Expand Up @@ -6,6 +6,7 @@
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Tienvx\Bundle\MbtBundle\Command\CommandRunnerInterface;
use Tienvx\Bundle\MbtBundle\Command\Runner\CustomCommandRunner;
use Tienvx\Bundle\MbtBundle\DependencyInjection\Configuration;
use Tienvx\Bundle\MbtBundle\DependencyInjection\TienvxMbtExtension;
use Tienvx\Bundle\MbtBundle\Plugin\PluginInterface;
Expand All @@ -19,6 +20,7 @@ class TienvxMbtExtensionTest extends TestCase
{
protected const CONFIGS = [[
Configuration::WEBDRIVER_URI => 'http://localhost:4444',
Configuration::UPLOAD_DIR => '/path/to/var/uploads',
]];

protected ContainerBuilder $container;
Expand All @@ -43,6 +45,10 @@ public function testUpdateServiceDefinitions(): void
$this->assertSame([
['setWebdriverUri', [static::CONFIGS[0][Configuration::WEBDRIVER_URI]]],
], $this->container->findDefinition(SelenoidHelperInterface::class)->getMethodCalls());
$this->assertSame([
['setWebdriverUri', [static::CONFIGS[0][Configuration::WEBDRIVER_URI]]],
['setUploadDir', [static::CONFIGS[0][Configuration::UPLOAD_DIR]]],
], $this->container->findDefinition(CustomCommandRunner::class)->getMethodCalls());
}

public function testRegisterForAutoconfiguration(): void
Expand Down
9 changes: 9 additions & 0 deletions tests/Fixtures/Exception/HttpClientException.php
@@ -0,0 +1,9 @@
<?php

namespace Tienvx\Bundle\MbtBundle\Tests\Fixtures\Exception;

use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;

class HttpClientException extends \Exception implements ExceptionInterface
{
}

0 comments on commit 3c89217

Please sign in to comment.