use shep_core::config::AppConfig;
use shep_core::protocol::{ProcessInfo, Response, SheepConfigView};
use shep_core::status::ProcStatus;
use crate::lookout::app::{App, Control, KeyPress, Msg, Sent};
use super::flock::with_selection;
pub fn sheep_config_view() -> SheepConfigView {
sheep_config_view_parking(vec!["kill_signal".to_string()])
}
pub(super) fn sheep_config_view_parking(pending: Vec<String>) -> SheepConfigView {
let mut config = AppConfig {
name: "web".to_string(),
script: "./srv".to_string(),
args: vec!["--port".to_string(), "8080".to_string()],
max_restarts: 32,
instances: 3,
..AppConfig::default()
};
config
.env
.insert("DB_HOST".to_string(), "db.internal".to_string());
config
.env
.insert("LOG_LEVEL".to_string(), "debug".to_string());
SheepConfigView::new(
config,
vec!["max_restarts".to_string(), "reuse_port".to_string()],
pending,
)
}
pub fn app_in_sheep_pane_with_env(env: &[(&str, &str)]) -> App {
let mut app = with_selection(
ProcessInfo::builder(9, "web", ProcStatus::Online)
.pid(Some(48_000))
.build(),
);
app.set_control_for_tests(Control::Allowed);
let mut config = AppConfig {
name: "web".to_string(),
..AppConfig::default()
};
for (key, value) in env {
config.env.insert((*key).to_string(), (*value).to_string());
}
open_config_pane(
&mut app,
SheepConfigView::new(config, Vec::new(), Vec::new()),
);
app
}
fn open_config_pane(app: &mut App, view: SheepConfigView) {
app.update(Msg::Key(KeyPress::Edit));
app.update(Msg::Replied {
sent: Sent::SheepConfig {
name: "web".to_string(),
},
result: Ok(Response::SheepConfig(Box::new(view))),
});
}
#[track_caller]
pub fn select_env_key(app: &mut App, key: &str) {
let pane = app.config_pane().expect("the pane is open");
let index = pane
.rows()
.iter()
.position(|row| match row {
crate::lookout::pane::PaneRow::Env(env_index) => {
pane.env_key_names().get(*env_index).map(String::as_str) == Some(key)
}
crate::lookout::pane::PaneRow::Field(_)
| crate::lookout::pane::PaneRow::Table(_)
| crate::lookout::pane::PaneRow::Entry(_)
| crate::lookout::pane::PaneRow::Choice { .. }
| crate::lookout::pane::PaneRow::Arm { .. }
| crate::lookout::pane::PaneRow::AddEnv => false,
})
.unwrap_or_else(|| panic!("no env key named {key}"));
app.update(Msg::Key(KeyPress::SelectFirst));
for _ in 0..index {
app.update(Msg::Key(KeyPress::SelectDown));
}
}
pub fn type_into_the_open_editor(app: &mut App, text: &str) {
app.update(Msg::Key(KeyPress::Confirm));
for character in text.chars() {
app.update(Msg::Key(KeyPress::TextChar(character)));
}
app.update(Msg::Key(KeyPress::TextApply));
}
pub fn app_in_sheep_pane_with_control() -> App {
let mut app = with_selection(
ProcessInfo::builder(9, "web", ProcStatus::Online)
.pid(Some(48_000))
.build(),
);
app.set_control_for_tests(Control::Allowed);
open_config_pane(&mut app, sheep_config_view());
app
}
pub fn app_in_sheep_pane_with_a_parked_field() -> App {
app_in_sheep_pane_with_control()
}
pub fn app_in_sheep_pane_with_two_parked_fields() -> App {
app_in_sheep_pane_parking(vec!["kill_signal".to_string(), "script".to_string()])
}
pub fn app_in_sheep_pane_with_nothing_parked() -> App {
app_in_sheep_pane_parking(Vec::new())
}
fn app_in_sheep_pane_parking(pending: Vec<String>) -> App {
let mut app = with_selection(
ProcessInfo::builder(9, "web", ProcStatus::Online)
.pid(Some(48_000))
.build(),
);
app.set_control_for_tests(Control::Allowed);
open_config_pane(&mut app, sheep_config_view_parking(pending));
app
}
pub fn app_in_sheep_pane() -> App {
let mut app = with_selection(
ProcessInfo::builder(9, "web", ProcStatus::Online)
.pid(Some(48_000))
.build(),
);
open_config_pane(&mut app, sheep_config_view());
app
}
pub fn app_in_sheep_pane_read_only() -> App {
let mut app = app_in_sheep_pane();
app.set_control_for_tests(Control::ReadOnly);
app
}
pub fn app_in_sheep_pane_on_a_stopped_sheep() -> App {
let mut app = with_selection(ProcessInfo::builder(9, "web", ProcStatus::Stopped).build());
app.set_control_for_tests(Control::Allowed);
open_config_pane(&mut app, sheep_config_view_parking(Vec::new()));
app
}
pub fn app_in_sheep_pane_on_a_draining_sheep() -> App {
let mut app = with_selection(ProcessInfo::builder(9, "web", ProcStatus::Stopping).build());
app.set_control_for_tests(Control::Allowed);
open_config_pane(&mut app, sheep_config_view_parking(Vec::new()));
app
}
pub fn file_edit(app: &mut App, key: &str, value: &str) {
app.set_control_for_tests(Control::Allowed);
select_field(app, key);
app.update(Msg::Key(KeyPress::Confirm));
for _ in 0..64 {
app.update(Msg::Key(KeyPress::TextBackspace));
}
for character in value.chars() {
app.update(Msg::Key(KeyPress::TextChar(character)));
}
app.update(Msg::Key(KeyPress::TextApply));
}
#[track_caller]
pub fn select_field(app: &mut App, key: &str) {
let pane = app.config_pane().expect("the pane is open");
let group = pane
.fields()
.by_key(key)
.unwrap_or_else(|| panic!("no field named {key}"))
.group
.clone();
if let Some(group) = group
&& let Some(position) = shep_core::config::GROUP_ORDER
.iter()
.position(|known| *known == group)
{
let digit = u8::try_from(position + 1).expect("nine groups fit a u8");
app.update(Msg::Key(KeyPress::Group(digit)));
}
while row_of(app, key).is_none() {
let pane = app.config_pane().expect("the pane is open");
let table = pane
.rows()
.iter()
.position(|row| match row {
crate::lookout::pane::PaneRow::Table(index) => {
pane.table_path(*index).is_some_and(|path| {
key.starts_with(&format!("{path}.")) && !pane.open_tables().contains(path)
})
}
crate::lookout::pane::PaneRow::Field(_)
| crate::lookout::pane::PaneRow::Entry(_)
| crate::lookout::pane::PaneRow::Choice { .. }
| crate::lookout::pane::PaneRow::Arm { .. }
| crate::lookout::pane::PaneRow::Env(_)
| crate::lookout::pane::PaneRow::AddEnv => false,
})
.unwrap_or_else(|| panic!("{key} is not in the active group's rows"));
walk_to_row(app, table);
app.update(Msg::Key(KeyPress::TabNext));
}
let index = row_of(app, key).expect("the loop above found the row");
walk_to_row(app, index);
}
fn row_of(app: &App, key: &str) -> Option<usize> {
let pane = app.config_pane().expect("the pane is open");
pane.rows().iter().position(|row| match row {
crate::lookout::pane::PaneRow::Field(field_index) => {
pane.fields().fields()[*field_index].key == key
}
crate::lookout::pane::PaneRow::Table(_)
| crate::lookout::pane::PaneRow::Entry(_)
| crate::lookout::pane::PaneRow::Choice { .. }
| crate::lookout::pane::PaneRow::Arm { .. }
| crate::lookout::pane::PaneRow::Env(_)
| crate::lookout::pane::PaneRow::AddEnv => false,
})
}
fn walk_to_row(app: &mut App, index: usize) {
app.update(Msg::Key(KeyPress::SelectFirst));
for _ in 0..index {
app.update(Msg::Key(KeyPress::SelectDown));
}
}
pub fn app_in_sheep_pane_with_two_edits() -> App {
let mut app = app_in_sheep_pane_with_nothing_parked();
for (key, typed) in [("cwd", "/srv/web"), ("max_memory", "40")] {
select_field(&mut app, key);
app.update(Msg::Key(KeyPress::Confirm));
for _ in 0..64 {
app.update(Msg::Key(KeyPress::TextBackspace));
}
for character in typed.chars() {
app.update(Msg::Key(KeyPress::TextChar(character)));
}
app.update(Msg::Key(KeyPress::TextApply));
}
assert_eq!(
app.config_pane().expect("the pane is open").edits().len(),
2,
"the fixture files two edits"
);
app
}
pub fn app_in_sheep_pane_with_one_edit() -> App {
let mut app = app_in_sheep_pane_with_nothing_parked();
file_edit(&mut app, "cwd", "/srv/web");
assert_eq!(
app.config_pane().expect("the pane is open").edits().len(),
1,
"the fixture files one edit"
);
app
}
pub fn app_with_plain_palette_in_sheep_pane() -> App {
app_in_sheep_pane()
}