修复 Windows MCP 连接拒绝分类并补充 CI 回归 (#805)
This commit is contained in:
1 parent
189a4b95ac
commit
066ecaae7d
5 files changed
+66
-2
No files matched your search
@@ -81,6 +81,12 @@ jobs:
|
||||
if: runner.os == 'Windows'
|
||||
run: go test -run '^$' ./...
|
||||
|
||||
# These checks use in-memory errors and loopback test servers. Run
|
||||
# the native Winsock refusal case rather than only compiling it.
|
||||
- name: Windows MCP health
|
||||
if: runner.os == 'Windows'
|
||||
run: go test -v -count=1 -timeout 2m ./internal/library -run '^(TestNetHealth|TestCheckHTTP)$'
|
||||
|
||||
# Usage isolates USERPROFILE and the agent homes; execute its native
|
||||
# ChangeTime checks rather than only cross-compiling the Windows API.
|
||||
- name: Windows usage cache
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/yetone/magpie/internal/gateway"
|
||||
@@ -403,7 +402,7 @@ func netHealth(ctx context.Context, err error) ServerHealth {
|
||||
if ctx.Err() != nil || errors.Is(err, context.DeadlineExceeded) {
|
||||
return timedOut()
|
||||
}
|
||||
if errors.Is(err, syscall.ECONNREFUSED) {
|
||||
if errors.Is(err, connectionRefused) {
|
||||
return failed("refused", err.Error())
|
||||
}
|
||||
var ue *url.Error
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
//go:build !windows
|
||||
|
||||
package library
|
||||
|
||||
import "syscall"
|
||||
|
||||
const connectionRefused = syscall.ECONNREFUSED
|
||||
@@ -0,0 +1,45 @@
|
||||
package library
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNetHealth(t *testing.T) {
|
||||
wrapped := &url.Error{
|
||||
Op: "Post", URL: "http://127.0.0.1/mcp",
|
||||
Err: &net.OpError{Op: "dial", Net: "tcp", Err: os.NewSyscallError("connect", connectionRefused)},
|
||||
}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
err error
|
||||
why string
|
||||
}{
|
||||
{"native refusal", connectionRefused, "refused"},
|
||||
{"wrapped refusal", wrapped, "refused"},
|
||||
{"deadline", &url.Error{Op: "Post", Err: context.DeadlineExceeded}, "timeout"},
|
||||
{"dns", &url.Error{Op: "Post", Err: &net.DNSError{Name: "missing.invalid", IsNotFound: true}}, "unreachable"},
|
||||
{"other error", errors.New("network unavailable"), "unreachable"},
|
||||
{"text alone", errors.New("connection refused"), "unreachable"},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
h := netHealth(context.Background(), test.err)
|
||||
if h.State != "error" || h.Why != test.why {
|
||||
t.Fatalf("got %+v, want error/%s", h, test.why)
|
||||
}
|
||||
if test.why == "refused" && h.Detail != test.err.Error() {
|
||||
t.Fatalf("lost the original error: %q, want %q", h.Detail, test.err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
if h := netHealth(ctx, wrapped); h.Why != "timeout" {
|
||||
t.Fatalf("an ended check should keep its timeout classification: %+v", h)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package library
|
||||
|
||||
import "golang.org/x/sys/windows"
|
||||
|
||||
// TCP failures carry Winsock errors. syscall.ECONNREFUSED is a different,
|
||||
// compatibility errno on Windows and does not match a refused connection.
|
||||
const connectionRefused = windows.WSAECONNREFUSED
|
||||
Reference in new issue
Block a user