Some checks failed
Deploy MineGeo to Dokploy / deploy (push) Failing after 3m40s
437 lines
12 KiB
JavaScript
437 lines
12 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile, readdir } from "node:fs/promises";
|
|
import { PGlite } from "../.data/sql-verification/node_modules/@electric-sql/pglite/dist/index.js";
|
|
|
|
const db = new PGlite();
|
|
try {
|
|
await db.exec(`create role anon; create role authenticated; create role service_role;
|
|
create schema auth; create table auth.users(id uuid primary key);
|
|
create function auth.uid() returns uuid language sql as $$ select null::uuid $$;
|
|
create schema storage;
|
|
create table storage.buckets(id text primary key,name text,public boolean,file_size_limit bigint,allowed_mime_types text[]);
|
|
create table storage.objects(id uuid primary key,bucket_id text,name text,owner_id text);
|
|
create function storage.foldername(text) returns text[] language sql as $$ select string_to_array($1, '/') $$;`);
|
|
for (const file of (await readdir("supabase/migrations"))
|
|
.filter((f) => f.endsWith(".sql"))
|
|
.sort()) {
|
|
if (file.endsWith("fix_difficulty_preset_names.sql"))
|
|
await assert.rejects(
|
|
db.query(
|
|
"insert into public.difficulty_presets(name,seconds,zoom) values('Normal',90,true)",
|
|
),
|
|
(error) => error.code === "23514",
|
|
);
|
|
await db.exec(await readFile(`supabase/migrations/${file}`, "utf8"));
|
|
}
|
|
const valid = [
|
|
"Normal",
|
|
"Speed 90",
|
|
"Hard",
|
|
"Тест",
|
|
"中文",
|
|
"😎😎",
|
|
"😎".repeat(40),
|
|
"a".repeat(40),
|
|
"a\\b",
|
|
];
|
|
for (const name of valid)
|
|
await db.query(
|
|
"insert into public.difficulty_presets(name,seconds,zoom) values($1,90,true)",
|
|
[name],
|
|
);
|
|
for (const name of [
|
|
"",
|
|
"a",
|
|
"😎",
|
|
"a".repeat(41),
|
|
"😎".repeat(41),
|
|
" leading",
|
|
"trailing ",
|
|
"x\nname",
|
|
"x\u0085name",
|
|
"x\u202ename",
|
|
"x\u2066name",
|
|
])
|
|
await assert.rejects(
|
|
db.query(
|
|
"insert into public.difficulty_presets(name,seconds,zoom) values($1,90,true)",
|
|
[name],
|
|
),
|
|
(error) => error.code === "23514",
|
|
);
|
|
for (const seconds of [0, 4, 14, 16, 601])
|
|
await assert.rejects(
|
|
db.query(
|
|
"insert into public.difficulty_presets(name,seconds,zoom) values('Invalid clock',$1,true)",
|
|
[seconds],
|
|
),
|
|
(error) => error.code === "23514",
|
|
);
|
|
await assert.rejects(
|
|
db.query(
|
|
"insert into public.difficulty_presets(name,seconds,zoom) values('normal',90,true)",
|
|
),
|
|
(error) => error.code === "23505",
|
|
);
|
|
|
|
const preset = (
|
|
await db.query(
|
|
"insert into public.difficulty_presets(name,seconds,zoom) values('Playable preset 45',45,false) returning id",
|
|
)
|
|
).rows[0].id;
|
|
for (const [id, seconds] of [
|
|
["easy", 180],
|
|
["normal", 90],
|
|
["hard", 30],
|
|
["void", 10],
|
|
])
|
|
assert.equal(
|
|
(
|
|
await db.query("select public.resolve_difficulty_preset($1) preset", [
|
|
id,
|
|
])
|
|
).rows[0].preset.seconds,
|
|
seconds,
|
|
);
|
|
await assert.rejects(
|
|
db.query(
|
|
"select public.resolve_difficulty_preset('00000000-0000-4000-8000-000000000000')",
|
|
),
|
|
/Choose a saved difficulty/,
|
|
);
|
|
assert.equal(
|
|
(
|
|
await db.query("select public.resolve_difficulty_preset($1) preset", [
|
|
preset.toUpperCase(),
|
|
])
|
|
).rows[0].preset.id,
|
|
preset,
|
|
);
|
|
const owner = (
|
|
await db.query(
|
|
"insert into auth.users values(gen_random_uuid()) returning id",
|
|
)
|
|
).rows[0].id;
|
|
await db.query(
|
|
"insert into public.profiles(id,display_name) values($1,'Difficulty host') on conflict(id) do update set display_name=excluded.display_name",
|
|
[owner],
|
|
);
|
|
const map = (
|
|
await db.query(
|
|
`insert into public.datasets(owner_id,name,source,bounds,state,panorama_count)
|
|
values($1,'Difficulty fixture','plugin','{"minX":0,"minZ":0,"maxX":64,"maxZ":64}','published',5) returning id`,
|
|
[owner],
|
|
)
|
|
).rows[0].id;
|
|
const manifest = {
|
|
bounds: { minX: 0, minZ: 0, maxX: 64, maxZ: 64 },
|
|
viewpoints: Array.from({ length: 5 }, (_, i) => ({
|
|
id: `p${i}`,
|
|
x: i,
|
|
y: 65,
|
|
z: i,
|
|
})),
|
|
};
|
|
const revision = (
|
|
await db.query(
|
|
"insert into public.revisions(dataset_id,asset_root,manifest) values($1,'fixture',$2) returning id",
|
|
[map, JSON.stringify(manifest)],
|
|
)
|
|
).rows[0].id;
|
|
await db.query("update public.datasets set revision_id=$1 where id=$2", [
|
|
revision,
|
|
map,
|
|
]);
|
|
const voidRules = {
|
|
id: "void",
|
|
name: "Void",
|
|
seconds: 10,
|
|
zoom: false,
|
|
pan: false,
|
|
compass: false,
|
|
coordinates: false,
|
|
mapZoom: false,
|
|
mapPan: false,
|
|
timerVisible: true,
|
|
scoring: "strict",
|
|
};
|
|
const voidSolo = (
|
|
await db.query("select public.create_game($1,'void',$2,'void-solo') id", [
|
|
map,
|
|
owner,
|
|
])
|
|
).rows[0].id;
|
|
const voidRoom = (
|
|
await db.query(
|
|
"select public.create_map_room($1,'void','Void host',2,$2,$3) id",
|
|
[map, "d".repeat(64), owner],
|
|
)
|
|
).rows[0].id;
|
|
for (const [table, id] of [
|
|
["game_sessions", voidSolo],
|
|
["multiplayer_rooms", voidRoom],
|
|
])
|
|
assert.deepEqual(
|
|
(
|
|
await db.query(
|
|
`select difficulty_settings from public.${table} where id=$1`,
|
|
[id],
|
|
)
|
|
).rows[0].difficulty_settings,
|
|
voidRules,
|
|
);
|
|
await db.query("select public.activate_round($1,0,'void-solo')", [voidSolo]);
|
|
const voidClock = (
|
|
await db.query(
|
|
"select extract(epoch from (deadline-clock_timestamp()))::float8 seconds from public.game_rounds where session_id=$1 and round_number=0",
|
|
[voidSolo],
|
|
)
|
|
).rows[0].seconds;
|
|
assert.ok(voidClock > 9 && voidClock <= 10);
|
|
await db.query(
|
|
"select public.multiplayer_action($1,$2,'join','{\"name\":\"Void guest\"}')",
|
|
[voidRoom, "e".repeat(64)],
|
|
);
|
|
await db.query("select public.multiplayer_action($1,$2,'start')", [
|
|
voidRoom,
|
|
"d".repeat(64),
|
|
]);
|
|
for (const token of ["d".repeat(64), "e".repeat(64)])
|
|
await db.query(
|
|
"select public.multiplayer_action($1,$2,'ready','{\"round\":0}')",
|
|
[voidRoom, token],
|
|
);
|
|
const voidMultiClock = (
|
|
await db.query(
|
|
"select extract(epoch from (deadline-clock_timestamp()))::float8 seconds from public.multiplayer_rounds where room_id=$1 and round_number=0",
|
|
[voidRoom],
|
|
)
|
|
).rows[0].seconds;
|
|
assert.ok(voidMultiClock > 9 && voidMultiClock <= 10);
|
|
const fiveSeconds = (
|
|
await db.query(
|
|
"insert into public.difficulty_presets(name,seconds,zoom,map_pan,timer_visible) values('Five second blind clock',5,false,false,false) returning id",
|
|
)
|
|
).rows[0].id;
|
|
const extraRules = (
|
|
await db.query("select public.resolve_difficulty_preset($1) rules", [
|
|
fiveSeconds,
|
|
])
|
|
).rows[0].rules;
|
|
assert.equal(extraRules.seconds, 5);
|
|
assert.equal(extraRules.mapPan, false);
|
|
assert.equal(extraRules.timerVisible, false);
|
|
const solo = (
|
|
await db.query("select public.create_game($1,$2,$3,$4) id", [
|
|
map,
|
|
preset,
|
|
owner,
|
|
"a".repeat(64),
|
|
])
|
|
).rows[0].id;
|
|
const multi = (
|
|
await db.query("select public.create_map_room($1,$2,'Host',2,$3,$4) id", [
|
|
map,
|
|
preset,
|
|
"b".repeat(64),
|
|
owner,
|
|
])
|
|
).rows[0].id;
|
|
for (const [table, id] of [
|
|
["game_sessions", solo],
|
|
["multiplayer_rooms", multi],
|
|
])
|
|
assert.deepEqual(
|
|
(
|
|
await db.query(
|
|
`select difficulty_settings from public.${table} where id=$1`,
|
|
[id],
|
|
)
|
|
).rows[0].difficulty_settings,
|
|
{
|
|
id: preset,
|
|
name: "Playable preset 45",
|
|
seconds: 45,
|
|
zoom: false,
|
|
pan: true,
|
|
compass: true,
|
|
coordinates: true,
|
|
mapZoom: true,
|
|
mapPan: true,
|
|
timerVisible: true,
|
|
scoring: "normal",
|
|
},
|
|
);
|
|
await assert.rejects(
|
|
db.query(
|
|
"update public.difficulty_presets set scoring='unsupported' where id=$1",
|
|
[preset],
|
|
),
|
|
(error) => error.code === "23514",
|
|
);
|
|
await db.query(
|
|
"update public.difficulty_presets set pan=false,compass=false,coordinates=false,map_zoom=false,scoring='strict' where id=$1",
|
|
[preset],
|
|
);
|
|
const settings = (
|
|
await db.query("select public.resolve_difficulty_preset($1) settings", [
|
|
preset,
|
|
])
|
|
).rows[0].settings;
|
|
assert.deepEqual(settings, {
|
|
id: preset,
|
|
name: "Playable preset 45",
|
|
seconds: 45,
|
|
zoom: false,
|
|
pan: false,
|
|
compass: false,
|
|
coordinates: false,
|
|
mapZoom: false,
|
|
mapPan: true,
|
|
timerVisible: true,
|
|
scoring: "strict",
|
|
});
|
|
// Existing sessions retain the original curve even after the library changes.
|
|
assert.equal(
|
|
(
|
|
await db.query(
|
|
"select difficulty_settings->>'scoring' scoring from public.game_sessions where id=$1",
|
|
[solo],
|
|
)
|
|
).rows[0].scoring,
|
|
"normal",
|
|
);
|
|
for (const scoring of ["strict", "normal", "gentle"]) {
|
|
await db.query(
|
|
"update public.difficulty_presets set scoring=$1 where id=$2",
|
|
[scoring, preset],
|
|
);
|
|
const sid = (
|
|
await db.query("select public.create_game($1,$2,$3,$4) id", [
|
|
map,
|
|
preset,
|
|
owner,
|
|
"score-" + scoring,
|
|
])
|
|
).rows[0].id;
|
|
assert.equal(
|
|
(
|
|
await db.query(
|
|
"select count(*)::int total from public.game_rounds where session_id=$1",
|
|
[sid],
|
|
)
|
|
).rows[0].total,
|
|
5,
|
|
);
|
|
await db.query("select public.activate_round($1,0,$2)", [
|
|
sid,
|
|
"score-" + scoring,
|
|
]);
|
|
const point = (
|
|
await db.query(
|
|
"select viewpoint from public.game_rounds where session_id=$1 and round_number=0",
|
|
[sid],
|
|
)
|
|
).rows[0].viewpoint;
|
|
const expected = (
|
|
await db.query("select public.score_difficulty_guess($1,$2,$3) points", [
|
|
Math.hypot(32 - point.x, 32 - point.z),
|
|
Math.hypot(64, 64),
|
|
scoring,
|
|
])
|
|
).rows[0].points;
|
|
const actual = (
|
|
await db.query("select public.submit_guess($1,0,$2,32,32) result", [
|
|
sid,
|
|
"score-" + scoring,
|
|
])
|
|
).rows[0].result;
|
|
assert.equal(actual.score, expected);
|
|
const room = (
|
|
await db.query(
|
|
"select public.create_map_room($1,$2,'Scoring host',2,$3,$4) id",
|
|
[map, preset, "a".repeat(64), owner],
|
|
)
|
|
).rows[0].id;
|
|
await db.query(
|
|
"select public.multiplayer_action($1,$2,'join','{\"name\":\"Guest\"}')",
|
|
[room, "c".repeat(64)],
|
|
);
|
|
await db.query("select public.multiplayer_action($1,$2,'start')", [
|
|
room,
|
|
"a".repeat(64),
|
|
]);
|
|
await db.query(
|
|
"select public.multiplayer_action($1,$2,'ready','{\"round\":0}')",
|
|
[room, "a".repeat(64)],
|
|
);
|
|
await db.query(
|
|
"select public.multiplayer_action($1,$2,'ready','{\"round\":0}')",
|
|
[room, "c".repeat(64)],
|
|
);
|
|
const mp = (
|
|
await db.query(
|
|
"select viewpoint from public.multiplayer_rounds where room_id=$1 and round_number=0",
|
|
[room],
|
|
)
|
|
).rows[0].viewpoint;
|
|
await db.query(
|
|
'select public.multiplayer_action($1,$2,\'guess\',\'{"round":0,"x":32,"z":32}\')',
|
|
[room, "a".repeat(64)],
|
|
);
|
|
const scored = (
|
|
await db.query(
|
|
"select result from public.multiplayer_guesses where room_id=$1 and round_number=0",
|
|
[room],
|
|
)
|
|
).rows[0].result;
|
|
const expectedMulti = (
|
|
await db.query("select public.score_difficulty_guess($1,$2,$3) points", [
|
|
Math.hypot(32 - mp.x, 32 - mp.z),
|
|
Math.hypot(64, 64),
|
|
scoring,
|
|
])
|
|
).rows[0].points;
|
|
assert.equal(scored.score, expectedMulti);
|
|
}
|
|
const decay = (
|
|
await db.query(
|
|
"select public.score_difficulty_guess(20,100,'strict') strict,public.score_difficulty_guess(20,100,'normal') normal,public.score_difficulty_guess(20,100,'gentle') gentle",
|
|
)
|
|
).rows[0];
|
|
assert.ok(decay.strict < decay.normal && decay.normal < decay.gentle);
|
|
assert.equal(
|
|
(
|
|
await db.query(
|
|
"select public.score_difficulty_guess(0,100,'strict') points",
|
|
)
|
|
).rows[0].points,
|
|
5000,
|
|
);
|
|
await assert.rejects(
|
|
db.query("select public.score_difficulty_guess(1,100,'unknown')"),
|
|
/Invalid scoring rules/,
|
|
);
|
|
assert.equal(
|
|
(
|
|
await db.query(
|
|
"select has_function_privilege('anon','public.score_difficulty_guess(double precision,double precision,text)','EXECUTE') allowed",
|
|
)
|
|
).rows[0].allowed,
|
|
false,
|
|
);
|
|
assert.equal(
|
|
(
|
|
await db.query(
|
|
"select has_table_privilege('anon','public.difficulty_presets','INSERT') allowed",
|
|
)
|
|
).rows[0].allowed,
|
|
false,
|
|
);
|
|
console.log(
|
|
"Difficulty SQL regressions passed: original failure reproduced, normal/Unicode names, unsafe names, duplicates, time limits, solo/multiplayer rules and permissions.",
|
|
);
|
|
} finally {
|
|
await db.close();
|
|
}
|