Merge pull request #316 from monarc-project/feature/stats

Statistics feature
feature/internationalization
Ruslan Baidan 2020-11-18 08:53:23 +01:00 committed by GitHub
commit 961105c7d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 11254 additions and 412 deletions

2
.gitignore vendored
View File

@ -5,7 +5,9 @@ nbproject
.idea
.project
.settings
*.cache
migrations
!tests/migrations
*.sublime-*
vagrant/.vagrant/
vagrant/*.log

View File

@ -1,6 +1,20 @@
MONARC Changelog
================
## 2.10.1 (2020-11-18) Includes 2 bug-fixes and a new feature of analysis statistics.
### Fix
- Detaching of recommendations doesn't work
([#314](https://github.com/monarc-project/MonarcAppFO/issues/314)).
- Record of processing activities creation from an existing.
([#315](https://github.com/monarc-project/MonarcAppFO/issues/315)).
### New
- Analysis statistics development (Epic)
([#268](https://github.com/monarc-project/MonarcAppFO/issues/268)).
## 2.9.16 (2020-08-14)
### Fix

View File

@ -1 +1 @@
{"major":2, "minor":9, "hotfix":16}
{"major":2, "minor":10, "hotfix":1}

View File

@ -40,9 +40,10 @@
}
],
"require": {
"php": "^7.1",
"php": "^7.2",
"ext-json": "*",
"ext-pdo": "*",
"ext-bcmath": "*",
"monarc/frontoffice": "^2.9.15",
"monarc/core": "^2.9.15",
"laminas/laminas-mvc": "^3.1",
@ -51,10 +52,19 @@
"laminas/laminas-log": "^2.11",
"laminas/laminas-i18n": "^2.9",
"symfony/console": "^5.0",
"laminas/laminas-dependency-plugin": "^1.0"
"laminas/laminas-dependency-plugin": "^2.0",
"ocramius/proxy-manager": "<2.3",
"ocramius/package-versions": "<1.5"
},
"require-dev": {
"roave/security-advisories": "dev-master"
"roave/security-advisories": "dev-master",
"phpunit/phpunit": "^8.3",
"laminas/laminas-test": "^3.4"
},
"autoload-dev": {
"psr-4": {
"MonarcAppFo\\Tests\\": "tests/"
}
},
"config": {
"bin-dir": "bin/"

3330
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,11 @@
* @see https://github.com/zendframework/ZFTool
*/
$env = getenv('APPLICATION_ENV') ?: 'production';
$appConfDir = getenv('APP_CONF_DIR') ?? '';
$appConfDir = getenv('APP_CONF_DIR') ?: null;
$confPaths = ['config/autoload/{,*.}{global,local}.php'];
if ($env !== 'testing') {
$confPaths = ['config/autoload/{,*.}{global,local}.php'];
}
$dataPath = 'data';
if (!empty($appConfDir)) {
$confPaths[] = $appConfDir . '/local.php';

View File

@ -1,6 +1,6 @@
{
"name": "MONARC",
"version": "2.9.16",
"version": "2.10.1",
"description": "Monarc front office application",
"private": true,
"repository": {

36
phpunit.xml Normal file
View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutTodoAnnotatedTests="true"
forceCoversAnnotation="true"
verbose="true">
<testsuites>
<testsuite name="Functional">
<directory suffix="Test.php">tests/Functional</directory>
</testsuite>
<testsuite name="Integration">
<directory suffix="Test.php">tests/Integration</directory>
</testsuite>
<testsuite name="Unit">
<directory suffix="Test.php">tests/Unit</directory>
</testsuite>
</testsuites>
<!--
<logging>
<log type="coverage-html" target="coverage"/>
</logging>
-->
<filter>
<whitelist>
<directory suffix=".php">module/Monarc/Core/src</directory>
<directory suffix=".php">module/Monarc/FrontOffice/src</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,19 @@
#! /usr/bin/env bash
# local use:
#for conf_file_path in /home/vagrant/monarc/config/*/local.php
for conf_file_path in /var/www/*/local.php
do
config_path=$(dirname "$conf_file_path")
export APP_CONF_DIR=$config_path
echo "[$(date)] Collecting stats for client: $config_path."
# local use:
#/home/vagrant/monarc/bin/console monarc:collect-stats >> "$config_path"/collect_stats.log
/var/lib/monarc/fo/bin/console monarc:collect-stats >> "$config_path"/collect_stats.log
echo "[$(date)] Finished."
done

View File

@ -0,0 +1,33 @@
vercomp () {
if [[ $1 == $2 ]]
then
return 1
fi
local IFS=.
local i ver1=($1) ver2=($2)
# fill empty fields in ver1 with zeros
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
do
ver1[i]=0
done
for ((i=0; i<${#ver1[@]}; i++))
do
if [[ -z ${ver2[i]} ]]
then
# fill empty fields in ver2 with zeros
ver2[i]=0
fi
if ((10#${ver1[i]} > 10#${ver2[i]}))
then
return 1
fi
done
return 0
}
php_version_string=`php -v | grep -Eow '^PHP [^ ]+' | grep -Eow '[0-9\.]{1,3}'`
echo Your php version is $php_version_string
if [[ $(vercomp $php_version_string 7.4; echo $?) -eq 1 ]]; then
composer require "ocramius/proxy-manager: ^2.8" --ignore-platform-reqs
fi

View File

@ -47,7 +47,7 @@ cd ../flags/ && find ../../node_modules/ng_client/node_modules/ng-country-flags/
cd ../js/
mkdir -p anr
cd anr && find ../../../node_modules/ng_anr/src -type f -maxdepth 1 -name "*" -exec ln -s {} \; 2>/dev/null
cd anr && find ../../../node_modules/ng_anr/src -type f -name "*" -exec ln -s {} \; 2>/dev/null
cd ..
cd ../views/

View File

@ -6,24 +6,27 @@ NC='\033[0m' # No Color
bypass=0
forceClearCache=0
while getopts "hbc" option
isDevEnv=0
while getopts "hbcd" option
do
case $option in
h)
echo -e "Update or install all Monarc modules, frontend views and migrate database."
echo -e "\t-b\tbypass migrate database"
echo -e "\t-c\tforce clear cache"
echo -e "\t-h\tdisplay this message"
exit 1
;;
b)
bypass=1
echo "Migrate database don't execute !!!"
;;
c)
forceClearCache=1
;;
esac
case $option in
h)
echo -e "Update or install all Monarc modules, frontend views and migrate database."
echo -e "\t-b\tbypass migrate database"
echo -e "\t-c\tforce clear cache"
echo -e "\t-h\tdisplay this message"
exit 1
;;
b)
bypass=1
echo "Migrate database don't execute !!!"
;;
c)
forceClearCache=1
;;
d)
isDevEnv=1
esac
done
pull_if_exists() {
@ -57,7 +60,11 @@ if [[ $? -eq 1 ]]; then
exit 1
fi
composer install -o --no-dev
if [[ $isDevEnv -eq 0 ]]; then
composer ins -o --no-dev
else
composer ins
fi
pathCore="module/Monarc/Core"
pathFO="module/Monarc/FrontOffice"

View File

@ -0,0 +1,35 @@
<?php declare(strict_types=1);
namespace MonarcAppFo\Tests\Functional;
use Laminas\ServiceManager\ServiceManager;
use Laminas\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
abstract class AbstractFunctionalTestCase extends AbstractHttpControllerTestCase
{
protected function setUp(): void
{
$this->setApplicationConfig(require dirname(__DIR__) . '/../config/application.config.php');
parent::setUp();
$this->configureServiceManager($this->getApplicationServiceLocator());
}
protected function tearDown(): void
{
}
public static function setUpBeforeClass(): void
{
shell_exec(getenv('TESTS_DIR') . '/scripts/setup_db.sh');
}
public static function tearDownAfterClass(): void
{
}
protected function configureServiceManager(ServiceManager $serviceManager)
{
}
}

View File

@ -0,0 +1,135 @@
<?php declare(strict_types=1);
namespace MonarcAppFo\Tests\Functional\Controller;
use Laminas\Http\Header\HeaderInterface;
use Laminas\ServiceManager\ServiceManager;
use Monarc\Core\Model\Table\UserTable;
use Monarc\Core\Service\AuthenticationService;
use Monarc\Core\Service\ConnectedUserService;
use Monarc\FrontOffice\Controller\ApiAdminUsersController;
use Monarc\FrontOffice\Model\Entity\User;
use Monarc\FrontOffice\Model\Entity\UserRole;
use MonarcAppFo\Tests\Functional\AbstractFunctionalTestCase;
class ApiAdminUsersControllerTest extends AbstractFunctionalTestCase
{
//protected $traceError = false;
/** @var ConnectedUserService */
private $connectedUserService;
/** @var AuthenticationService */
private $authenticationService;
protected function configureServiceManager(ServiceManager $serviceManager)
{
$serviceManager->setAllowOverride(true);
$this->connectedUserService = $this->createMock(ConnectedUserService::class);
$serviceManager->setService(ConnectedUserService::class, $this->connectedUserService);
$this->authenticationService = $this->createMock(AuthenticationService::class);
$serviceManager->setService(AuthenticationService::class, $this->authenticationService);
$serviceManager->setAllowOverride(false);
}
public function testUserCreationByAdminUser()
{
$user = $this->createMock(User::class);
$user->method('getRoles')->willReturn([UserRole::SUPER_ADMIN_FO]);
$user->method('getId')->willReturn(1);
$this->connectedUserService->method('getConnectedUser')->willReturn($user);
$header = $this->createMock(HeaderInterface::class);
$header->method('getFieldName')->willReturn('token');
$header->method('getFieldValue')->willReturn('token-value');
$this->getRequest()->getHeaders()->addHeader($header);
$this->authenticationService
->expects($this->once())
->method('checkConnect')
->with(['token' => 'token-value'])
->willReturn(true);
$email = 'testlast@gmail.com';
$this->dispatch('/api/users', 'POST', [
'firstname' => 'test',
'lastname' => 'testlast',
'email' => $email,
'role' => [UserRole::USER_FO],
], true);
$this->assertModuleName('Monarc');
$this->assertControllerName(ApiAdminUsersController::class);
$this->assertMatchedRouteName('monarc_api_admin_users');
$this->assertResponseStatusCode(200);
$this->assertEquals('{"status":"ok"}', $this->getResponse()->getContent());
$this->removeTestUser($email);
}
public function testUserCreationFailsWhenEmailIsAlreadyExist()
{
$user = $this->createMock(User::class);
$user->method('getRoles')->willReturn([UserRole::SUPER_ADMIN_FO]);
$user->method('getId')->willReturn(1);
$this->connectedUserService->method('getConnectedUser')->willReturn($user);
$header = $this->createMock(HeaderInterface::class);
$header->method('getFieldName')->willReturn('token');
$header->method('getFieldValue')->willReturn('token-value');
$this->getRequest()->getHeaders()->addHeader($header);
$this->authenticationService
->expects($this->once())
->method('checkConnect')
->with(['token' => 'token-value'])
->willReturn(true);
$email = 'testlast@gmail.com';
$this->createTestUser($email);
$this->dispatch('/api/users', 'POST', [
'firstname' => 'test',
'lastname' => 'testlast',
'email' => $email,
'role' => [UserRole::USER_FO],
], true);
$this->assertModuleName('Monarc');
$this->assertControllerName(ApiAdminUsersController::class);
$this->assertMatchedRouteName('monarc_api_admin_users');
$this->assertResponseStatusCode(400);
$this->assertStringContainsString('This email is already used', $this->getResponse()->getContent());
$this->removeTestUser($email);
}
protected function createTestUser(string $email): User
{
/** @var UserTable $userTable */
$userTable = $this->getApplicationServiceLocator()->get(UserTable::class);
$user = new User([
'email' => $email,
'firstname' => 'firstname',
'lastname' => 'lastname',
'language' => 'fr',
'creator' => 'Test',
'role' => [],
]);
$userTable->saveEntity($user);
return $user;
}
protected function removeTestUser(string $email): void
{
/** @var UserTable $userTable */
$userTable = $this->getApplicationServiceLocator()->get(UserTable::class);
$userTable->deleteEntity($userTable->findByEmail($email));
}
}

View File

@ -0,0 +1,43 @@
<?php declare(strict_types=1);
namespace MonarcAppFo\Tests\Integration;
use Laminas\ServiceManager\ServiceManager;
use Laminas\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
abstract class AbstractIntegrationTestCase extends AbstractHttpControllerTestCase
{
/** @var string */
protected $testPath;
protected function setUp(): void
{
$this->testPath = getenv('TESTS_DIR');
$this->setApplicationConfig(require dirname($this->testPath) . '/config/application.config.php');
parent::setUp();
$this->configureServiceManager($this->getApplicationServiceLocator());
}
public static function setUpBeforeClass(): void
{
// Creates the DB with initial data, executes all the migrations.
shell_exec(getenv('TESTS_DIR') . '/scripts/setup_db.sh');
}
public static function tearDownAfterClass(): void
{
shell_exec(getenv('TESTS_DIR') . '/scripts/clean_client_database.sh');
}
protected static function createMyPrintTestData(): void
{
shell_exec(getenv('TESTS_DIR') . '/scripts/insert_my_print_anrs.sh');
}
protected function configureServiceManager(ServiceManager $serviceManager)
{
}
}

View File

@ -0,0 +1,458 @@
<?php
namespace MonarcAppFo\Tests\Integration\Service;
use DateTime;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\Psr7\Response;
use Laminas\ServiceManager\ServiceManager;
use LogicException;
use Monarc\Core\Service\ConnectedUserService;
use Monarc\FrontOffice\Model\Entity\Anr;
use Monarc\FrontOffice\Model\Entity\UserAnr;
use Monarc\FrontOffice\Model\Entity\UserRole;
use Monarc\FrontOffice\Exception\AccessForbiddenException;
use Monarc\FrontOffice\Exception\UserNotAuthorizedException;
use Monarc\FrontOffice\Model\Entity\User;
use Monarc\FrontOffice\Model\Table\AnrTable;
use Monarc\FrontOffice\Model\Table\SettingTable;
use Monarc\FrontOffice\Stats\DataObject\StatsDataObject;
use Monarc\FrontOffice\Stats\Exception\StatsAlreadyCollectedException;
use Monarc\FrontOffice\Stats\Provider\StatsApiProvider;
use Monarc\FrontOffice\Stats\Service\StatsAnrService;
use MonarcAppFo\Tests\Integration\AbstractIntegrationTestCase;
use PHPUnit\Framework\MockObject\MockObject;
class StatsAnrServiceTest extends AbstractIntegrationTestCase
{
/** @var MockHandler */
private $statsApiMockHandler;
/** @var string */
private $currentDate;
/** @var StatsAnrService */
private $statsAnrService;
/** @var ConnectedUserService|MockObject */
private $connectedUserService;
public static function setUpBeforeClass(): void
{
parent::setUpBeforeClass();
static::createMyPrintTestData();
}
public function setUp(): void
{
parent::setUp();
$this->currentDate = (new DateTime())->format('Y-m-d');
$this->statsAnrService = $this->getApplicationServiceLocator()->get(StatsAnrService::class);
}
protected function configureServiceManager(ServiceManager $serviceManager)
{
$serviceManager->setAllowOverride(true);
$this->statsApiMockHandler = new MockHandler();
$statsApiProvider = new StatsApiProvider(
$serviceManager->get(SettingTable::class),
[],
$this->statsApiMockHandler
);
$serviceManager->setService(StatsApiProvider::class, $statsApiProvider);
$this->connectedUserService = $this->createMock(ConnectedUserService::class);
$serviceManager->setService(ConnectedUserService::class, $this->connectedUserService);
$serviceManager->setAllowOverride(false);
}
public function testItThrowsTheErrorWhenTheTheStatsAlreadyGeneratedForToday()
{
$this->expectException(StatsAlreadyCollectedException::class);
$this->expectExceptionMessage('The stats is already collected for today.');
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse([
new StatsDataObject([
'type' => StatsDataObject::TYPE_RISK,
'anr' => '1232-31abcd-213efgh-123klmp',
'data' => [
'total' => [
[
'label' => 'Low risks',
'value' => 50,
],
[
'label' => 'Medium risks',
'value' => 30,
],
[
'label' => 'High risks',
'value' => 10,
],
],
],
])
])));
$this->statsAnrService->collectStats();
}
public function testItDoesNotSendTheStatsWhenTheDataIsEmpty()
{
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsAnrService->collectStats([99, 78]);
$this->assertEquals('GET', $this->statsApiMockHandler->getLastRequest()->getMethod());
}
public function testItCanGenerateTheStatsForAllTheAnrs()
{
/** @var AnrTable $anrTable */
$anrTable = $this->getApplicationServiceLocator()->get(AnrTable::class);
$anrs = $anrTable->findAll();
$anrUuids = [];
foreach ($anrs as $anr) {
$anrUuids[] = $anr->getUuid();
}
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsApiMockHandler->append(new Response(201, [], '{"status": "ok"}'));
$this->statsAnrService->collectStats();
$this->assertJsonStringEqualsJsonString(
$this->getExpectedStatsDataJson($anrUuids),
$this->statsApiMockHandler->getLastRequest()->getBody()->getContents()
);
}
public function testItGenerateTheStatsOnlyForPassedAnrs()
{
$anrIdsToGenerateTheStats = [1, 2, 3];
/** @var AnrTable $anrTable */
$anrTable = $this->getApplicationServiceLocator()->get(AnrTable::class);
$anrs = $anrTable->findByIds($anrIdsToGenerateTheStats);
$anrUuids = [];
foreach ($anrs as $num => $anr) {
$anrUuids[] = $anr->getUuid();
}
$this->assertCount(\count($anrIdsToGenerateTheStats), $anrUuids);
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsApiMockHandler->append(new Response(201, [], '{"status": "ok"}'));
$this->statsAnrService->collectStats($anrIdsToGenerateTheStats);
$this->assertJsonStringEqualsJsonString(
$this->getExpectedStatsDataJson($anrUuids),
$this->statsApiMockHandler->getLastRequest()->getBody()->getContents()
);
}
public function testItThrowsTheExceptionIfUserIsNotLoggedIn()
{
$this->expectException(UserNotAuthorizedException::class);
$this->expectExceptionMessage('User not authorized.');
$this->statsAnrService->getStats([]);
}
public function testItThrowsTheExceptionIfUserDoesNotHaveTheRightsToGetTheStats()
{
$this->expectException(AccessForbiddenException::class);
$this->expectExceptionMessage('User does not have an access to the action.');
$user = $this->createMock(User::class);
$user->expects($this->once())->method('hasRole')->with(UserRole::USER_ROLE_CEO)->willReturn(false);
$user->method('getUserAnrs')->willReturn(new ArrayCollection());
$this->connectedUserService
->expects($this->once())
->method('getConnectedUser')
->willReturn($user);
$this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_CARTOGRAPHY]);
}
public function testItThrowsLogicExceptionIfTypeIsNotPassed()
{
$this->expectException(LogicException::class);
$this->expectExceptionMessage('Filter parameter \'type\' is mandatory to get the stats.');
$user = $this->createMock(User::class);
$this->connectedUserService
->expects($this->once())
->method('getConnectedUser')
->willReturn($user);
$this->statsAnrService->getStats([]);
}
public function testItAddsToTheFilterAllowedForTheUserAnrUuids()
{
$user = $this->createMock(User::class);
$user->expects($this->exactly(2))->method('hasRole')->with(UserRole::USER_ROLE_CEO)->willReturn(false);
/** @var Anr $anr1 */
$anr1 = (new Anr())->setId(1);
/** @var Anr $anr2 */
$anr2 = (new Anr())->setId(2);
/** @var Anr $anr3 */
$anr3 = (new Anr())->setId(3);
$user->method('getUserAnrs')->willReturn(new ArrayCollection([
(new UserAnr())->setAnr($anr1->generateAndSetUuid()),
(new UserAnr())->setAnr($anr2->generateAndSetUuid()),
(new UserAnr())->setAnr($anr3->generateAndSetUuid()),
]));
$this->connectedUserService->expects($this->exactly(2))->method('getConnectedUser')->willReturn($user);
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$stats = $this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_COMPLIANCE]);
$this->assertEmpty($stats);
$defaultDates = [
'date_from' => (new DateTime())->modify('-' . StatsAnrService::DEFAULT_STATS_DATES_RANGE)->format('Y-m-d'),
'date_to' => (new DateTime())->format('Y-m-d'),
];
$queryParams = [];
parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams);
$this->assertEquals(
array_merge([
'anrs' => [$anr1->getUuid(), $anr2->getUuid(), $anr3->getUuid()],
'type' => StatsDataObject::TYPE_COMPLIANCE,
'get_last' => 0,
], $defaultDates),
$queryParams
);
$statsResponse = $this->getStatsResponse([
new StatsDataObject([
'type' => StatsDataObject::TYPE_RISK,
'anr' => '1232-31abcd-213efgh-123klmp',
'data' => [
'risks' => [],
'total' => [],
],
])
]);
$this->statsApiMockHandler->append(new Response(200, [], $statsResponse));
$stats = $this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_RISK, 'anrs' => [1, 3, 7]]);
$this->assertEquals($this->getStatsResponse($stats), $this->getStatsResponse());
parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams);
$this->assertEquals(
array_merge([
'anrs' => [$anr1->getUuid(), $anr3->getUuid()],
'type' => StatsDataObject::TYPE_RISK,
'get_last' => 0,
], $defaultDates),
$queryParams
);
}
public function testItAllowsToFilterBySpecificAnrsForCeoRoleOrGetItWithoutLimitations()
{
$user = $this->createMock(User::class);
$user->expects($this->exactly(2))->method('hasRole')->with(UserRole::USER_ROLE_CEO)->willReturn(true);
$user->expects($this->never())->method('getUserAnrs');
$this->connectedUserService->expects($this->exactly(2))->method('getConnectedUser')->willReturn($user);
/** @var AnrTable $anrTable */
$anrTable = $this->getApplicationServiceLocator()->get(AnrTable::class);
$anrUuids = [];
foreach ($anrTable->findByIds([1, 2, 3]) as $anr) {
$anrUuids[] = $anr->getUuid();
}
$defaultDates = [
'date_from' => (new DateTime())->modify('-' . StatsAnrService::DEFAULT_STATS_DATES_RANGE)->format('Y-m-d'),
'date_to' => (new DateTime())->format('Y-m-d'),
];
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsAnrService->getStats([
'type' => StatsDataObject::TYPE_RISK,
'anrs' => [1, 2, 3, 99] // anr ID = 99 is not in thew db.
]);
parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams);
$this->assertEquals(array_merge([
'anrs' => $anrUuids,
'type' => StatsDataObject::TYPE_RISK,
'get_last' => 0,
], $defaultDates), $queryParams);
$this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_VULNERABILITY]);
parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams);
$this->assertEquals(
array_merge(['type' => StatsDataObject::TYPE_VULNERABILITY], $defaultDates + ['get_last' => 0]),
$queryParams
);
}
public function testItCanSendDifferentParamsToGetTheStats()
{
$user = $this->createMock(User::class);
$user->expects($this->exactly(3))->method('hasRole')->with(UserRole::USER_ROLE_CEO)->willReturn(true);
$user->expects($this->never())->method('getUserAnrs');
$this->connectedUserService->expects($this->exactly(3))->method('getConnectedUser')->willReturn($user);
/** @var AnrTable $anrTable */
$anrTable = $this->getApplicationServiceLocator()->get(AnrTable::class);
$anrUuids = [];
foreach ($anrTable->findByIds([1, 2, 3, 4]) as $anr) {
$anrUuids[] = $anr->getUuid();
}
$datesRange = [
'dateFrom' => (new DateTime())->modify('-1 year')->format('Y-m-d'),
'dateTo' => (new DateTime())->format('Y-m-d'),
];
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsAnrService->getStats(array_merge([
'anrs' => [1, 2, 3, 4],
'aggregationPeriod' => 'month',
'type' => StatsDataObject::TYPE_COMPLIANCE
], $datesRange));
parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams);
$this->assertEquals(array_merge([
'anrs' => $anrUuids,
'aggregation_period' => 'month',
'type' => StatsDataObject::TYPE_COMPLIANCE,
'get_last' => 0,
], [
'date_from' => $datesRange['dateFrom'],
'date_to' => $datesRange['dateTo'],
]), $queryParams);
$this->statsAnrService->getStats(array_merge([
'aggregationPeriod' => 'week',
'type' => StatsDataObject::TYPE_VULNERABILITY
], $datesRange));
parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams);
$this->assertEquals(array_merge([
'aggregation_period' => 'week',
'get_last' => 0,
'type' => StatsDataObject::TYPE_VULNERABILITY
], [
'date_from' => $datesRange['dateFrom'],
'date_to' => $datesRange['dateTo'],
]), $queryParams);
$this->statsAnrService->getStats(array_merge([
'getLast' => true,
'type' => StatsDataObject::TYPE_CARTOGRAPHY,
], $datesRange));
parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams);
$this->assertEquals(array_merge([
'get_last' => 1,
'type' => StatsDataObject::TYPE_CARTOGRAPHY
]), $queryParams);
}
public function testItFetchesStatsForDefaultPeriodIfFromAndToDatesAreNotPassed()
{
$user = $this->createMock(User::class);
$user->expects($this->exactly(3))->method('hasRole')->with(UserRole::USER_ROLE_CEO)->willReturn(true);
$user->expects($this->never())->method('getUserAnrs');
$this->connectedUserService->expects($this->exactly(3))->method('getConnectedUser')->willReturn($user);
$defaultDates = [
'dateFrom' => (new DateTime())->modify('-' . StatsAnrService::DEFAULT_STATS_DATES_RANGE)->format('Y-m-d'),
'dateTo' => (new DateTime())->format('Y-m-d'),
];
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsApiMockHandler->append(new Response(200, [], $this->getStatsResponse()));
$this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_THREAT]);
parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams);
$this->assertEquals([
'date_from' => $defaultDates['dateFrom'],
'date_to' => $defaultDates['dateTo'],
'type' => StatsDataObject::TYPE_THREAT,
'get_last' => 0,
], $queryParams);
$this->statsAnrService->getStats([
'type' => StatsDataObject::TYPE_THREAT,
'dateFrom' => (new DateTime())->modify('-6 months')->format('Y-m-d')
]);
parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams);
$this->assertEquals([
'date_from' => (new DateTime())->modify('-6 months')->format('Y-m-d'),
'date_to' => $defaultDates['dateTo'],
'type' => StatsDataObject::TYPE_THREAT,
'get_last' => 0,
], $queryParams);
$dateTo = (new DateTimeImmutable())->modify('-6 months');
$this->statsAnrService->getStats(['type' => StatsDataObject::TYPE_THREAT, 'dateTo' => $dateTo->format('Y-m-d')]);
parse_str($this->statsApiMockHandler->getLastRequest()->getUri()->getQuery(), $queryParams);
$this->assertEquals([
'type' => StatsDataObject::TYPE_THREAT,
'date_from' => $dateTo->modify('-' . StatsAnrService::DEFAULT_STATS_DATES_RANGE)->format('Y-m-d'),
'date_to' => $dateTo->format('Y-m-d'),
'get_last' => 0,
], $queryParams);
}
private function getStatsResponse(array $results = []): string
{
return json_encode([
'metadata' => [
'count' => \count($results),
'offset' => 0,
'limit' => 0,
],
'data' => $results,
]);
}
private function getExpectedStatsDataJson(array $anrUuids): string
{
$statsData = json_decode(
file_get_contents($this->testPath . '/data/expected_stats_data_for_my_print.json'),
true
);
$expectedStats = [];
foreach ($anrUuids as $num => $anrUuid) {
foreach ($statsData as $data) {
$data['anr'] = $anrUuid;
$data['date'] = $this->currentDate;
$expectedStats[] = $data;
}
}
return json_encode($expectedStats);
}
}

