Files
XC_VM/tests/Unit/UpdateChannelsTest.php
T
Divarion_D e865611205 feat(updates): add a dev update channel for nightly panel builds
The panel update channel gains 'dev' (BIN and FANOUT stay stable/beta).
On 'dev' the MAIN release client also reads the releases-only XC_VM_Dev
repository, merges both release lists by version_compare(), and fetches
each asset from the repository that published its tag (X.Y.Z-dev.N tags
live in XC_VM_Dev). An unreachable XC_VM_Dev leaves the channel on the
regular releases. Nightly changelogs are read from a release asset,
since XC_VM_Dev has no source tree.

- UpdateChannels::mainReleases() builds the MAIN client; the update
  command, update cron, web API bootstrap, rollback picker and server
  install use it instead of constructing their own.
- The releases API is requested with per_page=100 so prereleases cannot
  push stable releases off the default 30-item page.
- Nightly builds are excluded from the rollback picker (rollback accepts
  X.Y.Z only).
- Settings: 'Dev (nightly)' option for the panel channel plus a warning.
2026-09-25 22:40:51 +03:00

125 lines
4.2 KiB
PHP

<?php
use XcVm\Core\Config\SettingsManager;
use XcVm\Core\Updates\UpdateChannels;
use PHPUnit\Framework\TestCase;
// AppConfig.php (procedural) defines these in production but is never loaded in
// the test process; define the real values so forRepo() dispatch can be tested.
if (!defined('GIT_REPO_MAIN')) {
define('GIT_REPO_MAIN', 'XC_VM');
}
if (!defined('GIT_REPO_BIN')) {
define('GIT_REPO_BIN', 'XC_VM_Binaries');
}
if (!defined('GIT_REPO_FANOUT')) {
define('GIT_REPO_FANOUT', 'XC_VM_Fanout');
}
if (!defined('GIT_REPO_DEV')) {
define('GIT_REPO_DEV', 'XC_VM_Dev');
}
if (!defined('GIT_OWNER')) {
define('GIT_OWNER', 'Vateron-Media');
}
/**
* UpdateChannels — per-repository release channel resolution.
*
* Each core repo (MAIN/BIN/FANOUT) reads its own `update_channel_*` setting;
* values normalize to 'stable'/'beta' (with 'unstable' as a legacy alias for
* 'beta' and any unknown value falling back to 'stable'). forRepo() maps a
* GitHub repo name to the owning channel, with UPDATE/PROXY/unknown following
* MAIN. These lock that contract down against the seeded settings.
*/
final class UpdateChannelsTest extends TestCase {
protected function setUp(): void {
SettingsManager::set([]);
}
protected function tearDown(): void {
SettingsManager::set([]);
}
public function testChannelsDefaultToStableWhenUnset(): void {
$this->assertSame('stable', UpdateChannels::main());
$this->assertSame('stable', UpdateChannels::bin());
$this->assertSame('stable', UpdateChannels::fanout());
}
public function testEachChannelReadsItsOwnSetting(): void {
SettingsManager::set([
'update_channel_main' => 'beta',
'update_channel_bin' => 'stable',
'update_channel_fanout' => 'beta',
]);
$this->assertSame('beta', UpdateChannels::main());
$this->assertSame('stable', UpdateChannels::bin());
$this->assertSame('beta', UpdateChannels::fanout());
}
public function testUnstableIsALegacyAliasForBeta(): void {
SettingsManager::set(['update_channel_main' => 'unstable']);
$this->assertSame('beta', UpdateChannels::main());
}
public function testUnknownOrEmptyValueFallsBackToStable(): void {
SettingsManager::set(['update_channel_bin' => 'nightly']);
$this->assertSame('stable', UpdateChannels::bin());
SettingsManager::set(['update_channel_bin' => '']);
$this->assertSame('stable', UpdateChannels::bin());
}
public function testForRepoDispatchesToTheOwningChannel(): void {
SettingsManager::set([
'update_channel_main' => 'stable',
'update_channel_bin' => 'beta',
'update_channel_fanout' => 'beta',
]);
$this->assertSame('beta', UpdateChannels::forRepo(GIT_REPO_BIN), 'BIN repo → bin channel');
$this->assertSame('beta', UpdateChannels::forRepo(GIT_REPO_FANOUT), 'FANOUT repo → fanout channel');
$this->assertSame('stable', UpdateChannels::forRepo(GIT_REPO_MAIN), 'MAIN repo → main channel');
}
public function testForRepoFollowsMainForUnknownRepos(): void {
SettingsManager::set([
'update_channel_main' => 'beta',
'update_channel_bin' => 'stable',
]);
// UPDATE (GeoLite/ASN) and PROXY have no channel of their own → follow MAIN.
$this->assertSame('beta', UpdateChannels::forRepo('XC_VM_Data'));
$this->assertSame('beta', UpdateChannels::forRepo('some-unknown-repo'));
}
public function testDevChannelIsOfferedForMainOnly(): void {
SettingsManager::set([
'update_channel_main' => 'dev',
'update_channel_bin' => 'dev',
'update_channel_fanout' => 'dev',
]);
$this->assertSame('dev', UpdateChannels::main());
$this->assertSame('stable', UpdateChannels::bin(), 'BIN has no nightly builds');
$this->assertSame('stable', UpdateChannels::fanout(), 'FANOUT has no nightly builds');
$this->assertSame('dev', UpdateChannels::forRepo('XC_VM_Update'), 'UPDATE follows MAIN');
}
public function testMainReleasesCarriesTheConfiguredChannelAndDevRepo(): void {
SettingsManager::set(['update_channel_main' => 'dev']);
$releases = UpdateChannels::mainReleases();
$this->assertSame(
'https://github.com/Vateron-Media/XC_VM_Dev/releases/download/2.5.4-dev.3/xc_vm.tar.gz',
$releases->assetUrl('2.5.4-dev.3', 'xc_vm.tar.gz')
);
$this->assertSame(
'https://github.com/Vateron-Media/XC_VM/releases/download/2.5.3/xc_vm.tar.gz',
$releases->assetUrl('2.5.3', 'xc_vm.tar.gz')
);
}
}