Restore Gaia settings and media workflows, extend native network adapters, and align the APK payload. Generate French/English changelogs and website entries from the simplified JSON source. Validation: shared JS and Tundra unit tests; desktop workflows and persistence; signed APK payload parity; Sargo RAM and installed startup with boot readback. Android runtime qualification is recorded separately.
138 lines
6.5 KiB
JavaScript
138 lines
6.5 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { tundraWifi } from '../host/Tundra.sys.mjs';
|
|
|
|
test('Wi-Fi bursts share one scan, cache errors, and retry after cooldown', async () => {
|
|
const realNow = Date.now;
|
|
let now = realNow(), starts = 0, release;
|
|
let reply = {result:{networks:[]}};
|
|
let gate = new Promise(resolve => {release = resolve;});
|
|
Date.now = () => now;
|
|
globalThis.Services = {env:{get:() => '1'}};
|
|
globalThis.ChromeUtils = {importESModule:() => ({Subprocess:{call:async () => {
|
|
starts++;
|
|
let read = false;
|
|
return {stdin:{write:async () => {},close:async () => {}},
|
|
stdout:{readString:async () => {
|
|
await gate;
|
|
if (read) return null;
|
|
read = true;
|
|
return JSON.stringify(reply);
|
|
}},wait:async () => ({exitCode:0})};
|
|
}}})};
|
|
try {
|
|
const burst = Array.from({length:1000}, () => tundraWifi({operation:'scan'}));
|
|
assert.equal(starts, 1);
|
|
release();
|
|
assert.ok((await Promise.all(burst)).every(r => r.networks.length === 0));
|
|
await tundraWifi({operation:'scan'});
|
|
assert.equal(starts, 1);
|
|
await tundraWifi({operation:'known'});
|
|
await tundraWifi({operation:'status'});
|
|
await tundraWifi({operation:'scan'});
|
|
assert.equal(starts, 3, 'read-only status and saved networks preserve the radio scan cache');
|
|
starts -= 2;
|
|
now += 6000;
|
|
reply = {error:'WIFI_UNAVAILABLE'};
|
|
const failures = await Promise.allSettled(Array.from({length:1000}, () => tundraWifi({operation:'scan'})));
|
|
assert.ok(failures.every(r => r.status === 'rejected'));
|
|
assert.equal(starts, 2);
|
|
await assert.rejects(tundraWifi({operation:'scan'}), /WIFI_UNAVAILABLE/);
|
|
assert.equal(starts, 2);
|
|
now += 6000;
|
|
reply = {result:{networks:[]}};
|
|
await tundraWifi({operation:'scan'});
|
|
assert.equal(starts, 3);
|
|
reply = {result:{disconnected:true}};
|
|
await tundraWifi({operation:'disconnect'});
|
|
reply = {result:{networks:[]}};
|
|
await tundraWifi({operation:'scan'});
|
|
assert.equal(starts, 5, 'disconnect invalidates the scan cache');
|
|
} finally { Date.now = realNow; }
|
|
});
|
|
|
|
test('Gaia scans disconnected Wi-Fi every 20 seconds and stops when disabled', async () => {
|
|
const {readFile} = await import('node:fs/promises');
|
|
const vm = await import('node:vm');
|
|
let timer, interval, scans = 0, cleared = 0;
|
|
const observers = {};
|
|
const manager = {connection:{status:'disconnected'}, getNetworks:() => {scans++;}};
|
|
const window = {navigator:{mozSettings:{},mozWifiManager:manager,battery:{addEventListener(){}}},addEventListener(){}};
|
|
const context = vm.createContext({window,console,
|
|
LazyLoader:{load:async () => {}}, Service:{request:async () => {},registerState(){}},
|
|
WifiIcon:class {start(){} update(){}}, WifiWakeLockManager:class {start(){}},
|
|
SettingsListener:{getSettingsLock:() => ({get:() => ({})}),observe:(key,value,cb) => {observers[key]=cb;cb(value);}},
|
|
setInterval:(cb,ms) => {timer=cb;interval=ms;return 123;},clearTimeout:id => {if(id===123) cleared++;}
|
|
});
|
|
vm.runInContext(await readFile(new URL('../overrides/system.gaiamobile.org/js/wifi.js',import.meta.url),'utf8'),context);
|
|
window.Wifi.start();
|
|
assert.equal(interval,20000);
|
|
assert.equal(scans,0);
|
|
timer();assert.equal(scans,1);
|
|
manager.connection.status='connected';timer();assert.equal(scans,1);
|
|
observers['wifi.enabled'](false);assert.equal(cleared,1);
|
|
});
|
|
|
|
test('Native Wi-Fi acknowledges unchanged settings and completes delayed radio changes', async () => {
|
|
const {readFile} = await import('node:fs/promises');
|
|
const vm = await import('node:vm');
|
|
const events = {}, observers = new Map(), changes = [];
|
|
let hardware = false, completeRadio;
|
|
const navigator = {mozSettings:{addObserver:(key,fn)=>observers.set(key,fn)}};
|
|
const call = async (method, params) => {
|
|
if(method==='settings.set') {
|
|
for(const [key,value] of Object.entries(params.values)) observers.get(key)?.({settingValue:value});
|
|
return;
|
|
}
|
|
if(params.operation==='setEnabled') {
|
|
changes.push(params.enabled);
|
|
await new Promise(resolve=>{completeRadio=resolve;});
|
|
hardware=params.enabled;
|
|
}
|
|
return {enabled:hardware,networks:[]};
|
|
};
|
|
const context=vm.createContext({navigator,console,Event,EventTarget,DOMException,
|
|
window:{VulpesNativeWifi:true},location:{hostname:'system.localhost'},
|
|
VulpesCompat:{call,request:x=>x},addEventListener:(name,fn)=>{events[name]=fn;}});
|
|
vm.runInContext(await readFile(new URL('../host/gaia-wifi.js',import.meta.url),'utf8'),context);
|
|
let disabled=0,enabled=0;
|
|
navigator.mozWifiManager.ondisabled=()=>disabled++;
|
|
navigator.mozWifiManager.onenabled=()=>enabled++;
|
|
await events.DOMContentLoaded();
|
|
await new Promise(setImmediate);
|
|
assert.equal(disabled,1,'initial same-state acknowledgement releases Gaia controls');
|
|
observers.get('wifi.enabled')({settingValue:false});
|
|
await new Promise(setImmediate);
|
|
assert.equal(disabled,2);
|
|
assert.equal(changes.length,0,'no unnecessary hardware call');
|
|
observers.get('wifi.enabled')({settingValue:true});
|
|
await new Promise(setImmediate);
|
|
assert.equal(navigator.mozWifiManager.enabled,false,'do not announce success before hardware');
|
|
completeRadio();await new Promise(setImmediate);
|
|
assert.equal(enabled,1);
|
|
assert.equal(navigator.mozWifiManager.enabled,true);
|
|
});
|
|
|
|
test('scan without an association does not send Gaia an invalid signal event', async () => {
|
|
const {readFile}=await import('node:fs/promises');
|
|
const vm=await import('node:vm');
|
|
let connected=false, signals=0;
|
|
const navigator={};
|
|
const context=vm.createContext({navigator,console,Event,EventTarget,DOMException,
|
|
window:{VulpesNativeWifi:true},location:{hostname:'settings.localhost'},addEventListener(){},
|
|
VulpesCompat:{request:p=>p,call:async()=>({enabled:true,networks:[
|
|
{ssid:'Test network',id:'/ap/1',signal:80,security:'wpa-psk',connected}
|
|
]})}});
|
|
vm.runInContext(await readFile(new URL('../host/gaia-wifi.js',import.meta.url),'utf8'),context);
|
|
const manager=navigator.mozWifiManager;
|
|
manager.onconnectioninfoupdate=event=>{
|
|
// The original Settings WifiUtils reads event.network.ssid unconditionally.
|
|
assert.equal(event.network.ssid,'Test network');
|
|
assert.equal(event.relSignalStrength,80);signals++;
|
|
};
|
|
assert.equal((await manager.getNetworks()).length,1);
|
|
assert.equal(signals,0);assert.equal(manager.connectionInformation,null);
|
|
connected=true;await manager.getNetworks();
|
|
assert.equal(signals,1);assert.equal(manager.connection.status,'connected');
|
|
connected=false;await manager.getNetworks();assert.equal(signals,1);
|
|
});
|