init: 自 zomaintain/backend/zonat 平移独立成库; module path 改为 git.zeroonesoft.cn/golib/zonat; 内部 import 同步重写
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
// HTTP 穿透测试:验证"隧道模式全用 tcp"成立——真实 HTTP 服务(含 keep-alive、
|
||||
// 大 body)经纯 TCP 隧道完整可用,无需 zonat 的 http 反向代理模式。
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.zeroonesoft.cn/golib/zonat/agent"
|
||||
"git.zeroonesoft.cn/golib/zonat/internal/node"
|
||||
)
|
||||
|
||||
func startHTTPServer(t *testing.T) *httptest.Server {
|
||||
t.Helper()
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]string{"hello": "zonat", "via": "tcp-tunnel"})
|
||||
})
|
||||
mux.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "POST only", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
w.Write(body)
|
||||
})
|
||||
srv := httptest.NewServer(mux)
|
||||
t.Cleanup(srv.Close)
|
||||
return srv
|
||||
}
|
||||
|
||||
// registerHTTP 把 httptest.Server 登记为一条隧道,返回公网端口
|
||||
func registerHTTP(t *testing.T, n *node.Node, a *agent.Agent, srv *httptest.Server, id string) int {
|
||||
t.Helper()
|
||||
port, err := a.RegisterTunnel(buildTunnel(t, n, a, id, srv.Listener.Addr().String(), 0))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
func TestHTTPGetPostThroughTunnel(t *testing.T) {
|
||||
srv := startHTTPServer(t)
|
||||
n, a := startEnv(t)
|
||||
port := registerHTTP(t, n, a, srv, "http-tunnel")
|
||||
base := "http://127.0.0.1:" + strconv.Itoa(port)
|
||||
|
||||
// GET
|
||||
resp, err := http.Get(base + "/hello")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var body map[string]string
|
||||
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK || body["hello"] != "zonat" {
|
||||
t.Fatalf("GET /hello 异常: status=%d body=%v", resp.StatusCode, body)
|
||||
}
|
||||
|
||||
// POST 大 body(1MB,跨 smux 多帧)
|
||||
payload := make([]byte, 1<<20)
|
||||
if _, err := rand.Read(payload); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp2, err := http.Post(base+"/echo", "application/octet-stream", bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := io.ReadAll(resp2.Body)
|
||||
resp2.Body.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp2.StatusCode != http.StatusOK || !bytes.Equal(got, payload) {
|
||||
t.Fatalf("POST /echo 异常: status=%d len(got)=%d", resp2.StatusCode, len(got))
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPKeepAliveThroughTunnel(t *testing.T) {
|
||||
srv := startHTTPServer(t)
|
||||
n, a := startEnv(t)
|
||||
port := registerHTTP(t, n, a, srv, "http-ka")
|
||||
|
||||
// 同一 client 复用 TCP 连接(keep-alive),10 次请求走同一条隧道流
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
for i := 0; i < 10; i++ {
|
||||
resp, err := client.Get("http://127.0.0.1:" + strconv.Itoa(port) + "/hello")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("第 %d 次请求异常: %d", i+1, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user