Skip to content

Commit

Permalink
create update functionality to upgrade game
Browse files Browse the repository at this point in the history
  • Loading branch information
bratkartoffel committed Jan 8, 2023
1 parent 8622998 commit b5bd895
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 31 deletions.
3 changes: 1 addition & 2 deletions include/config-example.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@
* ------------------------------------------------------------------------------------------------------
*/
// version string as displayed in the footer
// dynamically calculated with the short git commit id as suffix
define('game_version', "1.10.0+" . substr(file_get_contents(dirname(__FILE__) . '/../.git/HEAD'), 0, 8));
require_once 'game_version.inc.php';

// should only be set when running tests
// disables the captcha validation
Expand Down
33 changes: 32 additions & 1 deletion include/database.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Database
public const TABLE_LOG_LOGIN = 'log_login';
public const TABLE_LOG_MAFIA = 'log_mafia';
public const TABLE_LOG_CONTRACTS = 'log_vertraege';
public const TABLE_UPDATE_INFO = 'update_info';

private static ?Database $INSTANCE = null;

Expand Down Expand Up @@ -1378,12 +1379,42 @@ public function deleteGroup(int $group_id): ?string
return null;
}

public function getInstallScriptChecksum(string $script): ?string
{
$stmt = $this->prepare("SELECT Checksum FROM update_info WHERE Script = :script");
$stmt->bindParam('script', $script);
return $this->executeAndExtractField($stmt, 'Checksum');
}

public function tableExists(string $table): bool
{
$db = database_database;
$stmt = $this->prepare("SELECT count(1) as count FROM information_schema.TABLES WHERE TABLE_SCHEMA = :schema AND TABLE_NAME = :table");
$stmt->bindParam('schema', $db);
$stmt->bindParam('table', $table);
return $this->executeAndExtractField($stmt, 'count') > 0;
}

public function executeFile(string $script): ?string
{
$commands = explode(';', file_get_contents($script));
for ($i = 0; $i < count($commands); $i++) {
$sql = $commands[$i];
if (trim($sql) == '') continue;
$stmt = $this->prepare($sql);
if (!$stmt->execute()) {
return $sql;
}
}
return null;
}

public function getQueryCount(): int
{
return $this->queries;
}

