Files
StarPilot/openpilot/starpilot/companion/android/tests/test_bluetooth_fetch.mjs
T

60 lines
3.3 KiB
JavaScript

import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import vm from 'node:vm'
import test from 'node:test'
const source = readFileSync(new URL('../app/src/main/assets/bluetooth-fetch.js', import.meta.url), 'utf8')
function environment() {
const sent = [], canceled = []
const scope = { Request, Response, URL, Uint8Array, Map, Promise, Error, DOMException, atob, btoa,
location: { href: 'https://galaxy-app.invalid/', origin: 'https://galaxy-app.invalid' },
StarPilotBLE: { request: (id, raw) => sent.push([id, JSON.parse(raw)]), cancel: id => canceled.push(id) },
fetch: async () => new Response('asset'),
}
scope.window = scope
vm.runInNewContext(source, scope)
return { scope, sent, canceled }
}
const turn = () => new Promise(resolve => setImmediate(resolve))
test('BLE forwards POST bytes once, preserves HTTP failure, and keeps assets local', async () => {
const { scope, sent } = environment()
const pending = scope.fetch('https://galaxy-app.invalid/api/settings/preview', {method: 'POST', body: '{"value":"é"}', headers: {'Content-Type': 'application/json'}})
await turn()
assert.equal(sent.length, 1)
assert.equal(Buffer.from(sent[0][1].body, 'base64').toString(), '{"value":"é"}')
scope.__galaxyBleReply(sent[0][0], {status: 409, headers: {'content-type': 'application/json'}, body: btoa('{"error":"Park first"}')})
assert.equal((await pending).status, 409)
assert.equal(await (await scope.fetch('https://galaxy-app.invalid/data/catalog.json')).text(), 'asset')
assert.equal(sent.length, 1)
await assert.rejects(scope.fetch('https://evil.test/api/settings/preview'), /External/)
})
test('cancellation does not replay mutations and late replies cannot resolve them', async () => {
const { scope, sent, canceled } = environment()
const controller = new AbortController()
const pending = scope.fetch('https://galaxy-app.invalid/api/settings/confirm', {method: 'POST', body: '{}', signal: controller.signal})
await turn()
controller.abort()
await assert.rejects(pending, /Check whether the change applied/)
assert.deepEqual(canceled, [sent[0][0]])
scope.__galaxyBleReply(sent[0][0], {status: 200, headers: {}, body: btoa('{}')})
assert.equal(sent.length, 1)
})
test('BLE reads live restart identity and refuses replay before sending a request', async () => {
const { scope, sent } = environment()
const pending = scope.fetch('https://galaxy-app.invalid/data/runtime.json')
await turn()
assert.equal(sent[0][1].path, '/api/companion/runtime')
scope.__galaxyBleReply(sent[0][0], {status: 200, headers: {}, body: btoa('{"schemaVersion":1,"monitor":"local","instance":"boot-2"}')})
assert.equal((await (await pending).json()).instance, 'boot-2')
for (const path of ['/api/replay/start', '/api/replay/media?sequence=1', '/api/recordings/local', '/api/cameras/snapshot',
'/api/starport/upload', '/api/spotify/upload', '/api/navigation/map/tiles/1/0/0.png', '/api/companion/app.apk', '/api/companion/uplink']) {
const blocked = await scope.fetch('https://galaxy-app.invalid' + path)
assert.equal(blocked.status, 501)
const body = await blocked.json()
assert.equal(body.code, 'bluetooth_unavailable')
assert.match(body.error, /not available over Bluetooth.*Wi-Fi or LAN/)
}
assert.equal(sent.length, 1)
})