Add basic behat test structure
Signed-off-by: Julius Haertl <jus@bitgrid.net>
This commit is contained in:
committed by
Julius Härtl
parent
11610f306a
commit
084d892ce6
23
tests/integration/composer.json
Normal file
23
tests/integration/composer.json
Normal file
@@ -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/BasicStructure.php",
|
||||
"../../../../build/integration/features/bootstrap/Provisioning.php",
|
||||
"../../../../build/integration/features/bootstrap/Sharing.php",
|
||||
"../../../../build/integration/features/bootstrap/WebDav.php"
|
||||
],
|
||||
"psr-0": {
|
||||
"": [
|
||||
"features/bootstrap/"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
12
tests/integration/config/behat.yml
Normal file
12
tests/integration/config/behat.yml
Normal file
@@ -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
|
||||
36
tests/integration/features/acl.feature
Normal file
36
tests/integration/features/acl.feature
Normal file
@@ -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"
|
||||
189
tests/integration/features/bootstrap/FeatureContext.php
Normal file
189
tests/integration/features/bootstrap/FeatureContext.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use GuzzleHttp\Client;
|
||||
use Behat\Behat\Tester\Exception\PendingException;
|
||||
use Behat\Gherkin\Node\PyStringNode;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
class FeatureContext implements Context {
|
||||
|
||||
use WebDav;
|
||||
|
||||
/** @var string */
|
||||
private $mappedUserId;
|
||||
|
||||
private $lastInsertIds = array();
|
||||
|
||||
/**
|
||||
* @When :user requests the deck list
|
||||
*/
|
||||
/**
|
||||
* @When Sending a :method to :url with JSON
|
||||
*/
|
||||
public function sendingAToWithJSON($method, $url, \Behat\Gherkin\Node\PyStringNode $data) {
|
||||
$baseUrl = substr($this->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, []);
|
||||
}
|
||||
|
||||
}
|
||||
37
tests/integration/features/decks.feature
Normal file
37
tests/integration/features/decks.feature
Normal file
@@ -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|
|
||||
44
tests/integration/run.sh
Executable file
44
tests/integration/run.sh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
OC_PATH=../../../../
|
||||
OCC=${OC_PATH}occ
|
||||
SCENARIO_TO_RUN=$1
|
||||
HIDE_OC_LOGS=$2
|
||||
|
||||
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
|
||||
|
||||
if [ -z $HIDE_OC_LOGS ]; then
|
||||
tail "${OC_PATH}/data/nextcloud.log"
|
||||
fi
|
||||
|
||||
echo "runsh: Exit code: $RESULT"
|
||||
exit $RESULT
|
||||
@@ -1,7 +1,7 @@
|
||||
<phpunit bootstrap="bootstrap.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="integration">
|
||||
<directory>./integration</directory>
|
||||
<testsuite name="integration-database">
|
||||
<directory>./integration/database</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
|
||||
Reference in New Issue
Block a user