mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-09-18 06:34:54 +08:00
feat(rpc): 补齐 issue #1 资源后端接口
This commit is contained in:
@@ -641,13 +641,18 @@ struct DaemonRpcAck {
|
||||
// 规范方法名采用国际惯例的 `<namespace>.<action>`。`bat.*` 保留为向后兼容别名。
|
||||
const RPC_METHOD_STATUS: &str = "daemon.status";
|
||||
const RPC_METHOD_STOP: &str = "daemon.stop";
|
||||
const RPC_METHOD_RESTART: &str = "daemon.restart";
|
||||
const RPC_METHOD_RELOAD: &str = "daemon.reload";
|
||||
const RPC_METHOD_REFRESH: &str = "daemon.refresh";
|
||||
const RPC_METHOD_LOGS: &str = "daemon.logs";
|
||||
const RPC_METHOD_DOCTOR: &str = "daemon.doctor";
|
||||
const RPC_METHOD_CLEAN_STABLE: &str = "daemon.clean-stable";
|
||||
const RPC_METHOD_RESOURCE_STATE: &str = "resource.state";
|
||||
const RPC_METHOD_RESOURCE_SYNC: &str = "resource.sync";
|
||||
const RPC_METHOD_RESOURCE_VERIFY: &str = "resource.verify";
|
||||
const RPC_METHOD_RESOURCE_REPAIR: &str = "resource.repair";
|
||||
const RPC_METHOD_RESOURCE_MANIFEST: &str = "resource.manifest";
|
||||
const RPC_METHOD_RESOURCE_LIST: &str = "resource.list";
|
||||
const RPC_METHOD_CATALOG_STATUS: &str = "catalog.status";
|
||||
const RPC_METHOD_CATALOG_VERSIONS: &str = "catalog.versions";
|
||||
const RPC_METHOD_CATALOG_DIFF: &str = "catalog.diff";
|
||||
@@ -667,6 +672,7 @@ const MAX_TASK_LOG_LINES: usize = 200;
|
||||
enum TaskKind {
|
||||
Sync,
|
||||
Verify,
|
||||
Repair,
|
||||
/// catalog 更新检查:只做发现 + 拉取计划(dry-run),不下载不审计。
|
||||
Refresh,
|
||||
}
|
||||
@@ -676,6 +682,7 @@ impl TaskKind {
|
||||
match self {
|
||||
Self::Sync => RPC_METHOD_RESOURCE_SYNC,
|
||||
Self::Verify => RPC_METHOD_RESOURCE_VERIFY,
|
||||
Self::Repair => RPC_METHOD_RESOURCE_REPAIR,
|
||||
Self::Refresh => RPC_METHOD_CATALOG_REFRESH,
|
||||
}
|
||||
}
|
||||
@@ -695,6 +702,12 @@ impl TaskKind {
|
||||
config.repair = false;
|
||||
config.force = false;
|
||||
}
|
||||
Self::Repair => {
|
||||
config.dry_run = false;
|
||||
config.audit_local = true;
|
||||
config.repair = true;
|
||||
config.force = false;
|
||||
}
|
||||
Self::Refresh => {
|
||||
config.dry_run = true;
|
||||
config.plan = true;
|
||||
@@ -800,6 +813,7 @@ fn task_kind_static(kind: &str) -> Option<&'static str> {
|
||||
match kind {
|
||||
RPC_METHOD_RESOURCE_SYNC => Some(RPC_METHOD_RESOURCE_SYNC),
|
||||
RPC_METHOD_RESOURCE_VERIFY => Some(RPC_METHOD_RESOURCE_VERIFY),
|
||||
RPC_METHOD_RESOURCE_REPAIR => Some(RPC_METHOD_RESOURCE_REPAIR),
|
||||
RPC_METHOD_CATALOG_REFRESH => Some(RPC_METHOD_CATALOG_REFRESH),
|
||||
_ => None,
|
||||
}
|
||||
@@ -1233,21 +1247,28 @@ fn canonical_rpc_method(method: &str) -> &str {
|
||||
match method {
|
||||
"bat.status" => RPC_METHOD_STATUS,
|
||||
"bat.stop" => RPC_METHOD_STOP,
|
||||
"bat.restart" => RPC_METHOD_RESTART,
|
||||
"bat.reload" => RPC_METHOD_RELOAD,
|
||||
"bat.refresh" => RPC_METHOD_REFRESH,
|
||||
"bat.logs" => RPC_METHOD_LOGS,
|
||||
"bat.doctor" => RPC_METHOD_DOCTOR,
|
||||
"bat.clean-stable" => RPC_METHOD_CLEAN_STABLE,
|
||||
RPC_METHOD_RESOURCE_LIST => RPC_METHOD_RESOURCE_MANIFEST,
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
/// 判断方法是否属于已规划但尚未实现的命名空间/动作(返回 not_implemented 而非 unknown)。
|
||||
fn is_pending_rpc_method(method: &str) -> bool {
|
||||
// task.create:任务统一由 resource.sync / resource.verify / catalog.refresh
|
||||
// task.create:任务统一由 resource.sync / resource.verify / resource.repair / catalog.refresh
|
||||
// 等语义方法创建,通用创建接口暂不开放。
|
||||
// resource.repair:引擎尚无独立修复模式(sync 自带审计+重下)。
|
||||
// daemon.restart / daemon.clean-stable:CLI 侧按进程生命周期处理;
|
||||
// live RPC 内不做自重启或在线清理。
|
||||
// patch.* / unityfs.*:被 bat-patch / bat-assetbundle 引擎阻塞。
|
||||
matches!(method, "task.create" | "resource.repair")
|
||||
|| method.starts_with("patch.")
|
||||
matches!(
|
||||
method,
|
||||
"task.create" | RPC_METHOD_RESTART | RPC_METHOD_CLEAN_STABLE
|
||||
) || method.starts_with("patch.")
|
||||
|| method.starts_with("unityfs.")
|
||||
}
|
||||
|
||||
@@ -1831,6 +1852,12 @@ fn dispatch_rpc_method(
|
||||
.and_then(|report| serde_json::to_value(report).map_err(anyhow::Error::from)),
|
||||
)
|
||||
}
|
||||
RPC_METHOD_DOCTOR => rpc_envelope_from_result(
|
||||
request_id,
|
||||
"daemon.doctor",
|
||||
build_doctor_report(state_dir, &tasks.base_config)
|
||||
.and_then(|report| serde_json::to_value(report).map_err(anyhow::Error::from)),
|
||||
),
|
||||
RPC_METHOD_STOP => {
|
||||
daemon_control_mark_stop_requested(control);
|
||||
let _ = update_daemon_state_only(state_dir, "stopping");
|
||||
@@ -1879,6 +1906,9 @@ fn dispatch_rpc_method(
|
||||
RPC_METHOD_RESOURCE_VERIFY => {
|
||||
enqueue_task_envelope(tasks, TaskKind::Verify, false, request_id)
|
||||
}
|
||||
RPC_METHOD_RESOURCE_REPAIR => {
|
||||
enqueue_task_envelope(tasks, TaskKind::Repair, false, request_id)
|
||||
}
|
||||
RPC_METHOD_RESOURCE_MANIFEST => {
|
||||
let (offset, limit) = match rpc_page_params(request.params.as_ref()) {
|
||||
Ok(page) => page,
|
||||
@@ -3006,19 +3036,27 @@ struct CommandReport<T> {
|
||||
}
|
||||
|
||||
fn run_sync_command(options: &CliOptions, command_name: &'static str) -> anyhow::Result<()> {
|
||||
if refresh_should_use_daemon_rpc(options, command_name)
|
||||
&& daemon_rpc_available(&options.state_dir)
|
||||
if let Some(rpc_method) = sync_command_rpc_method(options, command_name)
|
||||
.filter(|_| daemon_rpc_available(&options.state_dir))
|
||||
{
|
||||
let _control_lock = DaemonControlLock::acquire(&options.state_dir)?;
|
||||
let report = daemon_rpc_call(
|
||||
&options.state_dir,
|
||||
RPC_METHOD_REFRESH,
|
||||
Some(serde_json::json!({ "force": options.config.force })),
|
||||
)?;
|
||||
let params = if rpc_method == RPC_METHOD_REFRESH {
|
||||
Some(serde_json::json!({ "force": options.config.force }))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let report = daemon_rpc_call(&options.state_dir, rpc_method, params)?;
|
||||
print_json_value(options.output_format, &report)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
run_sync_command_foreground(options, command_name)
|
||||
}
|
||||
|
||||
fn run_sync_command_foreground(
|
||||
options: &CliOptions,
|
||||
command_name: &'static str,
|
||||
) -> anyhow::Result<()> {
|
||||
assert_no_live_daemon_output_conflict(options, command_name)?;
|
||||
let mut config = options.config.clone();
|
||||
if command_name == "repair" {
|
||||
@@ -3044,13 +3082,9 @@ fn run_sync_command(options: &CliOptions, command_name: &'static str) -> anyhow:
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn refresh_should_use_daemon_rpc(options: &CliOptions, command_name: &str) -> bool {
|
||||
if command_name != "refresh" {
|
||||
return false;
|
||||
}
|
||||
fn sync_command_rpc_method(options: &CliOptions, command_name: &str) -> Option<&'static str> {
|
||||
let defaults = OfficialUpdateConfig::default();
|
||||
options.command == CliCommand::Refresh
|
||||
&& !options.watch
|
||||
let default_daemon_shape = !options.watch
|
||||
&& !options.daemon
|
||||
&& !options.daemon_child
|
||||
&& !options.output_explicit
|
||||
@@ -3068,7 +3102,19 @@ fn refresh_should_use_daemon_rpc(options: &CliOptions, command_name: &str) -> bo
|
||||
&& !options.config.dry_run
|
||||
&& !options.config.plan
|
||||
&& options.config.audit_local == defaults.audit_local
|
||||
&& options.config.repair == defaults.repair
|
||||
&& options.config.repair == defaults.repair;
|
||||
if !default_daemon_shape {
|
||||
return None;
|
||||
}
|
||||
match (options.command, command_name) {
|
||||
(CliCommand::Refresh, "refresh") => Some(RPC_METHOD_REFRESH),
|
||||
(CliCommand::Repair, "repair") if !options.config.force => Some(RPC_METHOD_RESOURCE_REPAIR),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn refresh_should_use_daemon_rpc(options: &CliOptions, command_name: &str) -> bool {
|
||||
sync_command_rpc_method(options, command_name) == Some(RPC_METHOD_REFRESH)
|
||||
}
|
||||
|
||||
fn print_report<T>(format: OutputFormat, report: &T) -> anyhow::Result<()>
|
||||
@@ -3806,30 +3852,29 @@ struct DoctorReport {
|
||||
checks: Vec<DoctorCheck>,
|
||||
}
|
||||
|
||||
fn run_doctor_command(options: &CliOptions) -> anyhow::Result<bool> {
|
||||
fn build_doctor_report(
|
||||
state_dir: &Path,
|
||||
config: &OfficialUpdateConfig,
|
||||
) -> anyhow::Result<DoctorReport> {
|
||||
let mut checks = vec![
|
||||
path_check("state_dir", &options.state_dir, "后台状态目录可用"),
|
||||
path_check(
|
||||
"output_root",
|
||||
&options.config.output_root,
|
||||
"资源输出目录可用",
|
||||
),
|
||||
path_check("state_dir", state_dir, "后台状态目录可用"),
|
||||
path_check("output_root", &config.output_root, "资源输出目录可用"),
|
||||
safety_check(
|
||||
"output_root_safety",
|
||||
validate_output_root(&options.config.output_root),
|
||||
validate_output_root(&config.output_root),
|
||||
"资源输出目录安全边界通过",
|
||||
),
|
||||
safety_check(
|
||||
"state_dir_safety",
|
||||
validate_runtime_state_dir(&options.state_dir),
|
||||
validate_runtime_state_dir(state_dir),
|
||||
"后台状态目录安全边界通过",
|
||||
),
|
||||
command_check("curl", &options.config.curl_command),
|
||||
proxy_check(&options.config.curl_proxy),
|
||||
command_check("unzip", &options.config.unzip_command),
|
||||
command_check("curl", &config.curl_command),
|
||||
proxy_check(&config.curl_proxy),
|
||||
command_check("unzip", &config.unzip_command),
|
||||
];
|
||||
|
||||
let pid_path = daemon_pid_path(&options.state_dir);
|
||||
let pid_path = daemon_pid_path(state_dir);
|
||||
let daemon_running = read_pid_file(&pid_path)
|
||||
.ok()
|
||||
.flatten()
|
||||
@@ -3857,9 +3902,9 @@ fn run_doctor_command(options: &CliOptions) -> anyhow::Result<bool> {
|
||||
}),
|
||||
}
|
||||
|
||||
let socket_path = daemon_socket_path(&options.state_dir);
|
||||
let socket_path = daemon_socket_path(state_dir);
|
||||
let socket_exists = daemon_socket_path_exists(&socket_path).unwrap_or(false);
|
||||
let socket_available = daemon_rpc_available(&options.state_dir);
|
||||
let socket_available = daemon_rpc_available(state_dir);
|
||||
checks.push(DoctorCheck {
|
||||
name: "daemon_rpc",
|
||||
ok: if daemon_running {
|
||||
@@ -3884,7 +3929,7 @@ fn run_doctor_command(options: &CliOptions) -> anyhow::Result<bool> {
|
||||
},
|
||||
});
|
||||
|
||||
let lock_path = options.config.lock_path();
|
||||
let lock_path = config.lock_path();
|
||||
checks.push(match classify_pid_lock_file(&lock_path)? {
|
||||
PidLockState::Missing => DoctorCheck {
|
||||
name: "resource_lock",
|
||||
@@ -3917,7 +3962,7 @@ fn run_doctor_command(options: &CliOptions) -> anyhow::Result<bool> {
|
||||
},
|
||||
});
|
||||
|
||||
let control_lock_path = daemon_control_lock_path(&options.state_dir);
|
||||
let control_lock_path = daemon_control_lock_path(state_dir);
|
||||
checks.push(match classify_pid_lock_file(&control_lock_path)? {
|
||||
PidLockState::Missing => DoctorCheck {
|
||||
name: "daemon_control_lock",
|
||||
@@ -3950,7 +3995,7 @@ fn run_doctor_command(options: &CliOptions) -> anyhow::Result<bool> {
|
||||
},
|
||||
});
|
||||
|
||||
let status_path = daemon_status_path(&options.state_dir);
|
||||
let status_path = daemon_status_path(state_dir);
|
||||
// ok 与 message 从同一次解析结果派生,避免“ok=false 却提示可解析”的自相矛盾。
|
||||
let daemon_status_result = read_daemon_status_file(&status_path);
|
||||
checks.push(DoctorCheck {
|
||||
@@ -3964,7 +4009,7 @@ fn run_doctor_command(options: &CliOptions) -> anyhow::Result<bool> {
|
||||
});
|
||||
|
||||
let healthy = checks.iter().all(|check| check.ok);
|
||||
let report = DoctorReport {
|
||||
Ok(DoctorReport {
|
||||
command: "doctor",
|
||||
status: if healthy { "ok" } else { "issues_found" },
|
||||
message: if healthy {
|
||||
@@ -3974,7 +4019,12 @@ fn run_doctor_command(options: &CliOptions) -> anyhow::Result<bool> {
|
||||
},
|
||||
healthy,
|
||||
checks,
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
fn run_doctor_command(options: &CliOptions) -> anyhow::Result<bool> {
|
||||
let report = build_doctor_report(&options.state_dir, &options.config)?;
|
||||
let healthy = report.healthy;
|
||||
print_report(options.output_format, &report)?;
|
||||
Ok(healthy)
|
||||
}
|
||||
@@ -5919,11 +5969,13 @@ mod tests {
|
||||
"404",
|
||||
));
|
||||
});
|
||||
let repair_id = registry.create(TaskKind::Repair);
|
||||
registry.update(&repair_id, |record| record.status = "succeeded");
|
||||
drop(registry);
|
||||
|
||||
// 重启:恢复历史;running 任务标记中断;错误码经持久化往返保留。
|
||||
let (registry, summary) = TaskRegistry::with_persistence(state_dir);
|
||||
assert!(summary.contains("恢复任务历史 3 条"), "{summary}");
|
||||
assert!(summary.contains("恢复任务历史 4 条"), "{summary}");
|
||||
assert!(summary.contains("标记中断 1 条"), "{summary}");
|
||||
let finished = registry.get(&finished_id).unwrap();
|
||||
assert_eq!(finished.status, "succeeded");
|
||||
@@ -5944,16 +5996,19 @@ mod tests {
|
||||
failed.error.as_ref().unwrap().code(),
|
||||
ErrorCode::HTTP_NOT_FOUND
|
||||
);
|
||||
let repair = registry.get(&repair_id).unwrap();
|
||||
assert_eq!(repair.kind, "resource.repair");
|
||||
assert_eq!(repair.status, "succeeded");
|
||||
|
||||
// seq 持久化:重启后(本测试内 pid 相同)新任务不与历史撞 ID。
|
||||
let new_id = registry.create(TaskKind::Sync);
|
||||
assert!(
|
||||
[&finished_id, &running_id, &failed_id]
|
||||
[&finished_id, &running_id, &failed_id, &repair_id]
|
||||
.iter()
|
||||
.all(|id| **id != new_id),
|
||||
"新任务 ID {new_id} 与历史撞号"
|
||||
);
|
||||
assert_eq!(registry.list().len(), 4);
|
||||
assert_eq!(registry.list().len(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -6368,8 +6423,13 @@ mod tests {
|
||||
#[test]
|
||||
fn canonical_rpc_method_resolves_aliases() {
|
||||
assert_eq!(canonical_rpc_method("bat.status"), RPC_METHOD_STATUS);
|
||||
assert_eq!(canonical_rpc_method("bat.doctor"), RPC_METHOD_DOCTOR);
|
||||
assert_eq!(canonical_rpc_method("bat.refresh"), RPC_METHOD_REFRESH);
|
||||
assert_eq!(canonical_rpc_method("daemon.status"), RPC_METHOD_STATUS);
|
||||
assert_eq!(
|
||||
canonical_rpc_method("resource.list"),
|
||||
RPC_METHOD_RESOURCE_MANIFEST
|
||||
);
|
||||
assert_eq!(canonical_rpc_method("resource.state"), "resource.state");
|
||||
assert_eq!(canonical_rpc_method("unknown.method"), "unknown.method");
|
||||
}
|
||||
@@ -6379,17 +6439,20 @@ mod tests {
|
||||
assert!(is_pending_rpc_method("patch.apply"));
|
||||
assert!(is_pending_rpc_method("unityfs.inspect"));
|
||||
assert!(is_pending_rpc_method("task.create"));
|
||||
assert!(is_pending_rpc_method("resource.repair"));
|
||||
// sync/verify、task.cancel/logs、catalog.* 与 resource.manifest 已实现,
|
||||
// 不再是 pending。
|
||||
assert!(is_pending_rpc_method("daemon.restart"));
|
||||
assert!(is_pending_rpc_method("daemon.clean-stable"));
|
||||
// sync/verify/repair、task.cancel/logs、catalog.* 与 resource.manifest 已实现。
|
||||
assert!(!is_pending_rpc_method("resource.sync"));
|
||||
assert!(!is_pending_rpc_method("resource.verify"));
|
||||
assert!(!is_pending_rpc_method("resource.repair"));
|
||||
assert!(!is_pending_rpc_method("resource.manifest"));
|
||||
assert!(!is_pending_rpc_method("resource.list"));
|
||||
assert!(!is_pending_rpc_method("catalog.status"));
|
||||
assert!(!is_pending_rpc_method("catalog.refresh"));
|
||||
assert!(!is_pending_rpc_method("task.cancel"));
|
||||
assert!(!is_pending_rpc_method("task.logs"));
|
||||
assert!(!is_pending_rpc_method("daemon.status"));
|
||||
assert!(!is_pending_rpc_method("daemon.doctor"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -6502,6 +6565,36 @@ mod tests {
|
||||
assert_eq!(value["error"]["code"], "BAT-ERR-700004");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dispatch_daemon_doctor_returns_report() {
|
||||
let temp = tempfile::TempDir::new().unwrap();
|
||||
let state_dir = temp.path().join("state");
|
||||
let output_root = temp.path().join("output");
|
||||
let mut base_config = OfficialUpdateConfig::default();
|
||||
base_config.output_root = output_root;
|
||||
let (queue, _rx) = mpsc::channel::<TaskJob>();
|
||||
let context = DaemonTaskContext {
|
||||
registry: TaskRegistry::new(),
|
||||
queue,
|
||||
base_config,
|
||||
};
|
||||
|
||||
let envelope = dispatch_rpc_method(
|
||||
&rpc_request("daemon.doctor", None),
|
||||
&state_dir,
|
||||
&new_daemon_control(),
|
||||
&context,
|
||||
"req-doctor-1".to_string(),
|
||||
);
|
||||
let value = serde_json::to_value(&envelope).unwrap();
|
||||
assert_eq!(value["ok"], true);
|
||||
assert_eq!(value["status"], "ok");
|
||||
assert_eq!(value["data"]["command"], "doctor");
|
||||
assert!(value["data"]["healthy"].is_boolean());
|
||||
let checks = value["data"]["checks"].as_array().unwrap();
|
||||
assert!(checks.iter().any(|check| check["name"] == "daemon_rpc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dispatch_resource_sync_enqueues_task() {
|
||||
let temp = tempfile::TempDir::new().unwrap();
|
||||
@@ -6554,6 +6647,48 @@ mod tests {
|
||||
assert_eq!(status_value["data"]["status"], "queued");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dispatch_resource_repair_enqueues_repair_task() {
|
||||
let temp = tempfile::TempDir::new().unwrap();
|
||||
let control = new_daemon_control();
|
||||
// 保留 rx 让 send 成功(不启动 worker,任务停留在 queued)。
|
||||
let (queue, rx) = mpsc::channel::<TaskJob>();
|
||||
let mut base_config = OfficialUpdateConfig::default();
|
||||
base_config.force = true;
|
||||
base_config.dry_run = true;
|
||||
base_config.audit_local = false;
|
||||
base_config.repair = false;
|
||||
let context = DaemonTaskContext {
|
||||
registry: TaskRegistry::new(),
|
||||
queue,
|
||||
base_config,
|
||||
};
|
||||
|
||||
let envelope = dispatch_rpc_method(
|
||||
&rpc_request("resource.repair", None),
|
||||
temp.path(),
|
||||
&control,
|
||||
&context,
|
||||
"req-repair-1".to_string(),
|
||||
);
|
||||
let value = serde_json::to_value(&envelope).unwrap();
|
||||
assert_eq!(value["ok"], true);
|
||||
assert_eq!(value["status"], "accepted");
|
||||
assert_eq!(value["data"]["kind"], "resource.repair");
|
||||
let task_id = value["data"]["task_id"].as_str().unwrap();
|
||||
let record = context.registry.get(task_id).unwrap();
|
||||
assert_eq!(record.kind, "resource.repair");
|
||||
assert_eq!(record.status, "queued");
|
||||
|
||||
// repair 任务强制开启本地审计+修复,但不会继承 force/dry-run。
|
||||
let job = rx.try_recv().unwrap();
|
||||
assert_eq!(job.id, task_id);
|
||||
assert!(!job.config.dry_run);
|
||||
assert!(job.config.audit_local);
|
||||
assert!(job.config.repair);
|
||||
assert!(!job.config.force);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn task_registry_create_update_and_prune() {
|
||||
let registry = TaskRegistry::new();
|
||||
@@ -7092,21 +7227,41 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refresh_rpc_selection_only_for_default_daemon_shape() {
|
||||
fn sync_command_rpc_selection_only_for_default_daemon_shape() {
|
||||
let options = parse(&["bat", "refresh"]).unwrap();
|
||||
assert!(refresh_should_use_daemon_rpc(&options, "refresh"));
|
||||
assert_eq!(
|
||||
sync_command_rpc_method(&options, "refresh"),
|
||||
Some(RPC_METHOD_REFRESH)
|
||||
);
|
||||
|
||||
let options = parse(&["bat", "refresh", "--force"]).unwrap();
|
||||
assert!(refresh_should_use_daemon_rpc(&options, "refresh"));
|
||||
assert_eq!(
|
||||
sync_command_rpc_method(&options, "refresh"),
|
||||
Some(RPC_METHOD_REFRESH)
|
||||
);
|
||||
|
||||
let options = parse(&["bat", "refresh", "--output", "/tmp/other"]).unwrap();
|
||||
assert!(!refresh_should_use_daemon_rpc(&options, "refresh"));
|
||||
assert_eq!(sync_command_rpc_method(&options, "refresh"), None);
|
||||
|
||||
let options = parse(&["bat", "refresh", "--server-info-file", "ProdNotice.json"]).unwrap();
|
||||
assert!(!refresh_should_use_daemon_rpc(&options, "refresh"));
|
||||
assert_eq!(sync_command_rpc_method(&options, "refresh"), None);
|
||||
|
||||
let options = parse(&["bat", "repair"]).unwrap();
|
||||
assert!(!refresh_should_use_daemon_rpc(&options, "repair"));
|
||||
assert_eq!(
|
||||
sync_command_rpc_method(&options, "repair"),
|
||||
Some(RPC_METHOD_RESOURCE_REPAIR)
|
||||
);
|
||||
|
||||
let options = parse(&["bat", "repair", "--output", "/tmp/other"]).unwrap();
|
||||
assert_eq!(sync_command_rpc_method(&options, "repair"), None);
|
||||
|
||||
let options = parse(&["bat", "repair", "--force"]).unwrap();
|
||||
assert_eq!(sync_command_rpc_method(&options, "repair"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -7591,17 +7746,34 @@ mod tests {
|
||||
let value = serde_json::to_value(&envelope).unwrap();
|
||||
assert_eq!(value["ok"], false);
|
||||
assert_eq!(value["error"]["code"], "BAT-ERR-700002");
|
||||
|
||||
let envelope = dispatch_rpc_method(
|
||||
&rpc_request(
|
||||
"resource.list",
|
||||
Some(serde_json::json!({ "offset": 2, "limit": 1 })),
|
||||
),
|
||||
&state_dir,
|
||||
&new_daemon_control(),
|
||||
&test_task_context(),
|
||||
"req-man-3".to_string(),
|
||||
);
|
||||
let value = serde_json::to_value(&envelope).unwrap();
|
||||
assert_eq!(value["ok"], true);
|
||||
assert_eq!(value["data"]["available"], true);
|
||||
let entries = value["data"]["entries"].as_array().unwrap();
|
||||
assert_eq!(entries.len(), 1);
|
||||
assert_eq!(entries[0]["destination"], "c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dispatch_resource_repair_reports_not_implemented() {
|
||||
fn dispatch_daemon_clean_stable_reports_not_implemented() {
|
||||
let temp = tempfile::TempDir::new().unwrap();
|
||||
let envelope = dispatch_rpc_method(
|
||||
&rpc_request("resource.repair", None),
|
||||
&rpc_request("daemon.clean-stable", None),
|
||||
temp.path(),
|
||||
&new_daemon_control(),
|
||||
&test_task_context(),
|
||||
"req-rep-1".to_string(),
|
||||
"req-clean-1".to_string(),
|
||||
);
|
||||
let value = serde_json::to_value(&envelope).unwrap();
|
||||
assert_eq!(value["ok"], false);
|
||||
|
||||
Reference in New Issue
Block a user