Merge pull request #126 from nextcloud/saucelabs-tests

saucelabs tests
This commit is contained in:
Christoph Wurst 2017-03-06 10:42:21 +01:00 коммит произвёл GitHub
Родитель f0ac1ac79b 4045525705
Коммит 81b8ba0765
10 изменённых файлов: 297 добавлений и 11 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -5,3 +5,5 @@ vendor/
# Ignore NetBeans project
/nbproject/
tests/clover.xml

Просмотреть файл

@ -11,12 +11,17 @@ addons:
- mysql-server-5.6
- mysql-client-core-5.6
- mysql-client-5.6
sauce_connect:
username: "nextcloud-totp"
jwt:
secure: dUvqHso+T2Gkb4Nlg4feP3s1wnFy9XWwYakckpcl24HLd7yN/zMU3/qWfAZ0NzKOvQvILdBtjjj9Bdo4jJXzfnbRPwcWE7i2E9TvHMJYYOCEymUG0IZyKNZSyxlt4FlgTXYLUTyPLeEQwb4F01Uy3kbERowfT6LtPPeReLpKcE4R3Sbz4AI4p3ugWoI9E/+zHzUHAdWJTrlwLiIVx2/9eQ+fy5BJXeFPzNeNuDhzzC0ceXkv6bKAn5Fuh+QzPCf8AURezZQ04cWoSsIymSwAlzRDBZsUqib/aOyHgkwCQFsUuRuCaZwz2DhG+PwXe0FZD/EuRYE+huVL9jV6Q7mkaclOU3UyOlsIKogLLY9HhekMStOpH2rXP0+xYmogWT1eRqsvXcODD1/3ujPWsQOR78j5KlrIEHeqfKJ9TC3gBNLPTTHIjqmadTRBsuxuWkcoZAMthaQF/j2lBk0al5rk5h9sb53MQVUy3mzDL0ou9lFRJv4hEYQoyIS9tfe6CSyHbTtQAPkeMqSZ3fKI6Jl4AP4MtN1ITOyHsY2psmsdOzDj7qlC6/+A7ApyPsshRQ0vpr9YTZhMmNZFLS6Vr7y+mdGFlkH90LK4RPEUWkn1ROaaS2BeBPGoYqNJq16wT3I2ijN3uvA8/G+4Y2F9aezYIdgUW0WG3vvtP7SW57m80Do=
services:
- postgresql
env:
global:
- CORE_BRANCH=master
- PHP_COVERAGE=FALSE
- SAUCE=FALSE
matrix:
- DB=sqlite
branches:
@ -51,17 +56,28 @@ before_script:
# Set up core
- php -f core/occ maintenance:install --database-name nc_autotest --database-user nc_autotest --admin-user admin --admin-pass admin --database $DB --database-pass=''
# Enable debug mode to get more info in case a test fails
- php -f core/occ config:system:set debug --value=true --type boolean
# Set up app
- php -f core/occ app:enable twofactor_totp
- cd core/apps/twofactor_totp
# Start php server for acceptance tests
- php -S 0.0.0.0:8080 -t ../.. > webserver.log 2>&1 &
script:
- find . -name \*.php -not -path './vendor/*' -exec php -l "{}" \;
- if [[ "$SAUCE" = "FALSE" ]]; then find . -name \*.php -not -path './vendor/*' -exec php -l "{}" \;; fi
- cd tests
- phpunit --configuration phpunit.xml
- if [[ "$SAUCE" = "FALSE" ]]; then phpunit --group default --configuration phpunit.xml; fi
- if [[ "$SAUCE" = "TRUE" ]]; then phpunit --group Acceptance --no-coverage --configuration phpunit.xml; fi
- if [[ "$PHP_COVERAGE" = "TRUE" ]]; then wget https://scrutinizer-ci.com/ocular.phar; fi
- if [[ "$PHP_COVERAGE" = "TRUE" ]]; then php ocular.phar code-coverage:upload --format=php-clover clover.xml; fi
after_script:
- cd ..
- cat webserver.log
matrix:
include:
- php: 7
@ -70,5 +86,9 @@ matrix:
env: "DB=pgsql PHP_COVERAGE=TRUE"
- php: 7
env: "DB=mysql"
- php: 7.1
env: "DB=mysql SAUCE=TRUE SELENIUM_BROWSER=firefox"
- php: 7.1
env: "DB=mysql SAUCE=TRUE SELENIUM_BROWSER=chrome"
fast_finish: true

Просмотреть файл

@ -5,5 +5,8 @@
},
"platform": {
"php": ">=5.6.0"
},
"require-dev": {
"facebook/webdriver": "^1.3"
}
}