private function prepare(string $sql): ?PDOStatement
protected function prepare(string $sql): ?PDOStatement
{
$this->queries++;
$stmt = $this->link->prepare($sql);
Expand Down
14 changes: 14 additions & 0 deletions include/game_version.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
$version_extra = null;
{
$git_head = dirname(__FILE__) . '/../.git/HEAD';
if (file_exists($git_head)) {
$content = file_get_contents($git_head);
if (strpos($content, 'ref:') !== false) {
$tmp = explode('/', $content);
$content = trim($tmp[count($tmp) - 1]);
}
$version_extra = '+' . substr($content, 0, 8);
}
}
define('game_version', "1.10.1" . $version_extra);
File renamed without changes.
9 changes: 9 additions & 0 deletions install/sql/01-1.10.1-update_info.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
create table update_info
(
ID int auto_increment primary key,
Executed datetime not null default current_timestamp,
Script varchar(64) not null,
Checksum char(40) not null
);
create unique index Script on update_info (Script);

91 changes: 91 additions & 0 deletions install/update.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php
require_once('../include/config.inc.php');
require_once('../include/functions.inc.php');
require_once('../include/database.class.php');

header('Content-Type: text/plain; charset=UTF-8');
ob_start();
http_response_code(500);

echo "Checking installation for version " . game_version . "\n";
echo "Verifying database connection\n";
Database::getInstance();

echo "Checking base installation\n";
$executedScripts = array();
if (!Database::getInstance()->tableExists('auftrag')) {
echo "Base installation not found, executing setup script\n";
// initial setup
$script = 'sql/00-1.10.0-setup.sql';
$result = Database::getInstance()->executeFile($script);
if ($result !== null) {
die("Could not execute setup script, failed step: " . $result);
}
$executedScripts[$script] = sha1_file($script);
}

echo "Checking for update information\n";
if (!Database::getInstance()->tableExists('update_info')) {
echo "Update information not found, execute first update script\n";
// coming from v1.10.0
$script = 'sql/01-1.10.1-update_info.sql';
$result = Database::getInstance()->executeFile($script);
if ($result !== null) {
die("Could not execute setup script, failed step: " . $result);
}
$executedScripts[$script] = sha1_file($script);
}

echo "Enumerating update scripts\n";
$dh = opendir('sql/');
while (false !== ($entry = readdir($dh))) {
$script = 'sql/' . $entry;
if (mb_strpos($script, '.sql') === false) continue;
if (strpos($script, '/0') !== false) {
echo "Skipping $script\n";
continue;
}

echo "Verify update script: $script\n";
$dbChecksum = Database::getInstance()->getInstallScriptChecksum($script);
if ($dbChecksum === null) {
echo "> Script unknown, begin execution\n";
$result = Database::getInstance()->executeFile($script);
if ($result !== null) {
die("Could not execute setup script, failed step: " . $result);
}
$executedScripts[$script] = sha1_file($script);
} else {
echo "> Script already executed, verifying checksum\n";
$fsChecksum = sha1_file($script);
if ($dbChecksum !== $fsChecksum) {
die(sprintf("> Calculated checksum for '%s' is different between database (%s) and filesystem (%s). Please correct manually!",
$script, $dbChecksum, $fsChecksum));
} else {
echo ">> OK\n";
}
}
}

$script = '/tmp/99_testdata.sql';
if (file_exists($script)) {
echo "Verify update script: $script\n";
$result = Database::getInstance()->executeFile($script);
if ($result !== null) {
die("Could not execute setup script, failed step: " . $result);
}
}

Database::getInstance()->begin();
foreach ($executedScripts as $script => $checksum) {
if (Database::getInstance()->createTableEntry(Database::TABLE_UPDATE_INFO, array(
'Script' => $script,
'Checksum' => $checksum
)) !== 1) {
Database::getInstance()->rollBack();
die('Could not create update_info entry for ' . $script);
}
}
Database::getInstance()->commit();

http_response_code(200);
2 changes: 2 additions & 0 deletions pages/admin_benutzer.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,5 @@
?>
</table>
<?= createPaginationTable('/?p=admin_benutzer', $offset, $entriesCount, admin_log_page_size); ?>

<a href="/?p=admin">&lt;&lt; Zurück</a>
30 changes: 26 additions & 4 deletions tests/src/test/java/eu/fraho/blm2/st/AbstractTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package eu.fraho.blm2.st;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
Expand All @@ -24,19 +25,40 @@
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;

public abstract class AbstractTest {
private static final Logger log = LoggerFactory.getLogger(AbstractTest.class);

private static final WebDriver driver = SeleniumConfig.getWebDriver();

private static final AtomicBoolean installed = new AtomicBoolean();

@BeforeEach
void resetDriver() {
driver.manage().deleteAllCookies();
driver.get(String.format("http://localhost/?_=%d", System.currentTimeMillis()));
new WebDriverWait(driver, Duration.ofSeconds(1), Duration.ofMillis(100)).until(ExpectedConditions.titleContains("TST"));
}

@BeforeAll
static void install() {
if (installed.compareAndSet(false, true)) {
HttpClient httpClient = HttpClient.newHttpClient();
try {
HttpResponse<String> response = httpClient.send(
HttpRequest.newBuilder().GET().uri(URI.create("http://localhost/install/update.php")).build(),
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
Assertions.fail(response.body());
}
} catch (IOException | InterruptedException e) {
Assertions.fail(e);
}
}
}

protected static WebDriver getDriver() {
return driver;
}
Expand Down Expand Up @@ -76,10 +98,10 @@ protected void select(By by, String label) {
protected void resetPlayer(int id) {
HttpClient httpClient = HttpClient.newHttpClient();
try {
HttpResponse<String> response = httpClient.send(HttpRequest.newBuilder()
.GET()
.uri(URI.create("http://localhost/actions/test-reset-player.php?id=" + id))
.build(), HttpResponse.BodyHandlers.ofString());
HttpResponse<String> response = httpClient.send(
HttpRequest.newBuilder().GET().uri(URI.create("http://localhost/actions/test-reset-player.php?id=" + id)).build(),
HttpResponse.BodyHandlers.ofString()
);
Optional<String> location = response.headers().firstValue("Location");
Assertions.assertTrue(location.isPresent());
Assertions.assertEquals("/actions/logout.php", location.get());
Expand Down
4 changes: 2 additions & 2 deletions tests/src/test/resources/config.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
* ------------------------------------------------------------------------------------------------------
*/
// version string as displayed in the footer
// dynamically calculated with the short git commit id as suffix
const game_version = "1.10.0+test";
/** @noinspection PhpIncludeInspection */
require_once 'game_version.inc.php';

// should only be set when running tests
// disables the captcha validation, email sending and seeds the random number generator with a deterministic value
Expand Down
4 changes: 1 addition & 3 deletions tests/src/test/resources/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ services:
MARIADB_PASSWORD: "blm2_test"
ports:
- "3306:3306"
volumes:
- ../../../../development/setup-1.10.0.sql:/docker-entrypoint-initdb.d/0_setup.sql:ro
- ./testdata.sql:/docker-entrypoint-initdb.d/1_testdata.sql:ro

application:
image: bratkartoffel/web:blm2-dev
Expand All @@ -28,3 +25,4 @@ services:
- ../../../../:/var/www/html
- ./config.inc.php:/var/www/html/include/config.inc.php
- ./last_reset.inc.php:/var/www/html/include/last_reset.inc.php
- ./testdata.sql:/tmp/99_testdata.sql:ro
49 changes: 30 additions & 19 deletions tests/src/test/resources/testdata.sql
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
alter table mitglieder
auto_increment 100;

DELIMITER $$
CREATE OR REPLACE PROCEDURE InsertUsers(P_count int)
BEGIN
DECLARE NR int;
insertLoop:
LOOP
SET NR = coalesce(NR, 0) + 1;
-- all passwords are "changeit"

REPLACE INTO `mitglieder` (`ID`, `Name`, `EMail`, `Passwort`)
VALUES (10 + NR, concat('test', NR), concat('test', NR, '@example.com'),
-- password is "changeit"
'$argon2i$v=19$m=16384,t=8,p=2$cFlRVVl2WTdFREFkaU8zQg$kphB/S9ZP41FplBbhUH1uYSURQD4kK8JYQvjtieU/ZM');
INSERT INTO `statistik` (`user_id`) VALUES (10 + NR);
REPLACE INTO `mitglieder` (`ID`, `Name`, `EMail`, `Passwort`)
VALUES (11, 'test1', '[email protected]',
'$argon2i$v=19$m=16384,t=8,p=2$cFlRVVl2WTdFREFkaU8zQg$kphB/S9ZP41FplBbhUH1uYSURQD4kK8JYQvjtieU/ZM');
REPLACE INTO `statistik` (`user_id`)
VALUES (11);

REPLACE INTO `mitglieder` (`ID`, `Name`, `EMail`, `Passwort`)
VALUES (12, 'test2', '[email protected]',
'$argon2i$v=19$m=16384,t=8,p=2$cFlRVVl2WTdFREFkaU8zQg$kphB/S9ZP41FplBbhUH1uYSURQD4kK8JYQvjtieU/ZM');
REPLACE INTO `statistik` (`user_id`)
VALUES (12);

IF NR = P_count THEN LEAVE insertLoop; END IF;
END LOOP insertLoop;
END $$
DELIMITER ;
REPLACE INTO `mitglieder` (`ID`, `Name`, `EMail`, `Passwort`)
VALUES (13, 'test3', '[email protected]',
'$argon2i$v=19$m=16384,t=8,p=2$cFlRVVl2WTdFREFkaU8zQg$kphB/S9ZP41FplBbhUH1uYSURQD4kK8JYQvjtieU/ZM');
REPLACE INTO `statistik` (`user_id`)
VALUES (13);

CALL InsertUsers(5);
REPLACE INTO `mitglieder` (`ID`, `Name`, `EMail`, `Passwort`)
VALUES (14, 'test4', '[email protected]',
'$argon2i$v=19$m=16384,t=8,p=2$cFlRVVl2WTdFREFkaU8zQg$kphB/S9ZP41FplBbhUH1uYSURQD4kK8JYQvjtieU/ZM');
REPLACE INTO `statistik` (`user_id`)
VALUES (14);

REPLACE INTO `mitglieder` (`ID`, `Name`, `EMail`, `Passwort`)
VALUES (15, 'test5', '[email protected]',
'$argon2i$v=19$m=16384,t=8,p=2$cFlRVVl2WTdFREFkaU8zQg$kphB/S9ZP41FplBbhUH1uYSURQD4kK8JYQvjtieU/ZM');
REPLACE INTO `statistik` (`user_id`)
VALUES (15);

REPLACE INTO `mitglieder` (`ID`, `Name`, `EMail`, `Admin`, `Passwort`)
VALUES (9, 'admin', '[email protected]', 1,
-- password is "changeit"
'$argon2i$v=19$m=16384,t=8,p=2$cFlRVVl2WTdFREFkaU8zQg$kphB/S9ZP41FplBbhUH1uYSURQD4kK8JYQvjtieU/ZM');
INSERT INTO `statistik` (`user_id`) VALUES (9);
REPLACE INTO `statistik` (`user_id`)
VALUES (9);

0 comments on commit b5bd895

Please sign in to comment.