View File

@ -0,0 +1,10 @@
<?php declare(strict_types=1);
namespace MonarcAppFo\Tests\Unit;
use PHPUnit\Framework\TestCase;
class AbstractUnitTestCase extends TestCase
{
}

View File

@ -0,0 +1,224 @@
<?php declare(strict_types=1);
namespace MonarcAppFo\Tests\Unit\Stats\Validator;
use Doctrine\ORM\EntityNotFoundException;
use Laminas\InputFilter\InputFilter;
use Monarc\FrontOffice\Model\Entity\Anr;
use Monarc\FrontOffice\Model\Table\AnrTable;
use Monarc\FrontOffice\Stats\DataObject\StatsDataObject;
use Monarc\FrontOffice\Stats\Service\StatsAnrService;
use Monarc\FrontOffice\Stats\Validator\GetStatsQueryParamsValidator;
use Monarc\FrontOffice\Validator\FieldValidator\AnrExistenceValidator;
use MonarcAppFo\Tests\Unit\AbstractUnitTestCase;
use PHPUnit\Framework\MockObject\MockObject;
class GetStatsQueryParamsValidatorTest extends AbstractUnitTestCase
{
/** @var AnrTable|MockObject */
private $anrTable;
/** @var GetStatsQueryParamsValidator */
private $getStatsQueryParamsValidator;
public function setUp(): void
{
parent::setUp();
$this->anrTable = $this->createMock(AnrTable::class);
$this->getStatsQueryParamsValidator = new GetStatsQueryParamsValidator(
new InputFilter(),
$this->anrTable
);
}
public function testItIsNotValidWhenDateToLowerThenDateFromOrBiggerThenCurrentDate()
{
static::assertFalse($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
'dateFrom' => '2020-01-01',
'dateTo' => '2019-12-01',
]));
static::assertEquals(
[
'dateFrom' => ['"dateFrom" should be lower or equal to "dateTo".'],
'dateTo' => ['"dateTo" should be bigger or equal to "dateFrom".'],
],
$this->getStatsQueryParamsValidator->getErrorMessages()
);
static::assertFalse($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
'dateFrom' => '3020-01-01',
'dateTo' => '3019-12-01',
]));
static::assertEquals(
[
'dateFrom' => ['"dateFrom" should be lower or equal to current date.'],
'dateTo' => ['"dateTo" should be lower or equal to current date.'],
],
$this->getStatsQueryParamsValidator->getErrorMessages()
);
}
public function testItIsValidWhenTheDatesAreTheSameOrDateFromIsLessThenDateTo()
{
static::assertTrue($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
'dateFrom' => '2019-12-01',
'dateTo' => '2020-06-01',
]));
static::assertEmpty($this->getStatsQueryParamsValidator->getErrorMessages());
static::assertEquals(
[
'dateFrom' => '2019-12-01',
'dateTo' => '2020-06-01',
'anrs' => [],
'type' => StatsDataObject::TYPE_RISK,
'aggregationPeriod' => null,
'getLast' => false,
],
$this->getStatsQueryParamsValidator->getValidData()
);
static::assertTrue($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
'dateFrom' => '2019-12-01',
'dateTo' => '2019-12-01',
]));
static::assertEmpty($this->getStatsQueryParamsValidator->getErrorMessages());
static::assertEquals(
[
'dateFrom' => '2019-12-01',
'dateTo' => '2019-12-01',
'anrs' => [],
'type' => StatsDataObject::TYPE_RISK,
'aggregationPeriod' => null,
'getLast' => false,
],
$this->getStatsQueryParamsValidator->getValidData()
);
}
public function testItThrowAnExceptionWhenSomeAnrsAreNotPresentedInTheTable()
{
$this->anrTable->expects($this->at(0))->method('findById')->willReturn(new Anr());
$this->anrTable->expects($this->at(1))->method('findById')->willReturn(new Anr());
$this->anrTable->expects($this->at(2))->method('findById')->willThrowException(new EntityNotFoundException());
static::assertFalse($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
'anrs' => [1, 2, 3, 7],
]));
static::assertEquals(
[
'anrs' => [AnrExistenceValidator::ANR_DOES_NOT_EXIST => 'Anr with the ID (3) does not exist.']
],
$this->getStatsQueryParamsValidator->getErrorMessages()
);
}
public function testItIsNotValidWhenTypeIsNotPassedOrWrong()
{
static::assertFalse($this->getStatsQueryParamsValidator->isValid([]));
static::assertEquals(
[
'type' => ['isEmpty' => 'Value is required and can\'t be empty']
],
$this->getStatsQueryParamsValidator->getErrorMessages()
);
static::assertFalse($this->getStatsQueryParamsValidator->isValid([
'type' => 'not-existed-type'
]));
static::assertEquals(
[
'type' => [
'notInArray' => 'Should be one of the values: '
. implode(', ', StatsDataObject::getAvailableTypes())
]
],
$this->getStatsQueryParamsValidator->getErrorMessages()
);
}
public function testItIsNotValidOnlyWhenPassedWrongAggregationPeriod()
{
static::assertFalse($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
'aggregationPeriod' => 'not-existed-period'
]));
static::assertEquals(
[
'aggregationPeriod' => [
'notInArray' => 'Should be one of the values: '
. implode(', ', StatsAnrService::AVAILABLE_AGGREGATION_FIELDS)
]
],
$this->getStatsQueryParamsValidator->getErrorMessages()
);
static::assertTrue($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
]));
static::assertTrue($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
'aggregationType' => 'week',
]));
}
public function testGetLastIsSetToFalseWhenNotPassed()
{
static::assertTrue($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
]));
static::assertEquals(
[
'type' => StatsDataObject::TYPE_RISK,
'getLast' => false,
'anrs' => [],
'dateFrom' => null,
'dateTo' => null,
'aggregationPeriod' => null,
],
$this->getStatsQueryParamsValidator->getValidData()
);
static::assertTrue($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
'getLast' => true,
]));
static::assertEquals(
[
'type' => StatsDataObject::TYPE_RISK,
'getLast' => true,
'anrs' => [],
'dateFrom' => null,
'dateTo' => null,
'aggregationPeriod' => null,
],
$this->getStatsQueryParamsValidator->getValidData()
);
static::assertTrue($this->getStatsQueryParamsValidator->isValid([
'type' => StatsDataObject::TYPE_RISK,
'getLast' => 'the value is converted to boolean.',
]));
static::assertEquals(
[
'type' => StatsDataObject::TYPE_RISK,
'getLast' => true,
'anrs' => [],
'dateFrom' => null,
'dateTo' => null,
'aggregationPeriod' => null,
],
$this->getStatsQueryParamsValidator->getValidData()
);
}
}

13
tests/bootstrap.php Normal file
View File

@ -0,0 +1,13 @@
<?php declare(strict_types=1);
chdir(dirname(__DIR__));
if (date_default_timezone_get() !== ini_get('date.timezone')) {
date_default_timezone_set('Europe/Luxembourg');
}
putenv('APP_CONF_DIR=' . dirname(__DIR__) . '/tests/config');
putenv('TESTS_DIR=' . dirname(__DIR__) . '/tests');
putenv('APPLICATION_ENV=testing');
require dirname(__DIR__) . '/vendor/autoload.php';

0
tests/config/data/cache/.gitkeep vendored Normal file
View File

93
tests/config/local.php Normal file
View File

@ -0,0 +1,93 @@
<?php
use Doctrine\Common\Proxy\AbstractProxyFactory;
$dataPath = getenv('TESTS_DIR') . '/data';
return [
'doctrine' => [
'connection' => [
'orm_default' => [
'params' => [
'host' => '127.0.0.1',
'user' => 'sqlmonarcuser',
'password' => 'sqlmonarcuser',
'dbname' => 'monarc_common_test',
'port' => 3306,
// To execute tests from your host machine uncomment these lines:
'options' => [
PDO::MYSQL_ATTR_SSL_KEY => '~/web/monarc/MonarcAppFO/vagrant/.vagrant/machines/default/virtualbox/private_key'
]
],
],
'orm_cli' => [
'params' => [
'host' => '127.0.0.1',
'user' => 'sqlmonarcuser',
'password' => 'sqlmonarcuser',
'dbname' => 'monarc_cli_test',
'port' => 3306,
// To execute tests from your host machine uncomment these lines:
'options' => [
PDO::MYSQL_ATTR_SSL_KEY => '~/web/monarc/MonarcAppFO/vagrant/.vagrant/machines/default/virtualbox/private_key'
]
],
],
],
'entitymanager' => [
'orm_default' => [
'connection' => 'orm_default',
'configuration' => 'orm_default'
],
'orm_cli' => [
'connection' => 'orm_cli',
'configuration' => 'orm_cli',
],
],
'configuration' => [
'orm_default' => [
'metadata_cache' => 'array',
'query_cache' => 'array',
'result_cache' => 'array',
'driver' => 'orm_default',
'generate_proxies' => AbstractProxyFactory::AUTOGENERATE_EVAL,
'filters' => [],
'datetime_functions' => [],
'string_functions' => [],
'numeric_functions' => [],
'second_level_cache' => [],
],
'orm_cli' => [
'metadata_cache' => 'array',
'query_cache' => 'array',
'result_cache' => 'array',
'driver' => 'orm_cli',
'generate_proxies' => AbstractProxyFactory::AUTOGENERATE_EVAL,
'filters' => [],
'datetime_functions' => [],
'string_functions' => [],
'numeric_functions' => [],
'second_level_cache' => [],
],
],
],
'activeLanguages' => ['fr', 'en', 'de', 'nl',],
'appVersion' => '3.0.0',
'checkVersion' => false,
'appCheckingURL' => 'https://version.monarc.lu/check/MONARC',
'email' => [
'name' => 'MONARC',
'from' => 'info@monarc.lu',
],
'mospApiUrl' => 'https://objects.monarc.lu/api/v1/',
'monarc' => [
'ttl' => 60,
'salt' => '',
],
];

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
<?php
$config = require dirname(__DIR__) . '/config/local.php';
$connectionConf = [
'adapter' => 'mysql',
'host' => $config['doctrine']['connection']['orm_default']['params']['host'],
'name' => $config['doctrine']['connection']['orm_default']['params']['dbname'],
'user' => $config['doctrine']['connection']['orm_default']['params']['user'],
'pass' => $config['doctrine']['connection']['orm_default']['params']['password'],
'port' => $config['doctrine']['connection']['orm_default']['params']['port'],
'charset' => 'utf8',
];
if (isset($config['doctrine']['connection']['orm_default']['params']['options'][PDO::MYSQL_ATTR_SSL_KEY])) {
$connectionConf['ssl_key'] =
$config['doctrine']['connection']['orm_default']['params']['options'][PDO::MYSQL_ATTR_SSL_KEY];
}
return [
'paths' => [
'migrations' => dirname(__DIR__) . '/../module/Monarc/Core/migrations/db',
'seeds' => dirname(__DIR__) . '/../module/Monarc/Core/migrations/seeds',
],
'environments' => [
'default_migration_table' => 'phinxlog',
'default_database' => 'common',
'common' => $connectionConf,
],
];

