(t *testing.T)
| 69 | } |
| 70 | |
| 71 | func TestUserSubscriptionAndApplyFlow(t *testing.T) { |
| 72 | var capturedConfig string |
| 73 | mux, ibStore := setupTestMux(t, map[string]func(body any) (json.RawMessage, error){ |
| 74 | "Restart": func(b any) (json.RawMessage, error) { |
| 75 | req, _ := b.(nodes.ConfigRequest) |
| 76 | capturedConfig = req.Config |
| 77 | if !strings.Contains(req.Config, "\"protocol\": \"vless\"") { |
| 78 | return nil, &nodeAPIError{"bad config"} |
| 79 | } |
| 80 | return json.RawMessage(`{"running":true}`), nil |
| 81 | }, |
| 82 | }) |
| 83 | |
| 84 | // 在 ibStore 中注册 vless 入站和对应 host |
| 85 | _, _ = ibStore.UpsertInbound(inbounds.Inbound{ |
| 86 | ID: "ib-vless", |
| 87 | NodeID: "node-1", |
| 88 | Protocol: "vless", |
| 89 | Tag: "pulse-vless-node-1", |
| 90 | Port: 443, |
| 91 | }) |
| 92 | _, _ = ibStore.UpsertHost(inbounds.Host{ |
| 93 | ID: "host-1", |
| 94 | InboundID: "ib-vless", |
| 95 | Address: "example.com", |
| 96 | Port: 443, |
| 97 | }) |
| 98 | |
| 99 | // 创建 alice 并绑定 inbound |
| 100 | aliceID := createUser(t, mux, `{"id":"user-1","username":"alice"}`) |
| 101 | ibID := createUserInbound(t, mux, aliceID, "ib-vless") |
| 102 | |
| 103 | // 获取订阅链接 |
| 104 | rec := httptest.NewRecorder() |
| 105 | req := httptest.NewRequest(http.MethodGet, "/v1/users/"+aliceID+"/inbounds/"+ibID+"/subscription", nil) |
| 106 | mux.ServeHTTP(rec, req) |
| 107 | if rec.Code != http.StatusOK { |
| 108 | t.Fatalf("subscription status = %d body=%s", rec.Code, rec.Body.String()) |
| 109 | } |
| 110 | if !strings.Contains(rec.Body.String(), "vless://") { |
| 111 | t.Fatalf("expected vless link, got %s", rec.Body.String()) |
| 112 | } |
| 113 | |
| 114 | // 下发配置 |
| 115 | rec = httptest.NewRecorder() |
| 116 | req = httptest.NewRequest(http.MethodPost, "/v1/users/"+aliceID+"/inbounds/"+ibID+"/apply", nil) |
| 117 | mux.ServeHTTP(rec, req) |
| 118 | if rec.Code != http.StatusOK { |
| 119 | t.Fatalf("apply status = %d body=%s", rec.Code, rec.Body.String()) |
| 120 | } |
| 121 | if !strings.Contains(rec.Body.String(), "\"running\":true") { |
| 122 | t.Fatalf("expected running node status, got %s", rec.Body.String()) |
| 123 | } |
| 124 | |
| 125 | // 创建 bob 并绑定同一 inbound |
| 126 | bobID := createUser(t, mux, `{"id":"user-2","username":"bob"}`) |
| 127 | ibID2 := createUserInbound(t, mux, bobID, "ib-vless") |
| 128 |
nothing calls this directly
no test coverage detected