mirror of
https://github.com/friendica/friendica
synced 2025-05-12 07:04:09 +02:00
Merge branch 'develop' into phpstan-level-3
This commit is contained in:
commit
63558f92eb
50 changed files with 1362 additions and 611 deletions
|
@ -43,14 +43,10 @@ steps:
|
|||
- apt-get update -q
|
||||
- DEBIAN_FRONTEND=noninteractive apt-get install -q -y git
|
||||
- if [ ! -z "$${CI_COMMIT_PULL_REQUEST}" ]; then
|
||||
git fetch --no-tags origin ${CI_COMMIT_TARGET_BRANCH};
|
||||
CHANGED_FILES="$(git diff --name-only --diff-filter=ACMRTUXB $(git merge-base FETCH_HEAD origin/${CI_COMMIT_TARGET_BRANCH})..${CI_COMMIT_SHA})";
|
||||
git fetch --no-tags --unshallow origin ${CI_COMMIT_TARGET_BRANCH}:refs/remotes/origin/${CI_COMMIT_TARGET_BRANCH};
|
||||
CHANGED_FILES="$(git diff --name-only --diff-filter=ACMRTUXB $(git merge-base ${CI_COMMIT_SHA} origin/${CI_COMMIT_TARGET_BRANCH})..${CI_COMMIT_SHA})";
|
||||
else
|
||||
CHANGED_FILES="$(git diff --name-only --diff-filter=ACMRTUXB ${CI_COMMIT_SHA})";
|
||||
fi
|
||||
- if ! echo "$${CHANGED_FILES}" | grep -qE "^(\\.php-cs-fixer(\\.dist)?\\.php|composer\\.lock)$"; then
|
||||
EXTRA_ARGS=$(printf -- '--path-mode=intersection\n--\n%s' "$${CHANGED_FILES}");
|
||||
else
|
||||
EXTRA_ARGS='';
|
||||
fi
|
||||
- EXTRA_ARGS="--path-mode=intersection -- $${CHANGED_FILES}";
|
||||
- ./bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer check --config=.php-cs-fixer.dist.php -v --diff --using-cache=no $${EXTRA_ARGS}
|
||||
|
|
|
@ -153,6 +153,7 @@
|
|||
"dms/phpunit-arraysubset-asserts": "^0.3.1",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"mockery/mockery": "^1.3",
|
||||
"php-mock/php-mock-mockery": "^1.5",
|
||||
"php-mock/php-mock-phpunit": "^2.10",
|
||||
"phpmd/phpmd": "^2.15",
|
||||
"phpstan/phpstan": "^2.0",
|
||||
|
|
67
composer.lock
generated
67
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b77bf714197f04022a5feb001bf07852",
|
||||
"content-hash": "32af97f73ec49df2a6cfe98f11bc1d60",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asika/simple-console",
|
||||
|
@ -5441,6 +5441,71 @@
|
|||
],
|
||||
"time": "2024-02-10T21:37:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-mock/php-mock-mockery",
|
||||
"version": "1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-mock/php-mock-mockery.git",
|
||||
"reference": "291994acdc26daf1e3c659cfbe58b01eeb180b7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-mock/php-mock-mockery/zipball/291994acdc26daf1e3c659cfbe58b01eeb180b7f",
|
||||
"reference": "291994acdc26daf1e3c659cfbe58b01eeb180b7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"mockery/mockery": "^1",
|
||||
"php": ">=5.6",
|
||||
"php-mock/php-mock-integration": "^2.2.1 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4|^5|^8"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpmock\\mockery\\": "classes/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"WTFPL"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Markus Malkusch",
|
||||
"email": "markus@malkusch.de",
|
||||
"homepage": "http://markus.malkusch.de",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Mock built-in PHP functions (e.g. time()) with Mockery. This package relies on PHP's namespace fallback policy. No further extension is needed.",
|
||||
"homepage": "https://github.com/php-mock/php-mock-mockery",
|
||||
"keywords": [
|
||||
"BDD",
|
||||
"TDD",
|
||||
"function",
|
||||
"mock",
|
||||
"mockery",
|
||||
"stub",
|
||||
"test",
|
||||
"test double",
|
||||
"testing"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-mock/php-mock-mockery/issues",
|
||||
"source": "https://github.com/php-mock/php-mock-mockery/tree/1.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/michalbundyra",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-08T19:46:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-mock/php-mock-phpunit",
|
||||
"version": "2.10.0",
|
||||
|
|
|
@ -43,7 +43,7 @@ Some examples of common known configuration files:
|
|||
Addons can define their own default configuration values in `addon/[addon]/config/[addon].config.php` which is loaded when the addon is activated.
|
||||
|
||||
If needed, an alternative `config` path can be used by using the `FRIENDICA_CONFIG_DIR` environment variable (full path required!).
|
||||
This is useful in case of hardening the system by separating configuration from program binaries.
|
||||
This is useful in case of hardening the system by separating configuration from program binaries.
|
||||
|
||||
### Static Configuration location
|
||||
|
||||
|
@ -160,16 +160,6 @@ $a->config['register_policy'] = REGISTER_CLOSED;
|
|||
</tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
$a->path = "value";
|
||||
</pre></td>
|
||||
<td><pre>
|
||||
'system' => [
|
||||
'urlpath' => 'value',
|
||||
],
|
||||
</pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><pre>
|
||||
$default_timezone = "value";
|
||||
</pre></td>
|
||||
<td><pre>
|
||||
|
@ -313,7 +303,7 @@ Enabling the admin panel for an account, and thus making the account holder admi
|
|||
'config' => [
|
||||
'admin_email' => 'someone@example.com',
|
||||
]
|
||||
|
||||
|
||||
|
||||
Where you have to match the email address used for the account with the one you enter to the `config/local.config.php` file.
|
||||
If more than one account should be able to access the admin panel, separate the email addresses with a comma.
|
||||
|
|
|
@ -218,7 +218,6 @@ All options will be saved in the `config/local.config.php` and are overruling th
|
|||
- `-U|--dbuser <username>` The username of the mysql/mariadb database login (env `MYSQL_USER` or `MYSQL_USERNAME`)
|
||||
- `-P|--dbpass <password>` The password of the mysql/mariadb database login (env `MYSQL_PASSWORD`)
|
||||
- `-d|--dbdata <database>` The name of the mysql/mariadb database (env `MYSQL_DATABASE`)
|
||||
- `-u|--urlpath <url_path>` The URL path of Friendica - f.e. '/friendica' (env `FRIENDICA_URL_PATH`)
|
||||
- `-b|--phppath <php_path>` The path of the PHP binary (env `FRIENDICA_PHP_PATH`)
|
||||
- `-A|--admin <mail>` The admin email address of Friendica (env `FRIENDICA_ADMIN_MAIL`)
|
||||
- `-T|--tz <timezone>` The timezone of Friendica (env `FRIENDICA_TZ`)
|
||||
|
|
|
@ -419,7 +419,7 @@ We strongly discourage you from doing so, as this will break federation to other
|
|||
Say you have a subdirectory for tests and put Friendica into a further subdirectory, the config would be:
|
||||
|
||||
'system' => [
|
||||
'urlpath' => 'tests/friendica',
|
||||
'url' => 'https://example.com/tests/friendica',
|
||||
],
|
||||
|
||||
## Other exceptions
|
||||
|
|
|
@ -410,7 +410,7 @@ Wir raten allerdings dringen davon ab, da es die Interoperabilität mit anderen
|
|||
Mal angenommen, du hast ein Unterverzeichnis tests und willst Friendica in ein weiteres Unterverzeichnis installieren, dann lautet die Konfiguration hierfür:
|
||||
|
||||
'system' => [
|
||||
'urlpath' => 'tests/friendica',
|
||||
'url' => 'https://example.com/tests/friendica',
|
||||
],
|
||||
|
||||
## Weitere Ausnahmen
|
||||
|
|
35
doc/stats.md
Normal file
35
doc/stats.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
Monitoring
|
||||
===========
|
||||
|
||||
* [Home](help)
|
||||
|
||||
## Endpoints
|
||||
|
||||
Currently, there are two endpoints for statistics available
|
||||
|
||||
- `/stats` Returns some basic statistics of the current node
|
||||
- `/stats/caching` Returns statistics of cache or lock instances, which are used for the currend node
|
||||
|
||||
### `/stats`
|
||||
|
||||
The statistics contain data about the worker performance, the last cron call, number of reports, inbound and outbound packets, posts and comments.
|
||||
|
||||
### `/stats/caching`
|
||||
|
||||
The statistics contain data about the opcache, the used caching (like memory usage, hits/misses, entries, ...) and the used lock (including the cache data)
|
||||
|
||||
## Configuration
|
||||
|
||||
Please define 'stats_key' in your local.config.php in the 'system' section to be able to access the statistics page at /stats?key=your-defined-stats_key
|
||||
|
||||
## 3rd Party monitoring tools
|
||||
|
||||
### Zabbix
|
||||
|
||||
To monitor the health status of your Friendica installation, you can use for example a tool like Zabbix.
|
||||
|
||||
### Prometheus
|
||||
|
||||
To use [prometheus](https://prometheus.io) for gathering metrics, use the [Friendica exporter](https://git.friendi.ca/friendica/friendica-exporter).
|
||||
|
||||
You can find the installation instructions here: https://git.friendi.ca/friendica/friendica-exporter#installation
|
12
doc/tools.md
12
doc/tools.md
|
@ -78,15 +78,3 @@ The following will compress */var/log/friendica* (assuming this is the location
|
|||
daily
|
||||
rotate 2
|
||||
}
|
||||
|
||||
### Zabbix
|
||||
|
||||
To monitor the health status of your Friendica installation, you can use for example a tool like Zabbix. Please define 'stats_key' in your local.config.php in the 'system' section to be able to access the statistics page at /stats?key=your-defined-stats_key
|
||||
|
||||
The statistics contain data about the worker performance, the last cron call, number of reports, inbound and outbound packets, posts and comments.
|
||||
|
||||
### Prometheus
|
||||
|
||||
To use [prometheus](https://prometheus.io) for gathering metrics, use the [Friendica exporter](https://git.friendi.ca/friendica/friendica-exporter).
|
||||
|
||||
You can find the installation instructions here: https://git.friendi.ca/friendica/friendica-exporter#installation
|
||||
|
|
|
@ -17,8 +17,7 @@ use Psr\Http\Message\UriInterface;
|
|||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* A class which checks and contains the basic
|
||||
* environment for the BaseURL (url, urlpath, ssl_policy, hostname, scheme)
|
||||
* A class which checks and contains the basic environment for the BaseURL (url)
|
||||
*/
|
||||
class BaseURL extends Uri implements UriInterface
|
||||
{
|
||||
|
@ -43,8 +42,7 @@ class BaseURL extends Uri implements UriInterface
|
|||
/* Relative script path to the web server root
|
||||
* Not all of those $_SERVER properties can be present, so we do by inverse priority order
|
||||
*/
|
||||
$relativeScriptPath =
|
||||
($server['REDIRECT_URL'] ?? '') ?:
|
||||
$relativeScriptPath = ($server['REDIRECT_URL'] ?? '') ?:
|
||||
($server['REDIRECT_URI'] ?? '') ?:
|
||||
($server['REDIRECT_SCRIPT_URL'] ?? '') ?:
|
||||
($server['SCRIPT_URL'] ?? '') ?:
|
||||
|
|
|
@ -198,7 +198,7 @@ class Page implements ArrayAccess
|
|||
) {
|
||||
// Default title: current module called
|
||||
if (empty($this->page['title']) && $args->getModuleName()) {
|
||||
$this->page['title'] = ucfirst($args->getModuleName());
|
||||
$this->page['title'] = $l10n->t(ucfirst($args->getModuleName()));
|
||||
}
|
||||
|
||||
// Prepend the sitename to the page title
|
||||
|
|
|
@ -35,10 +35,12 @@ class TrendingTags
|
|||
}
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('widget/trending_tags.tpl');
|
||||
$o = Renderer::replaceMacros($tpl, [
|
||||
'$title' => DI::l10n()->tt('Trending Tags (last %d hour)', 'Trending Tags (last %d hours)', $period),
|
||||
'$more' => DI::l10n()->t('More Trending Tags'),
|
||||
'$tags' => $tags,
|
||||
$o = Renderer::replaceMacros($tpl, [
|
||||
'$title' => DI::l10n()->tt('Trending Tags (last %d hour)', 'Trending Tags (last %d hours)', $period),
|
||||
'$more' => DI::l10n()->t('More Trending Tags'),
|
||||
'$showmore' => DI::l10n()->t('Show More'),
|
||||
'$showless' => DI::l10n()->t('Show Less'),
|
||||
'$tags' => $tags,
|
||||
]);
|
||||
|
||||
return $o;
|
||||
|
|
|
@ -53,4 +53,11 @@ interface ICanCacheInMemory extends ICanCache
|
|||
* @throws CachePersistenceException In case the underlying cache driver has errors during persistence
|
||||
*/
|
||||
public function compareDelete(string $key, $value): bool;
|
||||
|
||||
/**
|
||||
* Returns some basic statistics of the used Cache instance
|
||||
*
|
||||
* @return array Returns an associative array of statistics
|
||||
*/
|
||||
public function getStats(): array;
|
||||
}
|
||||
|
|
|
@ -16,10 +16,9 @@ use Friendica\Core\Cache\Exception\InvalidCacheDriverException;
|
|||
*/
|
||||
class APCuCache extends AbstractCache implements ICanCacheInMemory
|
||||
{
|
||||
const NAME = 'apcu';
|
||||
|
||||
use CompareSetTrait;
|
||||
use CompareDeleteTrait;
|
||||
const NAME = 'apcu';
|
||||
|
||||
/**
|
||||
* @throws InvalidCacheDriverException
|
||||
|
@ -147,4 +146,19 @@ class APCuCache extends AbstractCache implements ICanCacheInMemory
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function getStats(): array
|
||||
{
|
||||
$apcu = apcu_cache_info();
|
||||
$sma = apcu_sma_info();
|
||||
|
||||
return [
|
||||
'entries' => $apcu['num_entries'] ?? null,
|
||||
'used_memory' => $apcu['mem_size'] ?? null,
|
||||
'hits' => $apcu['num_hits'] ?? null,
|
||||
'misses' => $apcu['num_misses'] ?? null,
|
||||
'avail_mem' => $sma['avail_mem'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,8 @@ use Friendica\Core\Cache\Enum;
|
|||
*/
|
||||
class ArrayCache extends AbstractCache implements ICanCacheInMemory
|
||||
{
|
||||
const NAME = 'array';
|
||||
|
||||
use CompareDeleteTrait;
|
||||
const NAME = 'array';
|
||||
|
||||
/** @var array Array with the cached data */
|
||||
protected $cachedData = [];
|
||||
|
@ -96,4 +95,10 @@ class ArrayCache extends AbstractCache implements ICanCacheInMemory
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function getStats(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,11 +19,10 @@ use Memcache;
|
|||
*/
|
||||
class MemcacheCache extends AbstractCache implements ICanCacheInMemory
|
||||
{
|
||||
const NAME = 'memcache';
|
||||
|
||||
use CompareSetTrait;
|
||||
use CompareDeleteTrait;
|
||||
use MemcacheCommandTrait;
|
||||
const NAME = 'memcache';
|
||||
|
||||
/**
|
||||
* @var Memcache
|
||||
|
@ -156,4 +155,21 @@ class MemcacheCache extends AbstractCache implements ICanCacheInMemory
|
|||
$cacheKey = $this->getCacheKey($key);
|
||||
return $this->memcache->add($cacheKey, serialize($value), MEMCACHE_COMPRESSED, $ttl);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function getStats(): array
|
||||
{
|
||||
$stats = $this->memcache->getStats();
|
||||
|
||||
return [
|
||||
'version' => $stats['version'] ?? null,
|
||||
'entries' => $stats['curr_items'] ?? null,
|
||||
'used_memory' => $stats['bytes'] ?? null,
|
||||
'uptime' => $stats['uptime'] ?? null,
|
||||
'connected_clients' => $stats['curr_connections'] ?? null,
|
||||
'hits' => $stats['get_hits'] ?? null,
|
||||
'misses' => $stats['get_misses'] ?? null,
|
||||
'evictions' => $stats['evictions'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,10 @@ use Psr\Log\LoggerInterface;
|
|||
*/
|
||||
class MemcachedCache extends AbstractCache implements ICanCacheInMemory
|
||||
{
|
||||
const NAME = 'memcached';
|
||||
|
||||
use CompareSetTrait;
|
||||
use CompareDeleteTrait;
|
||||
use MemcacheCommandTrait;
|
||||
const NAME = 'memcached';
|
||||
|
||||
/**
|
||||
* @var \Memcached
|
||||
|
@ -172,4 +171,27 @@ class MemcachedCache extends AbstractCache implements ICanCacheInMemory
|
|||
$cacheKey = $this->getCacheKey($key);
|
||||
return $this->memcached->add($cacheKey, $value, $ttl);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function getStats(): array
|
||||
{
|
||||
$stats = $this->memcached->getStats();
|
||||
|
||||
// get statistics of the first instance
|
||||
foreach ($stats as $value) {
|
||||
$stats = $value;
|
||||
break;
|
||||
}
|
||||
|
||||
return [
|
||||
'version' => $stats['version'] ?? null,
|
||||
'entries' => $stats['curr_items'] ?? null,
|
||||
'used_memory' => $stats['bytes'] ?? null,
|
||||
'uptime' => $stats['uptime'] ?? null,
|
||||
'connected_clients' => $stats['curr_connections'] ?? null,
|
||||
'hits' => $stats['get_hits'] ?? null,
|
||||
'misses' => $stats['get_misses'] ?? null,
|
||||
'evictions' => $stats['evictions'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,4 +166,14 @@ class ProfilerCacheDecorator implements ICanCache, ICanCacheInMemory
|
|||
{
|
||||
return $this->cache->getName() . ' (with profiler)';
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function getStats(): array
|
||||
{
|
||||
if ($this->cache instanceof ICanCacheInMemory) {
|
||||
return $this->cache->getStats();
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,4 +207,21 @@ class RedisCache extends AbstractCache implements ICanCacheInMemory
|
|||
$this->redis->unwatch();
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function getStats(): array
|
||||
{
|
||||
$info = $this->redis->info();
|
||||
|
||||
return [
|
||||
'version' => $info['redis_version'] ?? null,
|
||||
'entries' => $this->redis->dbSize() ?? null,
|
||||
'used_memory' => $info['used_memory'] ?? null,
|
||||
'connected_clients' => $info['connected_clients'] ?? null,
|
||||
'uptime' => $info['uptime_in_seconds'] ?? null,
|
||||
'hits' => $info['keyspace_hits'] ?? null,
|
||||
'misses' => $info['keyspace_misses'] ?? null,
|
||||
'evictions' => $info['evicted_keys'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Friendica\Core\Lock\Type;
|
||||
|
||||
use Friendica\Core\Cache\Capability\ICanCache;
|
||||
use Friendica\Core\Cache\Capability\ICanCacheInMemory;
|
||||
use Friendica\Core\Cache\Enum\Duration;
|
||||
use Friendica\Core\Cache\Exception\CachePersistenceException;
|
||||
|
@ -156,6 +155,16 @@ class CacheLock extends AbstractLock
|
|||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns stats about the cache provider
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCacheStats(): array
|
||||
{
|
||||
return $this->cache->getStats();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key The original key
|
||||
*
|
||||
|
|
|
@ -397,7 +397,7 @@ class Event
|
|||
{
|
||||
// First day of the week (0 = Sunday).
|
||||
$firstDay = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'calendar', 'first_day_of_week') ?? 0;
|
||||
$defaultView = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'calendar', 'defaultView') ?? 'month';
|
||||
$defaultView = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'calendar', 'default_view') ?? 'month';
|
||||
|
||||
return [
|
||||
'firstDay' => $firstDay,
|
||||
|
|
|
@ -7,11 +7,9 @@
|
|||
|
||||
namespace Friendica\Model;
|
||||
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
|
@ -26,13 +24,14 @@ class Nodeinfo
|
|||
*/
|
||||
public static function update()
|
||||
{
|
||||
$config = DI::config();
|
||||
$logger = DI::logger();
|
||||
$config = DI::config();
|
||||
$logger = DI::logger();
|
||||
$addonHelper = DI::addonHelper();
|
||||
|
||||
// If the addon 'statistics_json' is enabled then disable it and activate nodeinfo.
|
||||
if (Addon::isEnabled('statistics_json')) {
|
||||
if ($addonHelper->isAddonEnabled('statistics_json')) {
|
||||
$config->set('system', 'nodeinfo', true);
|
||||
Addon::uninstall('statistics_json');
|
||||
$addonHelper->uninstallAddon('statistics_json');
|
||||
}
|
||||
|
||||
if (empty($config->get('system', 'nodeinfo'))) {
|
||||
|
@ -50,12 +49,12 @@ class Nodeinfo
|
|||
|
||||
$logger->info('user statistics - done', $userStats);
|
||||
|
||||
$posts = DBA::count('post-thread', ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE NOT `deleted` AND `origin`)"]);
|
||||
$posts = DBA::count('post-thread', ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE NOT `deleted` AND `origin`)"]);
|
||||
$comments = DBA::count('post', ["NOT `deleted` AND `gravity` = ? AND `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)", Item::GRAVITY_COMMENT]);
|
||||
DI::keyValue()->set('nodeinfo_local_posts', $posts);
|
||||
DI::keyValue()->set('nodeinfo_local_comments', $comments);
|
||||
|
||||
$posts = DBA::count('post', ['deleted' => false, 'gravity' => Item::GRAVITY_COMMENT]);
|
||||
$posts = DBA::count('post', ['deleted' => false, 'gravity' => Item::GRAVITY_COMMENT]);
|
||||
$comments = DBA::count('post', ['deleted' => false, 'gravity' => Item::GRAVITY_COMMENT]);
|
||||
DI::keyValue()->set('nodeinfo_total_posts', $posts);
|
||||
DI::keyValue()->set('nodeinfo_total_comments', $comments);
|
||||
|
@ -66,21 +65,21 @@ class Nodeinfo
|
|||
/**
|
||||
* Return the supported services
|
||||
*
|
||||
* @return Object with supported services
|
||||
* @return stdClass with supported services
|
||||
*/
|
||||
public static function getUsage(bool $version2 = false)
|
||||
public static function getUsage(bool $version2 = false): stdClass
|
||||
{
|
||||
$config = DI::config();
|
||||
|
||||
$usage = new stdClass();
|
||||
$usage->users = new \stdClass;
|
||||
$usage = new stdClass();
|
||||
$usage->users = new stdClass();
|
||||
|
||||
if (!empty($config->get('system', 'nodeinfo'))) {
|
||||
$usage->users->total = intval(DI::keyValue()->get('nodeinfo_total_users'));
|
||||
$usage->users->total = intval(DI::keyValue()->get('nodeinfo_total_users'));
|
||||
$usage->users->activeHalfyear = intval(DI::keyValue()->get('nodeinfo_active_users_halfyear'));
|
||||
$usage->users->activeMonth = intval(DI::keyValue()->get('nodeinfo_active_users_monthly'));
|
||||
$usage->localPosts = intval(DI::keyValue()->get('nodeinfo_local_posts'));
|
||||
$usage->localComments = intval(DI::keyValue()->get('nodeinfo_local_comments'));
|
||||
$usage->users->activeMonth = intval(DI::keyValue()->get('nodeinfo_active_users_monthly'));
|
||||
$usage->localPosts = intval(DI::keyValue()->get('nodeinfo_local_posts'));
|
||||
$usage->localComments = intval(DI::keyValue()->get('nodeinfo_local_comments'));
|
||||
|
||||
if ($version2) {
|
||||
$usage->users->activeWeek = intval(DI::keyValue()->get('nodeinfo_active_users_weekly'));
|
||||
|
@ -97,45 +96,47 @@ class Nodeinfo
|
|||
*/
|
||||
public static function getServices(): array
|
||||
{
|
||||
$addonHelper = DI::addonHelper();
|
||||
|
||||
$services = [
|
||||
'inbound' => [],
|
||||
'outbound' => [],
|
||||
];
|
||||
|
||||
if (Addon::isEnabled('bluesky')) {
|
||||
$services['inbound'][] = 'bluesky';
|
||||
if ($addonHelper->isAddonEnabled('bluesky')) {
|
||||
$services['inbound'][] = 'bluesky';
|
||||
$services['outbound'][] = 'bluesky';
|
||||
}
|
||||
if (Addon::isEnabled('dwpost')) {
|
||||
if ($addonHelper->isAddonEnabled('dwpost')) {
|
||||
$services['outbound'][] = 'dreamwidth';
|
||||
}
|
||||
if (Addon::isEnabled('statusnet')) {
|
||||
$services['inbound'][] = 'gnusocial';
|
||||
if ($addonHelper->isAddonEnabled('statusnet')) {
|
||||
$services['inbound'][] = 'gnusocial';
|
||||
$services['outbound'][] = 'gnusocial';
|
||||
}
|
||||
if (Addon::isEnabled('ijpost')) {
|
||||
if ($addonHelper->isAddonEnabled('ijpost')) {
|
||||
$services['outbound'][] = 'insanejournal';
|
||||
}
|
||||
if (Addon::isEnabled('libertree')) {
|
||||
if ($addonHelper->isAddonEnabled('libertree')) {
|
||||
$services['outbound'][] = 'libertree';
|
||||
}
|
||||
if (Addon::isEnabled('ljpost')) {
|
||||
if ($addonHelper->isAddonEnabled('ljpost')) {
|
||||
$services['outbound'][] = 'livejournal';
|
||||
}
|
||||
if (Addon::isEnabled('pumpio')) {
|
||||
$services['inbound'][] = 'pumpio';
|
||||
if ($addonHelper->isAddonEnabled('pumpio')) {
|
||||
$services['inbound'][] = 'pumpio';
|
||||
$services['outbound'][] = 'pumpio';
|
||||
}
|
||||
|
||||
$services['outbound'][] = 'smtp';
|
||||
|
||||
if (Addon::isEnabled('tumblr')) {
|
||||
if ($addonHelper->isAddonEnabled('tumblr')) {
|
||||
$services['outbound'][] = 'tumblr';
|
||||
}
|
||||
if (Addon::isEnabled('twitter')) {
|
||||
if ($addonHelper->isAddonEnabled('twitter')) {
|
||||
$services['outbound'][] = 'twitter';
|
||||
}
|
||||
if (Addon::isEnabled('wppost')) {
|
||||
if ($addonHelper->isAddonEnabled('wppost')) {
|
||||
$services['outbound'][] = 'wordpress';
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
namespace Friendica\Module;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\App\Arguments;
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Addon\AddonHelper;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs;
|
||||
use Friendica\Core\L10n;
|
||||
|
@ -23,13 +25,27 @@ class Statistics extends BaseModule
|
|||
protected $config;
|
||||
/** @var IManageKeyValuePairs */
|
||||
protected $keyValue;
|
||||
private AddonHelper $addonHelper;
|
||||
|
||||
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, IManageConfigValues $config, IManageKeyValuePairs $keyValue, Response $response, array $server, array $parameters = [])
|
||||
{
|
||||
public function __construct(
|
||||
L10n $l10n,
|
||||
BaseURL $baseUrl,
|
||||
Arguments $args,
|
||||
LoggerInterface $logger,
|
||||
Profiler $profiler,
|
||||
IManageConfigValues $config,
|
||||
IManageKeyValuePairs $keyValue,
|
||||
AddonHelper $addonHelper,
|
||||
Response $response,
|
||||
array $server,
|
||||
array $parameters = []
|
||||
) {
|
||||
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->config = $config;
|
||||
$this->keyValue = $keyValue;
|
||||
$this->config = $config;
|
||||
$this->keyValue = $keyValue;
|
||||
$this->addonHelper = $addonHelper;
|
||||
|
||||
if (!$this->config->get("system", "nodeinfo")) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
@ -37,22 +53,21 @@ class Statistics extends BaseModule
|
|||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
$registration_open =
|
||||
Register::getPolicy() !== Register::CLOSED
|
||||
$registration_open = Register::getPolicy() !== Register::CLOSED
|
||||
&& !$this->config->get('config', 'invitation_only');
|
||||
|
||||
/// @todo mark the "service" addons and load them dynamically here
|
||||
$services = [
|
||||
'appnet' => Addon::isEnabled('appnet'),
|
||||
'bluesky' => Addon::isEnabled('bluesky'),
|
||||
'dreamwidth' => Addon::isEnabled('dreamwidth'),
|
||||
'gnusocial' => Addon::isEnabled('gnusocial'),
|
||||
'libertree' => Addon::isEnabled('libertree'),
|
||||
'livejournal' => Addon::isEnabled('livejournal'),
|
||||
'pumpio' => Addon::isEnabled('pumpio'),
|
||||
'twitter' => Addon::isEnabled('twitter'),
|
||||
'tumblr' => Addon::isEnabled('tumblr'),
|
||||
'wordpress' => Addon::isEnabled('wordpress'),
|
||||
'appnet' => $this->addonHelper->isAddonEnabled('appnet'),
|
||||
'bluesky' => $this->addonHelper->isAddonEnabled('bluesky'),
|
||||
'dreamwidth' => $this->addonHelper->isAddonEnabled('dreamwidth'),
|
||||
'gnusocial' => $this->addonHelper->isAddonEnabled('gnusocial'),
|
||||
'libertree' => $this->addonHelper->isAddonEnabled('libertree'),
|
||||
'livejournal' => $this->addonHelper->isAddonEnabled('livejournal'),
|
||||
'pumpio' => $this->addonHelper->isAddonEnabled('pumpio'),
|
||||
'twitter' => $this->addonHelper->isAddonEnabled('twitter'),
|
||||
'tumblr' => $this->addonHelper->isAddonEnabled('tumblr'),
|
||||
'wordpress' => $this->addonHelper->isAddonEnabled('wordpress'),
|
||||
];
|
||||
|
||||
$statistics = array_merge([
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
namespace Friendica\Module;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\App\Arguments;
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Addon\AddonHelper;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs;
|
||||
use Friendica\Core\L10n;
|
||||
|
@ -40,14 +42,28 @@ class Stats extends BaseModule
|
|||
protected $logger;
|
||||
/** @var IManageKeyValuePairs */
|
||||
protected $keyValue;
|
||||
private AddonHelper $addonHelper;
|
||||
|
||||
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, IManageConfigValues $config, IManageKeyValuePairs $keyValue, Database $dba, Response $response, array $server, array $parameters = [])
|
||||
{
|
||||
public function __construct(
|
||||
L10n $l10n,
|
||||
BaseURL $baseUrl,
|
||||
Arguments $args,
|
||||
LoggerInterface $logger,
|
||||
Profiler $profiler,
|
||||
IManageConfigValues $config,
|
||||
IManageKeyValuePairs $keyValue,
|
||||
Database $dba,
|
||||
AddonHelper $addonHelper,
|
||||
Response $response,
|
||||
array $server,
|
||||
array $parameters = []
|
||||
) {
|
||||
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->config = $config;
|
||||
$this->keyValue = $keyValue;
|
||||
$this->dba = $dba;
|
||||
$this->config = $config;
|
||||
$this->keyValue = $keyValue;
|
||||
$this->dba = $dba;
|
||||
$this->addonHelper = $addonHelper;
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
|
@ -85,14 +101,14 @@ class Stats extends BaseModule
|
|||
'datetime' => DateTimeFormat::utc($this->keyValue->get('last_worker_execution'), DateTimeFormat::JSON),
|
||||
'timestamp' => strtotime($this->keyValue->get('last_worker_execution')),
|
||||
],
|
||||
'jpm' => [
|
||||
'jpm' => [
|
||||
1 => $this->dba->count('workerqueue', ["`done` AND `executed` > ?", DateTimeFormat::utc('now - 1 minute')]),
|
||||
3 => round($this->dba->count('workerqueue', ["`done` AND `executed` > ?", DateTimeFormat::utc('now - 3 minute')]) / 3),
|
||||
5 => round($this->dba->count('workerqueue', ["`done` AND `executed` > ?", DateTimeFormat::utc('now - 5 minute')]) / 5),
|
||||
],
|
||||
'active' => [],
|
||||
'deferred' => [],
|
||||
'total' => [],
|
||||
'active' => [],
|
||||
'deferred' => [],
|
||||
'total' => [],
|
||||
],
|
||||
'jetstream' => [
|
||||
'drift' => intval($this->keyValue->get('jetstream_drift')),
|
||||
|
@ -145,14 +161,14 @@ class Stats extends BaseModule
|
|||
'closed' => $this->dba->count('report', ['status' => Report::STATUS_CLOSED]),
|
||||
],
|
||||
'update' => [
|
||||
'available' => Update::isAvailable(),
|
||||
'available' => Update::isAvailable(),
|
||||
'available_version' => Update::getAvailableVersion(),
|
||||
'status' => Update::getStatus(),
|
||||
'db_status' => DBStructure::getUpdateStatus(),
|
||||
'db_status' => DBStructure::getUpdateStatus(),
|
||||
],
|
||||
'server' => [
|
||||
'version' => App::VERSION,
|
||||
'php' => [
|
||||
'version' => App::VERSION,
|
||||
'php' => [
|
||||
'version' => phpversion(),
|
||||
'upload_max_filesize' => ini_get('upload_max_filesize'),
|
||||
'post_max_size' => ini_get('post_max_size'),
|
||||
|
@ -164,12 +180,12 @@ class Stats extends BaseModule
|
|||
],
|
||||
];
|
||||
|
||||
if (Addon::isEnabled('bluesky')) {
|
||||
$statistics['packets']['inbound'][Protocol::BLUESKY] = intval($this->keyValue->get('stats_packets_inbound_' . Protocol::BLUESKY) ?? 0);
|
||||
if ($this->addonHelper->isAddonEnabled('bluesky')) {
|
||||
$statistics['packets']['inbound'][Protocol::BLUESKY] = intval($this->keyValue->get('stats_packets_inbound_' . Protocol::BLUESKY) ?? 0);
|
||||
$statistics['packets']['outbound'][Protocol::BLUESKY] = intval($this->keyValue->get('stats_packets_outbound_' . Protocol::BLUESKY) ?? 0);
|
||||
}
|
||||
if (Addon::isEnabled('tumblr')) {
|
||||
$statistics['packets']['inbound'][Protocol::TUMBLR] = intval($this->keyValue->get('stats_packets_inbound_' . Protocol::TUMBLR) ?? 0);
|
||||
if ($this->addonHelper->isAddonEnabled('tumblr')) {
|
||||
$statistics['packets']['inbound'][Protocol::TUMBLR] = intval($this->keyValue->get('stats_packets_inbound_' . Protocol::TUMBLR) ?? 0);
|
||||
$statistics['packets']['outbound'][Protocol::TUMBLR] = intval($this->keyValue->get('stats_packets_outbound_' . Protocol::TUMBLR) ?? 0);
|
||||
}
|
||||
|
||||
|
@ -202,7 +218,7 @@ class Stats extends BaseModule
|
|||
|
||||
$jobs = $this->dba->p("SELECT COUNT(*) AS `entries`, `priority` FROM `workerqueue` WHERE NOT `done` AND `retrial` = ? GROUP BY `priority`", 0);
|
||||
while ($entry = $this->dba->fetch($jobs)) {
|
||||
$running = $this->dba->count('workerqueue-view', ['priority' => $entry['priority']]);
|
||||
$running = $this->dba->count('workerqueue-view', ['priority' => $entry['priority']]);
|
||||
$statistics['worker']['active']['total'] += $running;
|
||||
$statistics['worker']['active'][$entry['priority']] = $running;
|
||||
$statistics['worker']['total']['total'] += $entry['entries'];
|
||||
|
|
108
src/Module/StatsCaching.php
Normal file
108
src/Module/StatsCaching.php
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
namespace Friendica\Module;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\Cache\Capability\ICanCache;
|
||||
use Friendica\Core\Cache\Capability\ICanCacheInMemory;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
use Friendica\Core\Lock\Type\CacheLock;
|
||||
use Friendica\Network\HTTPException\NotFoundException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
||||
/**
|
||||
* Returns statistics of Cache / Lock instances
|
||||
*
|
||||
* @todo Currently not possible to get distributed cache statistics in case the distributed cache (for sessions) is different to the normal cache (not possible to get the distributed cache instance yet)
|
||||
*/
|
||||
class StatsCaching extends BaseModule
|
||||
{
|
||||
private IManageConfigValues $config;
|
||||
private ICanCache $cache;
|
||||
private ICanLock $lock;
|
||||
|
||||
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, IManageConfigValues $config, ICanCache $cache, ICanLock $lock, array $parameters = [])
|
||||
{
|
||||
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->config = $config;
|
||||
$this->cache = $cache;
|
||||
$this->lock = $lock;
|
||||
}
|
||||
|
||||
private function isAllowed(array $request): bool
|
||||
{
|
||||
return !empty($request['key']) && $request['key'] == $this->config->get('system', 'stats_key');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotFoundException In case the rquest isn't allowed
|
||||
*/
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
if (!$this->isAllowed($request)) {
|
||||
throw new HTTPException\NotFoundException($this->l10n->t('Page not found.'));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
if (!$this->isAllowed($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = [];
|
||||
|
||||
// OPcache
|
||||
if (function_exists('opcache_get_status')) {
|
||||
$status = opcache_get_status(false);
|
||||
$data['opcache'] = [
|
||||
'enabled' => $status['opcache_enabled'] ?? false,
|
||||
'hit_rate' => $status['opcache_statistics']['opcache_hit_rate'] ?? null,
|
||||
'used_memory' => $status['memory_usage']['used_memory'] ?? null,
|
||||
'free_memory' => $status['memory_usage']['free_memory'] ?? null,
|
||||
'num_cached_scripts' => $status['opcache_statistics']['num_cached_scripts'] ?? null,
|
||||
];
|
||||
} else {
|
||||
$data['opcache'] = [
|
||||
'enabled' => false,
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->cache instanceof ICanCacheInMemory) {
|
||||
$data['cache'] = [
|
||||
'type' => $this->cache->getName(),
|
||||
'stats' => $this->cache->getStats(),
|
||||
];
|
||||
} else {
|
||||
$data['cache'] = [
|
||||
'type' => $this->cache->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->lock instanceof CacheLock) {
|
||||
$data['lock'] = [
|
||||
'type' => $this->lock->getName(),
|
||||
'stats' => $this->lock->getCacheStats(),
|
||||
];
|
||||
} else {
|
||||
$data['lock'] = [
|
||||
'type' => $this->lock->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
$this->response->setType('json', 'application/json; charset=utf-8');
|
||||
$this->response->addContent(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ namespace Friendica\Object;
|
|||
|
||||
use Friendica\Content\ContactSelector;
|
||||
use Friendica\Content\Feature;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\DI;
|
||||
|
@ -1118,12 +1117,14 @@ class Post
|
|||
$conv = $this->getThread();
|
||||
|
||||
if ($conv->isWritable() && $this->isWritable()) {
|
||||
$addonHelper = DI::addonHelper();
|
||||
|
||||
/*
|
||||
* Hmmm, code depending on the presence of a particular addon?
|
||||
* This should be better if done by a hook
|
||||
*/
|
||||
$qcomment = null;
|
||||
if (Addon::isEnabled('qcomment')) {
|
||||
if ($addonHelper->isAddonEnabled('qcomment')) {
|
||||
$words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'qcomment', 'words');
|
||||
$qcomment = $words ? explode("\n", $words) : [];
|
||||
}
|
||||
|
|
|
@ -327,7 +327,7 @@ class Processor
|
|||
|
||||
private function getHeaderFromJetstream(stdClass $data, int $uid, int $protocol = Conversation::PARCEL_JETSTREAM): array
|
||||
{
|
||||
$contact = $this->actor->getContactByDID($data->did, $uid, 0);
|
||||
$contact = $this->actor->getContactByDID($data->did, $uid, 0, true);
|
||||
if (empty($contact)) {
|
||||
$this->logger->info('Contact not found for user', ['did' => $data->did, 'uid' => $uid]);
|
||||
return [];
|
||||
|
@ -392,7 +392,7 @@ class Processor
|
|||
if (empty($post->author) || empty($post->cid) || empty($parts->rkey)) {
|
||||
return [];
|
||||
}
|
||||
$contact = $this->actor->getContactByDID($post->author->did, $uid, 0);
|
||||
$contact = $this->actor->getContactByDID($post->author->did, $uid, 0, true);
|
||||
if (empty($contact)) {
|
||||
$this->logger->info('Contact not found for user', ['did' => $post->author->did, 'uid' => $uid]);
|
||||
return [];
|
||||
|
|
|
@ -126,6 +126,11 @@ return [
|
|||
// Display "Emoji Only" posts in big.
|
||||
'big_emojis' => true,
|
||||
|
||||
// basepath (String)
|
||||
// Absolute file path to your Friendica install
|
||||
// Examples: /var/www, /home/user/friendica...
|
||||
'basepath' => '',
|
||||
|
||||
// bulk_delivery (Boolean)
|
||||
// Delivers AP messages in a bulk (experimental)
|
||||
'bulk_delivery' => false,
|
||||
|
@ -577,6 +582,12 @@ return [
|
|||
// Transmit pending events upon accepted contact request for groups
|
||||
'transmit_pending_events' => false,
|
||||
|
||||
// url (String)
|
||||
// The absolute URL used to access your Friendica node. It should include the scheme, the domain name, and the
|
||||
// sub-folder if any. Used by command-line processes to send correct links to your Friendica server.
|
||||
// Example: https://example.com/friendica
|
||||
'url' => '',
|
||||
|
||||
// username_min_length (Integer)
|
||||
// The minimum character length a username can be.
|
||||
// This length is checked once the username has been trimmed and multiple spaces have been collapsed into one.
|
||||
|
|
|
@ -642,7 +642,8 @@ return [
|
|||
],
|
||||
],
|
||||
|
||||
'/stats' => [Module\Stats::class, [R::GET]],
|
||||
'/stats' => [Module\Stats::class, [R::GET]],
|
||||
'/stats/caching' => [Module\StatsCaching::class, [R::GET]],
|
||||
|
||||
'/network' => [
|
||||
'[/{content}]' => [Module\Conversation\Network::class, [R::GET]],
|
||||
|
|
26
tests/CacheLockTestCase.php
Normal file
26
tests/CacheLockTestCase.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
namespace Friendica\Test;
|
||||
|
||||
use Friendica\Core\Cache\Capability\ICanCacheInMemory;
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
|
||||
abstract class CacheLockTestCase extends LockTestCase
|
||||
{
|
||||
abstract protected function getCache(): ICanCacheInMemory;
|
||||
|
||||
abstract protected function getInstance(): ICanLock;
|
||||
|
||||
/**
|
||||
* Test if the getStats() result is identically to the getCacheStats()
|
||||
*/
|
||||
public function testGetStats()
|
||||
{
|
||||
self::assertSame(array_keys($this->getCache()->getStats()), array_keys($this->instance->getCacheStats()));
|
||||
}
|
||||
}
|
|
@ -8,21 +8,17 @@
|
|||
namespace Friendica\Test;
|
||||
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
use Friendica\Test\MockedTestCase;
|
||||
|
||||
abstract class LockTestCase extends MockedTestCase
|
||||
{
|
||||
/**
|
||||
* @var int Start time of the mock (used for time operations)
|
||||
* Start time of the mock (used for time operations)
|
||||
*/
|
||||
protected $startTime = 1417011228;
|
||||
protected int $startTime = 1417011228;
|
||||
protected ICanLock $instance;
|
||||
|
||||
/**
|
||||
* @var ICanLock
|
||||
*/
|
||||
protected $instance;
|
||||
abstract protected function getInstance(): ICanLock;
|
||||
|
||||
abstract protected function getInstance();
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
|
@ -205,4 +201,6 @@ abstract class LockTestCase extends MockedTestCase
|
|||
self::assertFalse($this->instance->isLocked('wrongLock'));
|
||||
self::assertFalse($this->instance->release('wrongLock'));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ return [
|
|||
'temppath' => '/tmp/friendica.local',
|
||||
'theme' => 'frio',
|
||||
'url' => 'https://friendica.local',
|
||||
'urlpath' => '',
|
||||
'build' => 1508,
|
||||
'maintenance' => false,
|
||||
'dbupdate' => 1,
|
||||
|
|
|
@ -129,7 +129,6 @@ class AutomaticInstallationConsoleTest extends ConsoleTestCase
|
|||
],
|
||||
'system' => [
|
||||
'basepath' => '',
|
||||
'urlpath' => '',
|
||||
'url' => 'http://friendica.local',
|
||||
'ssl_policy' => 0,
|
||||
'default_timezone' => '',
|
||||
|
@ -152,7 +151,6 @@ class AutomaticInstallationConsoleTest extends ConsoleTestCase
|
|||
'admin_email' => 'admin@philipp.info',
|
||||
],
|
||||
'system' => [
|
||||
'urlpath' => 'test/it',
|
||||
'url' => 'http://friendica.local/test/it',
|
||||
'basepath' => '',
|
||||
'ssl_policy' => '2',
|
||||
|
@ -176,7 +174,6 @@ class AutomaticInstallationConsoleTest extends ConsoleTestCase
|
|||
'admin_email' => 'admin@philipp.info',
|
||||
],
|
||||
'system' => [
|
||||
'urlpath' => 'test/it',
|
||||
'url' => 'https://friendica.local/test/it',
|
||||
'basepath' => '',
|
||||
'ssl_policy' => '1',
|
||||
|
@ -352,7 +349,6 @@ FIN;
|
|||
self::assertConfigEntry('system', 'default_timezone', $assertion, ($default) ? Installer::DEFAULT_TZ : null);
|
||||
self::assertConfigEntry('system', 'language', $assertion, ($default) ? Installer::DEFAULT_LANG : null);
|
||||
self::assertConfigEntry('system', 'url', $assertion);
|
||||
self::assertConfigEntry('system', 'urlpath', $assertion);
|
||||
self::assertConfigEntry('system', 'ssl_policy', $assertion, ($default) ? App\BaseURL::DEFAULT_SSL_SCHEME : null);
|
||||
self::assertConfigEntry('system', 'basepath', ($realBasepath) ? $this->root->url() : $assertion);
|
||||
}
|
||||
|
@ -446,7 +442,6 @@ return [
|
|||
],
|
||||
'system' => [
|
||||
'basepath' => '{$conf('system', 'basepath')}',
|
||||
'urlpath' => '{$conf('system', 'urlpath')}',
|
||||
'url' => '{$conf('system', 'url')}',
|
||||
'ssl_policy' => '{$conf('system', 'ssl_policy')}',
|
||||
'default_timezone' => '{$conf('system', 'default_timezone')}',
|
||||
|
@ -604,7 +599,7 @@ CONF;
|
|||
self::assertStuckDB($txt);
|
||||
self::assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.config.php'));
|
||||
|
||||
self::assertConfig(['config' => ['hostname' => 'friendica.local'], 'system' => ['url' => 'http://friendica.local', 'ssl_policy' => 0, 'urlpath' => '']], false, true, false, true);
|
||||
self::assertConfig(['config' => ['hostname' => 'friendica.local'], 'system' => ['url' => 'http://friendica.local', 'ssl_policy' => 0]], false, true, false, true);
|
||||
}
|
||||
|
||||
public function testGetHelp()
|
||||
|
|
|
@ -35,4 +35,18 @@ class APCuCacheTest extends MemoryCacheTestCase
|
|||
$this->cache->clear(false);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @small
|
||||
*/
|
||||
public function testStats()
|
||||
{
|
||||
$stats = $this->instance->getStats();
|
||||
|
||||
self::assertNotNull($stats['entries']);
|
||||
self::assertNotNull($stats['used_memory']);
|
||||
self::assertNotNull($stats['hits']);
|
||||
self::assertNotNull($stats['misses']);
|
||||
self::assertNotNull($stats['avail_mem']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,4 +33,12 @@ class ArrayCacheTest extends MemoryCacheTestCase
|
|||
self::markTestSkipped("Array Cache doesn't support TTL");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @small
|
||||
*/
|
||||
public function testGetStats()
|
||||
{
|
||||
self::assertEmpty($this->cache->getStats());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,4 +59,21 @@ class MemcacheCacheTest extends MemoryCacheTestCase
|
|||
{
|
||||
static::markTestIncomplete('Race condition because of too fast getAllKeys() which uses a workaround');
|
||||
}
|
||||
|
||||
/**
|
||||
* @small
|
||||
*/
|
||||
public function testStats()
|
||||
{
|
||||
$stats = $this->instance->getStats();
|
||||
|
||||
self::assertNotNull($stats['version']);
|
||||
self::assertIsNumeric($stats['hits']);
|
||||
self::assertIsNumeric($stats['misses']);
|
||||
self::assertIsNumeric($stats['evictions']);
|
||||
self::assertIsNumeric($stats['entries']);
|
||||
self::assertIsNumeric($stats['used_memory']);
|
||||
self::assertGreaterThan(0, $stats['connected_clients']);
|
||||
self::assertGreaterThan(0, $stats['uptime']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,4 +58,21 @@ class MemcachedCacheTest extends MemoryCacheTestCase
|
|||
{
|
||||
static::markTestIncomplete('Race condition because of too fast getAllKeys() which uses a workaround');
|
||||
}
|
||||
|
||||
/**
|
||||
* @small
|
||||
*/
|
||||
public function testStats()
|
||||
{
|
||||
$stats = $this->instance->getStats();
|
||||
|
||||
self::assertNotNull($stats['version']);
|
||||
self::assertIsNumeric($stats['hits']);
|
||||
self::assertIsNumeric($stats['misses']);
|
||||
self::assertIsNumeric($stats['evictions']);
|
||||
self::assertIsNumeric($stats['entries']);
|
||||
self::assertIsNumeric($stats['used_memory']);
|
||||
self::assertGreaterThan(0, $stats['connected_clients']);
|
||||
self::assertGreaterThan(0, $stats['uptime']);
|
||||
}
|
||||
}
|
||||
|
|
56
tests/src/Core/Cache/ProfilerCacheDecoratorTest.php
Normal file
56
tests/src/Core/Cache/ProfilerCacheDecoratorTest.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
namespace Core\Cache;
|
||||
|
||||
use Friendica\Core\Cache\Type\ArrayCache;
|
||||
use Friendica\Core\Cache\Type\ProfilerCacheDecorator;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Test\MemoryCacheTestCase;
|
||||
use Friendica\Util\Profiler;
|
||||
|
||||
class ProfilerCacheDecoratorTest extends MemoryCacheTestCase
|
||||
{
|
||||
protected function getInstance()
|
||||
{
|
||||
$config = \Mockery::mock(IManageConfigValues::class);
|
||||
$config->shouldReceive('get')->with('system', 'profiler')->once()->andReturn(false);
|
||||
$config->shouldReceive('get')->with('rendertime', 'callstack')->once()->andReturn(false);
|
||||
|
||||
$this->cache = new ProfilerCacheDecorator(new ArrayCache('localhost'), new Profiler($config));
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$this->cache->clear(false);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testTTL()
|
||||
{
|
||||
// Array Cache doesn't support TTL
|
||||
self::markTestSkipped("Array Cache doesn't support TTL");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @small
|
||||
*/
|
||||
public function testGetStats()
|
||||
{
|
||||
self::assertEmpty($this->cache->getStats());
|
||||
}
|
||||
|
||||
public function testGetName()
|
||||
{
|
||||
self::assertStringEndsWith(' (with profiler)', $this->instance->getName());
|
||||
}
|
||||
}
|
|
@ -57,4 +57,21 @@ class RedisCacheTest extends MemoryCacheTestCase
|
|||
$this->cache->clear(false);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @small
|
||||
*/
|
||||
public function testStats()
|
||||
{
|
||||
$stats = $this->instance->getStats();
|
||||
|
||||
self::assertNotNull($stats['version']);
|
||||
self::assertIsNumeric($stats['hits']);
|
||||
self::assertIsNumeric($stats['misses']);
|
||||
self::assertIsNumeric($stats['evictions']);
|
||||
self::assertIsNumeric($stats['entries']);
|
||||
self::assertIsNumeric($stats['used_memory']);
|
||||
self::assertGreaterThan(0, $stats['connected_clients']);
|
||||
self::assertGreaterThan(0, $stats['uptime']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,26 +7,39 @@
|
|||
|
||||
namespace Friendica\Test\src\Core\Lock;
|
||||
|
||||
use Friendica\Core\Cache\Capability\ICanCacheInMemory;
|
||||
use Friendica\Core\Cache\Type\APCuCache;
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
use Friendica\Core\Lock\Type\CacheLock;
|
||||
use Friendica\Test\LockTestCase;
|
||||
use Friendica\Test\CacheLockTestCase;
|
||||
|
||||
/**
|
||||
* @group APCU
|
||||
*/
|
||||
class APCuCacheLockTest extends LockTestCase
|
||||
class APCuCacheLockTest extends CacheLockTestCase
|
||||
{
|
||||
private APCuCache $cache;
|
||||
private ICanLock $lock;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
if (!APCuCache::isAvailable()) {
|
||||
static::markTestSkipped('APCu is not available');
|
||||
}
|
||||
|
||||
$this->cache = new APCuCache('localhost');
|
||||
$this->lock = new CacheLock($this->cache);
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
protected function getInstance()
|
||||
protected function getInstance(): CacheLock
|
||||
{
|
||||
return new CacheLock(new APCuCache('localhost'));
|
||||
return $this->lock;
|
||||
}
|
||||
|
||||
protected function getCache(): ICanCacheInMemory
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,15 +7,32 @@
|
|||
|
||||
namespace Friendica\Test\src\Core\Lock;
|
||||
|
||||
use Friendica\Core\Cache\Capability\ICanCacheInMemory;
|
||||
use Friendica\Core\Cache\Type\ArrayCache;
|
||||
use Friendica\Core\Lock\Type\CacheLock;
|
||||
use Friendica\Test\LockTestCase;
|
||||
use Friendica\Test\CacheLockTestCase;
|
||||
|
||||
class ArrayCacheLockTest extends LockTestCase
|
||||
class ArrayCacheLockTest extends CacheLockTestCase
|
||||
{
|
||||
protected function getInstance()
|
||||
private CacheLock $lock;
|
||||
private ArrayCache $cache;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
return new CacheLock(new ArrayCache('localhost'));
|
||||
$this->cache = new ArrayCache('localhost');
|
||||
$this->lock = new CacheLock($this->cache);
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
protected function getInstance(): CacheLock
|
||||
{
|
||||
return $this->lock;
|
||||
}
|
||||
|
||||
protected function getCache(): ICanCacheInMemory
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Friendica\Test\src\Core\Lock;
|
||||
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
use Friendica\Core\Lock\Type\DatabaseLock;
|
||||
use Friendica\Test\LockTestCase;
|
||||
use Friendica\Test\Util\CreateDatabaseTrait;
|
||||
|
@ -26,7 +27,7 @@ class DatabaseLockDriverTest extends LockTestCase
|
|||
parent::setUp();
|
||||
}
|
||||
|
||||
protected function getInstance()
|
||||
protected function getInstance(): ICanLock
|
||||
{
|
||||
return new DatabaseLock($this->getDbInstance(), $this->pid);
|
||||
}
|
||||
|
|
|
@ -8,19 +8,23 @@
|
|||
namespace Friendica\Test\src\Core\Lock;
|
||||
|
||||
use Exception;
|
||||
use Friendica\Core\Cache\Capability\ICanCacheInMemory;
|
||||
use Friendica\Core\Cache\Type\MemcacheCache;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Lock\Type\CacheLock;
|
||||
use Friendica\Test\LockTestCase;
|
||||
use Friendica\Test\CacheLockTestCase;
|
||||
use Mockery;
|
||||
|
||||
/**
|
||||
* @requires extension Memcache
|
||||
* @group MEMCACHE
|
||||
*/
|
||||
class MemcacheCacheLockTest extends LockTestCase
|
||||
class MemcacheCacheLockTest extends CacheLockTestCase
|
||||
{
|
||||
protected function getInstance()
|
||||
private CacheLock $lock;
|
||||
private MemcacheCache $cache;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$configMock = Mockery::mock(IManageConfigValues::class);
|
||||
|
||||
|
@ -36,16 +40,24 @@ class MemcacheCacheLockTest extends LockTestCase
|
|||
->with('system', 'memcache_port')
|
||||
->andReturn($port);
|
||||
|
||||
$lock = null;
|
||||
|
||||
try {
|
||||
$cache = new MemcacheCache($host, $configMock);
|
||||
$lock = new CacheLock($cache);
|
||||
$this->cache = new MemcacheCache($host, $configMock);
|
||||
$this->lock = new CacheLock($this->cache);
|
||||
} catch (Exception $e) {
|
||||
static::markTestSkipped('Memcache is not available');
|
||||
}
|
||||
|
||||
return $lock;
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
protected function getInstance(): CacheLock
|
||||
{
|
||||
return $this->lock;
|
||||
}
|
||||
|
||||
protected function getCache(): ICanCacheInMemory
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
namespace Friendica\Test\src\Core\Lock;
|
||||
|
||||
use Exception;
|
||||
use Friendica\Core\Cache\Capability\ICanCacheInMemory;
|
||||
use Friendica\Core\Cache\Type\MemcachedCache;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Lock\Type\CacheLock;
|
||||
use Friendica\Test\LockTestCase;
|
||||
use Friendica\Test\CacheLockTestCase;
|
||||
use Mockery;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
|
@ -19,9 +20,12 @@ use Psr\Log\NullLogger;
|
|||
* @requires extension memcached
|
||||
* @group MEMCACHED
|
||||
*/
|
||||
class MemcachedCacheLockTest extends LockTestCase
|
||||
class MemcachedCacheLockTest extends CacheLockTestCase
|
||||
{
|
||||
protected function getInstance()
|
||||
private MemcachedCache $cache;
|
||||
private CacheLock $lock;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$configMock = Mockery::mock(IManageConfigValues::class);
|
||||
|
||||
|
@ -35,16 +39,24 @@ class MemcachedCacheLockTest extends LockTestCase
|
|||
|
||||
$logger = new NullLogger();
|
||||
|
||||
$lock = null;
|
||||
|
||||
try {
|
||||
$cache = new MemcachedCache($host, $configMock, $logger);
|
||||
$lock = new CacheLock($cache);
|
||||
$this->cache = new MemcachedCache($host, $configMock, $logger);
|
||||
$this->lock = new CacheLock($this->cache);
|
||||
} catch (Exception $e) {
|
||||
static::markTestSkipped('Memcached is not available');
|
||||
}
|
||||
|
||||
return $lock;
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
protected function getInstance(): CacheLock
|
||||
{
|
||||
return $this->lock;
|
||||
}
|
||||
|
||||
protected function getCache(): ICanCacheInMemory
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,19 +8,20 @@
|
|||
namespace Friendica\Test\src\Core\Lock;
|
||||
|
||||
use Exception;
|
||||
use Friendica\Core\Cache\Capability\ICanCacheInMemory;
|
||||
use Friendica\Core\Cache\Type\RedisCache;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Lock\Type\CacheLock;
|
||||
use Friendica\Test\LockTestCase;
|
||||
use Friendica\Test\CacheLockTestCase;
|
||||
use Mockery;
|
||||
|
||||
/**
|
||||
* @requires extension redis
|
||||
* @group REDIS
|
||||
*/
|
||||
class RedisCacheLockTest extends LockTestCase
|
||||
class RedisCacheLockTest extends CacheLockTestCase
|
||||
{
|
||||
protected function getInstance()
|
||||
protected function setUp(): void
|
||||
{
|
||||
$configMock = Mockery::mock(IManageConfigValues::class);
|
||||
|
||||
|
@ -45,15 +46,23 @@ class RedisCacheLockTest extends LockTestCase
|
|||
->with('system', 'redis_password')
|
||||
->andReturn(null);
|
||||
|
||||
$lock = null;
|
||||
|
||||
try {
|
||||
$cache = new RedisCache($host, $configMock);
|
||||
$lock = new CacheLock($cache);
|
||||
$this->cache = new RedisCache($host, $configMock);
|
||||
$this->lock = new CacheLock($this->cache);
|
||||
} catch (Exception $e) {
|
||||
static::markTestSkipped('Redis is not available. Error: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return $lock;
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
protected function getInstance(): CAcheLock
|
||||
{
|
||||
return $this->lock;
|
||||
}
|
||||
|
||||
protected function getCache(): ICanCacheInMemory
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use Friendica\App;
|
|||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Config\Model\ReadOnlyFileConfig;
|
||||
use Friendica\Core\Config\ValueObject\Cache;
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
use Friendica\Core\Lock\Type\SemaphoreLock;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\DI;
|
||||
|
@ -31,7 +32,7 @@ class SemaphoreLockTest extends LockTestCase
|
|||
$dice->shouldReceive('create')->with(App::class)->andReturn($app);
|
||||
|
||||
$configCache = new Cache(['system' => ['temppath' => '/tmp']]);
|
||||
$configMock = new ReadOnlyFileConfig($configCache);
|
||||
$configMock = new ReadOnlyFileConfig($configCache);
|
||||
$dice->shouldReceive('create')->with(IManageConfigValues::class)->andReturn($configMock);
|
||||
|
||||
// @todo Because "get_temppath()" is using static methods, we have to initialize the BaseObject
|
||||
|
@ -40,7 +41,7 @@ class SemaphoreLockTest extends LockTestCase
|
|||
parent::setUp();
|
||||
}
|
||||
|
||||
protected function getInstance()
|
||||
protected function getInstance(): ICanLock
|
||||
{
|
||||
return new SemaphoreLock();
|
||||
}
|
||||
|
|
203
tests/src/Module/StatsCachingTest.php
Normal file
203
tests/src/Module/StatsCachingTest.php
Normal file
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
|
||||
// Copyright (C) 2010-2024, the Friendica project
|
||||
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
namespace Friendica\Test\src\Module;
|
||||
|
||||
use Friendica\Capabilities\ICanCreateResponses;
|
||||
use Friendica\Core\Cache\Capability\ICanCache;
|
||||
use Friendica\Core\Cache\Type\ArrayCache;
|
||||
use Friendica\Core\Cache\Type\DatabaseCache;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
use Friendica\Core\Lock\Type\CacheLock;
|
||||
use Friendica\Core\Lock\Type\DatabaseLock;
|
||||
use Friendica\DI;
|
||||
use Friendica\Module\Special\HTTPException;
|
||||
use Friendica\Module\StatsCaching;
|
||||
use Friendica\Test\FixtureTestCase;
|
||||
use Mockery\MockInterface;
|
||||
use phpmock\mockery\PHPMockery;
|
||||
|
||||
class StatsCachingTest extends FixtureTestCase
|
||||
{
|
||||
/** @var MockInterface|HTTPException */
|
||||
protected $httpExceptionMock;
|
||||
|
||||
protected ICanCache $cache;
|
||||
protected ICanLock $lock;
|
||||
|
||||
/** @var MockInterface|IManageConfigValues */
|
||||
protected $config;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->httpExceptionMock = \Mockery::mock(HTTPException::class);
|
||||
$this->config = \Mockery::mock(IManageConfigValues::class);
|
||||
$this->cache = new ArrayCache('localhost');
|
||||
$this->lock = new CacheLock($this->cache);
|
||||
}
|
||||
|
||||
public function testStatsCachingNotAllowed()
|
||||
{
|
||||
$this->httpExceptionMock->shouldReceive('content')->andReturn('failed')->once();
|
||||
|
||||
$response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
|
||||
->run($this->httpExceptionMock);
|
||||
|
||||
self::assertEquals('404', $response->getStatusCode());
|
||||
self::assertEquals('Page not found', $response->getReasonPhrase());
|
||||
self::assertEquals('failed', $response->getBody());
|
||||
}
|
||||
|
||||
public function testStatsCachingWitMinimumCache()
|
||||
{
|
||||
$request = [
|
||||
'key' => '12345',
|
||||
];
|
||||
$this->config->shouldReceive('get')->with('system', 'stats_key')->twice()->andReturn('12345');
|
||||
PHPMockery::mock("Friendica\\Module", "function_exists")->with('opcache_get_status')->once()->andReturn(false);
|
||||
|
||||
$response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
|
||||
->run($this->httpExceptionMock, $request);
|
||||
|
||||
self::assertJson($response->getBody());
|
||||
self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders());
|
||||
|
||||
$json = json_decode($response->getBody(), true);
|
||||
|
||||
self::assertEquals([
|
||||
'type' => 'array',
|
||||
'stats' => [],
|
||||
], $json['cache']);
|
||||
self::assertEquals([
|
||||
'type' => 'array',
|
||||
'stats' => [],
|
||||
], $json['lock']);
|
||||
}
|
||||
|
||||
public function testStatsCachingWithDatabase()
|
||||
{
|
||||
$request = [
|
||||
'key' => '12345',
|
||||
];
|
||||
$this->config->shouldReceive('get')->with('system', 'stats_key')->twice()->andReturn('12345');
|
||||
|
||||
$this->cache = new DatabaseCache('localhost', DI::dba());
|
||||
$this->lock = new DatabaseLock(DI::dba());
|
||||
PHPMockery::mock("Friendica\\Module", "function_exists")->with('opcache_get_status')->once()->andReturn(false);
|
||||
|
||||
$response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
|
||||
->run($this->httpExceptionMock, $request);
|
||||
|
||||
self::assertJson($response->getBody());
|
||||
self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders());
|
||||
|
||||
$json = json_decode($response->getBody(), true);
|
||||
|
||||
self::assertEquals(['enabled' => false], $json['opcache']);
|
||||
self::assertEquals(['type' => 'database'], $json['cache']);
|
||||
self::assertEquals(['type' => 'database'], $json['lock']);
|
||||
}
|
||||
|
||||
public function testStatsCachingWithCache()
|
||||
{
|
||||
$request = [
|
||||
'key' => '12345',
|
||||
];
|
||||
$this->config->shouldReceive('get')->with('system', 'stats_key')->twice()->andReturn('12345');
|
||||
|
||||
$this->cache = new DatabaseCache('localhost', DI::dba());
|
||||
$this->lock = new DatabaseLock(DI::dba());
|
||||
PHPMockery::mock("Friendica\\Module", "function_exists")->with('opcache_get_status')->once()->andReturn(false);
|
||||
|
||||
$response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
|
||||
->run($this->httpExceptionMock, $request);
|
||||
|
||||
self::assertJson($response->getBody());
|
||||
self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders());
|
||||
|
||||
$json = json_decode($response->getBody(), true);
|
||||
|
||||
self::assertEquals(['enabled' => false], $json['opcache']);
|
||||
self::assertEquals(['type' => 'database'], $json['cache']);
|
||||
self::assertEquals(['type' => 'database'], $json['lock']);
|
||||
}
|
||||
|
||||
public function testStatsCachingWithOpcacheAndNull()
|
||||
{
|
||||
$request = [
|
||||
'key' => '12345',
|
||||
];
|
||||
$this->config->shouldReceive('get')->with('system', 'stats_key')->twice()->andReturn('12345');
|
||||
|
||||
$this->cache = new DatabaseCache('localhost', DI::dba());
|
||||
$this->lock = new DatabaseLock(DI::dba());
|
||||
PHPMockery::mock("Friendica\\Module", "function_exists")->with('opcache_get_status')->once()->andReturn(true);
|
||||
PHPMockery::mock("Friendica\\Module", "opcache_get_status")->with(false)->once()->andReturn(false);
|
||||
|
||||
$response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
|
||||
->run($this->httpExceptionMock, $request);
|
||||
|
||||
self::assertJson($response->getBody());
|
||||
self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders());
|
||||
|
||||
$json = json_decode($response->getBody(), true);
|
||||
|
||||
self::assertEquals([
|
||||
'enabled' => false,
|
||||
'hit_rate' => null,
|
||||
'used_memory' => null,
|
||||
'free_memory' => null,
|
||||
'num_cached_scripts' => null,
|
||||
], $json['opcache']);
|
||||
self::assertEquals(['type' => 'database'], $json['cache']);
|
||||
self::assertEquals(['type' => 'database'], $json['lock']);
|
||||
}
|
||||
|
||||
public function testStatsCachingWithOpcacheAndValues()
|
||||
{
|
||||
$request = [
|
||||
'key' => '12345',
|
||||
];
|
||||
$this->config->shouldReceive('get')->with('system', 'stats_key')->twice()->andReturn('12345');
|
||||
|
||||
$this->cache = new DatabaseCache('localhost', DI::dba());
|
||||
$this->lock = new DatabaseLock(DI::dba());
|
||||
PHPMockery::mock("Friendica\\Module", "function_exists")->with('opcache_get_status')->once()->andReturn(true);
|
||||
PHPMockery::mock("Friendica\\Module", "opcache_get_status")->with(false)->once()->andReturn([
|
||||
'opcache_enabled' => true,
|
||||
'opcache_statistics' => [
|
||||
'opcache_hit_rate' => 1,
|
||||
'num_cached_scripts' => 2,
|
||||
],
|
||||
'memory_usage' => [
|
||||
'used_memory' => 3,
|
||||
'free_memory' => 4,
|
||||
]
|
||||
]);
|
||||
|
||||
$response = (new StatsCaching(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], $this->config, $this->cache, $this->lock, []))
|
||||
->run($this->httpExceptionMock, $request);
|
||||
|
||||
self::assertJson($response->getBody());
|
||||
self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders());
|
||||
|
||||
$json = json_decode($response->getBody(), true);
|
||||
|
||||
self::assertEquals([
|
||||
'enabled' => true,
|
||||
'hit_rate' => 1,
|
||||
'used_memory' => 3,
|
||||
'free_memory' => 4,
|
||||
'num_cached_scripts' => 2,
|
||||
], $json['opcache']);
|
||||
self::assertEquals(['type' => 'database'], $json['cache']);
|
||||
self::assertEquals(['type' => 'database'], $json['lock']);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -27,7 +27,7 @@
|
|||
<div style="text-align: left; margin-top: 10px;">
|
||||
<a href="#" onclick="toggleTags(event)" role="button" aria-expanded="false" aria-controls="more-tags" style="text-decoration: none; color: inherit; cursor: pointer; display: inline-flex; align-items: center; font-weight: bold;">
|
||||
<i id="caret-icon" class="fa fa-caret-right" aria-hidden="true" style="margin-right: 5px;"></i>
|
||||
<span id="link-text">Show More</span>
|
||||
<span id="link-text">{{$showmore}}</span>
|
||||
</a>
|
||||
</div>
|
||||
<ul id="more-tags" style="display:none; list-style-type: none; padding: 0; margin: 0;">
|
||||
|
@ -53,16 +53,16 @@
|
|||
|
||||
if (moreTags.style.display === 'none') {
|
||||
moreTags.style.display = 'block';
|
||||
linkText.textContent = 'Show Less';
|
||||
linkText.textContent = '{{$showless}}';
|
||||
link.setAttribute('aria-expanded', 'true');
|
||||
caretIcon.className = 'fa fa-caret-down';
|
||||
} else {
|
||||
moreTags.style.display = 'none';
|
||||
linkText.textContent = 'Show More';
|
||||
linkText.textContent = '{{$showmore}}';
|
||||
link.setAttribute('aria-expanded', 'false');
|
||||
caretIcon.className = 'fa fa-caret-right';
|
||||
}
|
||||
}
|
||||
|
||||
initWidget('trending-tags-sidebar', 'trending-tags-sidebar-inflated');
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
@ -14,9 +14,8 @@
|
|||
* Description: "Vier" is a very compact and modern theme. It uses the font awesome font library: http://fortawesome.github.com/Font-Awesome/
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\App\Mode;
|
||||
use Friendica\Content\GroupManager;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\Search;
|
||||
use Friendica\Database\DBA;
|
||||
|
@ -35,7 +34,7 @@ function vier_init()
|
|||
$args = DI::args();
|
||||
|
||||
if (
|
||||
DI::mode()->has(App\Mode::MAINTENANCEDISABLED)
|
||||
DI::mode()->has(Mode::MAINTENANCEDISABLED)
|
||||
&& (
|
||||
$args->get(0) === 'profile' && $args->get(1) === (DI::userSession()->getLocalUserNickname() ?? '')
|
||||
|| $args->get(0) === 'network' && DI::userSession()->getLocalUserId()
|
||||
|
@ -93,7 +92,7 @@ EOT;
|
|||
// Hide the left menu bar
|
||||
/// @TODO maybe move this static array out where it should belong?
|
||||
if (empty(DI::page()['aside']) && in_array($args->get(0), ["community", "calendar", "help", "delegation", "notifications",
|
||||
"probe", "webfinger", "login", "invite", "credits"])) {
|
||||
"probe", "webfinger", "login", "invite", "credits"])) {
|
||||
DI::page()['htmlhead'] .= "<link rel='stylesheet' href='view/theme/vier/hide.css' />";
|
||||
}
|
||||
}
|
||||
|
@ -117,12 +116,12 @@ function get_vier_config($key, $default = false, $admin = false)
|
|||
|
||||
function vier_community_info()
|
||||
{
|
||||
$show_pages = get_vier_config("show_pages", 1);
|
||||
$show_profiles = get_vier_config("show_profiles", 1);
|
||||
$show_helpers = get_vier_config("show_helpers", 1);
|
||||
$show_services = get_vier_config("show_services", 1);
|
||||
$show_friends = get_vier_config("show_friends", 1);
|
||||
$show_lastusers = get_vier_config("show_lastusers", 1);
|
||||
$show_pages = get_vier_config("show_pages", 1);
|
||||
$show_profiles = get_vier_config("show_profiles", 1);
|
||||
$show_helpers = get_vier_config("show_helpers", 1);
|
||||
$show_services = get_vier_config("show_services", 1);
|
||||
$show_friends = get_vier_config("show_friends", 1);
|
||||
$show_lastusers = get_vier_config("show_lastusers", 1);
|
||||
|
||||
// get_baseurl
|
||||
$aside['$url'] = $url = (string)DI::baseUrl();
|
||||
|
@ -138,10 +137,10 @@ function vier_community_info()
|
|||
|
||||
foreach ($contacts as $contact) {
|
||||
$entry = Renderer::replaceMacros($tpl, [
|
||||
'$id' => $contact['id'],
|
||||
'$id' => $contact['id'],
|
||||
'$profile_link' => 'contact/follow?url=' . urlencode($contact['url']),
|
||||
'$photo' => Contact::getMicro($contact),
|
||||
'$alt_text' => $contact['name'],
|
||||
'$photo' => Contact::getMicro($contact),
|
||||
'$alt_text' => $contact['name'],
|
||||
]);
|
||||
$aside['$community_profiles_items'][] = $entry;
|
||||
}
|
||||
|
@ -165,11 +164,11 @@ function vier_community_info()
|
|||
|
||||
foreach ($profiles as $profile) {
|
||||
$profile_link = 'profile/' . ((strlen($profile['nickname'])) ? $profile['nickname'] : $profile['uid']);
|
||||
$entry = Renderer::replaceMacros($tpl, [
|
||||
'$id' => $profile['id'],
|
||||
$entry = Renderer::replaceMacros($tpl, [
|
||||
'$id' => $profile['id'],
|
||||
'$profile_link' => $profile_link,
|
||||
'$photo' => DI::baseUrl()->remove($profile['thumb']),
|
||||
'$alt_text' => $profile['name']]);
|
||||
'$photo' => DI::baseUrl()->remove($profile['thumb']),
|
||||
'$alt_text' => $profile['name']]);
|
||||
$aside['$lastusers_items'][] = $entry;
|
||||
}
|
||||
}
|
||||
|
@ -177,18 +176,18 @@ function vier_community_info()
|
|||
|
||||
//right_aside FIND FRIENDS
|
||||
if ($show_friends && DI::userSession()->getLocalUserId()) {
|
||||
$nv = [];
|
||||
$nv['findpeople'] = DI::l10n()->t('Find People');
|
||||
$nv['desc'] = DI::l10n()->t('Enter name or interest');
|
||||
$nv['label'] = DI::l10n()->t('Connect/Follow');
|
||||
$nv['hint'] = DI::l10n()->t('Examples: Robert Morgenstein, Fishing');
|
||||
$nv['findthem'] = DI::l10n()->t('Find');
|
||||
$nv['suggest'] = DI::l10n()->t('Friend Suggestions');
|
||||
$nv['similar'] = DI::l10n()->t('Similar Interests');
|
||||
$nv['random'] = DI::l10n()->t('Random Profile');
|
||||
$nv['inv'] = DI::l10n()->t('Invite Friends');
|
||||
$nv['directory'] = DI::l10n()->t('Global Directory');
|
||||
$nv['global_dir'] = Search::getGlobalDirectory();
|
||||
$nv = [];
|
||||
$nv['findpeople'] = DI::l10n()->t('Find People');
|
||||
$nv['desc'] = DI::l10n()->t('Enter name or interest');
|
||||
$nv['label'] = DI::l10n()->t('Connect/Follow');
|
||||
$nv['hint'] = DI::l10n()->t('Examples: Robert Morgenstein, Fishing');
|
||||
$nv['findthem'] = DI::l10n()->t('Find');
|
||||
$nv['suggest'] = DI::l10n()->t('Friend Suggestions');
|
||||
$nv['similar'] = DI::l10n()->t('Similar Interests');
|
||||
$nv['random'] = DI::l10n()->t('Random Profile');
|
||||
$nv['inv'] = DI::l10n()->t('Invite Friends');
|
||||
$nv['directory'] = DI::l10n()->t('Global Directory');
|
||||
$nv['global_dir'] = Search::getGlobalDirectory();
|
||||
$nv['local_directory'] = DI::l10n()->t('Local Directory');
|
||||
|
||||
$aside['$nv'] = $nv;
|
||||
|
@ -224,14 +223,14 @@ function vier_community_info()
|
|||
$tpl = Renderer::getMarkupTemplate('ch_helpers.tpl');
|
||||
|
||||
if ($r) {
|
||||
$helpers = [];
|
||||
$helpers = [];
|
||||
$helpers['title'] = ["", DI::l10n()->t('Help'), "", ""];
|
||||
|
||||
$aside['$helpers_items'] = [];
|
||||
|
||||
foreach ($r as $rr) {
|
||||
$entry = Renderer::replaceMacros($tpl, [
|
||||
'$url' => $rr['url'],
|
||||
'$url' => $rr['url'],
|
||||
'$title' => $rr['name'],
|
||||
]);
|
||||
$aside['$helpers_items'][] = $entry;
|
||||
|
@ -244,55 +243,57 @@ function vier_community_info()
|
|||
|
||||
// connectable services
|
||||
if ($show_services) {
|
||||
$addonHelper = DI::addonHelper();
|
||||
|
||||
/// @TODO This whole thing is hard-coded, better rewrite to Intercepting Filter Pattern (future-todo)
|
||||
$r = [];
|
||||
|
||||
if (Addon::isEnabled("buffer")) {
|
||||
if ($addonHelper->isAddonEnabled("buffer")) {
|
||||
$r[] = ["photo" => "images/buffer.png", "name" => "Buffer"];
|
||||
}
|
||||
|
||||
if (Addon::isEnabled("blogger")) {
|
||||
if ($addonHelper->isAddonEnabled("blogger")) {
|
||||
$r[] = ["photo" => "images/blogger.png", "name" => "Blogger"];
|
||||
}
|
||||
|
||||
if (Addon::isEnabled("dwpost")) {
|
||||
if ($addonHelper->isAddonEnabled("dwpost")) {
|
||||
$r[] = ["photo" => "images/dreamwidth.png", "name" => "Dreamwidth"];
|
||||
}
|
||||
|
||||
if (Addon::isEnabled("ifttt")) {
|
||||
if ($addonHelper->isAddonEnabled("ifttt")) {
|
||||
$r[] = ["photo" => "addon/ifttt/ifttt.png", "name" => "IFTTT"];
|
||||
}
|
||||
|
||||
if (Addon::isEnabled("statusnet")) {
|
||||
if ($addonHelper->isAddonEnabled("statusnet")) {
|
||||
$r[] = ["photo" => "images/gnusocial.png", "name" => "GNU Social"];
|
||||
}
|
||||
|
||||
/// @TODO old-lost code (and below)?
|
||||
//if (Addon::isEnabled("ijpost")) {
|
||||
//if ($addonHelper->isAddonEnabled("ijpost")) {
|
||||
// $r[] = array("photo" => "images/", "name" => "");
|
||||
//}
|
||||
|
||||
if (Addon::isEnabled("libertree")) {
|
||||
if ($addonHelper->isAddonEnabled("libertree")) {
|
||||
$r[] = ["photo" => "images/libertree.png", "name" => "Libertree"];
|
||||
}
|
||||
|
||||
//if (Addon::isEnabled("ljpost")) {
|
||||
//if ($addonHelper->isAddonEnabled("ljpost")) {
|
||||
// $r[] = array("photo" => "images/", "name" => "");
|
||||
//}
|
||||
|
||||
if (Addon::isEnabled("pumpio")) {
|
||||
if ($addonHelper->isAddonEnabled("pumpio")) {
|
||||
$r[] = ["photo" => "images/pumpio.png", "name" => "pump.io"];
|
||||
}
|
||||
|
||||
if (Addon::isEnabled("tumblr")) {
|
||||
if ($addonHelper->isAddonEnabled("tumblr")) {
|
||||
$r[] = ["photo" => "images/tumblr.png", "name" => "Tumblr"];
|
||||
}
|
||||
|
||||
if (Addon::isEnabled("twitter")) {
|
||||
if ($addonHelper->isAddonEnabled("twitter")) {
|
||||
$r[] = ["photo" => "images/twitter.png", "name" => "Twitter"];
|
||||
}
|
||||
|
||||
if (Addon::isEnabled("wppost")) {
|
||||
if ($addonHelper->isAddonEnabled("wppost")) {
|
||||
$r[] = ["photo" => "images/wordpress.png", "name" => "Wordpress"];
|
||||
}
|
||||
|
||||
|
@ -303,14 +304,14 @@ function vier_community_info()
|
|||
$tpl = Renderer::getMarkupTemplate('ch_connectors.tpl');
|
||||
|
||||
if (DBA::isResult($r)) {
|
||||
$con_services = [];
|
||||
$con_services['title'] = ["", DI::l10n()->t('Connect Services'), "", ""];
|
||||
$con_services = [];
|
||||
$con_services['title'] = ["", DI::l10n()->t('Connect Services'), "", ""];
|
||||
$aside['$con_services'] = $con_services;
|
||||
|
||||
foreach ($r as $rr) {
|
||||
$entry = Renderer::replaceMacros($tpl, [
|
||||
'$url' => $url,
|
||||
'$photo' => $rr['photo'],
|
||||
'$url' => $url,
|
||||
'$photo' => $rr['photo'],
|
||||
'$alt_text' => $rr['name'],
|
||||
]);
|
||||
$aside['$connector_items'][] = $entry;
|
||||
|
@ -320,7 +321,7 @@ function vier_community_info()
|
|||
//end connectable services
|
||||
|
||||
//print right_aside
|
||||
$tpl = Renderer::getMarkupTemplate('communityhome.tpl');
|
||||
$tpl = Renderer::getMarkupTemplate('communityhome.tpl');
|
||||
DI::page()['right_aside'] = Renderer::replaceMacros($tpl, $aside);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue