mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-19 04:58:09 +00:00
Fix state management in the scheduler (#337)
This commit is contained in:
@ -86,21 +86,17 @@ impl Agent {
|
|||||||
|
|
||||||
async fn update(&mut self) -> Result<bool> {
|
async fn update(&mut self) -> Result<bool> {
|
||||||
let last = self.scheduler.take().ok_or_else(scheduler_error)?;
|
let last = self.scheduler.take().ok_or_else(scheduler_error)?;
|
||||||
|
let previous_state = NodeState::from(&last);
|
||||||
let next = match last {
|
let (next, done) = match last {
|
||||||
Scheduler::Free(s) => self.free(s).await?,
|
Scheduler::Free(s) => (self.free(s).await?, false),
|
||||||
Scheduler::SettingUp(s) => self.setting_up(s).await?,
|
Scheduler::SettingUp(s) => (self.setting_up(s).await?, false),
|
||||||
Scheduler::PendingReboot(s) => self.pending_reboot(s).await?,
|
Scheduler::PendingReboot(s) => (self.pending_reboot(s).await?, false),
|
||||||
Scheduler::Ready(s) => self.ready(s).await?,
|
Scheduler::Ready(s) => (self.ready(s).await?, false),
|
||||||
Scheduler::Busy(s) => self.busy(s).await?,
|
Scheduler::Busy(s) => (self.busy(s).await?, false),
|
||||||
Scheduler::Done(s) => self.done(s).await?,
|
Scheduler::Done(s) => (self.done(s).await?, true),
|
||||||
};
|
};
|
||||||
|
self.previous_state = previous_state;
|
||||||
self.previous_state = NodeState::from(&next);
|
|
||||||
let done = matches!(next, Scheduler::Done(..));
|
|
||||||
|
|
||||||
self.scheduler = Some(next);
|
self.scheduler = Some(next);
|
||||||
|
|
||||||
Ok(done)
|
Ok(done)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ use crate::setup::double::*;
|
|||||||
use crate::work::double::*;
|
use crate::work::double::*;
|
||||||
use crate::work::*;
|
use crate::work::*;
|
||||||
use crate::worker::double::*;
|
use crate::worker::double::*;
|
||||||
|
use crate::worker::WorkerEvent;
|
||||||
|
use onefuzz::process::ExitStatus;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -119,3 +121,101 @@ async fn test_update_free_has_work() {
|
|||||||
let double: &WorkQueueDouble = agent.work_queue.downcast_ref().unwrap();
|
let double: &WorkQueueDouble = agent.work_queue.downcast_ref().unwrap();
|
||||||
assert_eq!(double.claimed, &[Fixture.receipt()]);
|
assert_eq!(double.claimed, &[Fixture.receipt()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_emitted_state() {
|
||||||
|
let mut agent = Agent {
|
||||||
|
worker_runner: Box::new(WorkerRunnerDouble {
|
||||||
|
child: ChildDouble {
|
||||||
|
exit_status: Some(ExitStatus {
|
||||||
|
code: Some(0),
|
||||||
|
signal: None,
|
||||||
|
success: true,
|
||||||
|
}),
|
||||||
|
..ChildDouble::default()
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
..Fixture.agent()
|
||||||
|
};
|
||||||
|
|
||||||
|
agent
|
||||||
|
.work_queue
|
||||||
|
.downcast_mut::<WorkQueueDouble>()
|
||||||
|
.unwrap()
|
||||||
|
.available
|
||||||
|
.push(Fixture.message());
|
||||||
|
|
||||||
|
for _i in 0..10 {
|
||||||
|
if agent.update().await.unwrap() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let expected_events: Vec<NodeEvent> = vec![
|
||||||
|
NodeEvent::StateUpdate(StateUpdateEvent::Free),
|
||||||
|
NodeEvent::StateUpdate(StateUpdateEvent::SettingUp {
|
||||||
|
tasks: vec![Fixture.task_id()],
|
||||||
|
}),
|
||||||
|
NodeEvent::StateUpdate(StateUpdateEvent::Ready),
|
||||||
|
NodeEvent::StateUpdate(StateUpdateEvent::Busy),
|
||||||
|
NodeEvent::WorkerEvent(WorkerEvent::Running {
|
||||||
|
task_id: Fixture.task_id(),
|
||||||
|
}),
|
||||||
|
NodeEvent::WorkerEvent(WorkerEvent::Done {
|
||||||
|
task_id: Fixture.task_id(),
|
||||||
|
exit_status: ExitStatus {
|
||||||
|
code: Some(0),
|
||||||
|
signal: None,
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
stderr: String::default(),
|
||||||
|
stdout: String::default(),
|
||||||
|
}),
|
||||||
|
NodeEvent::StateUpdate(StateUpdateEvent::Done {
|
||||||
|
error: None,
|
||||||
|
script_output: None,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
let coordinator: &CoordinatorDouble = agent.coordinator.downcast_ref().unwrap();
|
||||||
|
let events = &coordinator.events;
|
||||||
|
assert_eq!(events, &expected_events);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_emitted_state_failed_setup() {
|
||||||
|
let error_message = "Failed setup";
|
||||||
|
let mut agent = Agent {
|
||||||
|
setup_runner: Box::new(SetupRunnerDouble {
|
||||||
|
error_message: Some(String::from(error_message)),
|
||||||
|
..SetupRunnerDouble::default()
|
||||||
|
}),
|
||||||
|
..Fixture.agent()
|
||||||
|
};
|
||||||
|
|
||||||
|
agent
|
||||||
|
.work_queue
|
||||||
|
.downcast_mut::<WorkQueueDouble>()
|
||||||
|
.unwrap()
|
||||||
|
.available
|
||||||
|
.push(Fixture.message());
|
||||||
|
|
||||||
|
for _i in 0..10 {
|
||||||
|
if agent.update().await.unwrap() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let expected_events: Vec<NodeEvent> = vec![
|
||||||
|
NodeEvent::StateUpdate(StateUpdateEvent::Free),
|
||||||
|
NodeEvent::StateUpdate(StateUpdateEvent::SettingUp {
|
||||||
|
tasks: vec![Fixture.task_id()],
|
||||||
|
}),
|
||||||
|
NodeEvent::StateUpdate(StateUpdateEvent::Done {
|
||||||
|
error: Some(String::from(error_message)),
|
||||||
|
script_output: None,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
let coordinator: &CoordinatorDouble = agent.coordinator.downcast_ref().unwrap();
|
||||||
|
let events = &coordinator.events;
|
||||||
|
assert_eq!(events, &expected_events);
|
||||||
|
}
|
||||||
|
@ -7,12 +7,16 @@ use super::*;
|
|||||||
pub struct SetupRunnerDouble {
|
pub struct SetupRunnerDouble {
|
||||||
pub ran: Vec<WorkSet>,
|
pub ran: Vec<WorkSet>,
|
||||||
pub script: SetupOutput,
|
pub script: SetupOutput,
|
||||||
|
pub error_message: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl ISetupRunner for SetupRunnerDouble {
|
impl ISetupRunner for SetupRunnerDouble {
|
||||||
async fn run(&mut self, work_set: &WorkSet) -> Result<SetupOutput> {
|
async fn run(&mut self, work_set: &WorkSet) -> Result<SetupOutput> {
|
||||||
self.ran.push(work_set.clone());
|
self.ran.push(work_set.clone());
|
||||||
|
if let Some(error) = self.error_message.clone() {
|
||||||
|
anyhow::bail!(error);
|
||||||
|
}
|
||||||
Ok(self.script.clone())
|
Ok(self.script.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
use crate::work::WorkUnit;
|
use crate::work::WorkUnit;
|
||||||
|
use crate::worker::double::ChildDouble;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -58,36 +59,6 @@ impl IWorkerRunner for RunnerDouble {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
|
||||||
pub struct ChildDouble {
|
|
||||||
id: u64,
|
|
||||||
exit_status: Option<ExitStatus>,
|
|
||||||
stderr: String,
|
|
||||||
stdout: String,
|
|
||||||
killed: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IWorkerChild for ChildDouble {
|
|
||||||
fn try_wait(&mut self) -> Result<Option<Output>> {
|
|
||||||
let output = if let Some(exit_status) = self.exit_status {
|
|
||||||
Some(Output {
|
|
||||||
exit_status,
|
|
||||||
stderr: self.stderr.clone(),
|
|
||||||
stdout: self.stdout.clone(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn kill(&mut self) -> Result<()> {
|
|
||||||
self.killed = true;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_ready_run() {
|
async fn test_ready_run() {
|
||||||
let mut runner = Fixture.runner(Fixture.child_running());
|
let mut runner = Fixture.runner(Fixture.child_running());
|
||||||
|
@ -190,6 +190,13 @@ def on_worker_event_running(
|
|||||||
# (as happens in 1.0.0 agents)
|
# (as happens in 1.0.0 agents)
|
||||||
task.on_start()
|
task.on_start()
|
||||||
|
|
||||||
|
task_event = TaskEvent(
|
||||||
|
task_id=task.task_id,
|
||||||
|
machine_id=machine_id,
|
||||||
|
event_data=WorkerEvent(running=event),
|
||||||
|
)
|
||||||
|
task_event.save()
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user