mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 20:48:56 +01:00
Better Unit Tests - Runs All Of Them On A Single Map (exc. map unit tests) and C&D Split-Up (#96368)
## About The Pull Request
### Don't run every single test
I've had this on my mind for several months and it being brought up
recently reminded me so here we are.
Unit tests only run on `runtimestation_minimal.dmm` now with the
exception of map tests. The following unit tests are declared as map
tests but I didn't see any map dependent logic so 🤷
- `/datum/unit_test/maptest_baseturfs_unmodified_scrape`
- `/datum/unit_test/maptest_baseturfs_placed_on_top`
- `/datum/unit_test/maptest_baseturfs_placed_on_bottom`
- `/datum/unit_test/maptest_get_turf_pixel`
- `/datum/unit_test/maptest_load_map_security`
- `/datum/unit_test/maptest_modular_map_loader`
- `/datum/unit_test/maptest_turf_icons`
`/datum/unit_test/subsystem_init` isn't really a mapping unit test but I
figured somehow, someway, maps might fuck with subsystem initializations
so I just decided to include it.
### Splits up the create & destroy test
Idk, pretty simple. Create & destroy is now split up across all
integration tests and ran in parallel.
## Why It's Good For The Game
oranges promised me "500 nzd" yo
## Changelog
No player facing changes
This commit is contained in:
@@ -39,7 +39,7 @@
|
||||
/// *Only* run the test provided within the parentheses
|
||||
/// This is useful for debugging when you want to reduce noise, but should never be pushed
|
||||
/// Intended to be used in the manner of `TEST_FOCUS(/datum/unit_test/math)`
|
||||
#define TEST_FOCUS(test_path) ##test_path { focus = TRUE; }
|
||||
#define TEST_FOCUS(test_path) ##test_path { test_flags = UNIT_TEST_FOCUS; }
|
||||
|
||||
/// Run the test provided within the parentheses run_count times
|
||||
/// Useful for debugging flaky tests that only fail sometimes
|
||||
@@ -67,6 +67,16 @@
|
||||
*/
|
||||
#define TEST_AFTER_CREATE_AND_DESTROY INFINITY
|
||||
|
||||
// Unit test bitflags
|
||||
|
||||
/// If any unit test has this bitflag, only unit tests with UNIT_TEST_FOCUS will run.
|
||||
#define UNIT_TEST_FOCUS (1<<0)
|
||||
/// This unit test only runs on specially designated unit test maps (Should only ever be one).
|
||||
#define UNIT_TEST_DEBUG_MAP_ONLY (1<<1)
|
||||
|
||||
#define UNIT_TEST_BASIC (UNIT_TEST_DEBUG_MAP_ONLY)
|
||||
#define UNIT_TEST_MAP_TEST (NONE)
|
||||
|
||||
/// Change color to red on ANSI terminal output, if enabled with -DANSICOLORS.
|
||||
#ifdef ANSICOLORS
|
||||
#define TEST_OUTPUT_RED(text) "\x1B\x5B1;31m[text]\x1B\x5B0m"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Verifies that an area's perception of their "turfs" is correct, and no other area overlaps with them
|
||||
/// Quite slow, but needed
|
||||
/datum/unit_test/maptest_area_contents
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
priority = TEST_LONGER
|
||||
|
||||
/datum/unit_test/maptest_area_contents/Run()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* This test checks that all areas are connected to their distribution loops
|
||||
*/
|
||||
/datum/unit_test/atmospherics_sanity
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
priority = TEST_LONGER // we iterate over all atmospherics devices on the starting networks
|
||||
|
||||
/// List of areas to start crawling from
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
///Checking all powernets to see if they are properly connected and powered.
|
||||
/datum/unit_test/cable_powernets
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
|
||||
/datum/unit_test/cable_powernets/Run()
|
||||
for(var/datum/powernet/powernets as anything in SSmachines.powernets)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/datum/unit_test/cargo_dep_order_locations
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
|
||||
/datum/unit_test/cargo_dep_order_locations/Run()
|
||||
for(var/datum/job_department/department as anything in SSjob.joinable_departments)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
///Delete one of every type, sleep a while, then check to see if anything has gone fucky
|
||||
/datum/unit_test/create_and_destroy
|
||||
// Since this unit test takes so damn long, we split it up across all runners
|
||||
test_flags = parent_type::test_flags & ~UNIT_TEST_DEBUG_MAP_ONLY
|
||||
//You absolutely must run after (almost) everything else
|
||||
priority = TEST_CREATE_AND_DESTROY
|
||||
|
||||
@@ -15,6 +17,30 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE)
|
||||
|
||||
GLOB.running_create_and_destroy = TRUE
|
||||
var/list/type_paths_to_check = (valid_typesof(/atom/movable) + valid_typesof(/turf)) - uncreatables // No areas please
|
||||
|
||||
// This code is responsible for splitting up create & destroy across multiple integration tests.
|
||||
var/total_amount_to_check = length(type_paths_to_check)
|
||||
var/runner_count = length(config.maplist)
|
||||
|
||||
var/split_up_amount = floor(total_amount_to_check / runner_count)
|
||||
|
||||
var/what_map_index_are_we = 1
|
||||
for(var/map_name, _map_config in config.maplist)
|
||||
var/datum/map_config/map_config = _map_config
|
||||
if(SSmapping.current_map.map_name == map_config.map_name)
|
||||
break
|
||||
what_map_index_are_we++
|
||||
|
||||
var/start_index = (what_map_index_are_we - 1) * split_up_amount
|
||||
// Instead of super trying to make it an equal split, we just give the remainder tests to the final runner
|
||||
var/end_index = (what_map_index_are_we == runner_count) ? total_amount_to_check : start_index + split_up_amount
|
||||
|
||||
// +1 because byond's list.Copy() implementation is weird
|
||||
type_paths_to_check = type_paths_to_check.Copy(start_index, end_index + 1)
|
||||
|
||||
log_world("Running create and destroy on [length(type_paths_to_check)] atoms out of the [total_amount_to_check] total")
|
||||
log_world("([start_index] [type_paths_to_check[1]]) - ([end_index] [type_paths_to_check[length(type_paths_to_check)]])")
|
||||
|
||||
for(var/type_path in type_paths_to_check)
|
||||
if(ispath(type_path, /turf))
|
||||
spawn_at.ChangeTurf(type_path)
|
||||
@@ -28,6 +54,8 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE)
|
||||
else
|
||||
var/atom/creation = new type_path(spawn_at)
|
||||
if(QDELETED(creation))
|
||||
// Same as below
|
||||
creation = null
|
||||
continue
|
||||
//Go all in
|
||||
qdel(creation, force = TRUE)
|
||||
@@ -50,7 +78,7 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE)
|
||||
|
||||
var/list/queues_we_care_about = list()
|
||||
// All of em, I want hard deletes too, since we rely on the debug info from them
|
||||
for(var/i in 1 to GC_QUEUE_HARDDELETE)
|
||||
for(var/i in GC_QUEUE_FILTER to GC_QUEUE_HARDDELETE)
|
||||
queues_we_care_about += i
|
||||
|
||||
//Now that we've qdel'd everything, let's sleep until the gc has processed all the shit we care about
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
* This unit test requires every (unless ignored) atom to have been created at least once
|
||||
* for a more accurate search, which is why it's run after create_and_destroy is done running.
|
||||
*/
|
||||
test_flags = parent_type::test_flags & ~UNIT_TEST_DEBUG_MAP_ONLY
|
||||
priority = TEST_AFTER_CREATE_AND_DESTROY
|
||||
|
||||
/datum/unit_test/dcs_check_list_arguments/Run()
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* Then, checks if every non-ignored region has a fire alarm in it
|
||||
*/
|
||||
/datum/unit_test/firedoor_regions
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
priority = TEST_LONGER
|
||||
|
||||
/datum/unit_test/firedoor_regions/Run()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/// Tests that [/datum/job/proc/get_default_roundstart_spawn_point] returns a landmark from all joinable jobs.
|
||||
/datum/unit_test/maptest_job_roundstart_spawnpoints
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
|
||||
/datum/unit_test/maptest_job_roundstart_spawnpoints/Run()
|
||||
for(var/datum/job/job as anything in SSjob.joinable_occupations)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Verifies that there are no space turfs inside a station area, or on any planetary z-level. Sometimes, these are introduced during the load of the map and are not present in the DMM itself.
|
||||
/// Let's just make sure that we have a stop-gap measure in place to catch these if they pop up so we don't put it onto production servers should something errant come up.
|
||||
/datum/unit_test/maptest_mapload_space_verification
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
// This test is quite taxing time-wise, so let's run it later than other faster tests.
|
||||
priority = TEST_LONGER
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/// Conveys all log_mapping messages as unit test failures, as they all indicate mapping problems.
|
||||
/datum/unit_test/maptest_log_mapping
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
// Happen before all other tests, to make sure we only capture normal mapping logs.
|
||||
priority = TEST_PRE
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
///Detects movables that may have been accidentally placed in space, as well as movables which do not have the proper nearspace area (meaning they aren't lit properly.)
|
||||
/datum/unit_test/maptest_mapping_nearstation_test
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
priority = TEST_PRE
|
||||
|
||||
/datum/unit_test/maptest_mapping_nearstation_test/Run()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Ensures we do not leave genturfs sitting around post work
|
||||
/// They serve as notice to the mapper and have no functionality, but it's good to make note of it here
|
||||
/datum/unit_test/orphaned_genturf
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
|
||||
/datum/unit_test/orphaned_genturf/Run()
|
||||
for(var/turf/open/genturf/orphaned in ALL_TURFS())
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* - In the type's initialize, REGISTER_REQUIRED_MAP_ITEM() a minimum and maximum
|
||||
*/
|
||||
/datum/unit_test/maptest_required_map_items
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
/// A list of all typepaths that we expect to be in the required items list
|
||||
var/list/expected_types = list()
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/// Tests that all subsystems that need to properly initialize.
|
||||
/datum/unit_test/subsystem_init
|
||||
test_flags = UNIT_TEST_MAP_TEST
|
||||
|
||||
/datum/unit_test/subsystem_init/Run()
|
||||
for(var/datum/controller/subsystem/subsystem as anything in Master.subsystems)
|
||||
|
||||
@@ -27,35 +27,37 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
|
||||
/proc/focused_tests()
|
||||
var/list/focused_tests = list()
|
||||
for (var/datum/unit_test/unit_test as anything in subtypesof(/datum/unit_test))
|
||||
if (initial(unit_test.focus))
|
||||
if (unit_test::test_flags & UNIT_TEST_FOCUS)
|
||||
focused_tests += unit_test
|
||||
|
||||
return focused_tests.len > 0 ? focused_tests : null
|
||||
return length(focused_tests) ? focused_tests : null
|
||||
|
||||
/datum/unit_test
|
||||
/// Do not instantiate if type matches this
|
||||
abstract_type = /datum/unit_test
|
||||
|
||||
//Bit of metadata for the future maybe
|
||||
var/list/procs_tested
|
||||
|
||||
/// The bottom left floor turf of the testing zone
|
||||
var/turf/run_loc_floor_bottom_left
|
||||
|
||||
/// The top right floor turf of the testing zone
|
||||
var/turf/run_loc_floor_top_right
|
||||
///The priority of the test, the larger it is the later it fires
|
||||
/// Behavior flags for this unit test
|
||||
var/test_flags = UNIT_TEST_BASIC
|
||||
/// The priority of the test, the larger it is the later it fires
|
||||
var/priority = TEST_DEFAULT
|
||||
//internal shit
|
||||
var/focus = FALSE
|
||||
var/succeeded = TRUE
|
||||
var/list/allocated
|
||||
var/list/fail_reasons
|
||||
/// How many times this unit test will run. Use the TEST_REPEAT() macro
|
||||
var/times_to_run = 1
|
||||
|
||||
/// List of atoms that we don't want to ever initialize in an agnostic context, like for Create and Destroy. Stored on the base datum for usability in other relevant tests that need this data.
|
||||
var/static/list/uncreatables = null
|
||||
// internal shit
|
||||
/// If this test has passed or not
|
||||
var/succeeded = TRUE
|
||||
/// The bottom left floor turf of the testing zone
|
||||
var/turf/run_loc_floor_bottom_left
|
||||
/// The top right floor turf of the testing zone
|
||||
var/turf/run_loc_floor_top_right
|
||||
/// A list of instances created by this unit test. Use allocate()
|
||||
var/list/allocated
|
||||
/// Lazy list of why this unit test failed.
|
||||
var/list/fail_reasons
|
||||
|
||||
/// List of atoms that we don't want to ever initialize in an agnostic context, like for Create and Destroy.
|
||||
/// Stored on the base datum for usability in other relevant tests that need this data.
|
||||
var/static/list/uncreatables = null
|
||||
/// Reference to the blank z-level containing our testing enviroment
|
||||
var/static/datum/space_level/reservation
|
||||
|
||||
/proc/cmp_unit_test_priority(datum/unit_test/a, datum/unit_test/b)
|
||||
@@ -66,10 +68,9 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
|
||||
var/datum/map_template/unit_tests/template = new
|
||||
reservation = template.load_new_z()
|
||||
|
||||
if (isnull(uncreatables))
|
||||
uncreatables = build_list_of_uncreatables()
|
||||
uncreatables ||= build_list_of_uncreatables()
|
||||
|
||||
allocated = new
|
||||
allocated = list()
|
||||
|
||||
run_loc_floor_bottom_left = get_turf(locate(/obj/effect/landmark/unit_test_bottom_left) in GLOB.landmarks_list)
|
||||
run_loc_floor_top_right = get_turf(locate(/obj/effect/landmark/unit_test_top_right) in GLOB.landmarks_list)
|
||||
@@ -367,15 +368,37 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
|
||||
/proc/RunUnitTests()
|
||||
CHECK_TICK
|
||||
|
||||
var/list/tests_to_run = subtypesof(/datum/unit_test)
|
||||
// Find our primary unit test map & find out if we are the secondary
|
||||
var/datum/map_config/primary_unit_test_map
|
||||
var/is_secondary_unit_test_map = FALSE
|
||||
var/found_secondary_unit_test_map = FALSE
|
||||
for(var/map_name, _map_config in config.maplist)
|
||||
var/datum/map_config/map_config = _map_config
|
||||
if(map_config.is_unit_test_map)
|
||||
primary_unit_test_map = map_config
|
||||
if(!LAZYLEN(map_config.skipped_tests) && !found_secondary_unit_test_map)
|
||||
found_secondary_unit_test_map = TRUE
|
||||
if(SSmapping.current_map.map_name == map_config.map_name)
|
||||
is_secondary_unit_test_map = TRUE
|
||||
|
||||
var/list/tests_to_run = list()
|
||||
var/list/focused_tests = list()
|
||||
for (var/_test_to_run in tests_to_run)
|
||||
var/datum/unit_test/test_to_run = _test_to_run
|
||||
if (initial(test_to_run.focus))
|
||||
focused_tests += test_to_run
|
||||
for (var/datum/unit_test/potential_test as anything in subtypesof(/datum/unit_test))
|
||||
// If the test has [UNIT_TEST_DEBUG_MAP_ONLY] and we aren't the primary unit test map, skip it.
|
||||
// HOWEVER, some unit tests are incompatible with the primary testing map, so we must offload them a secondary one with no blacklisted tests.
|
||||
if((potential_test::test_flags & UNIT_TEST_DEBUG_MAP_ONLY) && !SSmapping.current_map.is_unit_test_map && \
|
||||
!(primary_unit_test_map.skipped_tests?.Find(potential_test) && is_secondary_unit_test_map) \
|
||||
)
|
||||
continue
|
||||
if (potential_test::test_flags & UNIT_TEST_FOCUS)
|
||||
focused_tests += potential_test
|
||||
continue
|
||||
tests_to_run += potential_test
|
||||
if(length(focused_tests))
|
||||
tests_to_run = focused_tests
|
||||
|
||||
primary_unit_test_map = null // I'm paranoid
|
||||
|
||||
sortTim(tests_to_run, GLOBAL_PROC_REF(cmp_unit_test_priority))
|
||||
|
||||
var/list/test_results = list()
|
||||
|
||||
Reference in New Issue
Block a user