Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing framework with depends #3

Merged
merged 132 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
fa56e3d
feat(test_framework): add an in-game lua testing framework
salinecitrine Dec 24, 2023
712484f
style(test_framework): remove author field
salinecitrine Jan 11, 2024
162c953
feat(test_framework): run test code during Update() and GameFrame()
salinecitrine Jan 11, 2024
e35d010
feat(test_framework): add timers and waitTime
salinecitrine Jan 11, 2024
8dec91b
feat(test_framework): expose WG to tests
salinecitrine Jan 11, 2024
830691b
test(cmd_stop_selfd): add test for basic functionality
salinecitrine Jan 11, 2024
edb148d
fix(test_framework): fix waitTime timeout math
salinecitrine Jan 11, 2024
72acf65
fix(test_framework): temporarily disable Update step
salinecitrine Jan 11, 2024
9d5d99f
fix(test_framework): restore step during update, and update wait test
salinecitrine Jan 11, 2024
fc3ee0a
Add summary of serpent.lua
salinecitrine Jan 12, 2024
fa2abf4
style(barwidgets): remove extra whitespace
salinecitrine Jan 12, 2024
eb133c0
feat(barwidgets): add option to expose locals when loading widgets
salinecitrine Jan 12, 2024
7f72589
test(gui_selfd_icons): load widget with locals
salinecitrine Jan 12, 2024
af7b544
test(gui_battle_resource_tracker): load widget with locals
salinecitrine Jan 14, 2024
76d45fc
test(balance): restore game speed to 1 in cleanup
salinecitrine Jan 12, 2024
daa4d76
refactor(test_framework): store locals as an ordered list
salinecitrine Jan 13, 2024
f85ce0b
fix(test_framework): access correct field in callin buffer
salinecitrine Jan 14, 2024
a48fe73
feat(test_framework): don't start tests if tests are already running
salinecitrine Jan 14, 2024
74d1ff3
fix(test_framework): clear callin buffer between tests
salinecitrine Jan 14, 2024
85d5ec8
fix(test_framework): adjust error stack distance to match usage
salinecitrine Jan 14, 2024
ab667b1
test(cmd_stop_selfd): wait a bit longer in between checks
salinecitrine Jan 14, 2024
448caf1
test(test_framework): remove clutter log messages
salinecitrine Jan 14, 2024
46e5a33
test(test_framework): add some more debug log messages
salinecitrine Jan 14, 2024
3accbcf
feat(test_framework): always show all results
salinecitrine Jan 14, 2024
9b28df1
test(gui_battle_resource_tracker): fail earlier if widget is not present
salinecitrine Jan 16, 2024
3755348
docs(test_framework): use better widget/gadget names/descriptions
salinecitrine Jan 16, 2024
6291954
feat(test_framework): only step during update if we are pre-game
salinecitrine Jan 16, 2024
1643bbd
fix(test_framework): clear callin buffer after each waitUntilCallin
salinecitrine Jan 16, 2024
419cef4
test(test_framework): shorten some very long debug log messages
salinecitrine Jan 16, 2024
6351103
feat(test_framework): remove widget if not in dev mode
salinecitrine Jan 17, 2024
0c0aa7e
refactor(test_framework): rearrange and use timer functions
salinecitrine Jan 17, 2024
c01279f
fix(test_framework): add missing RemoveAction
salinecitrine Jan 17, 2024
bfc4b30
fix(test_framework): add nil checks on timer functions
salinecitrine Jan 17, 2024
50364b8
feat(test_framework): add Test.clearCallinBuffer()
salinecitrine Jan 17, 2024
d2682ac
feat(test_framework): add Test.waitUntilCallinArgs()
salinecitrine Jan 17, 2024
71f9698
feat(test_framework): add support for running in headless mode
salinecitrine Jan 16, 2024
8aa4a8c
feat(test_framework): add watchdog to handle runner crash in headless
salinecitrine Jan 17, 2024
c6fa4b8
fix(test_framework): use relativePath, not just filename for matching
salinecitrine Jan 21, 2024
793913d
refactor(test_framework): file -> filename
salinecitrine Jan 21, 2024
7422013
feat(test_framework): add index and filename to test result data
salinecitrine Jan 21, 2024
092676a
feat(test_framework): replace log file with real test results file
salinecitrine Jan 21, 2024
f787fa9
feat(test_framework): add docker setup for headless testing
salinecitrine Jan 21, 2024
9db911b
feat(test_framework): set env vars for pr-downloader and engine config
salinecitrine Jan 21, 2024
dbdeb0e
refactor(test_framework): refine docker scripts
salinecitrine Jan 21, 2024
761438a
feat(test_framework): Add workflow scripts to show test results in PRs
salinecitrine Jan 21, 2024
81a8b20
fix(test_framework): Only enable watchdog if running in headless mode
salinecitrine Jan 22, 2024
2f50a47
feat(test_framework): add support for skip() function in tests
salinecitrine Feb 6, 2024
23f207f
fix(test_framework): disable watchdog on load
salinecitrine Feb 6, 2024
653a6fd
fix(test_framework): fix return values in localsAccess metatable
salinecitrine Feb 6, 2024
d19d526
fix(test_framework): use proper method call syntax in watchdog widget
salinecitrine Feb 6, 2024
df09631
feat(test_framework): add assertTablesEqual
salinecitrine Jan 11, 2024
b017461
test(mex-building-overhaul): add a test for some pregame actions
salinecitrine Feb 6, 2024
a518063
feat(test_framework): add Test.mock()
salinecitrine Feb 10, 2024
be50aeb
fix(test_framework): misplaced return statement
salinecitrine Feb 10, 2024
911ddcb
refactor(test_framework): make SKIP color a little clearer
salinecitrine Feb 10, 2024
9ec24fa
test(mex-building-overhaul): skip pregame test if not pregame
salinecitrine Feb 10, 2024
c3c9d5a
fix(test_framework): remove extra Spring.Echo
salinecitrine Feb 10, 2024
c799609
test(test_framework): add an example test for mocks
salinecitrine Feb 10, 2024
3781c36
Test that building queue can be edited with a mex selected (not overr…
thehobojoe Feb 10, 2024
b0e6a99
Merge branch 'master' into testing_framework
saurtron Dec 18, 2024
fd076be
Try change the docker compose command.
saurtron Dec 18, 2024
632e796
Fix conflict.
saurtron Dec 18, 2024
1db677f
Disable cus_gl4.
saurtron Dec 18, 2024
5a3ebce
Add missing RemoveWidget at gfx_unit_stencil_gl4:goodbye.
saurtron Dec 18, 2024
7e47229
Return from Initialize when unitStencilShader could not be created.
saurtron Dec 18, 2024
a10e5f3
Add debug print.
saurtron Dec 18, 2024
c823ea1
Remove dbg_test_framework widget.
saurtron Dec 18, 2024
5bd737e
Remove if gl.CreateShader doesn't exist.
saurtron Dec 18, 2024
2a8a02e
Remove if no gl.CreateShader.
saurtron Dec 18, 2024
3fd9deb
Protect a few more widgets from no gl.CreateShader.
saurtron Dec 18, 2024
248acad
Protect cmd_extractor_snap Shutdown from no gl4.
saurtron Dec 18, 2024
e3168bc
Allow api_blueprint to work even with no gl4.
saurtron Dec 18, 2024
fb894ad
Add expectCallin to test_wait.
saurtron Dec 18, 2024
067ac23
Give orders with synced run at test_arm_vs_cor_fighters.
saurtron Dec 18, 2024
360bf54
Allow declaring capability dependencies at ghInfo and whInfo.
saurtron Dec 18, 2024
11f6127
Merge branch 'gadget-widget-depends' into testing_framework_with_depends
saurtron Dec 18, 2024
c4b70c9
Print some platform info.
saurtron Dec 18, 2024
70d7846
Fixes.
saurtron Dec 18, 2024
4f5393c
Allow declaring capability dependencies at ghInfo and whInfo.
saurtron Dec 18, 2024
2a876c7
Add depends stance to a few widgets and gadgets.
saurtron Dec 18, 2024
7795b32
Add parameter to gl.GetString
saurtron Dec 18, 2024
11e9991
Move widget capabilities check to InsertWidgetRaw and RemoveWidgetRaw.
saurtron Dec 18, 2024
10df978
Merge remote-tracking branch 'origin/gadget-widget-cap-depends' into …
saurtron Dec 18, 2024
78f65ce
Protect api_unit_tracker_gl4 from error in shutdown.
saurtron Dec 18, 2024
6c5ba98
Merge remote-tracking branch 'origin/gadget-widget-cap-depends' into …
saurtron Dec 18, 2024
f78c793
Add stance for pull request.
saurtron Dec 18, 2024
28f6b92
Different empty message.
saurtron Dec 18, 2024
4c8281a
Fix test_wait.lua.
saurtron Dec 18, 2024
8968b7c
Count skip as pass at least for now.
saurtron Dec 18, 2024
afea9ea
Count skipped independently.
saurtron Dec 18, 2024
35016e3
Fix typo.
saurtron Dec 18, 2024
a3779b8
Remove specific types since defaults are fine.
saurtron Dec 18, 2024
40c25f5
Don't remove if no gl.
saurtron Dec 18, 2024
fa6e9f2
SyncedRun for the test_arm_vs_cor_fighters orders.
saurtron Dec 18, 2024
f99feab
Remove battle resource tracker test.
saurtron Dec 18, 2024
e06d226
Also run on push to master.
saurtron Dec 18, 2024
2531761
Add missing locals.
saurtron Dec 18, 2024
08dc089
Update to use Supreme Isthmus v1.8.
saurtron Dec 18, 2024
d206969
Also set Supreme 1.8 at startscript.txt.
saurtron Dec 18, 2024
baa7b50
Add skipped as pending.
saurtron Dec 18, 2024
a45a386
Properly add skipped.
saurtron Dec 19, 2024
275ef81
Don't force map for test_cmd_stop_selfd.
saurtron Dec 19, 2024
46ec9fe
Try moving the camera with test_cmd_blueprint_line.
saurtron Dec 19, 2024
a50d0c2
Don't set overview camera.
saurtron Dec 19, 2024
b429aba
Warp after set camera target.
saurtron Dec 19, 2024
17f0a56
Add special infolog test.
saurtron Dec 19, 2024
d9c2b19
Make the infologtest test function global.
saurtron Dec 19, 2024
0390c33
Set LogFlushLevel to 0 for the headless test.
saurtron Dec 19, 2024
7eb8de5
Don't add context line for the infologtest error() call.
saurtron Dec 19, 2024
9f29973
Extract error from infolog line.
saurtron Dec 19, 2024
ea05c52
Extract error message at mocha_json_reporter instead.
saurtron Dec 20, 2024
7c7a565
Merge remote-tracking branch 'bar/master' into testing_framework_with…
saurtron Dec 20, 2024
f8d41b8
Revert unknown error string.
saurtron Dec 20, 2024
3920341
Remove files existing at a different location in master.
saurtron Dec 20, 2024
ee88f09
Use depends for some widgets instead of ad-hoc tests.
saurtron Dec 20, 2024
93f2eb4
Remove debug echo.
saurtron Dec 20, 2024
d23529a
Master has a local here.
saurtron Dec 20, 2024
0bcb501
Remove superfluous Platform.check.
saurtron Dec 20, 2024
fe0be3c
Add gl4 depends to gui_defenserange_gl4.
saurtron Dec 20, 2024
3b84e6f
Remove god mode.
saurtron Dec 20, 2024
d9659e5
Skip known engine errors.
saurtron Dec 20, 2024
5468c4e
Bring back godmode.
saurtron Dec 20, 2024
acbdc8b
Add missing 'line' argument.
saurtron Dec 20, 2024
d10538a
Remove test for WG['unittrackerapi'] at unit tracker shutdown.
saurtron Dec 20, 2024
5e03988
Merge 'upload event file' job into 'run tests'.
saurtron Dec 20, 2024
8a3e049
Deploy only on successful tests.
saurtron Dec 20, 2024
f5a3b88
Avoid overwrite of push and pr test results.
saurtron Dec 20, 2024
b6e872f
Fail on inconclusive.
saurtron Dec 20, 2024
98bb309
Pass event and branch from process_test_results to quick_deploy so we
saurtron Dec 20, 2024
097342e
Create new artifacts after downloading previous ones so the folder wi…
saurtron Dec 20, 2024
0359f0f
Move initial checks to get_context job.
saurtron Dec 20, 2024
64341e0
Add a timeout for the step running the tests.
saurtron Dec 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/process_test_results.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Process Test Results

on:
workflow_run:
workflows: ["Run Tests"]
types:
- completed

permissions: {}

jobs:
process-test-results:
name: Process Test Results
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion != 'skipped'

permissions:
checks: write

# needed unless run with comment_mode: off
pull-requests: write

# required by download step to access artifacts API
actions: read

steps:
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}

