implements PLN-0057 lifecycle tests
This commit is contained in:
parent
df9f82fcd2
commit
aebebcae04
@ -177,6 +177,8 @@ mod tests {
|
|||||||
use prometeu_hal::cartridge::{AppMode, AssetsPayloadSource};
|
use prometeu_hal::cartridge::{AppMode, AssetsPayloadSource};
|
||||||
use prometeu_hal::syscalls::caps;
|
use prometeu_hal::syscalls::caps;
|
||||||
use prometeu_system::CrashReport;
|
use prometeu_system::CrashReport;
|
||||||
|
use prometeu_system::process::ProcessState;
|
||||||
|
use prometeu_system::task::TaskState;
|
||||||
|
|
||||||
fn halting_program() -> Vec<u8> {
|
fn halting_program() -> Vec<u8> {
|
||||||
let code = assemble("HALT").expect("assemble");
|
let code = assemble("HALT").expect("assemble");
|
||||||
@ -289,7 +291,10 @@ mod tests {
|
|||||||
firmware.load_cartridge(trapping_game_cartridge());
|
firmware.load_cartridge(trapping_game_cartridge());
|
||||||
firmware.tick(&signals, &mut hardware);
|
firmware.tick(&signals, &mut hardware);
|
||||||
|
|
||||||
assert!(matches!(firmware.state, FirmwareState::GameRunning(_)));
|
let task_id = match &firmware.state {
|
||||||
|
FirmwareState::GameRunning(step) => step.task_id,
|
||||||
|
other => panic!("expected GameRunning state, got {:?}", other),
|
||||||
|
};
|
||||||
|
|
||||||
firmware.tick(&signals, &mut hardware);
|
firmware.tick(&signals, &mut hardware);
|
||||||
|
|
||||||
@ -302,6 +307,13 @@ mod tests {
|
|||||||
},
|
},
|
||||||
other => panic!("expected AppCrashes state, got {:?}", other),
|
other => panic!("expected AppCrashes state, got {:?}", other),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let task = firmware.os.task_manager.get(task_id).expect("task should exist");
|
||||||
|
let process =
|
||||||
|
firmware.os.process_manager.get(task.process_id).expect("process should exist");
|
||||||
|
|
||||||
|
assert_eq!(task.state, TaskState::Crashed);
|
||||||
|
assert_eq!(process.state, ProcessState::Crashed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -201,3 +201,124 @@ impl SystemOS {
|
|||||||
Ok(task.process_id)
|
Ok(task.process_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::process::ProcessState;
|
||||||
|
|
||||||
|
fn process_state_for_task(os: &SystemOS, task_id: TaskId) -> ProcessState {
|
||||||
|
let task = os.task_manager.get(task_id).expect("task should exist");
|
||||||
|
os.process_manager.get(task.process_id).expect("process should exist").state
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_foreground_task_marks_task_and_process_running() {
|
||||||
|
let mut os = SystemOS::new(None);
|
||||||
|
let task_id = os.create_vm_game_task(42, "Sector Crawl");
|
||||||
|
|
||||||
|
os.suspend_task(task_id).expect("suspend should succeed");
|
||||||
|
os.set_foreground_task(task_id).expect("foreground should succeed");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
os.task_manager.get(task_id).expect("task should exist").state,
|
||||||
|
TaskState::Foreground
|
||||||
|
);
|
||||||
|
assert_eq!(process_state_for_task(&os, task_id), ProcessState::Running);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn suspend_task_marks_task_and_process_suspended() {
|
||||||
|
let mut os = SystemOS::new(None);
|
||||||
|
let task_id = os.create_vm_game_task(42, "Sector Crawl");
|
||||||
|
|
||||||
|
os.suspend_task(task_id).expect("suspend should succeed");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
os.task_manager.get(task_id).expect("task should exist").state,
|
||||||
|
TaskState::Suspended
|
||||||
|
);
|
||||||
|
assert_eq!(process_state_for_task(&os, task_id), ProcessState::Suspended);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resume_task_marks_suspended_task_foreground_and_process_running() {
|
||||||
|
let mut os = SystemOS::new(None);
|
||||||
|
let task_id = os.create_vm_game_task(42, "Sector Crawl");
|
||||||
|
|
||||||
|
os.suspend_task(task_id).expect("suspend should succeed");
|
||||||
|
os.resume_task(task_id).expect("resume should succeed");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
os.task_manager.get(task_id).expect("task should exist").state,
|
||||||
|
TaskState::Foreground
|
||||||
|
);
|
||||||
|
assert_eq!(process_state_for_task(&os, task_id), ProcessState::Running);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn close_task_marks_task_closed_and_process_stopped_without_removing_entities() {
|
||||||
|
let mut os = SystemOS::new(None);
|
||||||
|
let task_id = os.create_vm_game_task(42, "Sector Crawl");
|
||||||
|
let process_id = os.task_manager.get(task_id).expect("task should exist").process_id;
|
||||||
|
|
||||||
|
os.close_task(task_id).expect("close should succeed");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
os.task_manager.get(task_id).expect("task should remain").state,
|
||||||
|
TaskState::Closed
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
os.process_manager.get(process_id).expect("process should remain").state,
|
||||||
|
ProcessState::Stopped
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn crash_task_marks_task_and_process_crashed() {
|
||||||
|
let mut os = SystemOS::new(None);
|
||||||
|
let task_id = os.create_vm_game_task(42, "Sector Crawl");
|
||||||
|
|
||||||
|
os.crash_task(task_id, None).expect("crash should succeed");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
os.task_manager.get(task_id).expect("task should exist").state,
|
||||||
|
TaskState::Crashed
|
||||||
|
);
|
||||||
|
assert_eq!(process_state_for_task(&os, task_id), ProcessState::Crashed);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lifecycle_operation_missing_task_returns_typed_error() {
|
||||||
|
let mut os = SystemOS::new(None);
|
||||||
|
|
||||||
|
assert_eq!(os.suspend_task(TaskId(999)), Err(LifecycleError::TaskNotFound(TaskId(999))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lifecycle_operation_missing_process_returns_typed_error() {
|
||||||
|
let mut os = SystemOS::new(None);
|
||||||
|
let task_id = os.create_vm_game_task(42, "Sector Crawl");
|
||||||
|
let process_id = os.task_manager.get(task_id).expect("task should exist").process_id;
|
||||||
|
|
||||||
|
os.process_manager.mark_stopped(process_id);
|
||||||
|
os.process_manager.remove_stopped();
|
||||||
|
|
||||||
|
assert_eq!(os.suspend_task(task_id), Err(LifecycleError::ProcessNotFound(process_id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resume_task_from_non_suspended_state_returns_invalid_transition() {
|
||||||
|
let mut os = SystemOS::new(None);
|
||||||
|
let task_id = os.create_vm_game_task(42, "Sector Crawl");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
os.resume_task(task_id),
|
||||||
|
Err(LifecycleError::InvalidTransition {
|
||||||
|
task_id,
|
||||||
|
from: TaskState::Foreground,
|
||||||
|
operation: LifecycleOperation::Resume,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -30,5 +30,5 @@
|
|||||||
{"type":"discussion","id":"DSC-0019","status":"done","ticket":"jenkinsfile-correction","title":"Jenkinsfile Correction and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins"],"agendas":[{"id":"AGD-0017","file":"AGD-0017-jenkinsfile-correction.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0002","file":"DEC-0002-jenkinsfile-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0002","file":"PLN-0002-jenkinsfile-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0020","file":"discussion/lessons/DSC-0019-jenkins-ci-standardization/LSN-0020-jenkins-standard-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
|
{"type":"discussion","id":"DSC-0019","status":"done","ticket":"jenkinsfile-correction","title":"Jenkinsfile Correction and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins"],"agendas":[{"id":"AGD-0017","file":"AGD-0017-jenkinsfile-correction.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0002","file":"DEC-0002-jenkinsfile-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0002","file":"PLN-0002-jenkinsfile-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0020","file":"discussion/lessons/DSC-0019-jenkins-ci-standardization/LSN-0020-jenkins-standard-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
|
||||||
{"type":"discussion","id":"DSC-0030","status":"done","ticket":"internal-viewport-270p","title":"Agenda - Internal Viewport 270p (480x270)","created_at":"2026-04-27","updated_at":"2026-04-28","tags":["gfx","runtime","viewport","resolution","frame-composer","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0030-internal-viewport-270p/LSN-0039-resolution-baseline-changes-are-runtime-wide-contracts.md","status":"done","created_at":"2026-04-28","updated_at":"2026-04-28"}]}
|
{"type":"discussion","id":"DSC-0030","status":"done","ticket":"internal-viewport-270p","title":"Agenda - Internal Viewport 270p (480x270)","created_at":"2026-04-27","updated_at":"2026-04-28","tags":["gfx","runtime","viewport","resolution","frame-composer","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0030-internal-viewport-270p/LSN-0039-resolution-baseline-changes-are-runtime-wide-contracts.md","status":"done","created_at":"2026-04-28","updated_at":"2026-04-28"}]}
|
||||||
{"type":"discussion","id":"DSC-0031","status":"done","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0040","file":"discussion/lessons/DSC-0031-runtime-mode-separation-game-system/LSN-0040-system-pipeline-separation.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14"}]}
|
{"type":"discussion","id":"DSC-0031","status":"done","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0040","file":"discussion/lessons/DSC-0031-runtime-mode-separation-game-system/LSN-0040-system-pipeline-separation.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14"}]}
|
||||||
{"type":"discussion","id":"DSC-0032","status":"in_progress","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[{"id":"AGD-0032","file":"AGD-0032-system-os-lifecycle-process-task-contract.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-15"}],"decisions":[{"id":"DEC-0025","file":"DEC-0025-systemos-lifecycle-authority-for-tasks-and-processes.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15","ref_agenda":"AGD-0032"}],"plans":[{"id":"PLN-0055","file":"PLN-0055-systemos-lifecycle-core-api.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0025"]},{"id":"PLN-0056","file":"PLN-0056-firmware-lifecycle-delegation.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0025"]},{"id":"PLN-0057","file":"PLN-0057-lifecycle-tests-and-invariants.md","status":"open","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0025"]}],"lessons":[]}
|
{"type":"discussion","id":"DSC-0032","status":"in_progress","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[{"id":"AGD-0032","file":"AGD-0032-system-os-lifecycle-process-task-contract.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-15"}],"decisions":[{"id":"DEC-0025","file":"DEC-0025-systemos-lifecycle-authority-for-tasks-and-processes.md","status":"accepted","created_at":"2026-05-15","updated_at":"2026-05-15","ref_agenda":"AGD-0032"}],"plans":[{"id":"PLN-0055","file":"PLN-0055-systemos-lifecycle-core-api.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0025"]},{"id":"PLN-0056","file":"PLN-0056-firmware-lifecycle-delegation.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0025"]},{"id":"PLN-0057","file":"PLN-0057-lifecycle-tests-and-invariants.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15","ref_decisions":["DEC-0025"]}],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0033","status":"in_progress","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-14","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[{"id":"AGD-0033","file":"AGD-0033-system-os-service-ownership-and-module-layout.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14"}],"decisions":[{"id":"DEC-0024","file":"DEC-0024-systemos-service-ownership-and-module-layout.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14","ref_agenda":"AGD-0033"}],"plans":[{"id":"PLN-0051","file":"PLN-0051-move-vm-runtime-into-services.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0052","file":"PLN-0052-promote-window-manager-to-systemos-service.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0053","file":"PLN-0053-move-logging-ownership-to-systemos.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0054","file":"PLN-0054-move-fs-and-memcard-ownership-to-systemos.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]}],"lessons":[]}
|
{"type":"discussion","id":"DSC-0033","status":"in_progress","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-14","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[{"id":"AGD-0033","file":"AGD-0033-system-os-service-ownership-and-module-layout.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14"}],"decisions":[{"id":"DEC-0024","file":"DEC-0024-systemos-service-ownership-and-module-layout.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14","ref_agenda":"AGD-0033"}],"plans":[{"id":"PLN-0051","file":"PLN-0051-move-vm-runtime-into-services.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0052","file":"PLN-0052-promote-window-manager-to-systemos-service.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0053","file":"PLN-0053-move-logging-ownership-to-systemos.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0054","file":"PLN-0054-move-fs-and-memcard-ownership-to-systemos.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]}],"lessons":[]}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
id: PLN-0057
|
id: PLN-0057
|
||||||
ticket: system-os-lifecycle-process-task-contract
|
ticket: system-os-lifecycle-process-task-contract
|
||||||
title: Lifecycle Tests and Invariants
|
title: Lifecycle Tests and Invariants
|
||||||
status: open
|
status: done
|
||||||
created: 2026-05-15
|
created: 2026-05-15
|
||||||
ref_decisions: [DEC-0025]
|
ref_decisions: [DEC-0025]
|
||||||
tags: [runtime, os, lifecycle, process, task, shell, firmware]
|
tags: [runtime, os, lifecycle, process, task, shell, firmware]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user