Travis Update Finale: Unit Tests + SQL Validation (#13331)

* SQL Validation, the first of many

* Initial test of the world loading

* This was prefixed when it shouldnt have been :v

* This also isnt a valid table

* Escape time

* Chmod

* This **should** work

* Oops

* RUST gone bust

* Please work

* Why did I do this twice

* I think I got it

* Fixes AFK SS

* AAAAAAAAAAAAAAAAAAAAAA

* Fixes AI cam runtime

* Cleanup

* *screams*

* Fare fixes

* Removes un-needed stuff

* I hope this works

* chmoooood

* SQL Version Unit Test

* Failure test

* Kinda ironic how I forgot this

* Task failed successfully

* Moves a global var around

* Bump SQL version in travis

* New test: SQL example DBconfig update

* Lets test an invalid version

* TASK FAILED SUCCESSFULLY

* Programmatic maplist generation

* Removes a duplicate check

* Lets try this

* What about this

* hnnng

* Lets just update BYOND
This commit is contained in:
AffectedArc07
2020-06-27 08:26:58 +01:00
committed by GitHub
parent 30d9be47be
commit 0c8d95dd65
28 changed files with 917 additions and 170 deletions
+12
View File
@@ -0,0 +1,12 @@
//include unit test files in this module in this ifdef
//Keep this sorted alphabetically
#ifdef UNIT_TESTS
#include "component_tests.dm"
#include "reagent_id_typos.dm"
#include "spawn_humans.dm"
#include "sql.dm"
#include "subsystem_init.dm"
#include "timer_sanity.dm"
#include "unit_test.dm"
#endif
@@ -0,0 +1,12 @@
/datum/unit_test/component_duping/Run()
var/list/bad_dms = list()
var/list/bad_dts = list()
for(var/t in typesof(/datum/component))
var/datum/component/comp = t
if(!isnum(initial(comp.dupe_mode)))
bad_dms += t
var/dupe_type = initial(comp.dupe_type)
if(dupe_type && !ispath(dupe_type))
bad_dts += t
if(length(bad_dms) || length(bad_dts))
Fail("Components with invalid dupe modes: ([bad_dms.Join(",")]) ||| Components with invalid dupe types: ([bad_dts.Join(",")])")
@@ -0,0 +1,11 @@
/datum/unit_test/reagent_id_typos
/datum/unit_test/reagent_id_typos/Run()
for(var/I in GLOB.chemical_reactions_list)
for(var/V in GLOB.chemical_reactions_list[I])
var/datum/chemical_reaction/R = V
for(var/id in (R.required_reagents + R.required_catalysts))
if(!GLOB.chemical_reagents_list[id])
Fail("Unknown chemical id \"[id]\" in recipe [R.type]")
+8
View File
@@ -0,0 +1,8 @@
/datum/unit_test/spawn_humans/Run()
var/locs = block(run_loc_bottom_left, run_loc_top_right)
for(var/I in 1 to 5)
new /mob/living/carbon/human(pick(locs))
// There is a 5 second delay here so that all the items on the humans have time to initialize and spawn
sleep(50)
+42
View File
@@ -0,0 +1,42 @@
// Unit test to check SQL version has been updated properly.,
/datum/unit_test/sql_version/Run()
// Check if the SQL version set in the code is equal to the travis DB config
if(config.sql_enabled && sql_version != SQL_VERSION)
Fail("SQL version error: Game is running V[SQL_VERSION] but config is V[sql_version]. You may need to update tools/travis/dbconfig.txt")
// Check if the travis DB config is up to date with the example dbconfig
// This proc is a little unclean but it works
var/example_db_version
var/list/Lines = file2list("config/example/dbconfig.txt")
for(var/t in Lines)
if(!t) continue
t = trim(t)
if(length(t) == 0)
continue
else if(copytext(t, 1, 2) == "#")
continue
var/pos = findtext(t, " ")
var/name = null
var/value = null
if(pos)
name = lowertext(copytext(t, 1, pos))
value = copytext(t, pos + 1)
else
name = lowertext(t)
if(!name)
continue
switch(name)
if("db_version")
example_db_version = text2num(value)
if(!example_db_version)
Fail("SQL version error: File config/example/dbconfig.txt does not have a valid SQL version set!")
if(example_db_version != SQL_VERSION)
Fail("SQL version error: Game is running V[SQL_VERSION] but config/example/dbconfig.txt is V[example_db_version].")
@@ -0,0 +1,7 @@
/datum/unit_test/subsystem_init/Run()
for(var/i in Master.subsystems)
var/datum/controller/subsystem/ss = i
if(ss.flags & SS_NO_INIT)
continue
if(!ss.initialized)
Fail("[ss]([ss.type]) is a subsystem meant to initialize but doesn't get set as initialized.")
+3
View File
@@ -0,0 +1,3 @@
/datum/unit_test/timer_sanity/Run()
if(SStimer.bucket_count < 0)
Fail("SStimer is going into negative bucket count from something")
+102
View File
@@ -0,0 +1,102 @@
/*
Usage:
Override /Run() to run your test code
Call Fail() to fail the test (You should specify a reason)
You may use /New() and /Destroy() for setup/teardown respectively
You can use the run_loc_bottom_left and run_loc_top_right to get turfs for testing
*/
/// VARS FOR UNIT TESTS
GLOBAL_DATUM(current_test, /datum/unit_test)
GLOBAL_VAR_INIT(failed_any_test, FALSE)
GLOBAL_VAR(test_log)
/datum/unit_test
//Bit of metadata for the future maybe
var/list/procs_tested
//usable vars
var/turf/run_loc_bottom_left
var/turf/run_loc_top_right
//internal shit
var/succeeded = TRUE
var/list/fail_reasons
/datum/unit_test/New()
run_loc_bottom_left = locate(1, 1, 1)
run_loc_top_right = locate(5, 5, 1)
/datum/unit_test/Destroy()
//clear the test area
for(var/atom/movable/AM in block(run_loc_bottom_left, run_loc_top_right))
qdel(AM)
return ..()
/datum/unit_test/proc/Run()
Fail("Run() called parent or not implemented")
/datum/unit_test/proc/Fail(reason = "No reason")
succeeded = FALSE
if(!istext(reason))
reason = "FORMATTED: [reason != null ? reason : "NULL"]"
LAZYADD(fail_reasons, reason)
/proc/RunUnitTests()
CHECK_TICK
for(var/I in subtypesof(/datum/unit_test))
var/datum/unit_test/test = new I
GLOB.current_test = test
var/duration = REALTIMEOFDAY
test.Run()
duration = REALTIMEOFDAY - duration
GLOB.current_test = null
GLOB.failed_any_test |= !test.succeeded
var/list/log_entry = list("[test.succeeded ? "PASS" : "FAIL"]: [I] [duration / 10]s")
var/list/fail_reasons = test.fail_reasons
qdel(test)
for(var/J in 1 to LAZYLEN(fail_reasons))
log_entry += "\tREASON #[J]: [fail_reasons[J]]"
log_world(log_entry.Join("\n"))
CHECK_TICK
world.Reboot("Unit Test Reboot", "end_test", "tests ended", 0)
// OTHER MISC PROCS RELATED TO UNIT TESTS //
/world/proc/HandleTestRun()
//trigger things to run the whole process
Master.sleep_offline_after_initializations = FALSE
// This will have the ticker set the game up
// 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
/world/proc/FinishTestRun()
set waitfor = FALSE
var/list/fail_reasons
if(GLOB)
if(GLOB.total_runtimes != 0)
fail_reasons = list("Total runtimes: [GLOB.total_runtimes]")
if(!GLOB.log_directory)
LAZYADD(fail_reasons, "Missing GLOB.log_directory!")
if(GLOB.failed_any_test)
LAZYADD(fail_reasons, "Unit Tests failed!")
else
fail_reasons = list("Missing GLOB!")
if(!fail_reasons)
text2file("Success!", "data/clean_run.lk")
else
log_world("Test run failed!\n[fail_reasons.Join("\n")]")
sleep(0) //yes, 0, this'll let Reboot finish and prevent byond memes
del(src) //shut it down