- name: Create context file
run: |
printf '{
"event": "${{github.event.workflow_run.event}}",
"branch": "${{github.event.workflow_run.head_branch}}"
}' >> artifacts/context.json

- name: Upload Context File
uses: actions/upload-artifact@v4
with:
name: Context File
path: artifacts/context.json

- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
with:
action_fail_on_inconclusive: true
check_name: "Test Results (${{ github.event.workflow_run.event || github.event_name }})"
time_unit: milliseconds
commit: ${{ github.event.workflow_run.head_sha }}
event_file: artifacts/Event File/event.json
event_name: ${{ github.event.workflow_run.event }}
files: "artifacts/Test Results/*.json"
30 changes: 26 additions & 4 deletions .github/workflows/quick_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,35 @@
# on push to master much quicker without waiting for cron jobs.
name: Deploy
on:
push:
branches:
- master
workflow_run:
workflows: ["Process Test Results"]
types:
- completed
jobs:
get_context:
runs-on: ubuntu-latest
if: |
github.repository == 'beyond-all-reason/Beyond-All-Reason' &&
github.event.workflow_run.conclusion == 'success'
outputs:
event: ${{ fromJson(steps.context.outputs.data).event }}
branch: ${{ fromJson(steps.context.outputs.data).branch }}
steps:
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
- name: Get context json
id: context
run: echo "data=$(jq -c . < 'artifacts/Context File/context.json')" >> $GITHUB_OUTPUT
deploy:
needs: [get_context]
runs-on: ubuntu-latest
if: github.repository == 'beyond-all-reason/Beyond-All-Reason'
if: |
needs.get_context.outputs.event == 'push' &&
needs.get_context.outputs.branch == 'master'
permissions:
id-token: write
steps:
Expand Down
35 changes: 35 additions & 0 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Run Tests

