Add basic behat test structure

Signed-off-by: Julius Haertl <jus@bitgrid.net>
This commit is contained in:
Julius Haertl
2017-03-04 12:22:12 +01:00
committed by Julius Härtl
parent 11610f306a
commit 084d892ce6
7 changed files with 343 additions and 2 deletions

View 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/"
]
}
}
}

View 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

View 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"

View 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, []);
}
}

View 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
View 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

View File

@@ -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>