Skip to content

Commit

Permalink
Separate station/unit tests and disable lavaland procgen and ruin spa…
Browse files Browse the repository at this point in the history
…wning in tests (for now). (ParadiseSS13#28106)

* Separate station/unit tests and disable lavaland.

* add CI/local test conflict check back
  • Loading branch information
warriorstar-orion authored Feb 8, 2025
1 parent 5237a14 commit 8e4dc61
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 106 deletions.
44 changes: 33 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,42 @@ jobs:
tools/ci/generate_maplist.sh
DreamMaker -DMULTIINSTANCE -DCIMAP paradise.dme
station_mapload_tests:
name: Station Tests
runs-on: ubuntu-22.04
strategy:
fail-fast: false # Let all map tests run to completion
matrix:
station:
['boxstation', 'deltastation', 'metastation', 'cerestation', 'emeraldstation']
byondtype: ['STABLE', 'BETA']
steps:
- uses: actions/checkout@v4
- name: Setup Cache
uses: actions/cache@v4
with:
path: $HOME/BYOND
key: ${{ runner.os }}-byond
- name: Install RUST_G Deps
run: |
sudo dpkg --add-architecture i386
sudo apt update || true
sudo apt install zlib1g-dev:i386
tools/ci/install_rustg.sh
- name: Compile & Run Unit Tests
run: |
tools/ci/install_byond.sh '${{ matrix.byondtype }}'
source $HOME/BYOND/byond/bin/byondsetup
DreamMaker -DMAP_TESTS -DTEST_CONFIG_OVERRIDE=\"unit_tests\" -DMULTIINSTANCE -DCIBUILDING paradise.dme
echo '/datum/map/${{ matrix.station }}' > data/next_map.txt
tools/ci/run_server.sh
unit_tests_and_sql:
name: Unit Tests + SQL Validation
runs-on: ubuntu-22.04
strategy:
fail-fast: false # Let all map tests run to completion
fail-fast: false
matrix:
maptype:
[
'/datum/map/boxstation',
'/datum/map/deltastation',
'/datum/map/metastation',
'/datum/map/cerestation',
'/datum/map/emeraldstation',
]
byondtype: ['STABLE', 'BETA']
services:
mariadb:
Expand Down Expand Up @@ -144,8 +166,8 @@ jobs:
run: |
tools/ci/install_byond.sh '${{ matrix.byondtype }}'
source $HOME/BYOND/byond/bin/byondsetup
DreamMaker -DMULTIINSTANCE -DCIBUILDING paradise.dme
echo '${{ matrix.maptype }}' > data/next_map.txt
DreamMaker -DGAME_TESTS -DTEST_CONFIG_OVERRIDE=\"unit_tests\" -DMULTIINSTANCE -DCIBUILDING paradise.dme
echo '/datum/map/test_tiny' > data/next_map.txt
tools/ci/run_server.sh
windows_dll_tests:
Expand Down
9 changes: 5 additions & 4 deletions code/_compile_options.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@

#ifdef LOCAL_GAME_TESTS
#define GAME_TESTS
#endif

#ifdef CIBUILDING
#define GAME_TESTS
#define MAP_TESTS
#endif

#if defined(CIBUILDING) && defined(LOCAL_GAME_TESTS)
#error CIBUILDING and LOCAL_GAME_TESTS should not be enabled at the same time!
#endif

#if defined(GAME_TESTS) || defined(MAP_TESTS)
#define TEST_RUNNER
#endif

/***** All toggles for the GC ref finder *****/

// #define REFERENCE_TRACKING // Uncomment to enable ref finding
Expand Down
7 changes: 3 additions & 4 deletions code/controllers/configuration/configuration_core.dm
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,12 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new())
safe_load(asset_cache, "asset_cache_configuration")

