CaiWuXiTong/tests/Feature/SystemSettings/UpstreamSharedDatabaseCacheTest.php

130 lines
4.8 KiB
PHP

<?php
namespace Tests\Feature\SystemSettings;
use App\Models\Auth\Permission;
use Illuminate\Cache\CacheManager;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\EcommerceFinance\Services\UpstreamQueryCache;
use Modules\EcommerceFinance\Services\UpstreamSourceRegistry;
use Tests\TestCase;
class UpstreamSharedDatabaseCacheTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
config()->set('upstreams.stored_configuration.enabled', false);
config()->set('upstreams.local_configuration.enabled', true);
config()->set('upstreams.snapshots.cache_store', 'upstream_shared');
config()->set('upstreams.runtime.max_concurrency', 4);
config()->set('upstreams.runtime.slot_wait_ms', 0);
config()->set('upstreams.sources.shared_source', [
'label' => '共享来源',
'config' => 'test_shared_source',
]);
config()->set('test_shared_source', [
'enabled' => true,
'allowed_scopes' => ['orders.*'],
'connection' => [
'connect_timeout' => 1,
'query_timeout' => 1,
],
'snapshots' => [
'ttl_seconds' => 60,
'summary_ttl_seconds' => 60,
'options_ttl_seconds' => 3600,
'stale_ttl_seconds' => 3600,
'active_ttl_seconds' => 3600,
'registry_limit' => 50,
'refresh_limit' => 2,
'miss_budget_per_window' => 6,
'budget_window_seconds' => 60,
'lock_seconds' => 15,
'lock_wait_seconds' => 1,
'max_concurrency' => 2,
'slot_wait_ms' => 0,
'failure_cooldown_seconds' => 60,
'query_failure_cooldown_seconds' => 60,
'slow_query_ms' => 5000,
'slow_query_cooldown_seconds' => 60,
'refresh_time_budget_seconds' => 10,
'refresh_pause_ms' => 0,
],
]);
}
public function test_two_runtime_instances_share_one_database_snapshot_without_copying_source_tables(): void
{
$sources = app(UpstreamSourceRegistry::class);
$cacheManager = app(CacheManager::class);
$firstRuntime = new UpstreamQueryCache($sources, 'shared_source', $cacheManager);
$secondRuntime = new UpstreamQueryCache($sources, 'shared_source', $cacheManager);
$calls = 0;
$first = $firstRuntime->remember('orders.list', ['month' => '2026-07'], function () use (&$calls): array {
$calls++;
return ['rows' => [['id' => 1]], 'total' => 1];
});
$second = $secondRuntime->remember('orders.list', ['month' => '2026-07'], function () use (&$calls): array {
$calls++;
return ['rows' => [['id' => 999]], 'total' => 999];
});
$this->assertSame($first, $second);
$this->assertSame(1, $calls);
$this->assertGreaterThan(0, DB::table('upstream_query_cache')->count());
$this->assertTrue(Schema::hasTable('upstream_query_cache'));
$this->assertTrue(Schema::hasTable('upstream_query_locks'));
$this->assertFalse(Schema::hasTable('orders'));
}
public function test_refresh_all_safely_skips_a_registered_but_disabled_source(): void
{
config()->set('jiansun.enabled', false);
$this->artisan('upstream:snapshots:refresh-all')
->expectsOutputToContain('同步未启用,本轮跳过')
->assertExitCode(0);
}
public function test_permission_change_creates_a_separate_snapshot_scope(): void
{
$user = user_model_class()::firstOrFail();
$user->companies()->firstOrFail()->makeCurrent();
$this->actingAs($user);
$sources = app(UpstreamSourceRegistry::class);
$cacheManager = app(CacheManager::class);
$calls = 0;
$before = (new UpstreamQueryCache($sources, 'shared_source', $cacheManager))
->remember('orders.list', [], function () use (&$calls): array {
$calls++;
return ['permission_version' => 1];
});
$permission = Permission::query()->create([
'name' => 'read-shared-snapshot-test',
'display_name' => 'Read Shared Snapshot Test',
'description' => '测试共享快照权限隔离',
]);
$user->attachPermission($permission);
$after = (new UpstreamQueryCache($sources, 'shared_source', $cacheManager))
->remember('orders.list', [], function () use (&$calls): array {
$calls++;
return ['permission_version' => 2];
});
$this->assertSame(1, $before['permission_version']);
$this->assertSame(2, $after['permission_version']);
$this->assertSame(2, $calls);
}
}