init testing environment

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
This commit is contained in:
Maxence Lange 2021-03-15 00:30:51 -01:00
parent b279b70874
commit 0f79395d17
3 changed files with 564 additions and 28 deletions

View file

@ -53,6 +53,7 @@ appstore: clean composer
--exclude=/issue_template.md \
--exclude=/README.md \
--exclude=/composer.json \
--exclude=/testConfiguration.json \
--exclude=/composer.lock \
--exclude=/.gitattributes \
--exclude=/.gitignore \

View file

@ -1,4 +1,6 @@
<?php declare(strict_types=1);
<?php
declare(strict_types=1);
/**
@ -8,7 +10,7 @@
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2017
* @copyright 2021
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
@ -29,11 +31,19 @@
namespace OCA\Circles\Command;
use daita\MySmallPhpTools\Exceptions\ItemNotFoundException;
use daita\MySmallPhpTools\Traits\TArrayTools;
use daita\MySmallPhpTools\Traits\TStringTools;
use Exception;
use OC\Core\Command\Base;
use OCA\Circles\AppInfo\Application;
use OCA\Circles\Db\CoreQueryBuilder;
use OCA\Circles\Exceptions\CircleNotFoundException;
use OCA\Circles\Model\Circle;
use OCA\Circles\Model\Member;
use OCA\Circles\Service\ConfigService;
use OCA\Circles\Service\GroupService;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@ -50,31 +60,61 @@ class CirclesTest extends Base {
use TArrayTools;
use TStringTools;
static $INSTANCES = [
'global-scale-1',
'global-scale-2',
'global-scale-3',
'passive',
'external',
'trusted'
];
/** @var CoreQueryBuilder */
private $coreQueryBuilder;
/** @var ConfigService */
private $configService;
/** @var OutputInterface */
private $output;
/** @var array */
private $config = [];
/** @var array */
private $sessions = [];
/** @var string */
private $local = '';
/** @var bool */
private $pOn = false;
/** @var array */
private $circles = [];
/** @var array */
private $members = [];
/**
* CirclesTest constructor.
*
* @param CoreQueryBuilder $coreQueryBuilder
* @param ConfigService $configService
*/
public function __construct(ConfigService $configService) {
public function __construct(CoreQueryBuilder $coreQueryBuilder, ConfigService $configService) {
parent::__construct();
$this->coreQueryBuilder = $coreQueryBuilder;
$this->configService = $configService;
}
/**
*
*/
protected function configure() {
parent::configure();
$this->setName('circles:test')
@ -92,11 +132,20 @@ class CirclesTest extends Base {
* @param OutputInterface $output
*
* @return int
* @throws Exception
* @throws ItemNotFoundException
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
$this->output = $output;
if ($input->getOption('am-i-aware-this-will-delete-all-my-data') == 'yes') {
$this->testCirclesApp();
try {
$this->testCirclesApp();
} catch (Exception $e) {
if ($this->pOn) {
$this->output->writeln('<error>' . $e->getMessage() . '</error>');
} else {
throw $e;
}
}
return 0;
}
@ -124,39 +173,311 @@ class CirclesTest extends Base {
* @throws ItemNotFoundException
*/
private function testCirclesApp() {
$this->t('Initialisation');
$this->loadConfiguration();
$this->initEnvironment();
$this->confirmVersion();
$this->confirmEmptyCircles();
$this->syncCircles();
$listing = $this->occ('global-scale-1', 'circles:manage:list');
$this->t('Fresh installation status');
$this->statusFreshInstances();
echo json_encode($listing, JSON_PRETTY_PRINT) . "\n";
}
/**
* @throws ItemNotFoundException
*/
private function loadConfiguration() {
$this->p('Loading configuration');
$configuration = file_get_contents(__DIR__ . '/../../testConfiguration.json');
$this->config = json_decode($configuration, true);
$this->r(true, 'testConfiguration.json');
$this->p('Checking configuration');
foreach (self::$INSTANCES as $instance) {
$cloudId = $this->getConfig($instance, 'config.frontal_cloud_id');
if ($this->configService->isLocalInstance($cloudId)) {
$this->local = $instance;
}
}
$this->r();
$this->p('Checking local');
if ($this->local === '') {
throw new ItemNotFoundException('local not defined');
}
$this->r(true, $this->local);
}
/**
* @throws ItemNotFoundException
*/
private function initEnvironment() {
$this->p('Init environment');
foreach ($this->getInstances(false) as $instance) {
$this->pm($instance);
$this->occ($instance, 'circles:clean --uninstall', false, false);
$this->occ($instance, 'app:enable circles', true, false);
}
$this->r();
$this->p('Init environment on local');
$this->coreQueryBuilder->cleanDatabase();
$this->r();
}
/**
* @throws ItemNotFoundException
* @throws Exception
*/
private function confirmVersion() {
$version = $this->configService->getAppValue('installed_version');
$this->p('Confirming version <info>' . $version . '</info>');
foreach ($this->getInstances(false) as $instance) {
$this->pm($instance);
$capabilities = $this->occ($instance, 'circles:check --capabilities');
$v = $this->get('version', $capabilities);
if ($v !== $version) {
throw new Exception($v);
}
}
$this->r();
}
/**
* @throws ItemNotFoundException
* @throws Exception
*/
private function confirmEmptyCircles() {
$this->p('Confirming empty database');
foreach ($this->getInstances() as $instance) {
$this->pm($instance);
$result = $this->occ($instance, 'circles:manage:list --all');
if (!is_array($result) || !empty($result)) {
throw new Exception('no');
}
}
$this->r();
}
/**
* @throws ItemNotFoundException
* @throws Exception
*/
private function syncCircles() {
$this->p('Running Circles Sync');
foreach ($this->getInstances() as $instance) {
$this->pm($instance);
$this->occ($instance, 'circles:sync');
}
$this->r();
}
private function statusFreshInstances() {
foreach ($this->getInstances() as $instanceId) {
$this->p('Circles on ' . $instanceId);
$result = $this->occ($instanceId, 'circles:manage:list --all');
$this->r(true, sizeof($result) . ' circles');
$members = $groups = [];
foreach ($result as $item) {
$circle = new Circle();
$circle->import($item);
if ($circle->isConfig(Circle::CFG_SINGLE)) {
$members[] = $circle;
}
if ($circle->getSource() === GroupService::GROUP_TYPE) {
$groups[] = $circle;
}
}
$instance = $this->getConfig($instanceId, 'config.frontal_cloud_id');
foreach ($this->getConfigArray($instanceId, 'users') as $userId) {
$this->p('Searching Single Circle for <comment>' . $userId . '@' . $instance . '</comment>');
$circle = $this->getSingleCircleForMember($members, $userId, $instance);
$compareToOwner = new Member();
$compareToOwner->setUserId($userId)
->setUserType(Member::TYPE_USER)
->setInstance($instance)
->setDisplayName($userId)
->setId('{CIRCLEID}')
->setCircleId('{CIRCLEID}')
->setSingleId('{CIRCLEID}')
->setStatus(Member::STATUS_MEMBER)
->setLevel(Member::LEVEL_OWNER);
$compareTo = new Circle();
$compareTo->setOwner($compareToOwner)
->setName('single:' . $userId . ':{CIRCLEID}')
->setDisplayName('single:' . $userId . ':{CIRCLEID}');
$this->confirmCircleData($circle, $compareTo);
$this->r(true, $circle->getId());
}
$this->p('Searching Single Circle for <comment>Circles App</comment>');
$circle = $this->getSingleCircleForMember($members, 'circles', $instance);
$compareToOwner = new Member();
$compareToOwner->setUserId(Application::APP_ID)
->setUserType(Member::TYPE_APP)
->setInstance($instance)
->setDisplayName(Application::APP_ID)
->setId('{CIRCLEID}')
->setCircleId('{CIRCLEID}')
->setSingleId('{CIRCLEID}')
->setStatus(Member::STATUS_MEMBER)
->setLevel(Member::LEVEL_OWNER);
$compareTo = new Circle();
$compareTo->setOwner($compareToOwner)
->setConfig(Circle::CFG_SINGLE)
// ->setConfig(Circle::CFG_HIDDEN + Circle::CFG_NO_OWNER + Circle::CFG_SYSTEM)
->setName('app:circles:{CIRCLEID}')
->setDisplayName('app:circles:{CIRCLEID}');
$this->confirmCircleData($circle, $compareTo);
$this->r(true, $circle->getId());
$this->output->writeln('');
}
}
/**
* @param array $circles
* @param string $userId
* @param string $instance
*
* @return Circle
* @throws CircleNotFoundException
*/
private function getSingleCircleForMember(array $circles, string $userId, string $instance): Circle {
$currMember = null;
foreach ($circles as $circle) {
$owner = $circle->getOwner();
if ($owner->getUserId() === $userId && $owner->getInstance() === $instance) {
return $circle;
}
}
throw new CircleNotFoundException('cannot find ' . $userId . ' in the list of Single Circle');
}
/**
* @param Circle $circle
* @param Circle $compareTo
*
* @throws Exception
*/
private function confirmCircleData(Circle $circle, Circle $compareTo) {
if ($circle->isConfig(Circle::CFG_SINGLE) && $circle->getConfig() !== Circle::CFG_SINGLE) {
throw new Exception('Circle is set as Single but have more flags');
}
$owner = $circle->getOwner();
$compareToOwner = $compareTo->getOwner();
$params = [
'CIRCLEID' => $circle->getId()
];
if ($compareTo->getName() !== ''
&& $this->feedStringWithParams($compareTo->getName(), $params) !== $circle->getName()) {
throw new Exception('wrong circle.name');
}
if ($compareTo->getDisplayName() !== ''
&& $this->feedStringWithParams($compareTo->getDisplayName(), $params)
!== $circle->getDisplayName()) {
throw new Exception('wrong circle.displayName');
}
if ($compareTo->getConfig() > 0
&& $compareTo->getConfig() !== $circle->getConfig()) {
throw new Exception('wrong circle.source');
}
if ($owner->getCircleId() !== $circle->getId()) {
throw new Exception('owner.circleId is different than circle.id');
}
if ($compareToOwner->getId() !== ''
&& $this->feedStringWithParams($compareToOwner->getId(), $params) !== $owner->getId()) {
throw new Exception('wrong owner.memberId');
}
if ($compareToOwner->getCircleId() !== ''
&& $this->feedStringWithParams($compareToOwner->getCircleId(), $params)
!== $owner->getCircleId()) {
throw new Exception('wrong owner.circleId');
}
if ($compareToOwner->getSingleId() !== ''
&& $this->feedStringWithParams($compareToOwner->getSingleId(), $params)
!== $owner->getSingleId()) {
throw new Exception('wrong owner.singleId');
}
if ($compareToOwner->getUserId() !== ''
&& $this->feedStringWithParams($compareToOwner->getUserId(), $params) !== $owner->getUserId()) {
throw new Exception('wrong owner.userId');
}
if ($compareToOwner->getInstance() !== ''
&& $this->feedStringWithParams($compareToOwner->getInstance(), $params)
!== $owner->getInstance()) {
throw new Exception('wrong owner.instance');
}
if ($compareToOwner->getUserType() > 0
&& $compareToOwner->getUserType() !== $owner->getUserType()) {
throw new Exception('wrong owner.userType');
}
}
/**
* @param bool $localIncluded
*
* @return array
*/
private function getInstances(bool $localIncluded = true): array {
$instances = self::$INSTANCES;
if (!$localIncluded) {
$instances = array_diff($instances, [$this->local]);
}
return $instances;
}
/**
* @param string $instance
* @param string $cmd
* @param string $key
*
* @return string
* @throws ItemNotFoundException
*/
private function getConfig(string $instance, string $key): string {
$config = $this->getConfigInstance($instance);
return $this->get($key, $config);
}
/**
* @param string $instance
* @param string $key
*
* @return array
* @throws ItemNotFoundException
*/
private function occ(string $instance, string $cmd): array {
$configInstance = $this->getConfigInstance($instance);
$path = $this->get('path', $configInstance);
$occ = rtrim($path, '/') . '/occ';
private function getConfigArray(string $instance, string $key): array {
$config = $this->getConfigInstance($instance);
$process = new Process(array_merge([$occ], explode(' ', $cmd), ['--output=json']));
$process->run();
return json_decode($process->getOutput(), true);
}
/**
*
*/
private function loadConfiguration() {
$configuration = file_get_contents(__DIR__ . '/../../testConfiguration.json');
$this->config = json_decode($configuration, true);
return $this->getArray($key, $config);
}
@ -173,7 +494,91 @@ class CirclesTest extends Base {
}
}
throw new ItemNotFoundException();
throw new ItemNotFoundException($instance . ' not found');
}
/**
* @param string $instance
* @param string $cmd
* @param bool $exceptionOnFail
* @param bool $jsonAsOutput
*
* @return array
* @throws ItemNotFoundException
* @throws Exception
*/
private function occ(
string $instance,
string $cmd,
bool $exceptionOnFail = true,
bool $jsonAsOutput = true
): ?array {
$configInstance = $this->getConfigInstance($instance);
$path = $this->get('path', $configInstance);
$occ = rtrim($path, '/') . '/occ';
$command = array_merge([$occ], explode(' ', $cmd));
if ($jsonAsOutput) {
$command = array_merge($command, ['--output=json']);
}
$process = new Process($command);
$process->run();
if ($exceptionOnFail && !$process->isSuccessful()) {
throw new Exception(implode(' ', $command) . ' failed');
}
$output = json_decode($process->getOutput(), true);
if (!is_array($output)) {
return null;
}
return $output;
}
//
//
//
/**
* @param string $title
*/
private function t(string $title): void {
$this->output->writeln('');
$this->output->writeln('<comment>### ' . $title . '</comment>');
$this->output->writeln('');
}
/**
* @param string $processing
*/
private function p(string $processing): void {
$this->pOn = true;
$this->output->write('- ' . $processing . ': ');
}
/**
* @param string $more
*/
private function pm(string $more): void {
$this->output->write($more . ' ');
}
/**
* @param bool $result
* @param string $info
*/
private function r(bool $result = true, string $info = ''): void {
$this->pOn = false;
if ($result) {
$this->output->writeln('<info>' . (($info !== '') ? $info : 'done') . '</info>');
} else {
$this->output->writeln('<error>fail</error>');
}
}
}

View file

@ -38,6 +38,136 @@
"test9"
]
}
},
{
"id": "global-scale-2",
"type": "GlobalScale",
"path": "/home/maxence/sites/federated/green/nextcloud",
"config": {
"frontal_cloud_id": "green.local",
"frontal_cloud_scheme": "http"
},
"users": [
"cult",
"test1",
"test2",
"test3",
"test4",
"test5",
"test6",
"test7",
"test8",
"test9"
],
"groups": {
"admin": [
"cult"
]
}
},
{
"id": "global-scale-3",
"type": "GlobalScale",
"path": "/home/maxence/sites/federated/purple/nextcloud",
"config": {
"frontal_cloud_id": "purple.local",
"frontal_cloud_scheme": "http"
},
"users": [
"cult",
"test1",
"test2",
"test3",
"test4",
"test5",
"test6",
"test7",
"test8",
"test9"
],
"groups": {
"admin": [
"cult"
]
}
},
{
"id": "passive",
"type": "Passive",
"path": "/home/maxence/sites/federated/passive/nextcloud",
"config": {
"frontal_cloud_id": "passive.local",
"frontal_cloud_scheme": "http"
},
"users": [
"cult",
"test1",
"test2",
"test3",
"test4",
"test5",
"test6",
"test7",
"test8",
"test9"
],
"groups": {
"admin": [
"cult"
]
}
},
{
"id": "external",
"type": "External",
"path": "/home/maxence/sites/federated/external/nextcloud",
"config": {
"frontal_cloud_id": "external.local",
"frontal_cloud_scheme": "http"
},
"users": [
"cult",
"test1",
"test2",
"test3",
"test4",
"test5",
"test6",
"test7",
"test8",
"test9"
],
"groups": {
"admin": [
"cult"
]
}
},
{
"id": "trusted",
"type": "Trusted",
"path": "/home/maxence/sites/federated/trusted/nextcloud",
"config": {
"frontal_cloud_id": "trusted.local",
"frontal_cloud_scheme": "http"
},
"users": [
"cult",
"test1",
"test2",
"test3",
"test4",
"test5",
"test6",
"test7",
"test8",
"test9"
],
"groups": {
"admin": [
"cult"
]
}
}
]
}