diff --git a/.drone.yml b/.drone.yml index 09719bda6..d57d9fc1f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -125,10 +125,29 @@ pipeline: - cd ../server/ - php occ app:enable deck - cd apps/$APP_NAME - - make test + - phpunit -c tests/phpunit.xml --coverage-clover build/php-unit.coverage.xml + - phpunit -c tests/phpunit.integration.xml --coverage-clover build/php-integration.coverage.xml when: matrix: TESTS: php7.1 + integration: + image: nextcloudci/integration-php7.0:integration-php7.0-3 + environment: + - APP_NAME=deck + - CORE_BRANCH=master + - DB=sqlite + commands: + # Pre-setup steps + - wget https://raw.githubusercontent.com/nextcloud/travis_ci/master/before_install.sh + - bash ./before_install.sh $APP_NAME $CORE_BRANCH $DB + - cd ../server/ + - php occ app:enable deck + - cd apps/$APP_NAME + - cd tests/integration + - ./run.sh + when: + matrix: + TESTS: integration jsbuild: image: mhart/alpine-node:6.8.0 commands: @@ -149,5 +168,6 @@ matrix: - TESTS: php7.0 - TESTS: php7.1 - TESTS: jsbuild + - TESTS: integration branches: [ master, stable* ] diff --git a/.gitignore b/.gitignore index 9d188b68e..ee470a22c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ js/node_modules/* js/vendor/ build/ js/public/ +tests/integration/vendor/ +tests/integration/composer.lock diff --git a/.travis.yml b/.travis.yml index b0831b712..c2c101ce3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ before_script: - cd apps/deck script: - - make test + - make test-unit after_failure: - cat ../../data/nextcloud.log diff --git a/Makefile b/Makefile index b33771854..b018d1035 100644 --- a/Makefile +++ b/Makefile @@ -69,8 +69,9 @@ appstore: clean-build build echo $(appstore_package_name).tar.gz +test: test-unit test-integration -test: +test-unit: mkdir -p build/ ifeq (, $(shell which phpunit 2> /dev/null)) @echo "No phpunit command available, downloading a copy from the web" @@ -83,6 +84,9 @@ else phpunit -c tests/phpunit.integration.xml --coverage-clover build/php-integration.coverage.xml endif -test-js: - cd js && run test +test-integration: + cd tests/integration && ./run.sh + +test-js: install-deps + cd js && run test diff --git a/tests/integration/AppTest.php b/tests/integration/app/AppTest.php similarity index 100% rename from tests/integration/AppTest.php rename to tests/integration/app/AppTest.php diff --git a/tests/integration/composer.json b/tests/integration/composer.json new file mode 100644 index 000000000..0d3700061 --- /dev/null +++ b/tests/integration/composer.json @@ -0,0 +1,23 @@ +{ + "require-dev": { + "phpunit/phpunit": "~4.6", + "behat/behat": "^3.0", + "guzzlehttp/guzzle": "~5.0", + "jarnaiz/behat-junit-formatter": "^1.3", + "sabre/dav": "3.2" + }, + "autoload": { + "files": [ + "../../../../build/integration/features/bootstrap/Auth.php", + "../../../../build/integration/features/bootstrap/Provisioning.php", + "../../../../build/integration/features/bootstrap/Sharing.php", + "../../../../build/integration/features/bootstrap/Trashbin.php", + "../../../../build/integration/features/bootstrap/WebDav.php" + ], + "psr-0": { + "": [ + "features/bootstrap/" + ] + } + } +} diff --git a/tests/integration/config/behat.yml b/tests/integration/config/behat.yml new file mode 100644 index 000000000..37aaed8f4 --- /dev/null +++ b/tests/integration/config/behat.yml @@ -0,0 +1,12 @@ +default: + suites: + test: + paths: + - %paths.base%/../features/ + contexts: + - FeatureContext: + baseUrl: http://localhost:8080/index.php/ocs/ + admin: + - admin + - admin + regular_user_password: 123456 \ No newline at end of file diff --git a/tests/integration/features/acl.feature b/tests/integration/features/acl.feature new file mode 100644 index 000000000..9ee4c1ebe --- /dev/null +++ b/tests/integration/features/acl.feature @@ -0,0 +1,36 @@ +Feature: acl + Routes should check for permissions when a user sends a requests + + Background: + Given user "admin" exists + And user "user0" exists + And user "user1" exists + And user "user2" exists + Given group "group0" exists + And group "group1" exists + Given user "user1" belongs to group "group1" + + Scenario: Request the main frontend page + Given Logging in using web as "user0" + When Sending a "GET" to "/index.php/apps/deck" without requesttoken + Then the HTTP status code should be "200" + + Scenario: Fetch the board list + Given Logging in using web as "user0" + When Sending a "GET" to "/index.php/apps/deck/boards" with requesttoken + Then the HTTP status code should be "200" + And the Content-Type should be "application/json; charset=utf-8" + + Scenario: Fetch board details of owned board + Given Logging in using web as "admin" + And creates a board named "MyPrivateAdminBoard" with color "fafafa" + When "admin" fetches the board named "MyPrivateAdminBoard" + Then the HTTP status code should be "200" + And the Content-Type should be "application/json; charset=utf-8" + + Scenario: Fetch board details of an other users board + Given Logging in using web as "admin" + And creates a board named "MyPrivateAdminBoard" with color "fafafa" + When "user0" fetches the board named "MyPrivateAdminBoard" + Then the HTTP status code should be "403" + And the Content-Type should be "application/json; charset=utf-8" \ No newline at end of file diff --git a/tests/integration/features/bootstrap/BasicStructure.php b/tests/integration/features/bootstrap/BasicStructure.php new file mode 100644 index 000000000..cf4176da3 --- /dev/null +++ b/tests/integration/features/bootstrap/BasicStructure.php @@ -0,0 +1,450 @@ + + * @author Joas Schilling + * @author Lukas Reschke + * @author Sergio Bertolin + * @author Thomas Müller + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +use GuzzleHttp\Client; +use GuzzleHttp\Cookie\CookieJar; +use GuzzleHttp\Exception\ClientException; +use GuzzleHttp\Message\ResponseInterface; + +require __DIR__ . '/../../vendor/autoload.php'; + +trait BasicStructure { + + use Auth; + + /** @var string */ + private $currentUser = ''; + + /** @var string */ + private $currentServer = ''; + + /** @var string */ + private $baseUrl = ''; + + /** @var int */ + private $apiVersion = 1; + + /** @var ResponseInterface */ + private $response = null; + + /** @var CookieJar */ + private $cookieJar; + + /** @var string */ + private $requestToken; + + public function __construct($baseUrl, $admin, $regular_user_password) { + + // Initialize your context here + $this->baseUrl = $baseUrl; + $this->adminUser = $admin; + $this->regularUser = $regular_user_password; + $this->localBaseUrl = $this->baseUrl; + $this->remoteBaseUrl = $this->baseUrl; + $this->currentServer = 'LOCAL'; + $this->cookieJar = new CookieJar(); + + // in case of ci deployment we take the server url from the environment + $testServerUrl = getenv('TEST_SERVER_URL'); + if ($testServerUrl !== false) { + $this->baseUrl = $testServerUrl; + $this->localBaseUrl = $testServerUrl; + } + + // federated server url from the environment + $testRemoteServerUrl = getenv('TEST_SERVER_FED_URL'); + if ($testRemoteServerUrl !== false) { + $this->remoteBaseUrl = $testRemoteServerUrl; + } + } + + /** + * @Given /^using api version "(\d+)"$/ + * @param string $version + */ + public function usingApiVersion($version) { + $this->apiVersion = (int) $version; + } + + /** + * @Given /^As an "([^"]*)"$/ + * @param string $user + */ + public function asAn($user) { + $this->currentUser = $user; + } + + /** + * @Given /^Using server "(LOCAL|REMOTE)"$/ + * @param string $server + * @return string Previous used server + */ + public function usingServer($server) { + $previousServer = $this->currentServer; + if ($server === 'LOCAL'){ + $this->baseUrl = $this->localBaseUrl; + $this->currentServer = 'LOCAL'; + return $previousServer; + } else { + $this->baseUrl = $this->remoteBaseUrl; + $this->currentServer = 'REMOTE'; + return $previousServer; + } + } + + /** + * @When /^sending "([^"]*)" to "([^"]*)"$/ + * @param string $verb + * @param string $url + */ + public function sendingTo($verb, $url) { + $this->sendingToWith($verb, $url, null); + } + + /** + * Parses the xml answer to get ocs response which doesn't match with + * http one in v1 of the api. + * @param ResponseInterface $response + * @return string + */ + public function getOCSResponse($response) { + return $response->xml()->meta[0]->statuscode; + } + + /** + * This function is needed to use a vertical fashion in the gherkin tables. + * @param array $arrayOfArrays + * @return array + */ + public function simplifyArray($arrayOfArrays){ + $a = array_map(function($subArray) { return $subArray[0]; }, $arrayOfArrays); + return $a; + } + + /** + * @When /^sending "([^"]*)" to "([^"]*)" with$/ + * @param string $verb + * @param string $url + * @param \Behat\Gherkin\Node\TableNode $body + */ + public function sendingToWith($verb, $url, $body) { + $fullUrl = $this->baseUrl . "v{$this->apiVersion}.php" . $url; + $client = new Client(); + $options = []; + if ($this->currentUser === 'admin') { + $options['auth'] = $this->adminUser; + } else { + $options['auth'] = [$this->currentUser, $this->regularUser]; + } + $options['headers'] = [ + 'OCS_APIREQUEST' => 'true' + ]; + if ($body instanceof \Behat\Gherkin\Node\TableNode) { + $fd = $body->getRowsHash(); + $options['body'] = $fd; + } + + // TODO: Fix this hack! + if ($verb === 'PUT' && $body === null) { + $options['body'] = [ + 'foo' => 'bar', + ]; + } + + try { + $this->response = $client->send($client->createRequest($verb, $fullUrl, $options)); + } catch (ClientException $ex) { + $this->response = $ex->getResponse(); + } + } + + /** + * @When /^sending "([^"]*)" with exact url to "([^"]*)"$/ + * @param string $verb + * @param string $url + */ + public function sendingToDirectUrl($verb, $url) { + $this->sendingToWithDirectUrl($verb, $url, null); + } + + public function sendingToWithDirectUrl($verb, $url, $body) { + $fullUrl = substr($this->baseUrl, 0, -5) . $url; + $client = new Client(); + $options = []; + if ($this->currentUser === 'admin') { + $options['auth'] = $this->adminUser; + } else { + $options['auth'] = [$this->currentUser, $this->regularUser]; + } + if ($body instanceof \Behat\Gherkin\Node\TableNode) { + $fd = $body->getRowsHash(); + $options['body'] = $fd; + } + + try { + $this->response = $client->send($client->createRequest($verb, $fullUrl, $options)); + } catch (ClientException $ex) { + $this->response = $ex->getResponse(); + } + } + + public function isExpectedUrl($possibleUrl, $finalPart){ + $baseUrlChopped = substr($this->baseUrl, 0, -4); + $endCharacter = strlen($baseUrlChopped) + strlen($finalPart); + return (substr($possibleUrl,0,$endCharacter) == "$baseUrlChopped" . "$finalPart"); + } + + /** + * @Then /^the OCS status code should be "([^"]*)"$/ + * @param int $statusCode + */ + public function theOCSStatusCodeShouldBe($statusCode) { + PHPUnit_Framework_Assert::assertEquals($statusCode, $this->getOCSResponse($this->response)); + } + + /** + * @Then /^the HTTP status code should be "([^"]*)"$/ + * @param int $statusCode + */ + public function theHTTPStatusCodeShouldBe($statusCode) { + PHPUnit_Framework_Assert::assertEquals($statusCode, $this->response->getStatusCode()); + } + + /** + * @Then /^the Content-Type should be "([^"]*)"$/ + * @param string $contentType + */ + public function theContentTypeShouldbe($contentType) { + PHPUnit_Framework_Assert::assertEquals($contentType, $this->response->getHeader('Content-Type')); + } + + /** + * @param ResponseInterface $response + */ + private function extracRequestTokenFromResponse(ResponseInterface $response) { + $this->requestToken = substr(preg_replace('/(.*)data-requesttoken="(.*)">(.*)/sm', '\2', $response->getBody()->getContents()), 0, 89); + } + + /** + * @Given Logging in using web as :user + * @param string $user + */ + public function loggingInUsingWebAs($user) { + $loginUrl = substr($this->baseUrl, 0, -5) . '/login'; + // Request a new session and extract CSRF token + $client = new Client(); + $response = $client->get( + $loginUrl, + [ + 'cookies' => $this->cookieJar, + ] + ); + $this->extracRequestTokenFromResponse($response); + + // Login and extract new token + $password = ($user === 'admin') ? 'admin' : '123456'; + $client = new Client(); + $response = $client->post( + $loginUrl, + [ + 'body' => [ + 'user' => $user, + 'password' => $password, + 'requesttoken' => $this->requestToken, + ], + 'cookies' => $this->cookieJar, + ] + ); + $this->extracRequestTokenFromResponse($response); + } + + /** + * @When Sending a :method to :url with requesttoken + * @param string $method + * @param string $url + */ + public function sendingAToWithRequesttoken($method, $url) { + $baseUrl = substr($this->baseUrl, 0, -5); + + $client = new Client(); + $request = $client->createRequest( + $method, + $baseUrl . $url, + [ + 'cookies' => $this->cookieJar, + ] + ); + $request->addHeader('requesttoken', $this->requestToken); + try { + $this->response = $client->send($request); + } catch (ClientException $e) { + $this->response = $e->getResponse(); + } + } + + /** + * @When Sending a :method to :url without requesttoken + * @param string $method + * @param string $url + */ + public function sendingAToWithoutRequesttoken($method, $url) { + $baseUrl = substr($this->baseUrl, 0, -5); + + $client = new Client(); + $request = $client->createRequest( + $method, + $baseUrl . $url, + [ + 'cookies' => $this->cookieJar, + ] + ); + try { + $this->response = $client->send($request); + } catch (ClientException $e) { + $this->response = $e->getResponse(); + } + } + + public static function removeFile($path, $filename){ + if (file_exists("$path" . "$filename")) { + unlink("$path" . "$filename"); + } + } + + /** + * @Given User :user modifies text of :filename with text :text + * @param string $user + * @param string $filename + * @param string $text + */ + public function modifyTextOfFile($user, $filename, $text) { + self::removeFile("../../data/$user/files", "$filename"); + file_put_contents("../../data/$user/files" . "$filename", "$text"); + } + + public function createFileSpecificSize($name, $size) { + $file = fopen("work/" . "$name", 'w'); + fseek($file, $size - 1 ,SEEK_CUR); + fwrite($file,'a'); // write a dummy char at SIZE position + fclose($file); + } + + public function createFileWithText($name, $text){ + $file = fopen("work/" . "$name", 'w'); + fwrite($file, $text); + fclose($file); + } + + /** + * @Given file :filename of size :size is created in local storage + * @param string $filename + * @param string $size + */ + public function fileIsCreatedInLocalStorageWithSize($filename, $size) { + $this->createFileSpecificSize("local_storage/$filename", $size); + } + + /** + * @Given file :filename with text :text is created in local storage + * @param string $filename + * @param string $text + */ + public function fileIsCreatedInLocalStorageWithText($filename, $text) { + $this->createFileWithText("local_storage/$filename", $text); + } + + /** + * @When Sleep for :seconds seconds + * @param int $seconds + */ + public function sleepForSeconds($seconds) { + sleep((int)$seconds); + } + + /** + * @BeforeSuite + */ + public static function addFilesToSkeleton(){ + for ($i=0; $i<5; $i++){ + file_put_contents("../../core/skeleton/" . "textfile" . "$i" . ".txt", "Nextcloud test text file\n"); + } + if (!file_exists("../../core/skeleton/FOLDER")) { + mkdir("../../core/skeleton/FOLDER", 0777, true); + } + if (!file_exists("../../core/skeleton/PARENT")) { + mkdir("../../core/skeleton/PARENT", 0777, true); + } + file_put_contents("../../core/skeleton/PARENT/" . "parent.txt", "Nextcloud test text file\n"); + if (!file_exists("../../core/skeleton/PARENT/CHILD")) { + mkdir("../../core/skeleton/PARENT/CHILD", 0777, true); + } + file_put_contents("../../core/skeleton/PARENT/CHILD/" . "child.txt", "Nextcloud test text file\n"); + } + + /** + * @AfterSuite + */ + public static function removeFilesFromSkeleton(){ + for ($i=0; $i<5; $i++){ + self::removeFile("../../core/skeleton/", "textfile" . "$i" . ".txt"); + } + if (is_dir("../../core/skeleton/FOLDER")) { + rmdir("../../core/skeleton/FOLDER"); + } + self::removeFile("../../core/skeleton/PARENT/CHILD/", "child.txt"); + if (is_dir("../../core/skeleton/PARENT/CHILD")) { + rmdir("../../core/skeleton/PARENT/CHILD"); + } + self::removeFile("../../core/skeleton/PARENT/", "parent.txt"); + if (is_dir("../../core/skeleton/PARENT")) { + rmdir("../../core/skeleton/PARENT"); + } + } + + /** + * @BeforeScenario @local_storage + */ + public static function removeFilesFromLocalStorageBefore(){ + $dir = "./work/local_storage/"; + $di = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS); + $ri = new RecursiveIteratorIterator($di, RecursiveIteratorIterator::CHILD_FIRST); + foreach ( $ri as $file ) { + $file->isDir() ? rmdir($file) : unlink($file); + } + } + + /** + * @AfterScenario @local_storage + */ + public static function removeFilesFromLocalStorageAfter(){ + $dir = "./work/local_storage/"; + $di = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS); + $ri = new RecursiveIteratorIterator($di, RecursiveIteratorIterator::CHILD_FIRST); + foreach ( $ri as $file ) { + $file->isDir() ? rmdir($file) : unlink($file); + } + } +} diff --git a/tests/integration/features/bootstrap/FeatureContext.php b/tests/integration/features/bootstrap/FeatureContext.php new file mode 100644 index 000000000..67e79df7c --- /dev/null +++ b/tests/integration/features/bootstrap/FeatureContext.php @@ -0,0 +1,194 @@ +baseUrl, 0, -5); + + $client = new Client; + $request = $client->createRequest( + $method, + $baseUrl . $url, + [ + 'cookies' => $this->cookieJar, + 'json' => json_decode($data) + ] + ); + $request->addHeader('requesttoken', $this->requestToken); + try { + $this->response = $client->send($request); + } catch (ClientException $e) { + $this->response = $e->getResponse(); + } + } + + + /** + * @When :user creates a new deck with name :name + */ + public function createsANewDeckWithName($user, $content) { + $client = new GuzzleHttp\Client(); + $this->response = $client->post( + 'http://localhost:8080/index.php/apps/deck/boards', + [ + 'form_params' => [ + 'name' => $name, + ], + 'auth' => [ + $this->mappedUserId, + 'test', + ], + ] + ); + } + + /** + * @Then the response should have a status code :code + * @param string $code + * @throws InvalidArgumentException + */ + public function theResponseShouldHaveAStatusCode($code) { + $currentCode = $this->response->getStatusCode(); + if ($currentCode !== (int)$code) { + throw new InvalidArgumentException( + sprintf( + 'Expected %s as code got %s', + $code, + $currentCode + ) + ); + } + } + + /** + * @Then the response should be a JSON array with the following mandatory values + * @param TableNode $table + * @throws InvalidArgumentException + */ + public function theResponseShouldBeAJsonArrayWithTheFollowingMandatoryValues(TableNode $table) { + $expectedValues = $table->getColumnsHash(); + $realResponseArray = json_decode($this->response->getBody()->getContents(), true); + + foreach ($expectedValues as $value) { + if ((string)$realResponseArray[$value['key']] !== (string)$value['value']) { + throw new InvalidArgumentException( + sprintf( + 'Expected %s for key %s got %s', + (string)$value['value'], + $value['key'], + (string)$realResponseArray[$value['key']] + ) + ); + } + } + } + + /** + * @Then the response should be a JSON array with a length of :length + * @param int $length + * @throws InvalidArgumentException + */ + public function theResponseShouldBeAJsonArrayWithALengthOf($length) { + $realResponseArray = json_decode($this->response->getBody()->getContents(), true); + PHPUnit_Framework_Assert::assertEquals($realResponseArray, "foo"); + if((int)count($realResponseArray) !== (int)$length) { + throw new InvalidArgumentException( + sprintf( + 'Expected %d as length got %d', + $length, + count($realResponseArray) + ) + ); + } + } + + /** + * @Then /^I should get:$/ + * + * @param PyStringNode $string + * @throws \Exception + */ + public function iShouldGet(PyStringNode $string) + { + if ((string) $string !== trim($this->cliOutput)) { + throw new Exception(sprintf( + 'Expected "%s" but received "%s".', + $string, + $this->cliOutput + )); + } + + return; + } + + private function sendJSONrequest($method, $url, $data) { + $baseUrl = substr($this->baseUrl, 0, -5); + + $client = new Client; + $request = $client->createRequest( + $method, + $baseUrl . $url, + [ + 'cookies' => $this->cookieJar, + 'json' => $data + ] + ); + $request->addHeader('requesttoken', $this->requestToken); + try { + $this->response = $client->send($request); + } catch (ClientException $e) { + $this->response = $e->getResponse(); + } + } + + /** + * @Given /^creates a board named "([^"]*)" with color "([^"]*)"$/ + */ + public function createsABoardNamedWithColor($title, $color) { + + $this->sendJSONrequest('POST', '/index.php/apps/deck/boards', [ + 'title' => $title, + 'color' => $color + ] + ); + $response = json_decode($this->response->getBody()->getContents(), true); + $this->lastInsertIds[$title] = $response['id']; + } + + /** + * @When /^"([^"]*)" fetches the board named "([^"]*)"$/ + */ + public function fetchesTheBoardNamed($user, $boardName) { + $this->loggingInUsingWebAs($user); + $id = $this->lastInsertIds[$boardName]; + $this->sendJSONrequest('GET', '/index.php/apps/deck/boards/'.$id, []); + } + +} diff --git a/tests/integration/features/decks.feature b/tests/integration/features/decks.feature new file mode 100644 index 000000000..405e0b823 --- /dev/null +++ b/tests/integration/features/decks.feature @@ -0,0 +1,37 @@ +Feature: decks + + Background: + Given user "user0" exists + + Scenario: Request the main frontend page + Given Logging in using web as "admin" + When Sending a "GET" to "/index.php/apps/deck" without requesttoken + Then the HTTP status code should be "200" + + Scenario: Fetch the board list + Given Logging in using web as "admin" + When Sending a "GET" to "/index.php/apps/deck/boards" with requesttoken + Then the HTTP status code should be "200" + And the Content-Type should be "application/json; charset=utf-8" + + Scenario: Fetch board details of a nonexisting board + Given Logging in using web as "admin" + When Sending a "GET" to "/index.php/apps/deck/boards/13379" with requesttoken + Then the HTTP status code should be "403" + And the Content-Type should be "application/json; charset=utf-8" + + Scenario: Create a new board + Given Logging in using web as "admin" + When Sending a "POST" to "/index.php/apps/deck/boards" with JSON + """ + { + "title": "MyBoard", + "color": "000000" + } + """ + Then the HTTP status code should be "200" + And the Content-Type should be "application/json; charset=utf-8" + And the response should be a JSON array with the following mandatory values + |key|value| + |title|MyBoard| + |color|000000| diff --git a/tests/integration/run.sh b/tests/integration/run.sh new file mode 100755 index 000000000..63a733723 --- /dev/null +++ b/tests/integration/run.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +OC_PATH=../../../../ +OCC=${OC_PATH}occ +SCENARIO_TO_RUN=$1 +HIDE_OC_LOGS=$2 + +# Nextcloud integration tests composer +( + cd ${OC_PATH}build/integration + composer install +) +INSTALLED=$($OCC status | grep installed: | cut -d " " -f 5) + +if [ "$INSTALLED" == "true" ]; then + $OCC app:enable deck +else + if [ "$SCENARIO_TO_RUN" != "setup_features/setup.feature" ]; then + echo "Nextcloud instance needs to be installed" >&2 + exit 1 + fi +fi + +composer install +composer dump-autoload + +# avoid port collision on jenkins - use $EXECUTOR_NUMBER +if [ -z "$EXECUTOR_NUMBER" ]; then + EXECUTOR_NUMBER=0 +fi +PORT=$((8080 + $EXECUTOR_NUMBER)) +echo $PORT +php -S localhost:$PORT -t $OC_PATH & +PHPPID=$! +echo $PHPPID + +export TEST_SERVER_URL="http://localhost:$PORT/ocs/" + +vendor/bin/behat +RESULT=$? + +kill $PHPPID + +echo "runsh: Exit code: $RESULT" +exit $RESULT diff --git a/tests/phpunit.integration.xml b/tests/phpunit.integration.xml index 4a7eddb02..45d0b5081 100644 --- a/tests/phpunit.integration.xml +++ b/tests/phpunit.integration.xml @@ -1,7 +1,10 @@ - - ./integration + + ./integration/database + + + ./integration/app