Add functional API tests
This commit is contained in:
parent
f90bb969cc
commit
56d21dc726
18
.travis.yml
18
.travis.yml
@ -2,7 +2,7 @@ git:
|
||||
depth: 3
|
||||
|
||||
language: php
|
||||
sudo: false
|
||||
sudo: required
|
||||
|
||||
php:
|
||||
- 7.0
|
||||
@ -10,11 +10,23 @@ php:
|
||||
- 5.5
|
||||
- 5.4
|
||||
- 5.3
|
||||
- hhvm
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y apache2 libapache2-mod-fastcgi
|
||||
|
||||
install:
|
||||
- composer install
|
||||
|
||||
before_script:
|
||||
- composer install
|
||||
- ./tests/ci/install.sh
|
||||
|
||||
script:
|
||||
- ./vendor/bin/phpunit -c tests/phpunit.unit.sqlite.xml
|
||||
- ./vendor/bin/phpunit -c tests/phpunit.unit.postgres.xml
|
||||
- ./vendor/bin/phpunit -c tests/phpunit.functional.sqlite.xml
|
||||
- cp ./tests/ci/config.postgres.php $TRAVIS_BUILD_DIR/config.php && ./vendor/bin/phpunit -c tests/phpunit.functional.postgres.xml
|
||||
|
||||
after_failure:
|
||||
- cat apache_error.log
|
||||
- cat apache_access.log
|
||||
|
@ -16,6 +16,7 @@ Version 1.2.0 (unreleased)
|
||||
* Add support for Expires and Cache-Control headers (HTTP cache)
|
||||
* Update Docker image to Ubuntu 16.04 and PHP 7.0
|
||||
* Add Docker compose file
|
||||
* Add functional tests (Json-RPC API)
|
||||
* Add unit tests
|
||||
|
||||
Migration procedure from 1.1.x to 1.2.0:
|
||||
|
4
Makefile
4
Makefile
@ -41,6 +41,10 @@ $(JS_FILE): assets/js/app.js \
|
||||
archive:
|
||||
@ git archive --format=zip --prefix=miniflux/ v${version} -o ${dst}/miniflux-${version}.zip
|
||||
|
||||
functional-test-sqlite:
|
||||
@ rm -f data/db.sqlite
|
||||
@ ./vendor/bin/phpunit -c tests/phpunit.functional.sqlite.xml
|
||||
|
||||
unit-test-sqlite:
|
||||
@ ./vendor/bin/phpunit -c tests/phpunit.unit.sqlite.xml
|
||||
|
||||
|
@ -84,7 +84,7 @@ function create_feed($user_id, $url, $download_content = false, $rtl = false, $c
|
||||
} else {
|
||||
fetch_favicon($feed_id, $feed->getSiteUrl(), $feed->getIcon());
|
||||
|
||||
if (! empty($feed_group_ids)) {
|
||||
if (! empty($feed_group_ids) || ! empty($group_name)) {
|
||||
Model\Group\update_feed_groups($user_id, $feed_id, $feed_group_ids, $group_name);
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ function get_favicons_with_data_url($user_id)
|
||||
->findAll();
|
||||
|
||||
foreach ($favicons as &$favicon) {
|
||||
$favicon['url'] = get_favicon_data_url($favicon['hash'], $favicon['type']);
|
||||
$favicon['data_url'] = get_favicon_data_url($favicon['hash'], $favicon['type']);
|
||||
}
|
||||
|
||||
return $favicons;
|
||||
|
60
jsonrpc.php
60
jsonrpc.php
@ -2,12 +2,14 @@
|
||||
|
||||
require __DIR__.'/app/common.php';
|
||||
|
||||
use JsonRPC\Exception\AccessDeniedException;
|
||||
use JsonRPC\Exception\AuthenticationFailureException;
|
||||
use JsonRPC\MiddlewareInterface;
|
||||
use JsonRPC\Server;
|
||||
use Miniflux\Handler;
|
||||
use Miniflux\Model;
|
||||
use Miniflux\Session\SessionStorage;
|
||||
use Miniflux\Validator;
|
||||
|
||||
class AuthMiddleware implements MiddlewareInterface
|
||||
{
|
||||
@ -28,7 +30,37 @@ $procedureHandler = $server->getProcedureHandler();
|
||||
|
||||
// Get version
|
||||
$procedureHandler->withCallback('getVersion', function () {
|
||||
return array('version' => APP_VERSION);
|
||||
return APP_VERSION;
|
||||
});
|
||||
|
||||
// Create user
|
||||
$procedureHandler->withCallback('createUser', function ($username, $password, $is_admin = false) {
|
||||
if (! SessionStorage::getInstance()->isAdmin()) {
|
||||
throw new AccessDeniedException('Reserved to administrators');
|
||||
}
|
||||
|
||||
$values = array(
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
'confirmation' => $password,
|
||||
);
|
||||
|
||||
list($valid) = Validator\User\validate_creation($values);
|
||||
|
||||
if ($valid) {
|
||||
return Model\User\create_user($username, $password, $is_admin);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// Get user
|
||||
$procedureHandler->withCallback('getUserByUsername', function ($username) {
|
||||
if (! SessionStorage::getInstance()->isAdmin()) {
|
||||
throw new AccessDeniedException('Reserved to administrators');
|
||||
}
|
||||
|
||||
return Model\User\get_user_by_username($username);
|
||||
});
|
||||
|
||||
// Get all feeds
|
||||
@ -46,13 +78,27 @@ $procedureHandler->withCallback('getFeeds', function () {
|
||||
// Get one feed
|
||||
$procedureHandler->withCallback('getFeed', function ($feed_id) {
|
||||
$user_id = SessionStorage::getInstance()->getUserId();
|
||||
return Model\Feed\get_feed($user_id, $feed_id);
|
||||
$feed = Model\Feed\get_feed($user_id, $feed_id);
|
||||
|
||||
if (! empty($feed)) {
|
||||
$feed['groups'] = Model\Group\get_feed_groups($feed['id']);
|
||||
}
|
||||
|
||||
return $feed;
|
||||
});
|
||||
|
||||
// Add a new feed
|
||||
$procedureHandler->withCallback('createFeed', function ($url) {
|
||||
$procedureHandler->withCallback('createFeed', function ($url, $download_content = false, $rtl = false, $group_name = null) {
|
||||
$user_id = SessionStorage::getInstance()->getUserId();
|
||||
list($feed_id,) = Handler\Feed\create_feed($user_id, $url);
|
||||
list($feed_id,) = Handler\Feed\create_feed(
|
||||
$user_id,
|
||||
$url,
|
||||
$download_content,
|
||||
$rtl,
|
||||
false,
|
||||
array(),
|
||||
$group_name
|
||||
);
|
||||
|
||||
if ($feed_id > 0) {
|
||||
return $feed_id;
|
||||
@ -62,7 +108,7 @@ $procedureHandler->withCallback('createFeed', function ($url) {
|
||||
});
|
||||
|
||||
// Delete a feed
|
||||
$procedureHandler->withCallback('deleteFeed', function ($feed_id) {
|
||||
$procedureHandler->withCallback('removeFeed', function ($feed_id) {
|
||||
$user_id = SessionStorage::getInstance()->getUserId();
|
||||
return Model\Feed\remove_feed($user_id, $feed_id);
|
||||
});
|
||||
@ -74,9 +120,9 @@ $procedureHandler->withCallback('refreshFeed', function ($feed_id) {
|
||||
});
|
||||
|
||||
// Get all items
|
||||
$procedureHandler->withCallback('getItems', function ($since_id = null, array $item_ids = array(), $offset = 50) {
|
||||
$procedureHandler->withCallback('getItems', function ($since_id = null, array $item_ids = array(), $limit = 50) {
|
||||
$user_id = SessionStorage::getInstance()->getUserId();
|
||||
return Model\Item\get_items($user_id, $since_id, $item_ids, $offset);
|
||||
return Model\Item\get_items($user_id, $since_id, $item_ids, $limit);
|
||||
});
|
||||
|
||||
// Get one item
|
||||
|
19
tests/ci/apache_vhost.conf
Normal file
19
tests/ci/apache_vhost.conf
Normal file
@ -0,0 +1,19 @@
|
||||
<VirtualHost *:80>
|
||||
DocumentRoot %TRAVIS_BUILD_DIR%
|
||||
ErrorLog "%TRAVIS_BUILD_DIR%/apache_error.log"
|
||||
CustomLog "%TRAVIS_BUILD_DIR%/apache_access.log" combined
|
||||
|
||||
<Directory "%TRAVIS_BUILD_DIR%">
|
||||
Options FollowSymLinks MultiViews ExecCGI
|
||||
AllowOverride All
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
<IfModule mod_fastcgi.c>
|
||||
AddHandler php5-fcgi .php
|
||||
Action php5-fcgi /php5-fcgi
|
||||
Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi
|
||||
FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -host 127.0.0.1:9000 -pass-header Authorization
|
||||
</IfModule>
|
||||
</VirtualHost>
|
7
tests/ci/config.postgres.php
Normal file
7
tests/ci/config.postgres.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
define('DB_DRIVER', 'postgres');
|
||||
define('DB_HOSTNAME', 'localhost');
|
||||
define('DB_NAME', 'miniflux_functional_test');
|
||||
define('DB_USERNAME', 'postgres');
|
||||
define('DB_PASSWORD', '');
|
18
tests/ci/install.sh
Executable file
18
tests/ci/install.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf
|
||||
|
||||
if [ "$TRAVIS_PHP_VERSION" = "7.0" -a -n "$(ls -A ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d)" ]; then
|
||||
sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d/www.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d/www.conf
|
||||
fi
|
||||
|
||||
echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
echo "always_populate_raw_post_data = -1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
|
||||
~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm
|
||||
|
||||
sudo a2enmod rewrite actions fastcgi alias ssl
|
||||
|
||||
sudo cp -f tests/ci/apache_vhost.conf /etc/apache2/sites-available/default
|
||||
sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/default
|
||||
sudo service apache2 restart
|
207
tests/functional/ApiTest.php
Normal file
207
tests/functional/ApiTest.php
Normal file
@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
use JsonRPC\Client;
|
||||
|
||||
require_once __DIR__.'/BaseApiTest.php';
|
||||
|
||||
class ApiTest extends BaseApiTest
|
||||
{
|
||||
public function testGetVersion()
|
||||
{
|
||||
$this->assertEquals('master', $this->getApiClient()->getVersion());
|
||||
}
|
||||
|
||||
public function testCreateUser()
|
||||
{
|
||||
$this->assertFalse($this->getApiClient()->createUser('admin', 'test123'));
|
||||
$this->assertNotFalse($this->getApiClient()->createUser(array(
|
||||
'username' => 'api_test',
|
||||
'password' => 'test123',
|
||||
)));
|
||||
}
|
||||
|
||||
public function testGetUser()
|
||||
{
|
||||
$this->assertNull($this->getApiClient()->getUserByUsername('notfound'));
|
||||
|
||||
$user = $this->getApiClient()->getUserByUsername('api_test');
|
||||
$this->assertEquals('api_test', $user['username']);
|
||||
$this->assertFalse((bool) $user['is_admin']);
|
||||
$this->assertArrayHasKey('password', $user);
|
||||
$this->assertArrayHasKey('api_token', $user);
|
||||
}
|
||||
|
||||
public function testCreateUserAsNonAdmin()
|
||||
{
|
||||
$user = $this->getApiClient()->getUserByUsername('api_test');
|
||||
|
||||
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
|
||||
$this->getApiClient($user)->createUser('someone', 'secret');
|
||||
}
|
||||
|
||||
public function testGetUserAsNonAdmin()
|
||||
{
|
||||
$user = $this->getApiClient()->getUserByUsername('api_test');
|
||||
|
||||
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
|
||||
$this->getApiClient($user)->getUserByUsername('admin');
|
||||
}
|
||||
|
||||
public function testCreateFeed()
|
||||
{
|
||||
$this->assertNotFalse($this->getApiClient()->createFeed(array(
|
||||
'url' => 'https://miniflux.net/feed',
|
||||
'group_name' => 'open source software',
|
||||
)));
|
||||
}
|
||||
|
||||
public function testGetAllFeeds()
|
||||
{
|
||||
$feeds = $this->getApiClient()->getFeeds();
|
||||
$this->assertCount(1, $feeds);
|
||||
$this->assertEquals(1, $feeds[0]['id']);
|
||||
$this->assertEquals('https://miniflux.net/feed', $feeds[0]['feed_url']);
|
||||
$this->assertTrue((bool) $feeds[0]['enabled']);
|
||||
$this->assertEquals('open source software', $feeds[0]['groups'][0]['title']);
|
||||
}
|
||||
|
||||
public function testGetFeed()
|
||||
{
|
||||
$this->assertNull($this->getApiClient()->getFeed(999));
|
||||
|
||||
$feed = $this->getApiClient()->getFeed(1);
|
||||
$this->assertEquals('https://miniflux.net/feed', $feed['feed_url']);
|
||||
$this->assertTrue((bool) $feed['enabled']);
|
||||
$this->assertEquals('open source software', $feed['groups'][0]['title']);
|
||||
}
|
||||
|
||||
public function testRefreshFeed()
|
||||
{
|
||||
$this->assertTrue($this->getApiClient()->refreshFeed(1));
|
||||
}
|
||||
|
||||
public function testGetItems()
|
||||
{
|
||||
$items = $this->getApiClient()->getItems();
|
||||
$this->assertNotEmpty($items);
|
||||
$this->assertEquals(1, $items[0]['id']);
|
||||
$this->assertEquals(1, $items[0]['feed_id']);
|
||||
$this->assertNotEmpty($items[0]['title']);
|
||||
$this->assertNotEmpty($items[0]['author']);
|
||||
$this->assertNotEmpty($items[0]['content']);
|
||||
$this->assertNotEmpty($items[0]['url']);
|
||||
}
|
||||
|
||||
public function testGetItemsSinceId()
|
||||
{
|
||||
$items = $this->getApiClient()->getItems(array('since_id' => 2));
|
||||
$this->assertNotEmpty($items);
|
||||
$this->assertEquals(3, $items[0]['id']);
|
||||
}
|
||||
|
||||
public function testGetSpecificItems()
|
||||
{
|
||||
$items = $this->getApiClient()->getItems(array('item_ids' => array(2, 3)));
|
||||
$this->assertNotEmpty($items);
|
||||
$this->assertEquals(2, $items[0]['id']);
|
||||
$this->assertEquals(3, $items[1]['id']);
|
||||
}
|
||||
|
||||
public function testGetItem()
|
||||
{
|
||||
$this->assertNull($this->getApiClient()->getItem(999));
|
||||
|
||||
$item = $this->getApiClient()->getItem(1);
|
||||
$this->assertNotEmpty($item);
|
||||
$this->assertEquals(1, $item['id']);
|
||||
$this->assertEquals(1, $item['feed_id']);
|
||||
$this->assertEquals('unread', $item['status']);
|
||||
$this->assertNotEmpty($item['title']);
|
||||
$this->assertNotEmpty($item['author']);
|
||||
$this->assertNotEmpty($item['content']);
|
||||
$this->assertNotEmpty($item['url']);
|
||||
}
|
||||
|
||||
public function testChangeItemsStatus()
|
||||
{
|
||||
$this->assertTrue($this->getApiClient()->changeItemsStatus(array(1), 'read'));
|
||||
|
||||
$item = $this->getApiClient()->getItem(1);
|
||||
$this->assertEquals('read', $item['status']);
|
||||
|
||||
$item = $this->getApiClient()->getItem(2);
|
||||
$this->assertEquals('unread', $item['status']);
|
||||
}
|
||||
|
||||
public function testAddBookmark()
|
||||
{
|
||||
$this->assertTrue($this->getApiClient()->addBookmark(1));
|
||||
|
||||
$item = $this->getApiClient()->getItem(1);
|
||||
$this->assertTrue((bool) $item['bookmark']);
|
||||
}
|
||||
|
||||
public function testRemoveBookmark()
|
||||
{
|
||||
$this->assertTrue($this->getApiClient()->removeBookmark(1));
|
||||
|
||||
$item = $this->getApiClient()->getItem(1);
|
||||
$this->assertFalse((bool) $item['bookmark']);
|
||||
}
|
||||
|
||||
public function testGetGroups()
|
||||
{
|
||||
$groups = $this->getApiClient()->getGroups();
|
||||
$this->assertCount(1, $groups);
|
||||
|
||||
$this->assertEquals(1, $groups[0]['id']);
|
||||
$this->assertEquals(1, $groups[0]['user_id']);
|
||||
$this->assertEquals('open source software', $groups[0]['title']);
|
||||
}
|
||||
|
||||
public function testCreateGroup()
|
||||
{
|
||||
$this->assertEquals(2, $this->getApiClient()->createGroup('foobar'));
|
||||
$this->assertEquals(2, $this->getApiClient()->createGroup('foobar'));
|
||||
|
||||
$groups = $this->getApiClient()->getGroups();
|
||||
$this->assertCount(2, $groups);
|
||||
}
|
||||
|
||||
public function testSetFeedGroups()
|
||||
{
|
||||
$this->assertTrue($this->getApiClient()->setFeedGroups(1, array(2)));
|
||||
|
||||
$feed = $this->getApiClient()->getFeed(1);
|
||||
$this->assertCount(1, $feed['groups']);
|
||||
$this->assertEquals('foobar', $feed['groups'][0]['title']);
|
||||
}
|
||||
|
||||
public function testGetFavicons()
|
||||
{
|
||||
$favicons = $this->getApiClient()->getFavicons();
|
||||
|
||||
$this->assertCount(1, $favicons);
|
||||
$this->assertEquals(1, $favicons[0]['feed_id']);
|
||||
$this->assertNotEmpty($favicons[0]['hash']);
|
||||
$this->assertNotEmpty($favicons[0]['type']);
|
||||
$this->assertNotEmpty($favicons[0]['data_url']);
|
||||
}
|
||||
|
||||
public function testDeleteFeed()
|
||||
{
|
||||
$this->assertTrue($this->getApiClient()->removeFeed(1));
|
||||
}
|
||||
|
||||
protected function getApiClient(array $user = array())
|
||||
{
|
||||
if (empty($user)) {
|
||||
$user = $this->adminUser;
|
||||
}
|
||||
|
||||
$apiUserClient = new Client(API_URL);
|
||||
$apiUserClient->authentication($user['username'], $user['api_token']);
|
||||
|
||||
return $apiUserClient;
|
||||
}
|
||||
}
|
19
tests/functional/BaseApiTest.php
Normal file
19
tests/functional/BaseApiTest.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/../../app/common.php';
|
||||
|
||||
abstract class BaseApiTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $adminUser = array();
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (DB_DRIVER === 'postgres') {
|
||||
$pdo = new PDO('pgsql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD);
|
||||
$pdo->exec('CREATE DATABASE '.DB_NAME.' WITH OWNER '.DB_USERNAME);
|
||||
}
|
||||
|
||||
$db = Miniflux\Database\get_connection();
|
||||
$this->adminUser = $db->table(Miniflux\Model\User\TABLE)->eq('username', 'admin')->findOne();
|
||||
}
|
||||
}
|
10
tests/phpunit.functional.postgres.xml
Normal file
10
tests/phpunit.functional.postgres.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<phpunit stopOnError="true" stopOnFailure="true" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="Miniflux Postgres Functional Tests">
|
||||
<directory>functional</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<const name="API_URL" value="http://127.0.0.1/jsonrpc.php" />
|
||||
</php>
|
||||
</phpunit>
|
11
tests/phpunit.functional.sqlite.xml
Normal file
11
tests/phpunit.functional.sqlite.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<phpunit stopOnError="true" stopOnFailure="true" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="Miniflux Sqlite Functional Tests">
|
||||
<directory>functional</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<const name="API_URL" value="http://127.0.0.1/jsonrpc.php" />
|
||||
<const name="DB_FILENAME" value="data/db.sqlite" />
|
||||
</php>
|
||||
</phpunit>
|
@ -131,12 +131,12 @@ class FaviconModelTest extends BaseTest
|
||||
$this->assertEquals(1, $favicons[0]['feed_id']);
|
||||
$this->assertEquals('57978a20204f7af6967571041c79d907a8a8072c', $favicons[0]['hash']);
|
||||
$this->assertEquals('image/png', $favicons[0]['type']);
|
||||
$this->assertEquals('data:image/png;base64,YmluYXJ5IGRhdGE=', $favicons[0]['url']);
|
||||
$this->assertEquals('data:image/png;base64,YmluYXJ5IGRhdGE=', $favicons[0]['data_url']);
|
||||
|
||||
$this->assertEquals(2, $favicons[1]['feed_id']);
|
||||
$this->assertEquals('36242b50974c41478569d66616346ee5f2ad7b6e', $favicons[1]['hash']);
|
||||
$this->assertEquals('image/gif', $favicons[1]['type']);
|
||||
$this->assertEquals('data:image/gif;base64,c29tZSBiaW5hcnkgZGF0YQ==', $favicons[1]['url']);
|
||||
$this->assertEquals('data:image/gif;base64,c29tZSBiaW5hcnkgZGF0YQ==', $favicons[1]['data_url']);
|
||||
}
|
||||
|
||||
public function testGetItemsFavicons()
|
||||
|
Loading…
Reference in New Issue
Block a user