// Proc to load up instance-specific overrides
/datum/server_configuration/proc/load_overrides()
var/override_file = "config/overrides_[world.port].toml"
/datum/server_configuration/proc/load_overrides(override_file)
if(!fexists(override_file))
DIRECT_OUTPUT(world.log, "Overrides not found for this instance.")
DIRECT_OUTPUT(world.log, "Override file [override_file] not found for this instance.")
return

DIRECT_OUTPUT(world.log, "Overrides found for this instance. Loading them.")
DIRECT_OUTPUT(world.log, "Override file [override_file] found. Loading.")
var/start = start_watch() // Time tracking

raw_data = rustg_read_toml_file(override_file)
Expand Down
11 changes: 0 additions & 11 deletions code/controllers/configuration/sections/database_configuration.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,6 @@
var/async_thread_limit = 50

/datum/configuration_section/database_configuration/load_data(list/data)
// UNIT TESTS ARE DEFINED - USE CUSTOM CI VALUES
#ifdef GAME_TESTS

enabled = TRUE
// This needs to happen in the CI environment to ensure the example SQL version gets updated.
CONFIG_LOAD_NUM(version, data["sql_version"])

#else
// Load the normal config. Were not in CI mode
// Use the load wrappers here. That way the default isnt made 'null' if you comment out the config line
CONFIG_LOAD_BOOL(enabled, data["sql_enabled"])
CONFIG_LOAD_NUM(version, data["sql_version"])
CONFIG_LOAD_STR(address, data["sql_address"])
Expand All @@ -40,4 +30,3 @@
CONFIG_LOAD_STR(db, data["sql_database"])
CONFIG_LOAD_NUM(async_query_timeout, data["async_query_timeout"])
CONFIG_LOAD_NUM(async_thread_limit, data["async_thread_limit"])
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,5 @@
var/connstring = "redis://127.0.0.1/"

/datum/configuration_section/redis_configuration/load_data(list/data)
// UNIT TESTS ARE DEFINED - USE CUSTOM CI VALUES
#ifdef GAME_TESTS

// enabled = TRUE

#else
// Load the normal config. Were not in CI mode
// Use the load wrappers here. That way the default isnt made 'null' if you comment out the config line
CONFIG_LOAD_BOOL(enabled, data["redis_enabled"])
CONFIG_LOAD_STR(connstring, data["redis_connstring"])
#endif
2 changes: 1 addition & 1 deletion code/controllers/master.dm
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new

/datum/controller/master/New()
if(!random_seed)
#ifdef GAME_TESTS
#ifdef TEST_RUNNER
random_seed = 29051994
#else
random_seed = rand(1, 1e9)
Expand Down
6 changes: 2 additions & 4 deletions code/controllers/subsystem/SSticker.dm
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,8 @@ SUBSYSTEM_DEF(ticker)
if(GLOB.configuration.general.enable_night_shifts)
SSnightshift.check_nightshift(TRUE)

#ifdef GAME_TESTS
// Run map tests first in case unit tests futz with map state
GLOB.test_runner.RunMap()
GLOB.test_runner.Run()
#ifdef TEST_RUNNER
GLOB.test_runner.RunAll()
#endif

// Do this 10 second after roundstart because of roundstart lag, and make it more visible
Expand Down
16 changes: 10 additions & 6 deletions code/game/world.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
GLOBAL_LIST_INIT(map_transition_config, list(CC_TRANSITION_CONFIG))

#ifdef GAME_TESTS
#ifdef TEST_RUNNER
GLOBAL_DATUM(test_runner, /datum/test_runner)
#endif

Expand All @@ -26,7 +26,11 @@ GLOBAL_DATUM(test_runner, /datum/test_runner)
GLOB.configuration.load_configuration() // Load up the base config.toml
// Load up overrides for this specific instance, based on port
// If this instance is listening on port 6666, the server will look for config/overrides_6666.toml
GLOB.configuration.load_overrides()
GLOB.configuration.load_overrides("config/overrides_[world.port].toml")

#ifdef TEST_CONFIG_OVERRIDE
GLOB.configuration.load_overrides("config/tests/config_[TEST_CONFIG_OVERRIDE].toml")
#endif

