mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-04 01:03:25 +00:00
The generic mutable-table blank template persisted incomplete company definitions before runtime domain validation. Seed valid company defaults, validate before SQL writes, and repair legacy blank entries.
148 lines
5.4 KiB
TypeScript
148 lines
5.4 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
const config = readFileSync(
|
|
new URL('../../sky_phone/config/config.lua', import.meta.url),
|
|
'utf8',
|
|
).replace(/\r\n/g, '\n')
|
|
const companiesServer = readFileSync(
|
|
new URL('../../sky_phone/source/server/companies.lua', import.meta.url),
|
|
'utf8',
|
|
).replace(/\r\n/g, '\n')
|
|
const configuratorServer = readFileSync(
|
|
new URL(
|
|
'../../sky_phone/source/server/phone_configurator.lua',
|
|
import.meta.url,
|
|
),
|
|
'utf8',
|
|
).replace(/\r\n/g, '\n')
|
|
const testServer = readFileSync(
|
|
new URL('../testserver/index.cjs', import.meta.url),
|
|
'utf8',
|
|
).replace(/\r\n/g, '\n')
|
|
|
|
function sourceBlock(source: string, startMarker: string, endMarker: string) {
|
|
const start = source.indexOf(startMarker)
|
|
const end = source.indexOf(endMarker, start)
|
|
|
|
expect(start).toBeGreaterThanOrEqual(0)
|
|
expect(end).toBeGreaterThan(start)
|
|
return source.slice(start, end)
|
|
}
|
|
|
|
describe('Companies emergency request contract', () => {
|
|
it('ships non-emergency police assistance as a requestable service', () => {
|
|
const police = sourceBlock(
|
|
config,
|
|
' police = {',
|
|
' ambulance = {',
|
|
)
|
|
const mockPolice = sourceBlock(
|
|
testServer,
|
|
'const companyProfiles = [',
|
|
' {\n acceptsRequests: false,\n announcement: null,',
|
|
)
|
|
|
|
expect(police).toContain('Emergency = true')
|
|
expect(police).toContain('AcceptsRequests = true')
|
|
expect(police).toContain('Id = "police-assistance"')
|
|
expect(police).toContain('RequestsEnabled = true')
|
|
expect(mockPolice).toContain('acceptsRequests: true')
|
|
expect(mockPolice).toContain("name: 'Los Santos Police Department'")
|
|
expect(mockPolice).toContain("id: 'police-assistance'")
|
|
})
|
|
|
|
it('authorizes configured emergency companies through the normal request gates', () => {
|
|
const validation = sourceBlock(
|
|
companiesServer,
|
|
'local function validate_configuration(configuration)',
|
|
'local function seed_companies()',
|
|
)
|
|
const payload = sourceBlock(
|
|
companiesServer,
|
|
'local function company_payload(',
|
|
'local function public_company(',
|
|
)
|
|
const createRequest = sourceBlock(
|
|
companiesServer,
|
|
'Bridge.Callbacks.Register("sky_phone:companies:create-request"',
|
|
'Bridge.Callbacks.Register("sky_phone:companies:cancel-request"',
|
|
)
|
|
const updateProfile = sourceBlock(
|
|
companiesServer,
|
|
'Bridge.Callbacks.Register("sky_phone:companies:update-profile"',
|
|
'Bridge.Callbacks.Register("sky_phone:companies:update-hours"',
|
|
)
|
|
|
|
expect(validation).not.toContain(
|
|
'definition.Emergency and definition.AcceptsRequests',
|
|
)
|
|
expect(payload).toContain(
|
|
'acceptsRequests = tonumber(row.accepts_requests) == 1,',
|
|
)
|
|
expect(payload).not.toContain('not definition.Emergency')
|
|
expect(createRequest).toContain(
|
|
'if not definition or not definition.Public then',
|
|
)
|
|
expect(createRequest).not.toContain('definition.Emergency')
|
|
expect(createRequest).toContain('SELECT `accepts_requests`')
|
|
expect(createRequest).toContain('AND `requests_enabled` = 1')
|
|
expect(updateProfile).not.toContain('member.definition.Emergency')
|
|
})
|
|
|
|
it('migrates existing requestable emergency profiles exactly once', () => {
|
|
const migration = sourceBlock(
|
|
companiesServer,
|
|
'local function migrate_requestable_emergency_companies()',
|
|
'local function tombstone_removed_companies()',
|
|
)
|
|
const refresh = sourceBlock(
|
|
companiesServer,
|
|
'local function refresh_runtime_configuration()',
|
|
'\n\nrefresh_runtime_configuration()',
|
|
)
|
|
|
|
expect(migration).toContain('sky-phone:companies:requestable-emergency:v1')
|
|
expect(migration).toContain(
|
|
'if definition.Emergency and definition.AcceptsRequests then',
|
|
)
|
|
expect(migration).toContain('SET `accepts_requests` = 1')
|
|
expect(migration).toContain('INSERT IGNORE INTO `sky_phone_migrations`')
|
|
expect(migration).toContain('Bridge.Database.Transaction(statements)')
|
|
expect(refresh.indexOf('seed_companies()')).toBeLessThan(
|
|
refresh.indexOf('migrate_requestable_emergency_companies()'),
|
|
)
|
|
expect(
|
|
refresh.indexOf('migrate_requestable_emergency_companies()'),
|
|
).toBeLessThan(refresh.indexOf('tombstone_removed_companies()'))
|
|
})
|
|
|
|
it('migrates the existing Phone Configurator police defaults', () => {
|
|
const migration = sourceBlock(
|
|
configuratorServer,
|
|
'local function migrate_police_request_defaults()',
|
|
'\n\ndefault_config = {}',
|
|
)
|
|
|
|
expect(migration).toContain('sky-phone:configurator:police-requests:v1')
|
|
expect(migration).toContain('police.AcceptsRequests == false')
|
|
expect(migration).toContain('next(police.Services) == nil')
|
|
expect(migration).toContain(
|
|
'police.AcceptsRequests = defaults.AcceptsRequests',
|
|
)
|
|
expect(migration).toContain(
|
|
'police.Services = copy_value(defaults.Services)',
|
|
)
|
|
expect(migration).toContain('SET `config_payload` = ?')
|
|
expect(migration).toContain('`revision` = `revision` + 1')
|
|
expect(migration).toContain('INSERT IGNORE INTO `sky_phone_migrations`')
|
|
expect(migration).toContain('Bridge.Database.Transaction(statements)')
|
|
expect(migration).toContain('apply_stored_row(read_stored_row())')
|
|
expect(migration).toContain('apply_runtime_configuration()')
|
|
expect(configuratorServer).toContain(
|
|
'Bridge.Database.AfterMigration("sky_phone", migrate_police_request_defaults)',
|
|
)
|
|
})
|
|
})
|