View File

@ -0,0 +1,29 @@
<?php
$config = require dirname(__DIR__) . '/config/local.php';
$connectionConf = [
'adapter' => 'mysql',
'host' => $config['doctrine']['connection']['orm_cli']['params']['host'],
'name' => $config['doctrine']['connection']['orm_cli']['params']['dbname'],
'user' => $config['doctrine']['connection']['orm_cli']['params']['user'],
'pass' => $config['doctrine']['connection']['orm_cli']['params']['password'],
'port' => $config['doctrine']['connection']['orm_cli']['params']['port'],
'charset' => 'utf8',
];
if (isset($config['doctrine']['connection']['orm_cli']['params']['options'][PDO::MYSQL_ATTR_SSL_KEY])) {
$connectionConf['ssl_key'] =
$config['doctrine']['connection']['orm_cli']['params']['options'][PDO::MYSQL_ATTR_SSL_KEY];
}
return [
'paths' => [
'migrations' => dirname(__DIR__) . '/../module/Monarc/FrontOffice/migrations/db',
'seeds' => dirname(__DIR__) . '/../module/Monarc/FrontOffice/migrations/seeds',
],
'environments' => [
'default_migration_table' => 'phinxlog',
'default_database' => 'cli',
'cli' => $connectionConf,
],
];

View File

@ -0,0 +1,10 @@
#!/bin/bash
DBHOST="127.0.0.1"
DBUSER_MONARC="sqlmonarcuser"
DBPASSWORD_MONARC="sqlmonarcuser"
# Comment/Uncomment and modify the following line to run tests from your host machine:
CONNECTION_OPTIONS="--ssl-key=~/web/monarc/MonarcAppFO/vagrant/.vagrant/machines/default/virtualbox/private_key"
#CONNECTION_OPTIONS=""
mysql -h $DBHOST -u $DBUSER_MONARC -p$DBPASSWORD_MONARC $CONNECTION_OPTIONS monarc_cli_test < tests/scripts/clean_client_database.sql > /dev/null

View File

@ -0,0 +1,44 @@
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE `anrs`;
TRUNCATE TABLE `amvs`;
TRUNCATE TABLE `anrs_objects`;
TRUNCATE TABLE `anrs_objects_categories`;
TRUNCATE TABLE `assets`;
TRUNCATE TABLE `deliveries`;
TRUNCATE TABLE `instances`;
TRUNCATE TABLE `instances_consequences`;
TRUNCATE TABLE `instances_risks`;
TRUNCATE TABLE `instances_risks_op`;
TRUNCATE TABLE `interviews`;
TRUNCATE TABLE `measures`;
TRUNCATE TABLE `measures_amvs`;
TRUNCATE TABLE `measures_measures`;
TRUNCATE TABLE `measures_rolf_risks`;
TRUNCATE TABLE `objects`;
TRUNCATE TABLE `objects_categories`;
TRUNCATE TABLE `objects_objects`;
TRUNCATE TABLE `questions`;
TRUNCATE TABLE `questions_choices`;
TRUNCATE TABLE `recommandations`;
TRUNCATE TABLE `recommandations_risks`;
TRUNCATE TABLE `recommandations_sets`;
TRUNCATE TABLE `referentials`;
TRUNCATE TABLE `rolf_risks_tags`;
TRUNCATE TABLE `rolf_risks`;
TRUNCATE TABLE `rolf_tags`;
TRUNCATE TABLE `scales`;
TRUNCATE TABLE `scales_comments`;
TRUNCATE TABLE `scales_impact_types`;
TRUNCATE TABLE `soa`;
TRUNCATE TABLE `soacategory`;
TRUNCATE TABLE `snapshots`;
TRUNCATE TABLE `themes`;
TRUNCATE TABLE `threats`;
TRUNCATE TABLE `user_tokens`;
TRUNCATE TABLE `users`;
TRUNCATE TABLE `users_anrs`;
TRUNCATE TABLE `users_roles`;
TRUNCATE TABLE `vulnerabilities`;
SET FOREIGN_KEY_CHECKS = 1;