// Right off the bat, load up the DB
SSdbcore.CheckSchemaVersion() // This doesnt just check the schema version, it also connects to the db! This needs to happen super early! I cannot stress this enough!
Expand All @@ -51,8 +55,8 @@ GLOBAL_DATUM(test_runner, /datum/test_runner)
if(TgsAvailable())
world.log = file("[GLOB.log_directory]/dd.log") //not all runtimes trigger world/Error, so this is the only way to ensure we can see all of them.

#ifdef GAME_TESTS
log_world("Unit Tests Are Enabled!")
#ifdef TEST_RUNNER
log_world("Test runner enabled.")
#endif

if(byond_version < MIN_COMPILER_VERSION || byond_build < MIN_COMPILER_BUILD)
Expand All @@ -69,7 +73,7 @@ GLOBAL_DATUM(test_runner, /datum/test_runner)
Master.Initialize(10, FALSE, TRUE)


#ifdef GAME_TESTS
#ifdef TEST_RUNNER
GLOB.test_runner = new
GLOB.test_runner.Start()
#endif
Expand Down Expand Up @@ -144,7 +148,7 @@ GLOBAL_LIST_EMPTY(world_topic_handlers)
Master.Shutdown() // Shutdown subsystems

// If we were running unit tests, finish that run
#ifdef GAME_TESTS
#ifdef TEST_RUNNER
GLOB.test_runner.Finalize()
return
#endif
Expand Down
20 changes: 20 additions & 0 deletions code/tests/_map_per_tile_test.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Map per-tile test.
*
* Per-tile map tests iterate over each tile of a map to perform a check, and
* fails the test if a tile does not pass the check. A new test can be
* written by extending /datum/map_per_tile_test, and implementing the check
* in CheckTile.
*/
/datum/map_per_tile_test
var/succeeded = TRUE
var/list/fail_reasons
var/failure_count = 0

/datum/map_per_tile_test/proc/CheckTile(turf/T)
Fail("CheckTile() called parent or not implemented")

/datum/map_per_tile_test/proc/Fail(turf/T, reason)
succeeded = FALSE
LAZYADD(fail_reasons, "[T.x],[T.y],[T.z]: [reason]")
failure_count++
15 changes: 11 additions & 4 deletions code/tests/game_tests.dm
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
//include game test files in this module in this ifdef
//Keep this sorted alphabetically

#ifdef GAME_TESTS
#ifdef TEST_RUNNER
#include "_game_test_puppeteer.dm"
#include "_game_test.dm"
#include "_map_per_tile_test.dm"
#include "test_runner.dm"
#endif

#ifdef GAME_TESTS
#include "atmos\test_ventcrawl.dm"
#include "attack_chain\test_attack_chain_cult_dagger.dm"
#include "attack_chain\test_attack_chain_machinery.dm"
Expand All @@ -13,7 +18,6 @@
#include "jobs\test_job_globals.dm"
#include "test_aicard_icons.dm"
#include "test_announcements.dm"
#include "test_areas_apcs.dm"
#include "test_components.dm"
#include "test_config_sanity.dm"
#include "test_crafting_lists.dm"
Expand All @@ -22,12 +26,10 @@
#include "test_init_sanity.dm"
#include "test_log_format.dm"
#include "test_map_templates.dm"
#include "test_map_tests.dm"
#include "test_missing_icons.dm"
#include "test_origin_tech.dm"
#include "test_purchase_reference_test.dm"
#include "test_reagent_id_typos.dm"
#include "test_runner.dm"
#include "test_rustg_version.dm"
#include "test_spawn_humans.dm"
#include "test_spell_targeting_test.dm"
Expand All @@ -37,3 +39,8 @@
#include "test_subsystem_metric_sanity.dm"
#include "test_timer_sanity.dm"
#endif

