| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- package admin
- import (
- "bytes"
- "encoding/json"
- "net/http"
- "net/http/httptest"
- "testing"
- "time"
- "github.com/Wei-Shaw/sub2api/internal/service"
- "github.com/gin-gonic/gin"
- "github.com/stretchr/testify/require"
- )
- type proxyDataResponse struct {
- Code int `json:"code"`
- Data DataPayload `json:"data"`
- }
- type proxyImportResponse struct {
- Code int `json:"code"`
- Data DataImportResult `json:"data"`
- }
- func setupProxyDataRouter() (*gin.Engine, *stubAdminService) {
- gin.SetMode(gin.TestMode)
- router := gin.New()
- adminSvc := newStubAdminService()
- h := NewProxyHandler(adminSvc)
- router.GET("/api/v1/admin/proxies/data", h.ExportData)
- router.POST("/api/v1/admin/proxies/data", h.ImportData)
- return router, adminSvc
- }
- func TestProxyExportDataRespectsFilters(t *testing.T) {
- router, adminSvc := setupProxyDataRouter()
- adminSvc.proxies = []service.Proxy{
- {
- ID: 1,
- Name: "proxy-a",
- Protocol: "http",
- Host: "127.0.0.1",
- Port: 8080,
- Username: "user",
- Password: "pass",
- Status: service.StatusActive,
- },
- {
- ID: 2,
- Name: "proxy-b",
- Protocol: "https",
- Host: "10.0.0.2",
- Port: 443,
- Username: "u",
- Password: "p",
- Status: service.StatusDisabled,
- },
- }
- rec := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/proxies/data?protocol=https", nil)
- router.ServeHTTP(rec, req)
- require.Equal(t, http.StatusOK, rec.Code)
- var resp proxyDataResponse
- require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
- require.Equal(t, 0, resp.Code)
- require.Empty(t, resp.Data.Type)
- require.Equal(t, 0, resp.Data.Version)
- require.Len(t, resp.Data.Proxies, 1)
- require.Len(t, resp.Data.Accounts, 0)
- require.Equal(t, "https", resp.Data.Proxies[0].Protocol)
- require.Equal(t, 1, adminSvc.lastListProxies.calls)
- require.Equal(t, "https", adminSvc.lastListProxies.protocol)
- require.Equal(t, "id", adminSvc.lastListProxies.sortBy)
- require.Equal(t, "desc", adminSvc.lastListProxies.sortOrder)
- }
- func TestProxyExportDataWithSelectedIDs(t *testing.T) {
- router, adminSvc := setupProxyDataRouter()
- adminSvc.proxies = []service.Proxy{
- {
- ID: 1,
- Name: "proxy-a",
- Protocol: "http",
- Host: "127.0.0.1",
- Port: 8080,
- Username: "user",
- Password: "pass",
- Status: service.StatusActive,
- },
- {
- ID: 2,
- Name: "proxy-b",
- Protocol: "https",
- Host: "10.0.0.2",
- Port: 443,
- Username: "u",
- Password: "p",
- Status: service.StatusDisabled,
- },
- }
- rec := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/proxies/data?ids=2", nil)
- router.ServeHTTP(rec, req)
- require.Equal(t, http.StatusOK, rec.Code)
- var resp proxyDataResponse
- require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
- require.Equal(t, 0, resp.Code)
- require.Len(t, resp.Data.Proxies, 1)
- require.Equal(t, "https", resp.Data.Proxies[0].Protocol)
- require.Equal(t, "10.0.0.2", resp.Data.Proxies[0].Host)
- require.Equal(t, 0, adminSvc.lastListProxies.calls)
- }
- func TestProxyExportDataPassesSortParams(t *testing.T) {
- router, adminSvc := setupProxyDataRouter()
- adminSvc.proxies = []service.Proxy{
- {
- ID: 1,
- Name: "proxy-a",
- Protocol: "http",
- Host: "127.0.0.1",
- Port: 8080,
- Username: "user",
- Password: "pass",
- Status: service.StatusActive,
- },
- }
- rec := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/proxies/data?protocol=http&status=active&search=proxy&sort_by=name&sort_order=asc", nil)
- router.ServeHTTP(rec, req)
- require.Equal(t, http.StatusOK, rec.Code)
- require.Equal(t, 1, adminSvc.lastListProxies.calls)
- require.Equal(t, "http", adminSvc.lastListProxies.protocol)
- require.Equal(t, "active", adminSvc.lastListProxies.status)
- require.Equal(t, "proxy", adminSvc.lastListProxies.search)
- require.Equal(t, "name", adminSvc.lastListProxies.sortBy)
- require.Equal(t, "asc", adminSvc.lastListProxies.sortOrder)
- }
- func TestProxyExportDataSortByAccountCountUsesAccountCountListing(t *testing.T) {
- router, adminSvc := setupProxyDataRouter()
- adminSvc.proxies = []service.Proxy{
- {
- ID: 1,
- Name: "proxy-id-1",
- Protocol: "http",
- Host: "127.0.0.1",
- Port: 8080,
- Status: service.StatusActive,
- },
- {
- ID: 2,
- Name: "proxy-id-2",
- Protocol: "http",
- Host: "127.0.0.2",
- Port: 8081,
- Status: service.StatusActive,
- },
- }
- adminSvc.proxyCounts = []service.ProxyWithAccountCount{
- {
- Proxy: service.Proxy{
- ID: 2,
- Name: "proxy-count-high",
- Protocol: "http",
- Host: "127.0.0.2",
- Port: 8081,
- Status: service.StatusActive,
- },
- AccountCount: 9,
- },
- {
- Proxy: service.Proxy{
- ID: 1,
- Name: "proxy-count-low",
- Protocol: "http",
- Host: "127.0.0.1",
- Port: 8080,
- Status: service.StatusActive,
- },
- AccountCount: 1,
- },
- }
- rec := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodGet, "/api/v1/admin/proxies/data?sort_by=account_count&sort_order=desc", nil)
- router.ServeHTTP(rec, req)
- require.Equal(t, http.StatusOK, rec.Code)
- var resp proxyDataResponse
- require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
- require.Equal(t, 0, resp.Code)
- require.Len(t, resp.Data.Proxies, 2)
- require.Equal(t, "proxy-count-high", resp.Data.Proxies[0].Name)
- require.Equal(t, "proxy-count-low", resp.Data.Proxies[1].Name)
- require.Equal(t, 0, adminSvc.lastListProxies.calls)
- }
- func TestProxyImportDataReusesAndTriggersLatencyProbe(t *testing.T) {
- router, adminSvc := setupProxyDataRouter()
- adminSvc.proxies = []service.Proxy{
- {
- ID: 1,
- Name: "proxy-a",
- Protocol: "http",
- Host: "127.0.0.1",
- Port: 8080,
- Username: "user",
- Password: "pass",
- Status: service.StatusActive,
- },
- }
- payload := map[string]any{
- "data": map[string]any{
- "type": dataType,
- "version": dataVersion,
- "proxies": []map[string]any{
- {
- "proxy_key": "http|127.0.0.1|8080|user|pass",
- "name": "proxy-a",
- "protocol": "http",
- "host": "127.0.0.1",
- "port": 8080,
- "username": "user",
- "password": "pass",
- "status": "inactive",
- },
- {
- "proxy_key": "https|10.0.0.2|443|u|p",
- "name": "proxy-b",
- "protocol": "https",
- "host": "10.0.0.2",
- "port": 443,
- "username": "u",
- "password": "p",
- "status": "active",
- },
- },
- "accounts": []map[string]any{},
- },
- }
- body, _ := json.Marshal(payload)
- rec := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodPost, "/api/v1/admin/proxies/data", bytes.NewReader(body))
- req.Header.Set("Content-Type", "application/json")
- router.ServeHTTP(rec, req)
- require.Equal(t, http.StatusOK, rec.Code)
- var resp proxyImportResponse
- require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
- require.Equal(t, 0, resp.Code)
- require.Equal(t, 1, resp.Data.ProxyCreated)
- require.Equal(t, 1, resp.Data.ProxyReused)
- require.Equal(t, 0, resp.Data.ProxyFailed)
- adminSvc.mu.Lock()
- updatedIDs := append([]int64(nil), adminSvc.updatedProxyIDs...)
- adminSvc.mu.Unlock()
- require.Contains(t, updatedIDs, int64(1))
- require.Eventually(t, func() bool {
- adminSvc.mu.Lock()
- defer adminSvc.mu.Unlock()
- return len(adminSvc.testedProxyIDs) == 1
- }, time.Second, 10*time.Millisecond)
- }
|