skin studio updates, save sync CLOSES #1533

This commit is contained in:
bryanthaboi
2026-08-19 05:57:44 -04:00
parent fd73ab2a11
commit 93374fbbbb
54 changed files with 9762 additions and 271 deletions
+125
View File
@@ -0,0 +1,125 @@
package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.harness")
local check, eq = T.check, T.eq
love = love or require("tests.love_stub")
local HostShell = require("src.core.HostShell")
local TOKEN = "0123456789abcdef0123456789abcdef"
local BODY = '{"blob":"return {}"}'
HostShell.haveCurl = function() return false end
love.system.getOS = function() return "Android" end
local calls = {}
local reply = "STATUS 200\n" .. '{"ok":true}'
love.system.httpRequest = function(url, method, headers, body, userAgent)
calls[#calls + 1] = { url = url, method = method, headers = headers,
body = body, userAgent = userAgent }
if type(reply) == "function" then return reply() end
return reply
end
check(HostShell.canHttpRequest(),
"the bridge counts as a request transport where curl does not exist")
local body, err, code = HostShell.httpRequest("https://sync.example/sync/save", {
method = "PUT",
body = BODY,
headers = {
["x-sync-account"] = "aa11bb22cc33dd44",
["x-sync-token"] = TOKEN,
["Content-Type"] = "application/json",
},
})
eq(code, 200, "a bridge request completes: " .. tostring(err))
eq(body, '{"ok":true}', "and the body arrives with the status line stripped")
eq(err, nil, "with no error alongside it")
eq(#calls, 1, "the bridge is called once")
local sent = calls[1]
eq(sent.url, "https://sync.example/sync/save", "the url goes through untouched")
eq(sent.method, "PUT", "and so does the method curl would have taken with -X")
eq(sent.body, BODY, "the save blob rides the body argument, not the url")
eq(sent.userAgent, "gen1recomp", "with the default user agent")
local seen = {}
for i = 1, #sent.headers, 2 do seen[sent.headers[i]] = sent.headers[i + 1] end
eq(seen["x-sync-token"], TOKEN, "auth headers arrive as flat name, value pairs")
eq(seen["x-sync-account"], "aa11bb22cc33dd44", "for the account id too")
eq(seen["Content-Type"], "application/json", "and for the content type")
eq(seen["User-Agent"], nil,
"the user agent stays its own argument rather than a duplicate header")
calls = {}
reply = "STATUS 409\n" .. '{"error":"the save moved on"}'
body, err, code = HostShell.httpRequest("https://sync.example/sync/save", {
method = "PUT", body = BODY, headers = { ["Accept"] = "application/json" },
})
eq(code, 409, "a conflict comes back as a status, not as a transport failure")
eq(body, '{"error":"the save moved on"}',
"and its body survives, which is the whole point of the request arm")
eq(err, nil, "a 4xx is the caller's to interpret")
calls = {}
reply = "ERROR the reply was too large\n"
body, err, code = HostShell.httpRequest("https://sync.example/sync/state", {
method = "GET",
})
eq(code, nil, "an ERROR envelope has no status")
eq(body, nil, "and no body")
check(err and err:find("the reply was too large", 1, true) ~= nil,
"the bridge's own complaint reaches the caller: " .. tostring(err))
check(err and err:find("https://sync.example/sync/state", 1, true) ~= nil,
"named with the url that failed")
calls = {}
reply = "STATUS 200\n" .. '{"ok":true}'
body, err, code = HostShell.httpRequest("https://sync.example/sync/save", {
method = "PUT", body = BODY,
headers = { ["x-sync-token"] = TOKEN .. "\r\nx-sync-account: stolen" },
})
eq(code, nil, "a header value carrying CRLF is refused")
eq(err, "bad request header", "with the same complaint the curl branch gives")
eq(#calls, 0, "and the bridge is never reached")
calls = {}
body, err, code = HostShell.httpRequest("https://sync.example/sync/save", {
method = "PATCH", body = BODY,
})
eq(code, nil, "a method the bridge cannot express is refused")
check(err and err:find("PATCH", 1, true) ~= nil,
"naming the method: " .. tostring(err))
eq(#calls, 0, "without calling the bridge")
calls = {}
reply = function() return nil end
body, err, code = HostShell.httpRequest("https://sync.example/sync/save", {
method = "PUT", body = BODY,
})
eq(code, nil, "an old app under a newer engine returns nothing")
check(err and err:find("update the app", 1, true) ~= nil,
"and degrades to an update notice rather than a crash: " .. tostring(err))
love.system.httpRequest = nil
love.system.httpDownload = function() return false end
check(not HostShell.canHttpRequest(),
"a build with only the download bridge cannot make signed requests")
body, err, code = HostShell.httpRequest("https://sync.example/sync/save", {
method = "PUT", body = BODY,
})
eq(code, nil, "so the request does not go out")
check(err and err:find("update the app", 1, true) ~= nil,
"and says what to do about it: " .. tostring(err))
love.system.httpDownload = nil
body, err, code = HostShell.httpRequest("https://sync.example/sync/save", {
method = "PUT", body = BODY,
})
eq(err, "no request transport on this platform",
"a platform with no bridge at all keeps its old answer")
T.finish("host shell bridge request")