You've already forked wp-prometheus
189 tests across 8 test classes covering all core plugin classes: CustomMetricBuilder, StorageFactory, Authentication, DashboardProvider, RuntimeCollector, Installer, Collector, and MetricsEndpoint. Added test job to Gitea release workflow that gates build-release. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
412 lines
14 KiB
PHP
412 lines
14 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Magdev\WpPrometheus\Tests\Unit\Metrics;
|
|
|
|
use Magdev\WpPrometheus\Metrics\StorageFactory;
|
|
use Magdev\WpPrometheus\Tests\Helpers\GlobalFunctionState;
|
|
use Magdev\WpPrometheus\Tests\Unit\TestCase;
|
|
use PHPUnit\Framework\Attributes\CoversClass;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use Prometheus\Storage\InMemory;
|
|
|
|
#[CoversClass(StorageFactory::class)]
|
|
class StorageFactoryTest extends TestCase
|
|
{
|
|
/** @var list<string> Environment variables to clean up after each test. */
|
|
private array $envVarsToClean = [];
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
StorageFactory::reset();
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
StorageFactory::reset();
|
|
foreach ($this->envVarsToClean as $var) {
|
|
putenv($var);
|
|
}
|
|
$this->envVarsToClean = [];
|
|
parent::tearDown();
|
|
}
|
|
|
|
// ── Adapter Constants ────────────────────────────────────────────
|
|
|
|
#[Test]
|
|
public function adapter_constants_are_defined(): void
|
|
{
|
|
$this->assertSame('inmemory', StorageFactory::ADAPTER_INMEMORY);
|
|
$this->assertSame('redis', StorageFactory::ADAPTER_REDIS);
|
|
$this->assertSame('apcu', StorageFactory::ADAPTER_APCU);
|
|
}
|
|
|
|
// ── get_available_adapters() ─────────────────────────────────────
|
|
|
|
#[Test]
|
|
public function get_available_adapters_returns_all_three(): void
|
|
{
|
|
$adapters = StorageFactory::get_available_adapters();
|
|
|
|
$this->assertArrayHasKey(StorageFactory::ADAPTER_INMEMORY, $adapters);
|
|
$this->assertArrayHasKey(StorageFactory::ADAPTER_REDIS, $adapters);
|
|
$this->assertArrayHasKey(StorageFactory::ADAPTER_APCU, $adapters);
|
|
$this->assertCount(3, $adapters);
|
|
}
|
|
|
|
// ── is_adapter_available() ───────────────────────────────────────
|
|
|
|
#[Test]
|
|
public function inmemory_adapter_is_always_available(): void
|
|
{
|
|
$this->assertTrue(StorageFactory::is_adapter_available(StorageFactory::ADAPTER_INMEMORY));
|
|
}
|
|
|
|
#[Test]
|
|
public function unknown_adapter_is_not_available(): void
|
|
{
|
|
$this->assertFalse(StorageFactory::is_adapter_available('unknown'));
|
|
}
|
|
|
|
#[Test]
|
|
public function redis_availability_depends_on_extension(): void
|
|
{
|
|
$extensionLoaded = $this->getFunctionMock(
|
|
'Magdev\\WpPrometheus\\Metrics',
|
|
'extension_loaded'
|
|
);
|
|
$extensionLoaded->expects($this->any())->willReturn(false);
|
|
|
|
$this->assertFalse(StorageFactory::is_adapter_available(StorageFactory::ADAPTER_REDIS));
|
|
}
|
|
|
|
#[Test]
|
|
public function apcu_availability_requires_extension_and_enabled(): void
|
|
{
|
|
$extensionLoaded = $this->getFunctionMock(
|
|
'Magdev\\WpPrometheus\\Metrics',
|
|
'extension_loaded'
|
|
);
|
|
$extensionLoaded->expects($this->any())->willReturn(true);
|
|
|
|
$apcuEnabled = $this->getFunctionMock(
|
|
'Magdev\\WpPrometheus\\Metrics',
|
|
'apcu_enabled'
|
|
);
|
|
$apcuEnabled->expects($this->any())->willReturn(false);
|
|
|
|
$this->assertFalse(StorageFactory::is_adapter_available(StorageFactory::ADAPTER_APCU));
|
|
}
|
|
|
|
// ── get_configured_adapter() ─────────────────────────────────────
|
|
|
|
#[Test]
|
|
public function default_configured_adapter_is_inmemory(): void
|
|
{
|
|
$this->assertSame('inmemory', StorageFactory::get_configured_adapter());
|
|
}
|
|
|
|
#[Test]
|
|
public function configured_adapter_reads_from_env_var(): void
|
|
{
|
|
$this->setEnv('WP_PROMETHEUS_STORAGE_ADAPTER', 'redis');
|
|
|
|
$this->assertSame('redis', StorageFactory::get_configured_adapter());
|
|
}
|
|
|
|
#[Test]
|
|
public function configured_adapter_reads_from_option(): void
|
|
{
|
|
GlobalFunctionState::$options['wp_prometheus_storage_adapter'] = 'apcu';
|
|
|
|
$this->assertSame('apcu', StorageFactory::get_configured_adapter());
|
|
}
|
|
|
|
#[Test]
|
|
public function env_var_takes_precedence_over_option(): void
|
|
{
|
|
$this->setEnv('WP_PROMETHEUS_STORAGE_ADAPTER', 'redis');
|
|
GlobalFunctionState::$options['wp_prometheus_storage_adapter'] = 'apcu';
|
|
|
|
$this->assertSame('redis', StorageFactory::get_configured_adapter());
|
|
}
|
|
|
|
#[Test]
|
|
public function configured_adapter_lowercases_env_value(): void
|
|
{
|
|
$this->setEnv('WP_PROMETHEUS_STORAGE_ADAPTER', 'REDIS');
|
|
|
|
$this->assertSame('redis', StorageFactory::get_configured_adapter());
|
|
}
|
|
|
|
// ── get_redis_config() ───────────────────────────────────────────
|
|
|
|
#[Test]
|
|
public function get_redis_config_returns_defaults(): void
|
|
{
|
|
$config = StorageFactory::get_redis_config();
|
|
|
|
$this->assertSame('127.0.0.1', $config['host']);
|
|
$this->assertSame(6379, $config['port']);
|
|
$this->assertSame('', $config['password']);
|
|
$this->assertSame(0, $config['database']);
|
|
$this->assertSame('WORDPRESS_PROMETHEUS_', $config['prefix']);
|
|
}
|
|
|
|
#[Test]
|
|
public function get_redis_config_reads_from_env_vars(): void
|
|
{
|
|
$this->setEnv('WP_PROMETHEUS_REDIS_HOST', '10.0.0.1');
|
|
$this->setEnv('WP_PROMETHEUS_REDIS_PORT', '6380');
|
|
$this->setEnv('WP_PROMETHEUS_REDIS_PASSWORD', 's3cret');
|
|
$this->setEnv('WP_PROMETHEUS_REDIS_DATABASE', '2');
|
|
$this->setEnv('WP_PROMETHEUS_REDIS_PREFIX', 'MY_PREFIX_');
|
|
|
|
$config = StorageFactory::get_redis_config();
|
|
|
|
$this->assertSame('10.0.0.1', $config['host']);
|
|
$this->assertSame(6380, $config['port']);
|
|
$this->assertSame('s3cret', $config['password']);
|
|
$this->assertSame(2, $config['database']);
|
|
$this->assertSame('MY_PREFIX_', $config['prefix']);
|
|
}
|
|
|
|
#[Test]
|
|
public function get_redis_config_reads_from_option(): void
|
|
{
|
|
GlobalFunctionState::$options['wp_prometheus_redis_config'] = [
|
|
'host' => '192.168.1.1',
|
|
'port' => 6381,
|
|
'password' => 'optpass',
|
|
'database' => 3,
|
|
'prefix' => 'OPT_',
|
|
];
|
|
|
|
$config = StorageFactory::get_redis_config();
|
|
|
|
$this->assertSame('192.168.1.1', $config['host']);
|
|
$this->assertSame(6381, $config['port']);
|
|
$this->assertSame('optpass', $config['password']);
|
|
$this->assertSame(3, $config['database']);
|
|
$this->assertSame('OPT_', $config['prefix']);
|
|
}
|
|
|
|
#[Test]
|
|
public function get_redis_config_env_takes_precedence(): void
|
|
{
|
|
$this->setEnv('WP_PROMETHEUS_REDIS_HOST', 'env-host');
|
|
GlobalFunctionState::$options['wp_prometheus_redis_config'] = [
|
|
'host' => 'option-host',
|
|
];
|
|
|
|
$config = StorageFactory::get_redis_config();
|
|
$this->assertSame('env-host', $config['host']);
|
|
}
|
|
|
|
// ── get_apcu_prefix() ────────────────────────────────────────────
|
|
|
|
#[Test]
|
|
public function get_apcu_prefix_returns_default(): void
|
|
{
|
|
$this->assertSame('wp_prom', StorageFactory::get_apcu_prefix());
|
|
}
|
|
|
|
#[Test]
|
|
public function get_apcu_prefix_reads_from_env(): void
|
|
{
|
|
$this->setEnv('WP_PROMETHEUS_APCU_PREFIX', 'custom_prefix');
|
|
|
|
$this->assertSame('custom_prefix', StorageFactory::get_apcu_prefix());
|
|
}
|
|
|
|
#[Test]
|
|
public function get_apcu_prefix_reads_from_option(): void
|
|
{
|
|
GlobalFunctionState::$options['wp_prometheus_apcu_prefix'] = 'opt_prefix';
|
|
|
|
$this->assertSame('opt_prefix', StorageFactory::get_apcu_prefix());
|
|
}
|
|
|
|
// ── save_config() ────────────────────────────────────────────────
|
|
|
|
#[Test]
|
|
public function save_config_stores_adapter(): void
|
|
{
|
|
StorageFactory::save_config(['adapter' => 'redis']);
|
|
|
|
$this->assertSame(
|
|
'redis',
|
|
GlobalFunctionState::$options['wp_prometheus_storage_adapter']
|
|
);
|
|
}
|
|
|
|
#[Test]
|
|
public function save_config_stores_redis_config(): void
|
|
{
|
|
StorageFactory::save_config([
|
|
'redis' => [
|
|
'host' => '10.0.0.5',
|
|
'port' => 6390,
|
|
'password' => 'pass123',
|
|
'database' => 1,
|
|
'prefix' => 'TEST_',
|
|
],
|
|
]);
|
|
|
|
$saved = GlobalFunctionState::$options['wp_prometheus_redis_config'];
|
|
$this->assertSame('10.0.0.5', $saved['host']);
|
|
$this->assertSame(6390, $saved['port']);
|
|
$this->assertSame('pass123', $saved['password']);
|
|
$this->assertSame(1, $saved['database']);
|
|
// sanitize_key lowercases the prefix
|
|
$this->assertSame('test_', $saved['prefix']);
|
|
}
|
|
|
|
#[Test]
|
|
public function save_config_stores_apcu_prefix(): void
|
|
{
|
|
StorageFactory::save_config(['apcu_prefix' => 'my_apcu']);
|
|
|
|
$this->assertSame(
|
|
'my_apcu',
|
|
GlobalFunctionState::$options['wp_prometheus_apcu_prefix']
|
|
);
|
|
}
|
|
|
|
#[Test]
|
|
public function save_config_resets_singleton(): void
|
|
{
|
|
// Get an adapter (creates singleton).
|
|
$adapter1 = StorageFactory::get_adapter();
|
|
|
|
// Save new config (should reset singleton).
|
|
StorageFactory::save_config(['adapter' => 'inmemory']);
|
|
|
|
// Get adapter again — should be a new instance.
|
|
$adapter2 = StorageFactory::get_adapter();
|
|
$this->assertNotSame($adapter1, $adapter2);
|
|
}
|
|
|
|
// ── test_connection() ────────────────────────────────────────────
|
|
|
|
#[Test]
|
|
public function test_connection_inmemory_always_succeeds(): void
|
|
{
|
|
$result = StorageFactory::test_connection(StorageFactory::ADAPTER_INMEMORY);
|
|
|
|
$this->assertTrue($result['success']);
|
|
$this->assertNotEmpty($result['message']);
|
|
}
|
|
|
|
#[Test]
|
|
public function test_connection_unknown_adapter_fails(): void
|
|
{
|
|
$result = StorageFactory::test_connection('unknown');
|
|
|
|
$this->assertFalse($result['success']);
|
|
$this->assertStringContainsString('Unknown', $result['message']);
|
|
}
|
|
|
|
#[Test]
|
|
public function test_connection_redis_fails_without_extension(): void
|
|
{
|
|
$extensionLoaded = $this->getFunctionMock(
|
|
'Magdev\\WpPrometheus\\Metrics',
|
|
'extension_loaded'
|
|
);
|
|
$extensionLoaded->expects($this->any())->willReturn(false);
|
|
|
|
$result = StorageFactory::test_connection(StorageFactory::ADAPTER_REDIS);
|
|
$this->assertFalse($result['success']);
|
|
$this->assertStringContainsString('not installed', $result['message']);
|
|
}
|
|
|
|
#[Test]
|
|
public function test_connection_apcu_fails_without_extension(): void
|
|
{
|
|
$extensionLoaded = $this->getFunctionMock(
|
|
'Magdev\\WpPrometheus\\Metrics',
|
|
'extension_loaded'
|
|
);
|
|
$extensionLoaded->expects($this->any())->willReturn(false);
|
|
|
|
$result = StorageFactory::test_connection(StorageFactory::ADAPTER_APCU);
|
|
$this->assertFalse($result['success']);
|
|
$this->assertStringContainsString('not installed', $result['message']);
|
|
}
|
|
|
|
// ── get_adapter() / reset() / singleton ──────────────────────────
|
|
|
|
#[Test]
|
|
public function get_adapter_returns_inmemory_by_default(): void
|
|
{
|
|
$adapter = StorageFactory::get_adapter();
|
|
$this->assertInstanceOf(InMemory::class, $adapter);
|
|
}
|
|
|
|
#[Test]
|
|
public function get_adapter_returns_singleton(): void
|
|
{
|
|
$adapter1 = StorageFactory::get_adapter();
|
|
$adapter2 = StorageFactory::get_adapter();
|
|
|
|
$this->assertSame($adapter1, $adapter2);
|
|
}
|
|
|
|
#[Test]
|
|
public function reset_clears_singleton_and_error(): void
|
|
{
|
|
StorageFactory::get_adapter();
|
|
StorageFactory::reset();
|
|
|
|
// After reset, get_last_error should be empty.
|
|
$this->assertEmpty(StorageFactory::get_last_error());
|
|
|
|
// Getting adapter again creates a new instance.
|
|
$adapter = StorageFactory::get_adapter();
|
|
$this->assertInstanceOf(InMemory::class, $adapter);
|
|
}
|
|
|
|
#[Test]
|
|
public function get_adapter_falls_back_to_inmemory_when_redis_unavailable(): void
|
|
{
|
|
$this->setEnv('WP_PROMETHEUS_STORAGE_ADAPTER', 'redis');
|
|
|
|
$extensionLoaded = $this->getFunctionMock(
|
|
'Magdev\\WpPrometheus\\Metrics',
|
|
'extension_loaded'
|
|
);
|
|
$extensionLoaded->expects($this->any())->willReturn(false);
|
|
|
|
$adapter = StorageFactory::get_adapter();
|
|
$this->assertInstanceOf(InMemory::class, $adapter);
|
|
$this->assertNotEmpty(StorageFactory::get_last_error());
|
|
}
|
|
|
|
#[Test]
|
|
public function get_adapter_falls_back_to_inmemory_when_apcu_unavailable(): void
|
|
{
|
|
$this->setEnv('WP_PROMETHEUS_STORAGE_ADAPTER', 'apcu');
|
|
|
|
$extensionLoaded = $this->getFunctionMock(
|
|
'Magdev\\WpPrometheus\\Metrics',
|
|
'extension_loaded'
|
|
);
|
|
$extensionLoaded->expects($this->any())->willReturn(false);
|
|
|
|
$adapter = StorageFactory::get_adapter();
|
|
$this->assertInstanceOf(InMemory::class, $adapter);
|
|
$this->assertNotEmpty(StorageFactory::get_last_error());
|
|
}
|
|
|
|
// ── Helpers ──────────────────────────────────────────────────────
|
|
|
|
private function setEnv(string $name, string $value): void
|
|
{
|
|
putenv("$name=$value");
|
|
$this->envVarsToClean[] = $name;
|
|
}
|
|
}
|