diff --git a/.github/workflows/byond.yml b/.github/workflows/byond.yml index b39f676ab72..9f7e7a2ccad 100644 --- a/.github/workflows/byond.yml +++ b/.github/workflows/byond.yml @@ -670,6 +670,131 @@ jobs: retention-days: 5 + +########################################### +############# EXOPLANETS TESTS ############ +########################################### + exoplanet_testing: + name: Run Exoplanet Tests + runs-on: ubuntu-22.04 + + if: ${{ !(contains(github.event.head_commit.message, '[ci skip]')) && !(contains(github.event.head_commit.message, '[ut skip]'))}} + needs: [validate-structure, lint-spacemandmm, lint-opendream, lint-tgui, lint-misc] + + services: + mariadb: + image: mariadb:10.11 + ports: + - 3306 + env: + MYSQL_USER: build + MYSQL_PASSWORD: build + MYSQL_DATABASE: game + MYSQL_ROOT_PASSWORD: root + + concurrency: + group: unit-tests-exoplanet_testing-${{ matrix.map }}-${{ matrix.pod }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + + strategy: + matrix: + map: [exoplanet_testing] + pod: [exoplanet_testing-1, exoplanet_testing-2, exoplanet_testing-3] + fail-fast: false + + steps: + + #This allows us to SSH into the pod, and it's only enabled if we're running in debug mode + - name: Setup TMATE session (Debug only) + uses: mxschmitt/action-tmate@v3 + if: ${{ env.RUNNER_DEBUG_SHELL == true }} + with: + detached: true + timeout-minutes: 5 + + #Checkout the repository + - name: Checkout repository + uses: actions/checkout@v4 + + #Initialize the environment variables + - name: Set ENV variables + run: bash dependencies.sh + + #Restores BYOND cache + - name: Restore BYOND cache + uses: actions/cache@v3 + with: + path: ~/BYOND/* + key: ${{ runner.os }}-byond-${{ env.BYOND_MAJOR }}-${{ env.BYOND_MINOR }} + + - name: Restore FlyWay cache + uses: actions/cache@v3 + with: + path: ~/flyway + key: ${{ runner.os }}-flyway-${{ env.FLYWAY_BUILD }} + + #Add the x86 architecture and update apt-get's local indexes + - name: Prepare OS Environtment + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + + #Installs the packages we need, from a cache + - name: Install OS Packages + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: gcc-multilib zlib1g-dev:i386 libssl-dev:i386 libgcc-s1:i386 libc6:i386 + version: 1.1 + + #And natively, the packages that break from a cache + - name: Install OS Packages (Native) + run: | + sudo apt-get install libgcc-s1:i386 libssl-dev:i386 + + #Install flyway + - name: Install Flyway + run: | + tools/ci/install_flyway.sh + + #Apply the database migration + - name: Apply Database Migrations (FlyWay) + env: + PORT: ${{ job.services.mariadb.ports[3306] }} + run: | + $HOME/flyway/flyway-$FLYWAY_BUILD/flyway migrate -user=root -password=root -url="jdbc:mariadb://localhost:$PORT/game" -validateMigrationNaming="true" + + - name: Install BYOND & rust_g + run: | + source dependencies.sh + bash tools/ci/install_byond.sh + source $HOME/BYOND/byond/bin/byondsetup + bash tools/ci/install_rust_g.sh + + - name: Configure pod, build and run + env: + PORT: ${{ job.services.mariadb.ports[3306] }} + POD: ${{ matrix.pod }} + run: | + export LD_LIBRARY_PATH=./:$PWD:$HOME/BYOND/byond/bin:/usr/local/lib:$LD_LIBRARY_PATH + scripts/dm.sh -DUNIT_TEST -M${{ matrix.map }} aurorastation.dme + grep "0 warnings" build_log.txt + echo -n "$POD" > config/unit_test/identifier.txt + + cp config/example/* config/ && cp config/ut/config-db.txt config/config.txt && cp config/ut/dbconfig.txt config/dbconfig.txt + echo "PORT $PORT" >> config/dbconfig.txt + $HOME/BYOND/byond/bin/DreamDaemon aurorastation.dmb -invisible -trusted -core 2>&1 | tee log.txt + grep "All Unit Tests Passed" log.txt + (! grep "runtime error:" log.txt) + + - name: Upload Condensed UT Log + uses: actions/upload-artifact@v3 + if: failure() || ${{ runner.debug }} + with: + name: condensed-${{ matrix.map }}-${{ matrix.pod }}.log + path: ./data/logs/**/condensed.log + retention-days: 5 + + ########################################### ############# TEST AWAY SITES ############# ########################################### diff --git a/code/modules/maps/planet_types/asteroid.dm b/code/modules/maps/planet_types/asteroid.dm index 1253e4712a2..e2ab8a72859 100644 --- a/code/modules/maps/planet_types/asteroid.dm +++ b/code/modules/maps/planet_types/asteroid.dm @@ -13,6 +13,8 @@ place_near_main = list(1, 1) + unit_test_groups = list(2) + /obj/effect/overmap/visitable/sector/exoplanet/barren/asteroid/update_icon() icon_state = "asteroid[rand(1,3)]" diff --git a/code/modules/maps/planet_types/barren.dm b/code/modules/maps/planet_types/barren.dm index a14b7144203..8f6182d5ab5 100644 --- a/code/modules/maps/planet_types/barren.dm +++ b/code/modules/maps/planet_types/barren.dm @@ -11,6 +11,7 @@ water_color = null ruin_planet_type = PLANET_BARREN ruin_allowed_tags = RUIN_AIRLESS|RUIN_LOWPOP|RUIN_MINING|RUIN_SCIENCE|RUIN_HOSTILE|RUIN_WRECK|RUIN_NATURAL + unit_test_groups = list(1) /obj/effect/overmap/visitable/sector/exoplanet/barren/generate_habitability() return HABITABILITY_BAD diff --git a/code/modules/maps/planet_types/crystal.dm b/code/modules/maps/planet_types/crystal.dm index ac0e1adc887..52851af4a12 100644 --- a/code/modules/maps/planet_types/crystal.dm +++ b/code/modules/maps/planet_types/crystal.dm @@ -13,6 +13,8 @@ ruin_planet_type = PLANET_CRYSTAL ruin_allowed_tags = RUIN_AIRLESS|RUIN_LOWPOP|RUIN_MINING|RUIN_SCIENCE|RUIN_HOSTILE|RUIN_WRECK|RUIN_NATURAL + unit_test_groups = list(3) + /obj/effect/overmap/visitable/sector/exoplanet/crystal/generate_habitability() return HABITABILITY_BAD diff --git a/code/modules/maps/planet_types/desert.dm b/code/modules/maps/planet_types/desert.dm index bf4c2a800e4..5dc12eec5be 100644 --- a/code/modules/maps/planet_types/desert.dm +++ b/code/modules/maps/planet_types/desert.dm @@ -16,6 +16,8 @@ ruin_planet_type = PLANET_DESERT ruin_allowed_tags = RUIN_LOWPOP|RUIN_MINING|RUIN_SCIENCE|RUIN_HOSTILE|RUIN_WRECK|RUIN_NATURAL + unit_test_groups = list(1) + /obj/effect/overmap/visitable/sector/exoplanet/desert/generate_map() lightlevel = rand(5,10)/10 //deserts are usually :lit: ..() diff --git a/code/modules/maps/planet_types/grass.dm b/code/modules/maps/planet_types/grass.dm index 78abf372341..60b112b31a3 100644 --- a/code/modules/maps/planet_types/grass.dm +++ b/code/modules/maps/planet_types/grass.dm @@ -15,6 +15,8 @@ ruin_planet_type = PLANET_GRASS ruin_allowed_tags = RUIN_LOWPOP|RUIN_SCIENCE|RUIN_HOSTILE|RUIN_WRECK|RUIN_NATURAL + unit_test_groups = list(2) + /obj/effect/overmap/visitable/sector/exoplanet/grass/generate_map() if(prob(40)) lightlevel = rand(1,7)/10 //give a chance of twilight jungle diff --git a/code/modules/maps/planet_types/jungle.dm b/code/modules/maps/planet_types/jungle.dm index ff83dc1e2d2..02ad3cbec15 100644 --- a/code/modules/maps/planet_types/jungle.dm +++ b/code/modules/maps/planet_types/jungle.dm @@ -13,5 +13,7 @@ ruin_planet_type = PLANET_GROVE ruin_allowed_tags = RUIN_LOWPOP|RUIN_SCIENCE|RUIN_HOSTILE|RUIN_WRECK|RUIN_NATURAL + unit_test_groups = list(3) + /obj/effect/overmap/visitable/sector/exoplanet/grass/grove/get_surface_color() return "#5C7F34" diff --git a/code/modules/maps/planet_types/lava.dm b/code/modules/maps/planet_types/lava.dm index a31bf8b49fe..51b7cf3b5cc 100644 --- a/code/modules/maps/planet_types/lava.dm +++ b/code/modules/maps/planet_types/lava.dm @@ -15,6 +15,8 @@ ruin_planet_type = PLANET_LAVA ruin_allowed_tags = RUIN_AIRLESS|RUIN_LOWPOP|RUIN_MINING|RUIN_SCIENCE|RUIN_HOSTILE|RUIN_WRECK|RUIN_NATURAL + unit_test_groups = list(1) + /obj/effect/overmap/visitable/sector/exoplanet/lava/generate_habitability() return HABITABILITY_BAD diff --git a/code/modules/maps/planet_types/snow.dm b/code/modules/maps/planet_types/snow.dm index 85c926641a1..0f76c2924f9 100644 --- a/code/modules/maps/planet_types/snow.dm +++ b/code/modules/maps/planet_types/snow.dm @@ -17,6 +17,8 @@ ruin_planet_type = PLANET_SNOW ruin_allowed_tags = RUIN_LOWPOP|RUIN_MINING|RUIN_SCIENCE|RUIN_HOSTILE|RUIN_WRECK|RUIN_NATURAL + unit_test_groups = list(2) + /obj/effect/overmap/visitable/sector/exoplanet/snow/generate_atmosphere() ..() if(atmosphere) diff --git a/code/modules/overmap/exoplanets/exoplanet.dm b/code/modules/overmap/exoplanets/exoplanet.dm index e0e6d0d5d1f..e0c00090982 100644 --- a/code/modules/overmap/exoplanets/exoplanet.dm +++ b/code/modules/overmap/exoplanets/exoplanet.dm @@ -75,6 +75,10 @@ var/generated_name = TRUE var/ring_chance = 20 //the chance of this exoplanet spawning with a ring on its sprite + ///A list of groups, as strings, that this exoplanet belongs to. When adding new map templates, try to keep this balanced on the CI execution time, or consider adding a new one + ///ONLY IF IT'S THE LONGEST RUNNING CI POD AND THEY ARE ALREADY BALANCED + var/list/unit_test_groups = list() + /obj/effect/overmap/visitable/sector/exoplanet/proc/generate_habitability() var/roll = rand(1,100) @@ -93,7 +97,31 @@ /obj/effect/overmap/visitable/sector/exoplanet/update_icon() icon_state = "globe[rand(1,3)]" -/obj/effect/overmap/visitable/sector/exoplanet/New(nloc, max_x, max_y) +/obj/effect/overmap/visitable/sector/exoplanet/New(loc, max_x, max_y, being_generated_for_unit_test = FALSE) + + //If we are being generated for unit testing, determine if we actually want to be generated here or not + if(being_generated_for_unit_test) + + //Check that noone forgot to set the test group on an exoplanet, except for the lore ones, we don't care about them + //as we do not test them currently + if(!length(src.unit_test_groups) && src.ruin_planet_type != PLANET_LORE) + SSunit_tests_config.UT.fail("**** The exoplanet --> [src.name] - [src.type] <-- does not have any unit test group set! ****", __FILE__, __LINE__) + qdel_self() + return FALSE + + //Check that we are in this test group, otherwise skip this exoplanet type from generation + var/in_this_test_group = FALSE + for(var/unit_test_group in src.unit_test_groups) + if((unit_test_group in SSunit_tests_config.config["exoplanet_types_unit_test_groups"]) || SSunit_tests_config.config["exoplanet_types_unit_test_groups"] == "*") + in_this_test_group = TRUE + break + + if(!in_this_test_group) + SSunit_tests_config.UT.debug("**** The exoplanet --> [src.name] - [src.type] <-- was not loaded as its group is not in the exoplanet_types_unit_test_groups! ****", __FILE__, __LINE__) + qdel_self() + return FALSE + + if(!SSatlas.current_map.use_overmap) return diff --git a/config/unit_test/ut_pods_configuration.json b/config/unit_test/ut_pods_configuration.json index a62beed9130..8d1a79de2e8 100644 --- a/config/unit_test/ut_pods_configuration.json +++ b/config/unit_test/ut_pods_configuration.json @@ -2,42 +2,68 @@ "generic":{ "unit_test_groups":["generic", "mob", "machinery"], "map_template_unit_test_groups":[false], + "exoplanet_types_unit_test_groups":[false], "exoplanets_ruins":true }, "create_and_destroy":{ "unit_test_groups":["create and destroy"], "map_template_unit_test_groups":[false], + "exoplanet_types_unit_test_groups":[false], "exoplanets_ruins":true }, "maptest":{ "unit_test_groups":["map"], "map_template_unit_test_groups":["*"], + "exoplanet_types_unit_test_groups":[false], + "exoplanets_ruins":true + }, + + "exoplanet_testing-1":{ + "unit_test_groups":["map"], + "map_template_unit_test_groups":["*"], + "exoplanet_types_unit_test_groups":[1], + "exoplanets_ruins":true + }, + "exoplanet_testing-2":{ + "unit_test_groups":["map"], + "map_template_unit_test_groups":["*"], + "exoplanet_types_unit_test_groups":[2], + "exoplanets_ruins":true + }, + "exoplanet_testing-3":{ + "unit_test_groups":["map"], + "map_template_unit_test_groups":["*"], + "exoplanet_types_unit_test_groups":[3], "exoplanets_ruins":true }, "ruins":{ "unit_test_groups":["ruins", "map"], "map_template_unit_test_groups":[false], + "exoplanet_types_unit_test_groups":[false], "exoplanets_ruins":false }, "awaysites-1":{ "unit_test_groups":["map"], "map_template_unit_test_groups":[1], + "exoplanet_types_unit_test_groups":[false], "exoplanets_ruins":true }, "awaysites-2":{ "unit_test_groups":["map"], "map_template_unit_test_groups":[2], + "exoplanet_types_unit_test_groups":[false], "exoplanets_ruins":true }, "awaysites-3":{ "unit_test_groups":["map"], "map_template_unit_test_groups":[3], + "exoplanet_types_unit_test_groups":[false], "exoplanets_ruins":true } } diff --git a/html/changelogs/fluffyghost-exoplanets_ut_load_balancing.yml b/html/changelogs/fluffyghost-exoplanets_ut_load_balancing.yml new file mode 100644 index 00000000000..f89ceaa3d1f --- /dev/null +++ b/html/changelogs/fluffyghost-exoplanets_ut_load_balancing.yml @@ -0,0 +1,41 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: FluffyGhost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - backend: "The CI should now load balance the exoplanets to test across 3 pods." diff --git a/maps/exoplanet_testing/exoplanet_testing.dm b/maps/exoplanet_testing/exoplanet_testing.dm index dea004f27db..d0aabd07773 100644 --- a/maps/exoplanet_testing/exoplanet_testing.dm +++ b/maps/exoplanet_testing/exoplanet_testing.dm @@ -37,40 +37,76 @@ all_ruins = build_exoplanets_for_testing(all_ruins) + var/sanity_count = 0 while(all_ruins.len) sanity_count++ var/types_needed = 0 var/planets_to_spawn = list() + for(var/datum/map_template/ruin/exoplanet/R in all_ruins) if(!R.planet_types) continue types_needed |= R.planet_types + for(var/EP in subtypesof(/obj/effect/overmap/visitable/sector/exoplanet)) var/obj/effect/overmap/visitable/sector/exoplanet/E = EP if(initial(E.ruin_planet_type) & types_needed) planets_to_spawn += EP var/PT = initial(E.ruin_planet_type) types_needed &= ~PT + all_ruins = build_exoplanets_for_testing(all_ruins, planets_to_spawn) - if(!planets_to_spawn || (sanity_count > 3)) - testing("[ascii_red]FAILED SPAWNING RUINS:[ascii_reset] [sanity_count > 3 ? "EXCEEDED SANITY COUNT" : "NO VALID PLANETS"] for ruins [english_list(all_ruins)]") + + if(!planets_to_spawn || (sanity_count > 5)) + //Build a list of types + var/list/types_fail_list = list() + for(var/datum/map_template/ruin/exoplanet/ruin as anything in all_ruins) + types_fail_list += ruin.type + + SSunit_tests_config.UT.fail("**** [ascii_red]FAILED SPAWNING RUINS:[ascii_reset] [sanity_count > 5 ? "EXCEEDED SANITY COUNT" : "NO VALID PLANETS"] \ + for ruins [english_list(types_fail_list)] ****", __FILE__, __LINE__) break /datum/map/exoplanet_testing/proc/build_exoplanets_for_testing(list/ruins_to_test = list(), list/exoplanet_types = subtypesof(/obj/effect/overmap/visitable/sector/exoplanet)) - for(var/P in exoplanet_types) - var/obj/effect/overmap/visitable/sector/exoplanet/new_planet = P + for(var/exoplanet_type in exoplanet_types) + + var/obj/effect/overmap/visitable/sector/exoplanet/new_planet = exoplanet_type + var/list/ruins_to_spawn = list() if(!initial(new_planet.ruin_planet_type) || initial(new_planet.ruin_planet_type) == PLANET_LORE) continue - new_planet = new new_planet(null, planet_size[1], planet_size[2]) + + new_planet = new new_planet(null, planet_size[1], planet_size[2], being_generated_for_unit_test = TRUE) + + //Check if the planet decided to delete itself, that should mean (in this test) that the unit test group does not match, + //if so, leave it alone and continue with the rest + if(QDELETED(new_planet)) + SSunit_tests_config.UT.debug("**** The exoplanet type [exoplanet_type] was not generated, as it does not belong to this test group ****", __FILE__, __LINE__) + + for(var/datum/map_template/ruin/exoplanet/R in ruins_to_test) + + if(new_planet.ruin_planet_type & R.planet_types) + SSunit_tests_config.UT.debug("**** Ruin [R.name] - [R.type] got the exoplanet type of [new_planet.type] removed,\ + as this exoplanet does not load in this unit test pod****", __FILE__, __LINE__) + R.planet_types &= ~new_planet.ruin_planet_type + + if(!(R.planet_types)) + SSunit_tests_config.UT.debug("**** Ruin [R.name] - [R.type] got removed from the list of valid ruins to test in this pod,\ + as it had no suitable planets left that can run in this pod****", __FILE__, __LINE__) + ruins_to_test -= R + + continue //Proceed to check the next exoplanet type + for(var/datum/map_template/ruin/exoplanet/R in ruins_to_test) if(new_planet.ruin_planet_type & R.planet_types) ruins_to_spawn |= R testing("[ascii_green]LOADING EXOPLANET:[ascii_reset] Spawning [new_planet.name] on Z [english_list(GetConnectedZlevels(world.maxz))]") testing("With ruins: [english_list(ruins_to_spawn)]") + new_planet.build_level_for_testing(ruins_to_spawn) + for(var/datum/map_template/ruin/exoplanet/R in new_planet.spawned_features) ruins_to_test -= R