dbxapp 4.1.3
CMS, Shop, Workflows und modulare Geschäftsanwendungen
Loading...
Searching...
No Matches
dbxUpdateService_database_adapter_test.php
Go to the documentation of this file.
1<?php
2
3declare(strict_types=1);
4
5require_once dirname(__DIR__) . '/include/dbxUpdateService.class.php';
6
8
10{
11 public array $calls = array();
12 public bool $failApply = false;
13
14 public function prepare(string $root, array $manifest, string $backup): array
15 {
16 $this->calls[] = 'prepare';
17 return array('pending' => array('test-migration'), 'backups' => array());
18 }
19
20 public function apply(array $state): array
21 {
22 $this->calls[] = 'apply';
23 if ($this->failApply) {
24 throw new RuntimeException('erwarteter DB-Fehler');
25 }
26 return array('applied' => $state['pending']);
27 }
28
29 public function rollback(array $state): array
30 {
31 $this->calls[] = 'rollback';
32 return array('rolled_back' => $state['pending']);
33 }
34}
35
36function update_db_write(string $file, string $content): void
37{
38 if (!is_dir(dirname($file))) {
39 mkdir(dirname($file), 0775, true);
40 }
41 file_put_contents($file, $content);
42}
43
44function update_db_remove(string $root): void
45{
46 if (!is_dir($root)) {
47 return;
48 }
49 $iterator = new RecursiveIteratorIterator(
50 new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS),
51 RecursiveIteratorIterator::CHILD_FIRST
52 );
53 foreach ($iterator as $item) {
54 $item->isDir() ? rmdir($item->getPathname()) : unlink($item->getPathname());
55 }
56 rmdir($root);
57}
58
60 string $root,
61 string $version,
62 string $newIndex
63): array {
64 update_db_write($root . '/VERSION', "4.0.1\n");
65 update_db_write($root . '/index.php', "<?php echo 'old';\n");
66 update_db_write($root . '/dbx/include/dbxApi.php', "<?php // old api\n");
67 $oldInventory = array(
68 'schema' => 1,
69 'product' => 'dbxapp',
70 'version' => '4.0.1',
71 'files' => array(
72 'VERSION' => hash('sha256', "4.0.1\n"),
73 'index.php' => hash('sha256', "<?php echo 'old';\n"),
74 'dbx/include/dbxApi.php' => hash('sha256', "<?php // old api\n"),
75 '.dbx-release-files.json' => null,
76 ),
77 );
79 $root . '/.dbx-release-files.json',
80 json_encode($oldInventory, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
81 );
82
83 $work = $root . '/files/update';
84 $zipFile = $work . '/downloads/dbxapp-' . $version . '.zip';
85 if (!is_dir(dirname($zipFile))) {
86 mkdir(dirname($zipFile), 0775, true);
87 }
88 $contents = array(
89 'VERSION' => $version . "\n",
90 'index.php' => $newIndex,
91 'dbx/include/dbxApi.php' => "<?php // new api\n",
92 );
93 $files = array();
94 foreach ($contents as $path => $content) {
95 $files[$path] = hash('sha256', $content);
96 }
97 $files['.dbx-release-files.json'] = null;
98 $inventory = json_encode(array(
99 'schema' => 1,
100 'product' => 'dbxapp',
101 'version' => $version,
102 'files' => $files,
103 ), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL;
104
105 $zip = new ZipArchive();
106 $zip->open($zipFile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
107 foreach ($contents as $path => $content) {
108 $zip->addFromString($path, $content);
109 }
110 $zip->addFromString('.dbx-release-files.json', $inventory);
111 $zip->close();
112
113 $manifest = array(
114 'schema' => 1,
115 'product' => 'dbxapp',
116 'channel' => 'stable',
117 'version' => $version,
118 'release_url' => 'https://github.com/ecb-dbxApp/dbxapp/releases/tag/v' . $version,
119 'zip_url' => 'https://github.com/ecb-dbxApp/dbxapp/releases/download/v'
120 . $version . '/dbxapp-' . $version . '.zip',
121 'sha256' => hash_file('sha256', $zipFile),
122 'requires' => array(
123 'php' => '>=8.2',
124 'extensions' => array('json', 'pdo', 'zip'),
125 ),
126 );
127
128 $service = new dbxUpdateService($root);
129 $package = $service->inspectPackage($zipFile, $manifest);
130 $staging = $work . '/staging/' . $version;
131 mkdir($staging, 0775, true);
132 $zip = new ZipArchive();
133 $zip->open($zipFile);
134 $zip->extractTo($staging);
135 $zip->close();
136 update_db_write($work . '/staged.json', json_encode(array(
137 'schema' => 1,
138 'staged_at' => gmdate('c'),
139 'zip_file' => $zipFile,
140 'staging_directory' => $staging,
141 'manifest' => $manifest,
142 'files' => $package['files'],
143 ), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
144
145 return array($manifest, $staging);
146}
147
148function update_db_assert(bool $condition, string $message): void
149{
150 if (!$condition) {
151 throw new RuntimeException($message);
152 }
153}
154
155$root = sys_get_temp_dir() . '/dbx-update-db-adapter-' . bin2hex(random_bytes(5));
156try {
157 [$manifest] = update_db_stage($root, '4.0.2', "<?php echo 'new';\n");
158 $adapter = new UpdateDatabaseAdapterStub();
159 $service = new dbxUpdateService($root, '', 21600, $adapter);
160 $service->install();
162 $adapter->calls === array('prepare', 'apply'),
163 'DB-Adapter wurde bei erfolgreicher Installation nicht korrekt aufgerufen.'
164 );
165 $service->rollback();
167 $adapter->calls === array('prepare', 'apply', 'rollback')
168 && trim((string)file_get_contents($root . '/VERSION')) === '4.0.1',
169 'Expliziter Rollback hat DB und Dateien nicht gemeinsam behandelt.'
170 );
171} finally {
173}
174
175$root = sys_get_temp_dir() . '/dbx-update-db-failure-' . bin2hex(random_bytes(5));
176try {
177 update_db_stage($root, '4.0.2', "<?php echo 'new';\n");
178 $adapter = new UpdateDatabaseAdapterStub();
179 $adapter->failApply = true;
180 $service = new dbxUpdateService($root, '', 21600, $adapter);
181 try {
182 $service->install();
183 throw new RuntimeException('Erwarteter DB-Migrationsfehler blieb aus.');
184 } catch (RuntimeException $exception) {
186 str_contains($exception->getMessage(), 'zurückgerollt'),
187 'DB-Migrationsfehler meldet keinen koordinierten Rollback.'
188 );
189 }
191 $adapter->calls === array('prepare', 'apply', 'rollback')
192 && trim((string)file_get_contents($root . '/VERSION')) === '4.0.1'
193 && str_contains((string)file_get_contents($root . '/index.php'), 'old'),
194 'Fehlerpfad hat DB und Dateien nicht vollständig zurückgerollt.'
195 );
196} finally {
198}
199
200echo "OK updater coordinates database prepare, apply and rollback\n";
prepare(string $root, array $manifest, string $backup)
Sicherer dbxApp Release-Updater fuer Dateien und optionale DB-Migrationen.
update_db_assert(bool $condition, string $message)
update_db_stage(string $root, string $version, string $newIndex)
update_db_remove(string $root)
update_db_write(string $file, string $content)
catch(RuntimeException $exception) $staging