Skip to content

Commit

Permalink
test_runner: Stress test scenario system (#4000)
Browse files Browse the repository at this point in the history
* Add a "scenario" subsystem to the test runner.
* Adds the /runscenario command.

This is designed to run one file at a time, and allow running parameterized scenarios, to test different units, stress levels, etc.
  • Loading branch information
saurtron authored Jan 2, 2025
1 parent c40fae4 commit 4e6ba76
Show file tree
Hide file tree
Showing 7 changed files with 425 additions and 2 deletions.
48 changes: 48 additions & 0 deletions luaui/Scenarios/stresstest/circle_attack.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
VFS.Include("luaui/Scenarios/stresstest/multi_attack.lua")

function radius_attack(targetsCenter, nattackers)
local y = Spring.GetGroundHeight(targetsCenter[1], targetsCenter[2])
local targetPosition = {targetsCenter[1], y+5, targetsCenter[2], targetsCenter[3]}

local CMD_ATTACK = CMD.ATTACK

-- get units
local spGetUnitDefID = Spring.GetUnitDefID

local attackers = table.new and table.new(nattackers) or {}
local attackerDefID = UnitDefNames[Scenario.attackerDef].id

local all_units = Spring.GetAllUnits()
for _, unitID in ipairs(all_units) do
local unitDefID = spGetUnitDefID(unitID)
if unitDefID == attackerDefID then
attackers[#attackers+1] = unitID
end
end

-- give order
Spring.SelectUnitArray(attackers)
Spring.GiveOrder(CMD_ATTACK, targetPosition, 0)
Spring.SelectUnitArray({})
end

function test()
local t0 = os.clock()

local nattackers = 100*Scenario.stressLevel
local ntargets = 100*Scenario.stressLevel
local attackerDef = Scenario.attackerDef
local targetDef = Scenario.targetDef
local radarDef = Scenario.radarDef
local doCircle = true

local circle = SyncedRun(synced_setup)
Spring.Echo("init time preinit:", os.clock()-t0)

Test.waitFrames(1)

radius_attack(circle, nattackers)

Spring.Echo("total time:", os.clock()-t0)
end

135 changes: 135 additions & 0 deletions luaui/Scenarios/stresstest/multi_attack.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@

function skip()
return Spring.GetGameFrame() <= 0
end

function scenario_arguments()
return {{stressLevel = 1}, {attackerDef = "armpw"}, {targetDef = "armwin"}, {radarDef = "armarad"}}
end

function setup()
-- test on quicksilver remake 1.24
Test.clearMap()

Spring.SetCameraTarget(Game.mapSizeX/2, 50, Game.mapSizeZ / 2 - 500, 0.5)
end

function synced_setup(locals)
local function createUnitAt(unitdefname, x, z, teamID)
local y = Spring.GetGroundHeight(x, z)
return Spring.CreateUnit(unitdefname, x, y, z, 1, teamID)
end

local doCircle = locals.doCircle
local colattackers = 10
local coltargets = 20
local rowattackers = math.floor(locals.nattackers/colattackers)
local rowtargets = math.floor(locals.ntargets/coltargets)
local attackerDef = locals.attackerDef
local targetDef = locals.targetDef

local x, z = Game.mapSizeX / 2, Game.mapSizeZ / 2
x = x+450

local team1 = 0
local team2 = 1
local sep = 40
local currunit
local attackers = {}
local circle
if doCircle then
-- when circle requested just return the targets center and radius
local maxX = (coltargets*sep)/2.0
local maxZ = (rowtargets*sep)/2.0
local targetsCenter = {x-1500+maxX, z-maxZ}
local radius = math.sqrt(maxX*maxX + maxZ*maxZ)
circle = {targetsCenter[1], targetsCenter[2], radius}
end

createUnitAt(locals.radarDef, x-1000, z+300, team1)

for i=0, colattackers-1 do
for j=0, rowattackers-1 do
currunit = createUnitAt(attackerDef, x+i*sep, z-j*sep, team1)
attackers[#attackers+1] = currunit
end
end

for i=0, coltargets-1 do
for j=0, rowtargets-1 do
createUnitAt(targetDef, x-1500+i*sep, z-j*sep, team2)
end
end
-- make sure the attackers don't have other orders
for _, unitID in pairs(attackers) do
Spring.GiveOrderToUnit(unitID, CMD.STOP, 0, 0)
end
return circle
end

function run_commands(nattackers, ntargets, attackerDef, targetDef)
if type(nattackers) == 'table' then
-- comes from SyncedRun
locals = nattackers
ntargets = locals.ntargets
attackerDef = locals.attackerDef
targetDef = locals.targetDef
nattackers = locals.nattackers
end
local shiftOpts = {"shift"}
local currOpt
local CMD_ATTACK = CMD.ATTACK
local spGiveOrderToUnit = Spring.GiveOrderToUnit
local attackerTeam = 0
local defenderTeam = 1

-- get units
local spGetUnitDefID = Spring.GetUnitDefID
local spGetUnitTeam = Spring.GetUnitTeam

local attackers = table.new and table.new(nattackers) or {}
local targets = table.new and table.new(ntargets) or {}
local attackerDefID = UnitDefNames[attackerDef].id
local targetDefID = UnitDefNames[targetDef].id

local all_units = Spring.GetAllUnits()
for _, unitID in ipairs(all_units) do
local unitDefID = spGetUnitDefID(unitID)
local unitTeamID = spGetUnitTeam(unitID)
if unitDefID == attackerDefID and unitTeamID == attackerTeam then
attackers[#attackers+1] = unitID
elseif unitDefID == targetDefID and unitTeamID == defenderTeam then
targets[#targets+1] = unitID
end
end

-- give orders
local arr = {}
for _, unitID in pairs(attackers) do
for idx, targetID in pairs(targets) do
currOpt = (idx == 1) and opts or shiftOpts
arr[1] = targetID
spGiveOrderToUnit(unitID, CMD_ATTACK, arr, currOpt)
end
end
end

function test()
local t0 = os.clock()

local nattackers = 100*Scenario.stressLevel
local ntargets = 100*Scenario.stressLevel
local attackerDef = Scenario.attackerDef
local targetDef = Scenario.targetDef
local radarDef = Scenario.radarDef

SyncedRun(synced_setup)
Spring.Echo("init time preinit:", os.clock()-t0)

Test.waitFrames(1)

SyncedRun(run_commands)

Spring.Echo("total time:", os.clock()-t0)
end

21 changes: 21 additions & 0 deletions luaui/Scenarios/stresstest/multi_unsynced_attack.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
VFS.Include("luaui/Scenarios/stresstest/multi_attack.lua")

function test()
local t0 = os.clock()

local nattackers = 100*Scenario.stressLevel
local ntargets = 100*Scenario.stressLevel
local attackerDef = Scenario.attackerDef
local targetDef = Scenario.targetDef
local radarDef = Scenario.radarDef

SyncedRun(synced_setup)
Spring.Echo("init time preinit:", os.clock()-t0)

Test.waitFrames(1)

run_commands(nattackers, ntargets, attackerDef, targetDef)

Spring.Echo("total time:", os.clock()-t0)
end

115 changes: 115 additions & 0 deletions luaui/Scenarios/stresstest/nano_commands.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@

function skip()
return Spring.GetGameFrame() <= 0
end

function scenario_arguments()
return {{stressLevel = 1}, {builderDef = "armnanotc"}, {targetDef = "armwin"}}
end

function setup()
-- test on quicksilver remake 1.24
Test.clearMap()

Spring.SetCameraTarget(Game.mapSizeX/2 + 500, 50, Game.mapSizeZ / 2 - 500, 0.5)
end

function synced_nano_setup(locals)
local function createUnitAt(unitdefname, x, z, teamID)
local y = Spring.GetGroundHeight(x, z)
return Spring.CreateUnit(unitdefname, x, y, z, 1, teamID)
end

local colturrets = 5
local coltargets = 8
local rowturrets = math.floor(locals.nturrets/colturrets)
local rowtargets = math.floor(locals.ntargets/coltargets)
local turretDef = locals.turretDef
local targetDef = locals.targetDef

local x, z = Game.mapSizeX / 2, Game.mapSizeZ / 2
x = x+450

local team1 = 0
local sep = 50
local currunit
local turrets = {}
for i=0, colturrets-1 do
for j=0, rowturrets-1 do
currunit = createUnitAt(turretDef, x+i*sep-100, z-j*sep, team1)
turrets[#turrets+1] = currunit
end
end

for i=0, coltargets-1 do
for j=0, rowtargets-1 do
createUnitAt(targetDef, x+350+i*sep, z-j*sep, team1)
end
end
-- make sure the turrets don't have other orders
for _, unitID in pairs(turrets) do
Spring.GiveOrderToUnit(unitID, CMD.STOP, 0, 0)
end
end

function run_nano_commands(nturrets, ntargets, turretDef, targetDef)
if type(nturrets) == 'table' then
local locals = nturrets
ntargets = locals.ntargets
turretDef = locals.turretDef
targetDef = locals.targetDef
nturrets = locals.nturrets
end
local shiftOpts = {"shift"}
local currOpt
local CMD_RECLAIM = CMD.RECLAIM
local spGiveOrderToUnit = Spring.GiveOrderToUnit

-- get units
local spGetUnitDefID = Spring.GetUnitDefID

local turrets = table.new and table.new(nturrets) or {}
local targets = table.new and table.new(ntargets) or {}
local turretDefID = UnitDefNames[turretDef].id
local targetDefID = UnitDefNames[targetDef].id

local all_units = Spring.GetAllUnits()
for _, unitID in ipairs(all_units) do
local unitDefID = spGetUnitDefID(unitID)
if unitDefID == turretDefID then
turrets[#turrets+1] = unitID
elseif unitDefID == targetDefID then
targets[#targets+1] = unitID
end
end

-- give orders
local arr = {}
for _, unitID in pairs(turrets) do
for idx, targetID in pairs(targets) do
currOpt = (idx == 1) and opts or shiftOpts
arr[1] = targetID
spGiveOrderToUnit(unitID, CMD_RECLAIM, arr, currOpt)
end
end
end

function test()
local t0 = os.clock()

local nturrets = 50*Scenario.stressLevel
local ntargets = 50*Scenario.stressLevel
local turretDef = Scenario.builderDef
local targetDef = Scenario.targetDef

SyncedRun(synced_nano_setup)
Spring.Echo("init time preinit:", os.clock()-t0)

Test.waitFrames(1)

SyncedRun(run_nano_commands)

Spring.Echo("total time:", os.clock()-t0)
end


21 changes: 21 additions & 0 deletions luaui/Scenarios/stresstest/nano_unsynced_commands.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
VFS.Include("luaui/Scenarios/stresstest/nano_commands.lua")

function test()
local t0 = os.clock()

local nturrets = 50*Scenario.stressLevel
local ntargets = 50*Scenario.stressLevel
local turretDef = Scenario.builderDef
local targetDef = Scenario.targetDef

SyncedRun(synced_nano_setup)
Spring.Echo("init time preinit:", os.clock()-t0)

Test.waitFrames(1)

run_nano_commands(nturrets, ntargets, turretDef, targetDef)

Spring.Echo("total time:", os.clock()-t0)
end


31 changes: 31 additions & 0 deletions luaui/Scenarios/stresstest/unsynced_attack.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
VFS.Include("luaui/Scenarios/stresstest/multi_attack.lua")

function radius_attack(attackers, targetsCenter)
local y = Spring.GetGroundHeight(targetsCenter[1], targetsCenter[2])
local targetPosition = {targetsCenter[1], y+5, targetsCenter[2], targetsCenter[3]}

local CMD_ATTACK = CMD.ATTACK
local spGiveOrderToUnit = Spring.GiveOrderToUnit

Spring.SelectUnitArray(attackers)
Spring.GiveOrder(CMD_ATTACK, targetPosition, 0)
end

function test()
local t0 = os.clock()

local nattackers = 100*Scenario.stressLevel
local ntargets = 100*Scenario.stressLevel
local attackerDef = Scenario.attackerDef
local targetDef = Scenario.targetDef
local radarDef = Scenario.radarDef

local attackers, targetsCenter = SyncedRun(synced_setup)

Test.waitFrames(1)

radius_attack(attackers, targetsCenter)

Spring.Echo("total time:", os.clock()-t0)
end

Loading

0 comments on commit 4e6ba76

Please sign in to comment.