View File

@ -0,0 +1,13 @@
#!/bin/bash
DBHOST="127.0.0.1"
DBUSER_MONARC="sqlmonarcuser"
DBPASSWORD_MONARC="sqlmonarcuser"
# Comment/Uncomment and modify the following line to run tests from your host machine:
CONNECTION_OPTIONS="--ssl-key=~/web/monarc/MonarcAppFO/vagrant/.vagrant/machines/default/virtualbox/private_key"
#CONNECTION_OPTIONS=""
for i in {0..5}
do
mysql -h $DBHOST -u $DBUSER_MONARC -p$DBPASSWORD_MONARC $CONNECTION_OPTIONS monarc_cli_test < tests/scripts/insert_my_print_anrs.sql > /dev/null
done

File diff suppressed because it is too large Load Diff

26
tests/scripts/setup_db.sh Normal file
View File

@ -0,0 +1,26 @@
#!/bin/bash
DBHOST="127.0.0.1"
DBUSER_MONARC="sqlmonarcuser"
DBPASSWORD_MONARC="sqlmonarcuser"
# Comment/Uncomment and modify the following line to run tests from your host machine:
CONNECTION_OPTIONS="--ssl-key=~/web/monarc/MonarcAppFO/vagrant/.vagrant/machines/default/virtualbox/private_key"
#CONNECTION_OPTIONS=""
mysql -h $DBHOST -u $DBUSER_MONARC -p$DBPASSWORD_MONARC $CONNECTION_OPTIONS -e "CREATE DATABASE IF NOT EXISTS monarc_cli_test DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;" > /dev/null
# Check if the database is already exist we don't need to create the structure and import the data.
if ! mysql -h $DBHOST -u $DBUSER_MONARC -p$DBPASSWORD_MONARC $CONNECTION_OPTIONS -e "use monarc_common_test"; then
mysql -h $DBHOST -u $DBUSER_MONARC -p$DBPASSWORD_MONARC $CONNECTION_OPTIONS -e "CREATE DATABASE monarc_common_test DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;" > /dev/null
mysql -h $DBHOST -u $DBUSER_MONARC -p$DBPASSWORD_MONARC $CONNECTION_OPTIONS monarc_common_test < db-bootstrap/monarc_structure.sql > /dev/null
mysql -h $DBHOST -u $DBUSER_MONARC -p$DBPASSWORD_MONARC $CONNECTION_OPTIONS monarc_common_test < db-bootstrap/monarc_data.sql > /dev/null
fi
if [[ ! $(mysql -h $DBHOST -u $DBUSER_MONARC -p$DBPASSWORD_MONARC $CONNECTION_OPTIONS -e 'SHOW TABLES LIKE "phinxlog"' monarc_common_test) ]]
then
php bin/phinx migrate -c tests/migrations/phinx_core.php
fi
if [[ ! $(mysql -h $DBHOST -u $DBUSER_MONARC -p$DBPASSWORD_MONARC $CONNECTION_OPTIONS -e 'SHOW TABLES LIKE "phinxlog"' monarc_cli_test) ]]
then
php bin/phinx migrate -c tests/migrations/phinx_frontoffice.php
fi

