diff --git a/go-backend/internal/http/handler/tunnel_quality_prober.go b/go-backend/internal/http/handler/tunnel_quality_prober.go index bdc5683..0e2188f 100644 --- a/go-backend/internal/http/handler/tunnel_quality_prober.go +++ b/go-backend/internal/http/handler/tunnel_quality_prober.go @@ -229,6 +229,9 @@ func (p *tunnelQualityProber) probeTunnel(tunnelID int64) { p.storeResult(snap) return } + probeTarget := effectiveTunnelProbeTargetValues(tunnel.ProbeTargetHost, tunnel.ProbeTargetPort) + snap.ProbeTargetHost = probeTarget.Host + snap.ProbeTargetPort = probeTarget.Port chainRows, err := h.listChainNodesForTunnel(tunnelID) if err != nil || len(chainRows) == 0 { @@ -245,20 +248,13 @@ func (p *tunnelQualityProber) probeTunnel(tunnelID int64) { pingTimeoutMS: tunnelQualityPingTimeoutMs, timeoutMessage: "探测超时", } - probeTarget := effectiveTunnelProbeTargetValues(tunnel.ProbeTargetHost, tunnel.ProbeTargetPort) - snap.ProbeTargetHost = probeTarget.Host - snap.ProbeTargetPort = probeTarget.Port p.probeBestExitOwners(tunnelID, inNodes, midNodesGrouped, outNodes, ipPreference, options, probeTarget) switch tunnel.Type { case 1: - // Port forwarding: exit/public edge → public probe target when available. - publicProbeNodes := inNodes - if len(outNodes) > 0 { - publicProbeNodes = outNodes - } - if len(publicProbeNodes) > 0 { - lat, loss, err := p.pingNode(publicProbeNodes[0].NodeID, probeTarget.Host, probeTarget.Port, options) + // Port forwarding: entry → public probe target only. + if len(inNodes) > 0 { + lat, loss, err := p.pingNode(inNodes[0].NodeID, probeTarget.Host, probeTarget.Port, options) if err == nil { snap.ExitToBingLatency = lat snap.ExitToBingLoss = loss @@ -370,13 +366,9 @@ func (p *tunnelQualityProber) probeTunnel(tunnelID int64) { snap.Success = probeOK default: - // Unknown type: use exit/public edge when available, otherwise entry. - publicProbeNodes := inNodes - if len(outNodes) > 0 { - publicProbeNodes = outNodes - } - if len(publicProbeNodes) > 0 { - lat, loss, err := p.pingNode(publicProbeNodes[0].NodeID, probeTarget.Host, probeTarget.Port, options) + // Unknown type: entry → public probe target. + if len(inNodes) > 0 { + lat, loss, err := p.pingNode(inNodes[0].NodeID, probeTarget.Host, probeTarget.Port, options) if err == nil { snap.ExitToBingLatency = lat snap.ExitToBingLoss = loss diff --git a/go-backend/internal/http/handler/tunnel_quality_prober_test.go b/go-backend/internal/http/handler/tunnel_quality_prober_test.go index 34f1e7b..0b93a29 100644 --- a/go-backend/internal/http/handler/tunnel_quality_prober_test.go +++ b/go-backend/internal/http/handler/tunnel_quality_prober_test.go @@ -31,8 +31,11 @@ func TestTunnelQualityProberUsesConfiguredProbeTarget(t *testing.T) { } p.probeTunnel(77) - if !slices.Contains(calls, "30|speed.example.com|8443") { - t.Fatalf("expected exit probe to configured target, calls=%+v", calls) + if !slices.Contains(calls, "10|speed.example.com|8443") { + t.Fatalf("expected type 1 public probe from entry to configured target, calls=%+v", calls) + } + if slices.Contains(calls, "30|speed.example.com|8443") { + t.Fatalf("did not expect type 1 public probe from exit node, calls=%+v", calls) } snaps := p.GetAll() if len(snaps) != 1 { @@ -42,3 +45,25 @@ func TestTunnelQualityProberUsesConfiguredProbeTarget(t *testing.T) { t.Fatalf("unexpected snapshot target metadata: %+v", snaps[0]) } } + +func TestTunnelQualityProberStoresProbeTargetWhenChainIncomplete(t *testing.T) { + h := setupProbeTargetTunnelHandler(t) + seedProbeTargetTunnel(t, h, 78, "quality-target-incomplete", "speed.example.com", 8443) + if err := h.repo.DB().Exec(`DELETE FROM chain_tunnel WHERE tunnel_id = ?`, 78).Error; err != nil { + t.Fatalf("delete chain rows: %v", err) + } + + p := newTunnelQualityProber(h) + p.probeTunnel(78) + + snaps := p.GetAll() + if len(snaps) != 1 { + t.Fatalf("expected one quality snapshot, got %+v", snaps) + } + if snaps[0].ErrorMessage == "" { + t.Fatalf("expected incomplete chain error, got %+v", snaps[0]) + } + if snaps[0].ProbeTargetHost != "speed.example.com" || snaps[0].ProbeTargetPort != 8443 { + t.Fatalf("unexpected snapshot target metadata: %+v", snaps[0]) + } +}