112
composer.lock сгенерированный
Просмотреть файл

@ -4,8 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "56e515ddb1d2e85e3b723819b9bab28e",
"content-hash": "a5cf309909d0bb78424ce70f0fb83e8d",
"content-hash": "00ae934f22af3ba602fd75a3d4cbbc75",
"packages": [
{
"name": "christian-riesen/base32",
@ -59,7 +58,7 @@
"encode",
"rfc4648"
],
"time": "2016-05-05 11:49:03"
"time": "2016-05-05T11:49:03+00:00"
},
{
"name": "christian-riesen/otp",
@ -110,7 +109,7 @@
"rfc6238",
"totp"
],
"time": "2015-10-08 08:17:59"
"time": "2015-10-08T08:17:59+00:00"
},
{
"name": "endroid/qrcode",
@ -161,7 +160,7 @@
"qr",
"qrcode"
],
"time": "2016-07-26 09:39:07"
"time": "2016-07-26T09:39:07+00:00"
},
{
"name": "symfony/options-resolver",
@ -215,10 +214,109 @@
"configuration",
"options"
],
"time": "2016-05-12 15:59:27"
"time": "2016-05-12T15:59:27+00:00"
}
],
"packages-dev": [
{
"name": "facebook/webdriver",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/facebook/php-webdriver.git",
"reference": "77300c4ab2025d4316635f592ec849ca7323bd8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/facebook/php-webdriver/zipball/77300c4ab2025d4316635f592ec849ca7323bd8c",
"reference": "77300c4ab2025d4316635f592ec849ca7323bd8c",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": "^5.5 || ~7.0",
"symfony/process": "^2.8 || ^3.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^1.11",
"php-mock/php-mock-phpunit": "^1.1",
"phpunit/phpunit": "4.6.* || ~5.0",
"satooshi/php-coveralls": "^1.0",
"squizlabs/php_codesniffer": "^2.6"
},
"suggest": {
"phpdocumentor/phpdocumentor": "2.*"
},
"type": "library",
"autoload": {
"psr-4": {
"Facebook\\WebDriver\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"description": "A PHP client for WebDriver",
"homepage": "https://github.com/facebook/php-webdriver",
"keywords": [
"facebook",
"php",
"selenium",
"webdriver"
],
"time": "2017-01-13T15:48:08+00:00"
},
{
"name": "symfony/process",
"version": "v3.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "350e810019fc52dd06ae844b6a6d382f8a0e8893"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/350e810019fc52dd06ae844b6a6d382f8a0e8893",
"reference": "350e810019fc52dd06ae844b6a6d382f8a0e8893",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2017-01-02T20:32:22+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],

Просмотреть файл

@ -26,12 +26,12 @@ use Base32\Base32;
use OCA\TwoFactorTOTP\Db\TotpSecret;
use OCA\TwoFactorTOTP\Db\TotpSecretMapper;
use OCA\TwoFactorTOTP\Exception\NoTotpSecretFoundException;
use OCP\Activity\IManager as ActivityManager;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\IUser;
use OCP\Security\ICrypto;
use Otp\GoogleAuthenticator;
use Otp\Otp;
use OCP\Activity\IManager as ActivityManager;
class Totp implements ITotp {

Просмотреть файл

@ -0,0 +1,160 @@
<?php
/**
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @copyright Copyright (c) 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* Two-factor TOTP
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\TwoFactorTOTP\Tests\Acceptance;
use Facebook\WebDriver\Exception\ElementNotSelectableException;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\WebDriverBrowserType;
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
use Facebook\WebDriver\WebDriver;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverExpectedCondition;
use OC;
use OCA\TwoFactorTOTP\Db\TotpSecret;
use OCA\TwoFactorTOTP\Db\TotpSecretMapper;
use OCP\IUser;
use Otp\GoogleAuthenticator;
use PHPUnit_Framework_TestCase;
/**
* @group Acceptance
*/
class TOTPAcceptenceTest extends PHPUnit_Framework_TestCase {
/** @var IUser */
private static $user;
/** @var TotpSecretMapper */
private static $secretMapper;
/** @var RemoteWebDriver */
protected $webDriver;
public static function setUpBeforeClass() {
parent::setUpBeforeClass();
self::$user = OC::$server->getUserManager()->get('admin');
self::$secretMapper = new TotpSecretMapper(OC::$server->getDatabaseConnection());
}
public function setUp() {
$capabilities = [
WebDriverCapabilityType::BROWSER_NAME => $this->getBrowser(),
];
if ($this->isRunningOnCI()) {
$capabilities['tunnel-identifier'] = getenv('TRAVIS_JOB_NUMBER');
$capabilities['build'] = getenv('TRAVIS_BUILD_NUMBER');
$capabilities['name'] = 'PR' . getenv('TRAVIS_PULL_REQUEST') . ', Build ' . getenv('TRAVIS_BUILD_NUMBER');
$user = 'nextcloud-totp';
$accessKey = getenv('SAUCE_ACCESS_KEY');
$this->webDriver = RemoteWebDriver::create("http://$user:$accessKey@ondemand.saucelabs.com/wd/hub", $capabilities);
} else {
$this->webDriver = RemoteWebDriver::create("http://localhost:4444/wd/hub", $capabilities);
}
}
private function getBrowser() {
$env = getenv('SELENIUM_BROWSER');
if ($env !== false) {
return $env;
}
return WebDriverBrowserType::FIREFOX;
}
private function isRunningOnCI() {
return getenv('TRAVIS') !== false;
}
public function tearDown() {
// Always delete secret again
$secret = self::$secretMapper->getSecret(self::$user);
if (!is_null($secret)) {
self::$secretMapper->delete($secret);
}
$this->webDriver->quit();
}
public function testEnableTOTP() {
$this->webDriver->get('http://localhost:8080/index.php/login');
$this->assertContains('Nextcloud', $this->webDriver->getTitle());
// Log in
$this->webDriver->findElement(WebDriverBy::id('user'))->sendKeys('admin');
$this->webDriver->findElement(WebDriverBy::id('password'))->sendKeys('admin');
$this->webDriver->findElement(WebDriverBy::cssSelector('form[name=login] input[type=submit]'))->click();
// Go to personal settings
$this->webDriver->wait(20, 1000)->until(WebDriverExpectedCondition::elementToBeClickable(WebDriverBy::id('expandDisplayName')));
$this->webDriver->findElement(WebDriverBy::id('expandDisplayName'))->click();
$this->webDriver->findElement(WebDriverBy::linkText('Personal'))->click();
// Go to TOTP settings
$this->webDriver->wait(20, 1000)->until(WebDriverExpectedCondition::elementToBeClickable(WebDriverBy::linkText('TOTP second-factor auth')));
$this->webDriver->findElement(WebDriverBy::linkText('TOTP second-factor auth'))->click();
// Enable TOTP
usleep(15 * 1000 * 1000); // Hard-coded sleep because the scripts need some time load the page
$this->webDriver->wait(20, 1000)->until(function(WebDriver $driver) {
try {
return count($driver->findElements(WebDriverBy::id('totp-enabled'))) > 0;
} catch (ElementNotSelectableException $ex) {
return false;
}
return true;
});
$this->webDriver->executeScript('arguments[0].click(); console.log(arguments[0]);', [
$this->webDriver->findElement(WebDriverBy::id('totp-enabled')),
]);
$this->webDriver->wait(20, 1000)->until(WebDriverExpectedCondition::elementTextContains(WebDriverBy::id('twofactor-totp-settings'), 'This is your new TOTP secret:'));
}
private function createSecret() {
$secret = GoogleAuthenticator::generateRandom();
$dbsecret = new TotpSecret();
$dbsecret->setSecret(OC::$server->getCrypto()->encrypt($secret));
$dbsecret->setUserId(self::$user->getUID());
self::$secretMapper->insert($dbsecret);
return $secret;
}
public function testLoginShouldFailWithWrongOTP() {
$this->createSecret();
$this->webDriver->get('http://localhost:8080/index.php/login');
$this->assertContains('Nextcloud', $this->webDriver->getTitle());
// Log in
$this->webDriver->findElement(WebDriverBy::id('user'))->sendKeys('admin');
$this->webDriver->findElement(WebDriverBy::id('password'))->sendKeys('admin');
$this->webDriver->findElement(WebDriverBy::cssSelector('form[name=login] input[type=submit]'))->click();
// Enter a wrong OTP
$this->webDriver->findElement(WebDriverBy::name('challenge'))->sendKeys('000');
$this->webDriver->findElement(WebDriverBy::cssSelector('input.confirm-inline.icon-confirm'))->click();
$this->assertEquals('http://localhost:8080/index.php/login/challenge/totp', $this->webDriver->getCurrentURL());
}
}

Просмотреть файл

@ -19,4 +19,7 @@
*
*/
require_once __DIR__ . '/../../../tests/bootstrap.php';
require_once __DIR__ . '/../../../tests/bootstrap.php';
\OC_App::loadApp('twofactor_totp');