From e85df135f9d880d5acc5680479c7cc16031c77bb Mon Sep 17 00:00:00 2001 From: Christopher Gervais Date: Mon, 14 Mar 2016 22:27:36 +0000 Subject: [PATCH] Add some tests for installer, and CLI context. --- features/bootstrap/FeatureContext.php | 176 +++++++++++++++++++++++--- features/cli_context.feature | 17 +++ features/installer.feature | 27 ++++ mk/tasks/test.mk | 5 + scripts/install.sh | 11 ++ 5 files changed, 217 insertions(+), 19 deletions(-) create mode 100644 features/cli_context.feature create mode 100644 features/installer.feature create mode 100755 scripts/install.sh diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index f09e64d..190bbef 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -13,6 +13,12 @@ */ class FeatureContext extends RawDrupalContext implements SnippetAcceptingContext { + private $debug = FALSE; + + private $tempDir; + + private $orig_dir; + /** * Initializes context. * @@ -23,32 +29,164 @@ class FeatureContext extends RawDrupalContext implements SnippetAcceptingContext public function __construct() { } - /** - * @When I run :command - */ - public function iRun($command) - { - $process = new Process("{$command}"); - $process->setTimeout(300); - $process->run(); + /** + * Clean up temporary directories. + */ + public function __destruct() { + $this->rmdir($this->tempDir); + } + + /** + * Run a command in a sub-process, and set its output. + */ + private function exec($command) { + $process = new Process("{$command}"); + $process->setTimeout(300); + $process->run(); if (!$process->isSuccessful()) { throw new \RuntimeException($process->getErrorOutput()); } - $this->output = $process->getOutput(); + $this->output = $process->getOutput(); + if ($this->debug) { + print_r($this->output); + } + } + + /** + * Run a command that is expected to fail in a sub-process, and set its output. + */ + private function fail($command) { + $process = new Process("{$command}"); + $process->setTimeout(300); + $process->run(); + + if ($process->isSuccessful()) { + throw new \RuntimeException($process->getOutput()); + } + + $this->output = $process->getErrorOutput(); + if ($this->debug) { + print_r($this->output); + } + } + + /** + * Create a temporary directory + */ + private function makeTempDir() { + $tempfile = tempnam(sys_get_temp_dir(),'behat_cli_'); + if (file_exists($tempfile)) { + unlink($tempfile); + } + mkdir($tempfile); + $this->tempDir = $tempfile; + } + + /** + * Recursively delete a directory and its contents. + */ + private function rmdir($dir) { + if (is_dir($dir)) { + foreach(scandir($dir) as $file) { + if ('.' === $file || '..' === $file) continue; + if (is_dir("$dir/$file")) $this->rmdir("$dir/$file"); + else unlink("$dir/$file"); + } + rmdir($dir); + } + } + + /** + * Set a debug flag when running scenarios tagged @debug. + * + * @BeforeScenario @debug + */ + public function setDebugFlag() { + $this->debug = TRUE; + } + + /** + * @When I run :command + */ + public function iRun($command) + { + $this->exec($command); + } + + /** + * @Then I should get: + */ + public function iShouldGet(PyStringNode $output) + { + foreach ($output->getStrings() as $string) { + if (strpos($this->output, $string) === FALSE) { + throw new \RuntimeException("'$string' was not found in command output."); + } + } + } + + /** + * @Then I should not get: + */ + public function iShouldNotGet(PyStringNode $output) + { + foreach ($output->getStrings() as $string) { + if (strpos($this->output, $string) !== FALSE) { + throw new \RuntimeException("'$string' was found in command output."); + } + } + } + /** + * @Given I am in a temporary directory + */ + public function iAmInATemporaryDirectory() + { + static $orig_dir; + if (!isset($orig_dir)) { + $orig_dir = getcwd(); } + $this->orig_dir = $orig_dir; + $this->makeTempDir(); + chdir($this->tempDir); + } + + + /** + * Execute a script in our project, even if we've moved to a temporary directory. + * + * @When I execute :script + */ + public function iExecute($script) + { + if (isset($this->orig_dir)) { + $script = $this->orig_dir . DIRECTORY_SEPARATOR . $script; + } + $this->exec($script); + } - /** - * @Then I should get: - */ - public function iShouldGet(PyStringNode $output) - { - foreach ($output->getStrings() as $string) { - if (strpos($this->output, $string) === FALSE) { - throw new \RuntimeException("'$string' was not found in command output."); - } - } + /** + * @Then executing :script should fail + */ + public function executingShouldFail($script) + { + if (isset($this->orig_dir)) { + $script = $this->orig_dir . DIRECTORY_SEPARATOR . $script; + } + $this->fail($script); + } + + /** + * @Then the following files should exist: + */ + public function theFollowingFilesShouldExist(PyStringNode $files) + { + foreach ($files->getStrings() as $file) { + if (!file_exists($file)) { + throw new \RuntimeException("Expected file '$file' was not found."); + } } + } } diff --git a/features/cli_context.feature b/features/cli_context.feature new file mode 100644 index 0000000..1de9f22 --- /dev/null +++ b/features/cli_context.feature @@ -0,0 +1,17 @@ +Feature: CLI Context + In order to write new CLI commands + As a developer + I need to be able to test CLI commands + + Scenario: Create a test file in a temporary directory + Given I am in a temporary directory + When I run "touch test.txt" + And I run "ls" + Then I should get: + """ + test.txt + """ + Then I should not get: + """ + Makefile + """ diff --git a/features/installer.feature b/features/installer.feature new file mode 100644 index 0000000..76291ad --- /dev/null +++ b/features/installer.feature @@ -0,0 +1,27 @@ +Feature: Install drumkit + In order to use drumkit's features + As a Drupal developer + I need to be able to install drumkit easily + + Scenario: Fail if installer is not running in the root of a git repo + Given I am in a temporary directory + Then executing "scripts/install.sh" should fail + And I should get: + """ + ERROR: This script must be run at the root of a git repository. + """ + + @debug + Scenario: Succeed if installer is running in the root of a git repo + Given I am in a temporary directory + And I run "git init" + And I execute "scripts/install.sh" + Then I should not get: + """ + ERROR: This script must be run at the root of a git repository. + """ + And the following files should exist: + """ + Makefile + .mk/Makefile + """ diff --git a/mk/tasks/test.mk b/mk/tasks/test.mk index be01103..9c25b69 100644 --- a/mk/tasks/test.mk +++ b/mk/tasks/test.mk @@ -7,4 +7,9 @@ test: behat-config wip: behat-config @source behat_params.sh && bin/behat --tags=wip +self-test: behat + @behat +self-wip: behat + @behat --tags=wip --append-snippets + # vi:syntax=makefile diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..a2007dc --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +echoerr() { echo "$@" 1>&2; } + +if [[ ! -d .git ]]; then + echoerr "ERROR: This script must be run at the root of a git repository." + exit 1 +fi + +git submodule add https://github.com/ergonlogic/drumkit .mk +echo "include .mk/Makefile" > Makefile