diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65d388e70df..eff6c453acd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,6 +80,7 @@ jobs: sudo dpkg --add-architecture i386 sudo apt update || true sudo apt install libssl1.1:i386 + ldd librust_g.so - name: Compile & Run Unit Tests run: | tools/ci/install_byond.sh @@ -87,3 +88,13 @@ jobs: tools/ci/dm.sh -DCIBUILDING paradise.dme tools/ci/run_server.sh + windows_dll_tests: + name: Windows RUSTG Validation + runs-on: windows-2016 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: '3.8.2' # Script was made for 3.8.2 + architecture: 'x86' # This MUST be x86 + - run: python tools/ci/validate_rustg_windows.py diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm index c7b8bca1437..fe4b644096b 100644 --- a/code/__DEFINES/rust_g.dm +++ b/code/__DEFINES/rust_g.dm @@ -1,5 +1,10 @@ -/// Locator for the RUSTG DLL or SO depending on system type +#ifndef RUST_G +/// Locator for the RUSTG DLL or SO depending on system type. Override if needed. #define RUST_G (world.system_type == UNIX ? "./librust_g.so" : "./rust_g.dll") +#endif + +// Gets the version of RUSTG +/proc/rustg_get_version() return call(RUST_G, "get_version")() // Defines for internal job subsystem // #define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET" @@ -10,6 +15,7 @@ #define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname) #define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data) +// Noise related operations // #define rustg_noise_get_at_coordinates(seed, x, y) call(RUST_G, "noise_get_at_coordinates")(seed, x, y) // Git related operations // @@ -43,3 +49,6 @@ #define rustg_sql_connected(handle) call(RUST_G, "sql_connected")(handle) #define rustg_sql_disconnect_pool(handle) call(RUST_G, "sql_disconnect_pool")(handle) #define rustg_sql_check_query(job_id) call(RUST_G, "sql_check_query")("[job_id]") + +// RUSTG Version // +#define RUST_G_VERSION "0.4.5-P2" diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 80467d19846..4f8cc28d54b 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -3,8 +3,10 @@ #ifdef UNIT_TESTS #include "component_tests.dm" +#include "log_format.dm" #include "map_templates.dm" #include "reagent_id_typos.dm" +#include "rustg_version.dm" #include "spawn_humans.dm" #include "sql.dm" #include "subsystem_init.dm" diff --git a/code/modules/unit_tests/log_format.dm b/code/modules/unit_tests/log_format.dm new file mode 100644 index 00000000000..11bcd9fd9fe --- /dev/null +++ b/code/modules/unit_tests/log_format.dm @@ -0,0 +1,26 @@ +// This exists so that logs are the designated format. If they arent, it breaks logging tooling. Also 8601 is king. +#define TEST_MESSAGE "Log time format test" +#define TEST_LOG_FILE "data/ci_testing.log" + +/proc/generate_test_log_message(time) + var/date_portion = time2text(time, "YYYY-MM-DD") + var/time_portion = time2text(time, "hh:mm:ss") + return "\[[date_portion]T[time_portion]] [TEST_MESSAGE]" + + +/datum/unit_test/log_format/Run() + // Generate a list of valid log timestamps. It can be the current time, or up to 2 seconds later to account for spurious CI lag + var/valid_lines = list( + "[generate_test_log_message(world.timeofday)]", + "[generate_test_log_message(world.timeofday + 10)]", + "[generate_test_log_message(world.timeofday + 20)]", + ) + + rustg_log_write(TEST_LOG_FILE, TEST_MESSAGE) + + var/list/lines = file2list(TEST_LOG_FILE) + if(!(lines[1] in valid_lines)) + Fail("RUSTG log format is not valid 8601 format. Expected '[generate_test_log_message(world.timeofday)]', got '[lines[1]]'") + +#undef TEST_MESSAGE +#undef TEST_LOG_FILE diff --git a/code/modules/unit_tests/rustg_version.dm b/code/modules/unit_tests/rustg_version.dm new file mode 100644 index 00000000000..0a259990b97 --- /dev/null +++ b/code/modules/unit_tests/rustg_version.dm @@ -0,0 +1,4 @@ +/datum/unit_test/rustg_version/Run() + var/library_version = rustg_get_version() + if(library_version != RUST_G_VERSION) + Fail("Invalid RUSTG Version. Library is [library_version], but in-code API is [RUST_G_VERSION]") diff --git a/librust_g.so b/librust_g.so index d5c25f422d2..6587d39c0a2 100644 Binary files a/librust_g.so and b/librust_g.so differ diff --git a/rust_g.dll b/rust_g.dll index 8e80d194a08..bb414674e2e 100644 Binary files a/rust_g.dll and b/rust_g.dll differ diff --git a/tools/ci/validate_rustg_windows.py b/tools/ci/validate_rustg_windows.py new file mode 100644 index 00000000000..3d4535484ed --- /dev/null +++ b/tools/ci/validate_rustg_windows.py @@ -0,0 +1,91 @@ +# Script to validate RUSTG DLL functions under windows (Running DD under windows in a CI environment is pain) +# Author: AffectedArc07 +# This script is invoked by GitHub actions as part of CI to validate that the windows DLL for RUSTG works and creates proper formats + +# Imports +import os, sys +from ctypes import * +from datetime import datetime, timedelta + +# Initial vars +ci_log_file = "ci_log.log" +ci_testing_text = "This is a test message" + +# Helpers +def success(msg): + print("[Y] {}".format(msg)) + +def fail(msg): + print("[X] {}".format(msg)) + exit(1) # Exit with 1 to fail the CI + +# Cleanup +if os.path.exists(ci_log_file): + os.remove(ci_log_file) + +# Check the DLL exists at all +if os.path.exists("rust_g.dll"): + success("RUSTG Dll exists") +else: + fail("RUSTG Dll does NOT exist") + +# Check DM header file exists +if os.path.exists("code/__DEFINES/rust_g.dm"): + success("RUSTG DM header file exists") +else: + fail("RUSTG DM header file does NOT exist") + +# Parse the version from the DM file +f = open("code/__DEFINES/rust_g.dm", "r") +lines = f.readlines() +f.close() +dm_version = None +for line in lines: + if line.startswith("#define RUST_G_VERSION"): + dm_version = line.split("#define RUST_G_VERSION")[1].strip().strip("\"") + break + +if not dm_version: + fail("Could not detect RUSTG version inside DM header file") + +# Begin DLL loading +rustg_dll = CDLL("./rust_g.dll") + + +# Set args for version retrieval +rustg_dll.get_version.restype = c_char_p +dll_version = rustg_dll.get_version().decode() + +if dll_version == dm_version: + success("DLL and DM versions match") +else: + fail("DLL and DM version mismatch! Got {} DM version, got {} DLL version".format(dm_version, dll_version)) + +# Now test log writing. This hurt to write. +string_array = c_char_p * 2 +sa = string_array(bytes(ci_log_file, "ascii"), bytes(ci_testing_text, "ascii")) +rustg_dll.log_write.argtypes = [c_int, c_char_p * 2] + +timestamp = datetime.now() + +# Generate valid results for the time now and the next 2 seconds. This is so we can account for spurious CI lag. +valid_results = [] +for count in range(3): + timestamp_text = timestamp.strftime('[%Y-%m-%dT%H:%M:%S]') # 8601 is king + valid_results.append("{} {}".format(timestamp_text, ci_testing_text)) + timestamp = timestamp + timedelta(seconds=1) + +# Invoke this now we have prepared +rustg_dll.log_write(2, sa) + +# Now read the output back +logfile = open(ci_log_file, "r") +logline = logfile.readlines()[0].strip("\n") # Remove newline +logfile.close() + +if logline in valid_results: + success("Log timestamp is valid 8601") +else: + fail("Log timestamp is not valid 8601. Got {}".format(logline)) + +exit(0) # Success