update docs

This commit is contained in:
2026-09-22 13:23:34 +08:00
parent 99bc3d15c5
commit 8a4788fca8
126 changed files with 7198 additions and 2425 deletions
+55 -5
View File
@@ -53,7 +53,7 @@ def desktop(vm, enabled):
return p['desktop']==('windowmaker' if enabled else 'cli') and (p['ready_ns'] is not None if enabled else True)
return json.loads(wait(vm,'fds --json profiles',condition))['profiles']
def image(name, replacements):
replacements={**replacements, **{f'usr/bin/{binary}':(project/'out'/binary).read_bytes() for binary in ['fds','fds-cartridged','fds-profile']}}
replacements={**replacements, **{f'usr/bin/{binary}':(project/'out'/binary).read_bytes() for binary in ['fds','fds-program','fds-control','fds-cartridged','fds-profile']}}
with tarfile.open(project/'out/rootfs-development.tar') as source, tarfile.open(work/(name+'.tar'),'w',format=tarfile.PAX_FORMAT) as output:
assert source.extractfile('usr/share/fds/image-profile').read().strip()==b'development', 'Build PROFILE=development before this test'
seen=set()
@@ -86,10 +86,13 @@ with VM(work,'probe',probe,extra=['-device',controller,'-device','usb-kbd,bus=xh
print(capture(vm,'cat /run/log/xserver/current /run/log/desktop/current /run/log/cartridged/current'),flush=True)
raise
shell(vm,'test ! -d /home/fds/.cache/fontconfig','M8_PREBUILT_FONT_CACHE')
shell(vm,'cmp /etc/WindowMaker/WindowMaker /usr/share/fds/eink/WindowMaker && cmp /etc/WindowMaker/WMRootMenu /usr/share/fds/eink/WMRootMenu && grep -q "FDS Control" /etc/WindowMaker/WMRootMenu','FDS_GLOBAL_RETRO_DEFAULTS')
(work/'activation.json').write_text(json.dumps(p,indent=2)+'\n')
assert p['ready_ns']>=p['activation_ns']>0
shell(vm,'export DISPLAY=:0 XAUTHORITY=/run/fds/x11/authority; s6-setuidgid fds xdpyinfo >/tmp/display-info; ! grep -q "COMPOSITE" /tmp/display-info','M8_X11_AUTHENTICATED')
shell(vm,'if env XAUTHORITY=/dev/null xdpyinfo >/dev/null 2>&1; then false; else true; fi','M8_X11_REJECTS_NO_COOKIE')
panel=wait(vm,'s6-setuidgid fds xdotool search --onlyvisible --name "^FDS Control$"',lambda s:s.isdigit())
shell(vm,'test "$(ps -o uid= -C fds-control | xargs)" = 1000','FDS_CONTROL_UNPRIVILEGED')
window=wait(vm,'s6-setuidgid fds xdotool search --onlyvisible --name "^FDS Terminal$"',lambda s:s.isdigit())
shell(vm,f's6-setuidgid fds xdotool windowactivate --sync {window} type --clearmodifiers "printf M8_INPUT_WORKED > /home/fds/desktop-input"; s6-setuidgid fds xdotool key --clearmodifiers Return','M8_X11_INPUT_SENT')
wait(vm,'cat /home/fds/desktop-input 2>/dev/null',lambda s:s=='M8_INPUT_WORKED')
@@ -145,12 +148,58 @@ with VM(work,'cartridges',fixture,extra=['-device',controller,'-netdev','user,id
add(env,2);bay(vm,2,'mounted_read_only');desktop(vm,True);remove(2);desktop(vm,False)
add(program,4);entry=bay(vm,4,'mounted_read_only');assert entry['mount']=='/run/fds/apps/fds.program.test'
shell(vm,'test ! -e /home/fds/program-identity && ! /run/fds/apps/fds.program.test/app/bin/check','M8_NO_AUTORUN')
started=query(vm,'s6-setuidgid fds fds --json run 4 -- check');assert started['started_pid']>1
shell(vm,'fds profile activate windowmaker','FDS_CONTROL_START_DESKTOP')
desktop(vm,True)
shell(vm,'export DISPLAY=:0 XAUTHORITY=/run/fds/x11/authority','FDS_CONTROL_DISPLAY')
panel=wait(vm,'s6-setuidgid fds xdotool search --onlyvisible --name "^FDS Control$"',lambda s:s.isdigit())
wait(vm,'s6-setuidgid fds xdotool search --onlyvisible --name "^FDS Terminal$"',lambda s:s.isdigit())
shell(vm,f's6-setuidgid fds xdotool windowactivate --sync {panel} windowraise {panel} mousemove --window {panel} 70 218 click 1','FDS_CONTROL_SELECT_BAY')
def panel_state():
output=capture(vm,f's6-setuidgid fds xprop -id {panel} _FDS_CONTROL_STATE')
return json.loads(json.loads(output.split(' = ',1)[1]))
deadline=time.monotonic()+30
while True:
snapshot=panel_state()
if snapshot['bay']==4 and snapshot['commands']>0 and not snapshot['busy']: break
assert time.monotonic()<deadline,snapshot
shell(vm,f's6-setuidgid fds xdotool windowactivate --sync {panel} windowraise {panel} mousemove --window {panel} 420 518 click 1','FDS_CONTROL_RUN_CLICK')
wait(vm,'cat /home/fds/program-identity 2>/dev/null',lambda s:'uid=1000(fds)' in s)
assert query(vm,'fds --json bay 4')['bays'][0]['consumers']>0
shell(vm,f's6-setuidgid fds xdotool windowactivate --sync {panel}','FDS_CONTROL_SHOW_PANEL')
shell(vm,'s6-setuidgid fds xwd -root -silent -out /home/fds/control.xwd','FDS_CONTROL_SCREENSHOT')
(work/'legacy-control.xwd').write_bytes(gzip.decompress(base64.b64decode(capture(vm,'gzip -c /home/fds/control.xwd | base64 -w0'))))
wait(vm,'cat /home/fds/program-identity 2>/dev/null',lambda s:'uid=1000(fds)' in s)
assert '/run/fds/apps/fds.program.test/app/lib' in capture(vm,'cat /home/fds/program-paths')
shell(vm,'if fds run 4 -- escape; then false; else true; fi','M8_PROGRAM_ESCAPE_REJECTED')
shell(vm,'if fds run 4 -- ../check; then false; else true; fi; fds eject 4','M8_PROGRAM_SAFE')
shell(vm,'if fds run 4 -- ../check; then false; else true; fi','M8_PROGRAM_PATH_REJECTED')
deadline=time.monotonic()+30
while panel_state()['busy']:
assert time.monotonic()<deadline
shell(vm,f's6-setuidgid fds xdotool windowactivate --sync {panel} windowraise {panel} mousemove --window {panel} 612 518 click 1','FDS_CONTROL_EJECT_CLICK')
assert bay(vm,4,'safe')['consumers']==0;remove(4)
# Launch a format-2, Void-built command through the real panel as well.
built=Path((project/'out/workstation-images-current.txt').read_text().strip())
assert json.loads((built/'acceptance.json').read_text())['status']=='passed'
add(built/'software.img',4);bay(vm,4,'mounted_read_only')
deadline=time.monotonic()+30
while True:
snapshot=panel_state()
if snapshot['commands']>=2 and not snapshot['busy']: break
assert time.monotonic()<deadline,snapshot
shell(vm,f's6-setuidgid fds xdotool windowactivate --sync {panel} windowraise {panel} mousemove --window {panel} 420 518 click 1','FDS_CONTROL_RUN_VOID')
hello_window=wait(vm,'s6-setuidgid fds xdotool search --onlyvisible --name "^demo.hello:hello$"',lambda s:s.isdigit())
shell(vm,f's6-setuidgid fds xdotool windowsize {hello_window} 650 360 windowmove {hello_window} 930 70 windowactivate --sync {panel}','FDS_CONTROL_VOID_RESULT')
shell(vm,'s6-setuidgid fds xwd -root -silent -out /home/fds/control.xwd','FDS_CONTROL_VOID_SCREENSHOT')
(work/'control.xwd').write_bytes(gzip.decompress(base64.b64decode(capture(vm,'gzip -c /home/fds/control.xwd | base64 -w0'))))
shell(vm,f's6-setuidgid fds xdotool windowactivate --sync {panel} windowraise {panel} key r','FDS_CONTROL_KEYBOARD_RESCAN')
deadline=time.monotonic()+30
while True:
snapshot=panel_state()
if not snapshot['busy'] and snapshot['status']=='Cartridge inventory refreshed.': break
assert time.monotonic()<deadline,snapshot
shell(vm,f's6-setuidgid fds xdotool windowactivate --sync {panel} windowraise {panel} mousemove --window {panel} 612 518 click 1','FDS_CONTROL_EJECT_VOID')
assert bay(vm,4,'safe')['consumers']==0;remove(4)
shell(vm,'fds profile deactivate && ! pgrep -x fds-control','FDS_CONTROL_SESSION_STOPPED')
shell(vm,'modprobe cdc_ether','M8_NETWORK_DRIVER')
vm.qmp('device_add',{'driver':'usb-net','id':'ethernet','netdev':'net','bus':'xhci.0','port':'3'})
wait(vm,'fds --json profiles',lambda s:len(json.loads(s)['profiles']['network'])==1)
@@ -173,7 +222,7 @@ with VM(work,'no-dhcp-server',fixture,extra=['-device',controller,'-netdev','hub
shell(vm,'fds network off','M8_NO_DHCP_STOPPED')
print('PASS: console and service controls work with Ethernet present and no DHCP server',flush=True)
# Convert this test's raw X11 screenshot to a portable PNG without external tools.
data=(work/'desktop.xwd').read_bytes();header=struct.unpack('>25I',data[:100]);size,version,fmt,depth,width,height,xoff,order,unit,bitorder,pad,bpp,stride,visual,rm,gm,bm,*_=header
data=(work/'control.xwd').read_bytes();header=struct.unpack('>25I',data[:100]);size,version,fmt,depth,width,height,xoff,order,unit,bitorder,pad,bpp,stride,visual,rm,gm,bm,*_=header
assert version==7 and fmt==2 and bpp==32 and (rm,gm,bm)==(0xff0000,0xff00,0xff)
offset=size+header[19]*12
raw=bytearray()
@@ -183,7 +232,8 @@ for y in range(height):
pixel=int.from_bytes(data[offset+y*stride+x*4:offset+y*stride+x*4+4], 'little' if order==0 else 'big')
raw.extend(((pixel>>16)&255,(pixel>>8)&255,pixel&255))
def chunk(kind,body):return struct.pack('>I',len(body))+kind+body+struct.pack('>I',zlib.crc32(kind+body)&0xffffffff)
(work/'desktop.png').write_bytes(b'\x89PNG\r\n\x1a\n'+chunk(b'IHDR',struct.pack('>IIBBBBB',width,height,8,2,0,0,0))+chunk(b'IDAT',zlib.compress(raw))+chunk(b'IEND',b''))
(work/'control.png').write_bytes(b'\x89PNG\r\n\x1a\n'+chunk(b'IHDR',struct.pack('>IIBBBBB',width,height,8,2,0,0,0))+chunk(b'IDAT',zlib.compress(raw))+chunk(b'IEND',b''))
(work/'acceptance.json').write_text(json.dumps(dict(status='passed', native_arm_x11=True, panel_uid=1000, global_grayscale_defaults=True, legacy_and_void_programs_launched_by_mouse=True, keyboard_rescan=True, panel_safe_eject=True, desktop_stop_removes_panel=True, physical_display='not tested'),indent=2)+'\n')
link=project/'out/m8-vm-latest';temporary=link.with_suffix('.next');temporary.symlink_to(work.name);temporary.replace(link)
print(f'PASS: M8 ARM desktop and network verification: {work}')
print('SKIP: Pi DRM/VC4 output, physical E-Ink quality and monitor input-to-refresh latency')