#ifdef MAP_TESTS
#include "test_areas_apcs.dm"
#include "test_map_tests.dm"
#endif
21 changes: 0 additions & 21 deletions code/tests/test_map_tests.dm
Original file line number Diff line number Diff line change
@@ -1,24 +1,3 @@
/**
* Map per-tile test.
*
* Per-tile map tests iterate over each tile of a map to perform a check, and
* fails the test if a tile does not pass the check. A new test can be
* written by extending /datum/map_per_tile_test, and implementing the check
* in CheckTile.
*/
/datum/map_per_tile_test
var/succeeded = TRUE
var/list/fail_reasons
var/failure_count = 0

/datum/map_per_tile_test/proc/CheckTile(turf/T)
Fail("CheckTile() called parent or not implemented")

/datum/map_per_tile_test/proc/Fail(turf/T, reason)
succeeded = FALSE
LAZYADD(fail_reasons, "[T.x],[T.y],[T.z]: [reason]")
failure_count++

/**
* Check to ensure that APCs have a cable node on their tile.
*/
Expand Down
70 changes: 39 additions & 31 deletions code/tests/test_runner.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,18 @@
// Running the tests is part of the ticker's start function, because I cant think of any better place to put it
SSticker.force_start = TRUE


/datum/test_runner/proc/RunMap(z_level = 2)
CHECK_TICK

var/list/tests = list()

for(var/I in subtypesof(/datum/map_per_tile_test))
tests += new I
test_logs[I] = list()
durations[I] = 0

for(var/turf/T in block(1, 1, z_level, world.maxx, world.maxy, z_level))
for(var/datum/map_per_tile_test/test in tests)
if(test.failure_count < MAX_MAP_TEST_FAILURE_COUNT)
var/duration = REALTIMEOFDAY
test.CheckTile(T)
durations[test.type] += REALTIMEOFDAY - duration

if(test.failure_count >= MAX_MAP_TEST_FAILURE_COUNT)
test.Fail(T, "failure threshold reached at this tile")

CHECK_TICK

for(var/datum/map_per_tile_test/test in tests)
if(!test.succeeded)
failed_any_test = TRUE
test_logs[test.type] += test.fail_reasons

QDEL_LIST_CONTENTS(tests)

/datum/test_runner/proc/RunAll()
#ifdef MAP_TESTS
// Run map tests first in case unit tests futz with map state
RunMap()
#endif
#ifdef GAME_TESTS
Run()
#endif
SSticker.reboot_helper("Unit Test Reboot", "tests ended", 0)

/datum/test_runner/proc/Run()
log_world("Test runner: game tests.")
CHECK_TICK

for(var/I in subtypesof(/datum/game_test))
Expand Down Expand Up @@ -84,10 +64,38 @@

CHECK_TICK

SSticker.reboot_helper("Unit Test Reboot", "tests ended", 0)
/datum/test_runner/proc/RunMap(z_level = 2)
log_world("Test runner: map tests.")
CHECK_TICK

var/list/tests = list()

for(var/I in subtypesof(/datum/map_per_tile_test))
tests += new I
test_logs[I] = list()
durations[I] = 0

for(var/turf/T in block(1, 1, z_level, world.maxx, world.maxy, z_level))
for(var/datum/map_per_tile_test/test in tests)
if(test.failure_count < MAX_MAP_TEST_FAILURE_COUNT)
var/duration = REALTIMEOFDAY
test.CheckTile(T)
durations[test.type] += REALTIMEOFDAY - duration

if(test.failure_count >= MAX_MAP_TEST_FAILURE_COUNT)
test.Fail(T, "failure threshold reached at this tile")

CHECK_TICK

for(var/datum/map_per_tile_test/test in tests)
if(!test.succeeded)
failed_any_test = TRUE
test_logs[test.type] += test.fail_reasons

QDEL_LIST_CONTENTS(tests)

/datum/test_runner/proc/Finalize(emit_failures = FALSE)
log_world("Test runner: finalizing.")
var/time = world.timeofday
set waitfor = FALSE

Expand Down
Loading

0 comments on commit 8e4dc61

Please sign in to comment.