on:
# pull_request
workflow_dispatch:
pull_request:
push:
branches:
- 'master'

jobs:
run-tests:
name: Run Tests
runs-on: ubuntu-latest
steps:
- name: Upload Event File
uses: actions/upload-artifact@v4
with:
name: Event File
path: ${{ github.event_path }}

- name: Checkout Repository
uses: actions/checkout@v4

- name: Run Tests
run: docker compose -f tools/headless_testing/docker-compose.yml up
timeout-minutes: 30

- name: Upload Test Results
if: always()
uses: actions/upload-artifact@v4
with:
name: Test Results
path: |
tools/headless_testing/testlog/results.json
32 changes: 32 additions & 0 deletions common/testing/infologtest.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
local maxErrors = 10

local function skipErrors(line)
if string.find(line, 'Could not finalize projectile-texture atlas', nil, true) then
return true
end
end

local function infologTest()
local errors = {}
local infolog = VFS.LoadFile("infolog.txt")
if infolog then
local fileLines = string.lines(infolog)
for i, line in ipairs(fileLines) do
if string.find(line, 'Error:', nil, true) and not skipErrors(line) then
errors[#errors+1] = line
if #errors > maxErrors then
return errors
end
end
end
end
return errors
end


function test()
local errors = infologTest()
if #errors > 0 then
error(table.concat(errors, "\n"), 0)
end
end
33 changes: 28 additions & 5 deletions common/testing/mocha_json_reporter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ function MochaJSONReporter:new()
local obj = {
totalTests = 0,
totalPasses = 0,
totalSkipped = 0,
totalFailures = 0,
startTime = nil,
endTime = nil,
duration = nil,
tests = {}
tests = {},
skipped = {}
}
setmetatable(obj, self)
self.__index = self
Expand All @@ -28,21 +30,37 @@ function MochaJSONReporter:endTests(duration)
self.duration = duration
end

function MochaJSONReporter:testResult(label, filePath, success, duration, errorMessage)
function MochaJSONReporter:extractError(text)
local errorIndex = text:match'^%[string "[%p%a%s]*%"]:[%d]+:().*'
if errorIndex and errorIndex > 0 then
text = text:sub(errorIndex + 1)
return text
end
errorIndex = text:match'^%[t=[%d%.:]*%]%[f=[%-%d]*%] ().*'
if errorIndex and errorIndex > 0 then
text = text:sub(errorIndex)
end
return text
end

function MochaJSONReporter:testResult(label, filePath, success, skipped, duration, errorMessage)
local result = {
title = label,
fullTitle = label,
file = filePath,
duration = duration,
}
if success then
if skipped then
self.totalSkipped = self.totalSkipped + 1
result.err = {}
elseif success then
self.totalPasses = self.totalPasses + 1
result.err = {}
else
self.totalFailures = self.totalFailures + 1
if errorMessage ~= nil then
result.err = {
message = errorMessage,
message = self:extractError(errorMessage),
stack = errorMessage
}
else
Expand All @@ -54,6 +72,9 @@ function MochaJSONReporter:testResult(label, filePath, success, duration, errorM

self.totalTests = self.totalTests + 1
self.tests[#(self.tests) + 1] = result
if skipped then
self.skipped[#(self.skipped) + 1] = {fullTitle = label}
end
end

function MochaJSONReporter:report(filePath)
Expand All @@ -63,12 +84,14 @@ function MochaJSONReporter:report(filePath)
["tests"] = self.totalTests,
["passes"] = self.totalPasses,
["pending"] = 0,
["skipped"] = self.totalSkipped,
["failures"] = self.totalFailures,
["start"] = formatTimestamp(self.startTime),
["end"] = formatTimestamp(self.endTime),
["duration"] = self.duration
},
["tests"] = self.tests
["tests"] = self.tests,
["pending"] = self.skipped
}

local encoded = Json.encode(output)
Expand Down
97 changes: 97 additions & 0 deletions luaui/Widgets/Tests/balance/test_arm_vs_cor_fighters.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
function setup()
Test.clearMap()
end

function cleanup()
Test.clearMap()

Spring.SendCommands("setspeed " .. 1)
end

function test()
local units = {
[0] = "armfig",
[1] = "corveng"
}
local n = 200

local midX, midZ = Game.mapSizeX / 2, Game.mapSizeZ / 2
local xOffset = 1000
local zStep = 10
local startZ = midZ - zStep * n / 2

-- make two lines of units facing each other
SyncedRun(function(locals)
do
local x = locals.midX - locals.xOffset
for i = 1, locals.n do
local z = locals.startZ + locals.zStep * i
local y = Spring.GetGroundHeight(x, z)
local unitID = Spring.CreateUnit(locals.units[0], x, y, z, "east", 0)
end
end

do
local x = locals.midX + locals.xOffset
for i = 1, locals.n do
local z = locals.startZ + locals.zStep * i
local y = Spring.GetGroundHeight(x, z)
local unitID = Spring.CreateUnit(locals.units[1], x, y, z, "west", 1)
end

end
end)

Test.waitFrames(1)

if false then
Spring.GiveOrderToUnitArray(Spring.GetTeamUnits(0), CMD.FIGHT, { midX, 0, midZ }, 0)
Spring.GiveOrderToUnitArray(Spring.GetTeamUnits(1), CMD.FIGHT, { midX, 0, midZ }, 0)
else
SyncedRun(function(locals)
local midX = locals.midX
local midZ = locals.midZ
for _, unitID in ipairs(Spring.GetAllUnits()) do
local ux, uy, uz = Spring.GetUnitPosition(unitID)

Spring.GiveOrderToUnit(unitID, CMD.FIGHT, { 2 * midX - ux, 0, uz }, 0)
Spring.GiveOrderToUnit(unitID, CMD.FIGHT, { midX, 0, midZ }, { "shift" })
end
end)
end

Spring.SendCommands("setspeed " .. 5)

-- wait until one team has no units left
Test.waitUntil(function()
return #(Spring.GetTeamUnits(0)) == 0 or #(Spring.GetTeamUnits(1)) == 0
end, 60 * 30)

Spring.SendCommands("setspeed " .. 1)

if #(Spring.GetTeamUnits(0)) > #(Spring.GetTeamUnits(1)) then
winner = 0
elseif #(Spring.GetTeamUnits(1)) > #(Spring.GetTeamUnits(0)) then
winner = 1
end

resultStr = "RESULT: "
if winner ~= nil then
unitName = units[winner]
if UnitDefNames and units[winner] and UnitDefNames[units[winner]] then
unitName = UnitDefNames[units[winner]].translatedHumanName or units[winner]
end
unitsLeft = #(Spring.GetAllUnits())
resultStr = resultStr .. "team " .. winner .. " wins"
resultStr = resultStr .. " with " .. unitsLeft
resultStr = resultStr .. " (" .. string.format("%.f%%", 100 * unitsLeft / n) .. ")"
resultStr = resultStr .. " " .. unitName .. " left"
else
resultStr = resultStr .. "tie"
end

Spring.Echo(resultStr)

-- cor fighters should win
assert(winner == 1)
end
Loading
Loading