fix: single load in remove, use dataclasses.replace in config_cmd, add remove-running test

This commit is contained in:
2026-05-21 12:45:08 +08:00
parent 9e9ba66f1f
commit 2bb08e92c7
2 changed files with 19 additions and 10 deletions

View File

@@ -1,4 +1,5 @@
import click import click
from dataclasses import replace
from autossh_mgr.config import ( from autossh_mgr.config import (
TunnelConfig, get_config_dir, ensure_dirs, TunnelConfig, get_config_dir, ensure_dirs,
load_tunnels, save_tunnels, get_tunnel, load_tunnels, save_tunnels, get_tunnel,
@@ -98,14 +99,15 @@ def add(
def remove(ctx, name): def remove(ctx, name):
"""Remove a tunnel configuration.""" """Remove a tunnel configuration."""
config_dir = ctx.obj["config_dir"] config_dir = ctx.obj["config_dir"]
get_tunnel(config_dir, name) # raises if not found tunnels = load_tunnels(config_dir)
if not any(t.name == name for t in tunnels):
raise click.ClickException(f"No tunnel named '{name}'")
status = get_status(config_dir, name) status = get_status(config_dir, name)
if status.state == "running": if status.state == "running":
raise click.ClickException(f"Stop '{name}' before removing it") raise click.ClickException(f"Stop '{name}' before removing it")
if not click.confirm(f"Remove tunnel '{name}'?"): if not click.confirm(f"Remove tunnel '{name}'?"):
return return
tunnels = [t for t in load_tunnels(config_dir) if t.name != name] save_tunnels(config_dir, [t for t in tunnels if t.name != name])
save_tunnels(config_dir, tunnels)
click.echo(f"Removed tunnel '{name}'") click.echo(f"Removed tunnel '{name}'")
@@ -149,13 +151,8 @@ def config_cmd(ctx, name, key, value):
f"Invalid value for '{key}': expected {_FIELD_TYPES[key].__name__}" f"Invalid value for '{key}': expected {_FIELD_TYPES[key].__name__}"
) )
tunnels = load_tunnels(config_dir) tunnels = load_tunnels(config_dir)
found = False if not any(t.name == name for t in tunnels):
for t in tunnels:
if t.name == name:
setattr(t, key, typed_value)
found = True
break
if not found:
raise click.ClickException(f"No tunnel named '{name}'") raise click.ClickException(f"No tunnel named '{name}'")
tunnels = [replace(t, **{key: typed_value}) if t.name == name else t for t in tunnels]
save_tunnels(config_dir, tunnels) save_tunnels(config_dir, tunnels)
click.echo(f"Updated {name}.{key} = {typed_value}") click.echo(f"Updated {name}.{key} = {typed_value}")

View File

@@ -1,7 +1,10 @@
import os
import pytest import pytest
from datetime import datetime, timezone
from click.testing import CliRunner from click.testing import CliRunner
from autossh_mgr.cli import cli from autossh_mgr.cli import cli
from autossh_mgr.config import load_tunnels, save_tunnels from autossh_mgr.config import load_tunnels, save_tunnels
from autossh_mgr.process import write_pid_file
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@@ -126,3 +129,12 @@ def test_config_invalid_type(runner, config_dir, sample_tunnel):
save_tunnels(config_dir, [sample_tunnel]) save_tunnels(config_dir, [sample_tunnel])
result = runner.invoke(cli, ["config", "web-service", "port", "notanumber"]) result = runner.invoke(cli, ["config", "web-service", "port", "notanumber"])
assert result.exit_code != 0 assert result.exit_code != 0
def test_remove_running_tunnel_fails(runner, config_dir, sample_tunnel):
save_tunnels(config_dir, [sample_tunnel])
write_pid_file(config_dir, "web-service", os.getpid(), datetime.now(timezone.utc))
result = runner.invoke(cli, ["remove", "web-service"], input="y\n")
assert result.exit_code != 0
assert "Stop" in result.output
assert len(load_tunnels(config_dir)) == 1