View File

@ -37,3 +37,11 @@ The username is *admin@admin.localhost* and the password is *admin*.
You can now edit the source code with your favorite editor and test it in your
browser. The only thing is to not forget to restart Apache in the VM after a
modification.
------------------------------
Run tests.
The test can be run from Monarc root folder (/home/ubuntu/monarc) of your vagrant VM (params in square brackets are optional):
sudo ./bin/phpunit [--testsuite Functional | --testsuite Integration | --testsuite Unit]
In case of changing the DB configuration (tests/local.php) you can run them from your host machine.

2
vagrant/Vagrantfile vendored
View File

@ -23,7 +23,9 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
config.vm.network :forwarded_port, guest: 80, host: 5001
config.vm.network :forwarded_port, guest: 5005, host: 5005
config.vm.network :forwarded_port, guest: 3306, host: 3306
config.vm.network :forwarded_port, guest: 5432, host: 5435
# Create a private network, which allows host-only access to the machine
# using a specific IP.

View File

@ -1,10 +1,15 @@
#! /usr/bin/env bash
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
PATH_TO_MONARC='/home/vagrant/monarc'
APPENV='local'
ENVIRONMENT='development'
# MariaDB database
DBHOST='localhost'
DBNAME_COMMON='monarc_common'
DBNAME_CLI='monarc_cli'
@ -13,15 +18,31 @@ DBPASSWORD_ADMIN="root"
DBUSER_MONARC='sqlmonarcuser'
DBPASSWORD_MONARC="sqlmonarcuser"
# PHP configuration
upload_max_filesize=200M
post_max_size=50M
max_execution_time=100
max_input_time=223
memory_limit=512M
# session expires in 1 week:
session.gc_maxlifetime=604800
session.gc_probability=1
session.gc_divisor=1000
PHP_INI=/etc/php/7.2/apache2/php.ini
XDEBUG_CFG=/etc/php/7.2/apache2/conf.d/20-xdebug.ini
MARIA_DB_CFG=/etc/mysql/mariadb.conf.d/50-server.cnf
# Stats service
STATS_PATH='/home/vagrant/stats-service'
STATS_HOST='0.0.0.0'
STATS_PORT='5005'
STATS_DB_NAME='statsservice'
STATS_DB_USER='sqlmonarcuser'
STATS_DB_PASSWORD="sqlmonarcuser"
STATS_SECRET_KEY="$(openssl rand -hex 32)"
export DEBIAN_FRONTEND=noninteractive
export LANGUAGE=en_US.UTF-8
export LANG=en_US.UTF-8
@ -80,7 +101,7 @@ sudo mysql -u root -p$DBPASSWORD_ADMIN -e "FLUSH PRIVILEGES;"
sudo systemctl restart mariadb.service > /dev/null
echo -e "\n--- Installing PHP-specific packages… ---\n"
sudo apt-get -y install php apache2 libapache2-mod-php php-curl php-gd php-mysql php-pear php-apcu php-xml php-mbstring php-intl php-imagick php-zip php-xdebug > /dev/null
sudo apt-get -y install php apache2 libapache2-mod-php php-curl php-gd php-mysql php-pear php-apcu php-xml php-mbstring php-intl php-imagick php-zip php-xdebug php-bcmath > /dev/null
echo -e "\n--- Configuring PHP… ---\n"
for key in upload_max_filesize post_max_size max_execution_time max_input_time memory_limit
@ -118,7 +139,7 @@ cd $PATH_TO_MONARC
git config core.fileMode false
echo -e "\n--- Installing the dependencies… ---\n"
composer install -o
composer ins
# Make modules symlinks.
@ -178,50 +199,125 @@ echo -e "\n--- Restarting Apache… ---\n"
sudo systemctl restart apache2.service > /dev/null
echo -e "\n--- Installing the stats service… ---\n"
sudo apt-get -y install postgresql python3-pip python3-venv
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 10
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 20
sudo -u postgres psql -c "CREATE USER $STATS_DB_USER WITH PASSWORD '$STATS_DB_PASSWORD';"
sudo -u postgres psql -c "ALTER USER $STATS_DB_USER WITH SUPERUSER;"
cd ~
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
echo 'export PATH="$PATH:$HOME/.poetry/bin"' >> ~/.bashrc
echo 'export FLASK_APP=runserver.py' >> ~/.bashrc
echo 'export STATS_CONFIG=production.py' >> ~/.bashrc
source ~/.bashrc
source $HOME/.poetry/env
git clone https://github.com/monarc-project/stats-service $STATS_PATH
cd $STATS_PATH
npm install
poetry install --no-dev
bash -c "cat << EOF > $STATS_PATH/instance/production.py
HOST = '$STATS_HOST'
PORT = $STATS_PORT
DEBUG = False
TESTING = False
INSTANCE_URL = 'http://127.0.0.1:$STATS_PORT'
ADMIN_EMAIL = 'info@cases.lu'
ADMIN_URL = 'https://www.cases.lu'
REMOTE_STATS_SERVER = 'https://dashboard.monarc.lu'
DB_CONFIG_DICT = {
'user': '$STATS_DB_USER',
'password': '$STATS_DB_PASSWORD',
'host': 'localhost',
'port': 5432,
}
DATABASE_NAME = '$STATS_DB_NAME'
SQLALCHEMY_DATABASE_URI = 'postgres://{user}:{password}@{host}:{port}/{name}'.format(
name=DATABASE_NAME, **DB_CONFIG_DICT
)
SQLALCHEMY_TRACK_MODIFICATIONS = False
SECRET_KEY = '$STATS_SECRET_KEY'
LOG_PATH = './var/stats.log'
MOSP_URL = 'https://objects.monarc.lu'
EOF"
export FLASK_APP=runserver.py
export STATS_CONFIG=production.py
FLASK_APP=runserver.py poetry run flask db_create
FLASK_APP=runserver.py poetry run flask db_init
FLASK_APP=runserver.py poetry run flask client_create --name ADMIN --role admin
sudo bash -c "cat << EOF > /etc/systemd/system/statsservice.service
[Unit]
Description=MONARC Stats service
After=network.target
[Service]
User=vagrant
Environment=LANG=en_US.UTF-8
Environment=LC_ALL=en_US.UTF-8
Environment=FLASK_APP=runserver.py
Environment=FLASK_ENV=production
Environment=STATS_CONFIG=production.py
Environment=FLASK_RUN_HOST=$STATS_HOST
Environment=FLASK_RUN_PORT=$STATS_PORT
WorkingDirectory=$STATS_PATH
ExecStart=/home/vagrant/.poetry/bin/poetry run flask run
Restart=always
[Install]
WantedBy=multi-user.target
EOF"
sudo systemctl daemon-reload > /dev/null
sleep 1
sudo systemctl enable statsservice.service > /dev/null
sleep 3
sudo systemctl restart statsservice > /dev/null
#systemctl status statsservice.service
# Create a new client and set the apiKey.
cd $STATS_PATH ; apiKey=$(poetry run flask client_create --name admin_localhost | sed -nr 's/Token: (.*)$/\1/p')
cd $PATH_TO_MONARC
echo -e "\n--- Configuration of MONARC database connection ---\n"
sudo bash -c "cat << EOF > config/autoload/local.php
<?php
return array(
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'params' => array(
return [
'doctrine' => [
'connection' => [
'orm_default' => [
'params' => [
'host' => '$DBHOST',
'user' => '$DBUSER_MONARC',
'password' => '$DBPASSWORD_MONARC',
'dbname' => '$DBNAME_COMMON',
),
),
'orm_cli' => array(
'params' => array(
],
],
'orm_cli' => [
'params' => [
'host' => '$DBHOST',
'user' => '$DBUSER_MONARC',
'password' => '$DBPASSWORD_MONARC',
'dbname' => '$DBNAME_CLI',
),
),
),
),
],
],
],
],
/* Link with (ModuleCore)
config['languages'] = [
'fr' => array(
'index' => 1,
'label' => 'Français'
),
'en' => array(
'index' => 2,
'label' => 'English'
),
'de' => array(
'index' => 3,
'label' => 'Deutsch'
),
]
*/
'activeLanguages' => array('fr','en','de','nl',),
'activeLanguages' => ['fr','en','de','nl'],
'appVersion' => '-master',
@ -229,17 +325,22 @@ return array(
'appCheckingURL' => 'https://version.monarc.lu/check/MONARC',
'email' => [
'name' => 'MONARC',
'from' => 'info@monarc.lu',
'name' => 'MONARC',
'from' => 'info@monarc.lu',
],
'mospApiUrl' => 'https://objects.monarc.lu/api/v1/',
'monarc' => array(
'monarc' => [
'ttl' => 60, // timeout
'salt' => '', // private salt for password encryption
),
);
],
'statsApi' => [
'baseUrl' => 'http://127.0.0.1:$STATS_PORT'
'apiKey' => '$apiKey',
],
];
EOF"
@ -251,45 +352,35 @@ mysql -u $DBUSER_MONARC -p$DBPASSWORD_MONARC monarc_common < db-bootstrap/monarc
mysql -u $DBUSER_MONARC -p$DBPASSWORD_MONARC monarc_common < db-bootstrap/monarc_data.sql > /dev/null
echo -e "\n--- Installation of Grunt… ---\n"
curl -sL https://deb.nodesource.com/setup_13.x | sudo bash -
curl -sL https://deb.nodesource.com/setup_14.x | sudo bash -
sudo apt-get install -y nodejs
sudo npm install -g grunt-cli
echo -e "\n--- Creating cache folders for backend… ---\n"
mkdir -p $PATH_TO_MONARC/data/cache
mkdir -p $PATH_TO_MONARC/data/LazyServices/Proxy
mkdir -p $PATH_TO_MONARC/data/DoctrineORMModule/Proxy
echo -e "\n--- Adjusting user mod… ---\n"
sudo usermod -aG www-data vagrant
sudo usermod -aG vagrant www-data
echo -e "\n--- Update the project… ---\n"
sudo chown -R $USER:$(id -gn $USER) /home/vagrant/.config
./scripts/update-all.sh > /dev/null
./scripts/update-all.sh -d > /dev/null
echo -e "\n--- Create initial user and client ---\n"
php ./bin/phinx seed:run -c ./module/Monarc/FrontOffice/migrations/phinx.php
echo -e "\n--- Restarting Apache… ---\n"
sudo systemctl restart apache2.service > /dev/null
echo -e "\n--- MONARC is ready! Point your Web browser to http://127.0.0.1:5001 ---\n"
echo -e "MONARC is ready and avalable at http://127.0.0.1:5001"
echo -e "Stats service is ready and available at http://127.0.0.1:$STATS_PORT"