From 4c882d907b93625df3f8a63e1b8f1e5498cf07d1 Mon Sep 17 00:00:00 2001 From: sagitchu Date: Sat, 2 May 2026 00:08:24 +0800 Subject: [PATCH] fix: preserve probe targets on legacy updates --- go-backend/internal/http/handler/mutations.go | 25 +++++++++++------ .../handler/tunnel_probe_target_api_test.go | 27 +++++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/go-backend/internal/http/handler/mutations.go b/go-backend/internal/http/handler/mutations.go index 632d260..5ac689e 100644 --- a/go-backend/internal/http/handler/mutations.go +++ b/go-backend/internal/http/handler/mutations.go @@ -886,19 +886,28 @@ func (h *Handler) tunnelUpdate(w http.ResponseWriter, r *http.Request) { } typeVal := asInt(req["type"], 1) ipPreference := asString(req["ipPreference"]) - probeTarget, probeTargetConfigured, err := parseTunnelProbeTargetFromRequest(req) - if err != nil { - response.WriteJSON(w, response.ErrDefault(err.Error())) - return - } + _, hasProbeTargetHost := req["probeTargetHost"] + _, hasProbeTargetPort := req["probeTargetPort"] + probeTargetFieldsPresent := hasProbeTargetHost || hasProbeTargetPort probeTargetHost := "" probeTargetPort := 0 - if probeTargetConfigured { - probeTargetHost = probeTarget.Host - probeTargetPort = probeTarget.Port + if probeTargetFieldsPresent { + probeTarget, probeTargetConfigured, err := parseTunnelProbeTargetFromRequest(req) + if err != nil { + response.WriteJSON(w, response.ErrDefault(err.Error())) + return + } + if probeTargetConfigured { + probeTargetHost = probeTarget.Host + probeTargetPort = probeTarget.Port + } } oldEntryNodeIDs, _ := h.tunnelEntryNodeIDs(id) oldTunnel, _ := h.getTunnelRecord(id) + if !probeTargetFieldsPresent && oldTunnel != nil { + probeTargetHost = oldTunnel.ProbeTargetHost + probeTargetPort = oldTunnel.ProbeTargetPort + } oldChainRows, _ := h.listChainNodesForTunnel(id) if oldTunnel != nil && oldTunnel.Type == 2 && typeVal != 2 { h.cleanupTunnelRuntime(id) diff --git a/go-backend/internal/http/handler/tunnel_probe_target_api_test.go b/go-backend/internal/http/handler/tunnel_probe_target_api_test.go index 3072006..01f4e8b 100644 --- a/go-backend/internal/http/handler/tunnel_probe_target_api_test.go +++ b/go-backend/internal/http/handler/tunnel_probe_target_api_test.go @@ -74,6 +74,33 @@ func TestTunnelUpdatePersistsDefaultProbeTargetAsEmpty(t *testing.T) { } } +func TestTunnelUpdateWithoutProbeTargetFieldsPreservesExistingTarget(t *testing.T) { + h := setupProbeTargetTunnelHandler(t) + seedProbeTargetTunnel(t, h, 79, "existing", "old.example.com", 9443) + body := bytes.NewReader([]byte(`{ + "id":79, + "name":"existing", + "type":1, + "flow":1, + "trafficRatio":1, + "status":1, + "inNodeId":[{"nodeId":10,"protocol":"tls"}] + }`)) + + res := httptest.NewRecorder() + h.tunnelUpdate(res, httptest.NewRequest(http.MethodPost, "/api/v1/tunnel/update", body)) + assertProbeTargetSuccess(t, res) + + items, err := h.repo.ListTunnels() + if err != nil { + t.Fatalf("list tunnels: %v", err) + } + item := findProbeTargetTunnelItem(t, items, 79) + if item["probeTargetHost"] != "old.example.com" || item["probeTargetPort"] != 9443 { + t.Fatalf("expected omitted probe target fields to preserve existing target, got %+v", item) + } +} + func TestTunnelCreateRejectsInvalidProbeTarget(t *testing.T) { h := setupProbeTargetTunnelHandler(t) body := bytes.NewReader([]byte(`{