36 lines
2.9 KiB
PHP
36 lines
2.9 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
require dirname(__DIR__) . '/bootstrap.php';
|
|
use PrelandAdmin\Config;
|
|
use PrelandAdmin\Store;
|
|
use PrelandAdmin\Transport;
|
|
use PrelandAdmin\Jobs;
|
|
function check(bool $value, string $message): void { if (!$value) throw new RuntimeException($message); echo "PASS $message\n"; }
|
|
$root = sys_get_temp_dir() . '/preland-admin-' . bin2hex(random_bytes(6));
|
|
mkdir($root, 0700, true); mkdir($root . '/site',0700); mkdir($root . '/state',0700);
|
|
putenv('ADMIN_STATE_DIR=' . $root . '/state'); putenv('ADMIN_LOCAL_ROOTS=' . $root . '/site');
|
|
$initial = (object)['host'=>'zoomzilla.ru','requisites'=>['one'],'custom'=>(object)['flag'=>true,'zero'=>0,'empty'=>(object)[]],'utm'=>(object)[]];
|
|
file_put_contents($root . '/site/config.json', json_encode($initial));
|
|
$store = new Store($root . '/state');
|
|
$target = $store->saveTarget(['id'=>'test','name'=>'Тест','domain'=>'test.invalid','environment'=>'stage','type'=>'local','root'=>$root . '/site','enabled'=>true]);
|
|
$store->verifyTarget('test');$target=$store->target('test');
|
|
$transport = new Transport($store, $target);
|
|
$before = $transport->readConfig();
|
|
$next = Config::patch($before['config'], [['path'=>['host'],'value'=>'example.org']]);
|
|
check($next->custom->flag === true && $next->custom->zero === 0 && $next->custom->empty instanceof stdClass, 'selected patch preserves unrelated values and types');
|
|
$transport->writeConfig($before['version'], Config::encode($next));
|
|
$after = $transport->readConfig(); check($after['config']->host === 'example.org','atomic save and reread');
|
|
try { $transport->writeConfig($before['version'], Config::encode($initial)); throw new RuntimeException('missed conflict'); } catch (PrelandAdmin\Conflict $e) { check(true,'stale version conflicts'); }
|
|
check(count($store->backups('test')) === 1,'private backup saved');
|
|
$jobs = new Jobs($store);
|
|
$job = $jobs->create('apply', ['targets'=>[['id'=>'test','version'=>$after['version']],['id'=>'missing','version'=>'x']], 'changes'=>[['path'=>['custom','flag'],'value'=>false]]]);
|
|
$jobs->run($job['id']); $job=$jobs->get($job['id']);
|
|
check($job['results'][0]['status']==='success' && $job['results'][1]['status']==='error','one target failure does not undo successful target');
|
|
$restored=$transport->readConfig();
|
|
$backup=$store->backups('test')[0];
|
|
$job=$jobs->create('restore',['target'=>'test','id'=>$backup['id'],'version'=>$restored['version']]);$jobs->run($job['id']);
|
|
check($jobs->get($job['id'])['results'][0]['status']==='success','backup restores with version protection');
|
|
try { $store->saveTarget(['id'=>'escape','type'=>'local','root'=>'/etc','domain'=>'a.invalid']); throw new RuntimeException('unsafe root accepted'); } catch (PrelandAdmin\Problem $e) {check(true,'local root confined to explicit mounts');}
|
|
try { Config::patch($initial,[['path'=>['__proto__'],'value'=>1]]); throw new RuntimeException('unsafe key accepted'); } catch(PrelandAdmin\Problem $e) {check(true,'unsafe patch path rejected');}
|
|
echo "Backend contract complete\n";
|