mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-05 09:36:37 +08:00
refactor(tests): consolidate contract test helpers and add Playwright e2e tests (#224)
## Summary - Add Playwright e2e test suite for frontend and API - Consolidate contract test helpers, removing redundant internal test file - Simplify test setup across multiple contract test files
This commit is contained in:
@@ -1,19 +0,0 @@
|
|||||||
package contract
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go-backend/internal/store/repo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func mustLastInsertID(t *testing.T, r *repo.Repository, label string) int64 {
|
|
||||||
t.Helper()
|
|
||||||
var id int64
|
|
||||||
if err := r.DB().Raw("SELECT last_insert_rowid()").Row().Scan(&id); err != nil {
|
|
||||||
t.Fatalf("read last_insert_rowid for %s: %v", label, err)
|
|
||||||
}
|
|
||||||
if id <= 0 {
|
|
||||||
t.Fatalf("invalid last_insert_rowid for %s: %d", label, id)
|
|
||||||
}
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,8 @@ package contract_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go-backend/internal/store/repo"
|
"go-backend/internal/store/repo"
|
||||||
@@ -117,3 +119,43 @@ func tryQueryInt(t *testing.T, r *repo.Repository, query string, args ...interfa
|
|||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func valueAsInt(v interface{}) int {
|
||||||
|
switch n := v.(type) {
|
||||||
|
case float64:
|
||||||
|
return int(n)
|
||||||
|
case int:
|
||||||
|
return n
|
||||||
|
case int64:
|
||||||
|
return int(n)
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueAsString(v interface{}) string {
|
||||||
|
s, _ := v.(string)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueAsBool(v interface{}) bool {
|
||||||
|
switch b := v.(type) {
|
||||||
|
case bool:
|
||||||
|
return b
|
||||||
|
case float64:
|
||||||
|
return b != 0
|
||||||
|
case int:
|
||||||
|
return b != 0
|
||||||
|
case int64:
|
||||||
|
return b != 0
|
||||||
|
case string:
|
||||||
|
s := strings.TrimSpace(strings.ToLower(b))
|
||||||
|
return s == "1" || s == "t" || s == "true" || s == "yes" || s == "y"
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonInt64(v int64) string {
|
||||||
|
return strconv.FormatInt(v, 10)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package contract
|
package contract_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -13,15 +12,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go-backend/internal/auth"
|
"go-backend/internal/auth"
|
||||||
httpserver "go-backend/internal/http"
|
|
||||||
"go-backend/internal/http/handler"
|
|
||||||
"go-backend/internal/http/response"
|
"go-backend/internal/http/response"
|
||||||
"go-backend/internal/store/repo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDiagnosisChainCoverageContracts(t *testing.T) {
|
func TestDiagnosisChainCoverageContracts(t *testing.T) {
|
||||||
secret := "contract-jwt-secret"
|
secret := "contract-jwt-secret"
|
||||||
router, r := setupDiagnosisContractRouter(t, secret)
|
router, r := setupContractRouter(t, secret)
|
||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
|
|
||||||
if err := r.DB().Exec(`
|
if err := r.DB().Exec(`
|
||||||
@@ -195,7 +191,7 @@ func TestDiagnosisChainCoverageContracts(t *testing.T) {
|
|||||||
|
|
||||||
func TestForwardDiagnosisRespectsTunnelIPPreferenceContract(t *testing.T) {
|
func TestForwardDiagnosisRespectsTunnelIPPreferenceContract(t *testing.T) {
|
||||||
secret := "contract-jwt-secret"
|
secret := "contract-jwt-secret"
|
||||||
router, r := setupDiagnosisContractRouter(t, secret)
|
router, r := setupContractRouter(t, secret)
|
||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
|
|
||||||
if err := r.DB().Exec(`
|
if err := r.DB().Exec(`
|
||||||
@@ -315,7 +311,7 @@ func TestForwardDiagnosisRespectsTunnelIPPreferenceContract(t *testing.T) {
|
|||||||
|
|
||||||
func TestDiagnosisUsesFederationRuntimeForRemoteNodes(t *testing.T) {
|
func TestDiagnosisUsesFederationRuntimeForRemoteNodes(t *testing.T) {
|
||||||
secret := "contract-jwt-secret"
|
secret := "contract-jwt-secret"
|
||||||
router, r := setupDiagnosisContractRouter(t, secret)
|
router, r := setupContractRouter(t, secret)
|
||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
|
|
||||||
remoteToken := "remote-diagnose-token"
|
remoteToken := "remote-diagnose-token"
|
||||||
@@ -465,54 +461,3 @@ func TestDiagnosisUsesFederationRuntimeForRemoteNodes(t *testing.T) {
|
|||||||
t.Fatalf("expected federation runtime diagnose endpoint to be called")
|
t.Fatalf("expected federation runtime diagnose endpoint to be called")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func valueAsInt(v interface{}) int {
|
|
||||||
switch n := v.(type) {
|
|
||||||
case float64:
|
|
||||||
return int(n)
|
|
||||||
case int:
|
|
||||||
return n
|
|
||||||
case int64:
|
|
||||||
return int(n)
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func valueAsString(v interface{}) string {
|
|
||||||
s, _ := v.(string)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func valueAsBool(v interface{}) bool {
|
|
||||||
switch b := v.(type) {
|
|
||||||
case bool:
|
|
||||||
return b
|
|
||||||
case float64:
|
|
||||||
return b != 0
|
|
||||||
case int:
|
|
||||||
return b != 0
|
|
||||||
case int64:
|
|
||||||
return b != 0
|
|
||||||
case string:
|
|
||||||
s := strings.TrimSpace(strings.ToLower(b))
|
|
||||||
return s == "1" || s == "t" || s == "true" || s == "yes" || s == "y"
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupDiagnosisContractRouter(t *testing.T, jwtSecret string) (http.Handler, *repo.Repository) {
|
|
||||||
t.Helper()
|
|
||||||
dbPath := filepath.Join(t.TempDir(), "diagnosis-contract.db")
|
|
||||||
r, err := repo.Open(dbPath)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("open sqlite: %v", err)
|
|
||||||
}
|
|
||||||
t.Cleanup(func() {
|
|
||||||
_ = r.Close()
|
|
||||||
})
|
|
||||||
|
|
||||||
h := handler.New(r, jwtSecret)
|
|
||||||
return httpserver.NewRouter(h, jwtSecret), r
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -624,42 +624,6 @@ func waitNodeStatus(t *testing.T, r *repo.Repository, nodeID int64, expectedStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func valueAsInt(v interface{}) int {
|
|
||||||
switch n := v.(type) {
|
|
||||||
case float64:
|
|
||||||
return int(n)
|
|
||||||
case int:
|
|
||||||
return n
|
|
||||||
case int64:
|
|
||||||
return int(n)
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func valueAsString(v interface{}) string {
|
|
||||||
s, _ := v.(string)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func valueAsBool(v interface{}) bool {
|
|
||||||
switch b := v.(type) {
|
|
||||||
case bool:
|
|
||||||
return b
|
|
||||||
case float64:
|
|
||||||
return b != 0
|
|
||||||
case int:
|
|
||||||
return b != 0
|
|
||||||
case int64:
|
|
||||||
return b != 0
|
|
||||||
case string:
|
|
||||||
s := strings.TrimSpace(strings.ToLower(b))
|
|
||||||
return s == "1" || s == "t" || s == "true" || s == "yes" || s == "y"
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFederationRuntimeCommandPortRangeEnforcement(t *testing.T) {
|
func TestFederationRuntimeCommandPortRangeEnforcement(t *testing.T) {
|
||||||
providerSecret := "provider-portrange-jwt"
|
providerSecret := "provider-portrange-jwt"
|
||||||
providerRouter, providerRepo := setupContractRouter(t, providerSecret)
|
providerRouter, providerRepo := setupContractRouter(t, providerSecret)
|
||||||
|
|||||||
@@ -109,7 +109,11 @@ func TestForwardOwnershipAndScopeContracts(t *testing.T) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected object item, got %T", arr[0])
|
t.Fatalf("expected object item, got %T", arr[0])
|
||||||
}
|
}
|
||||||
if got := int64(item["id"].(float64)); got != userForwardID {
|
idFloat, ok := item["id"].(float64)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected id to be float64, got %T", item["id"])
|
||||||
|
}
|
||||||
|
if got := int64(idFloat); got != userForwardID {
|
||||||
t.Fatalf("expected forward id %d, got %d", userForwardID, got)
|
t.Fatalf("expected forward id %d, got %d", userForwardID, got)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -144,7 +148,11 @@ func TestForwardOwnershipAndScopeContracts(t *testing.T) {
|
|||||||
if _, ok := first["message"]; !ok {
|
if _, ok := first["message"]; !ok {
|
||||||
t.Fatalf("expected message field in diagnosis result")
|
t.Fatalf("expected message field in diagnosis result")
|
||||||
}
|
}
|
||||||
if got := int(first["fromChainType"].(float64)); got != 1 {
|
fromChainTypeFloat, ok := first["fromChainType"].(float64)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected fromChainType to be float64, got %T", first["fromChainType"])
|
||||||
|
}
|
||||||
|
if got := int(fromChainTypeFloat); got != 1 {
|
||||||
t.Fatalf("expected fromChainType=1, got %d", got)
|
t.Fatalf("expected fromChainType=1, got %d", got)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package contract
|
package contract_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
|
|
||||||
func TestUserTunnelVisibleListContracts(t *testing.T) {
|
func TestUserTunnelVisibleListContracts(t *testing.T) {
|
||||||
secret := "contract-jwt-secret"
|
secret := "contract-jwt-secret"
|
||||||
router, repo := setupDiagnosisContractRouter(t, secret)
|
router, repo := setupContractRouter(t, secret)
|
||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
|
|
||||||
if err := repo.DB().Exec(`
|
if err := repo.DB().Exec(`
|
||||||
@@ -126,8 +126,11 @@ func collectTunnelIDs(t *testing.T, data interface{}) map[int64]bool {
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected object item, got %T", item)
|
t.Fatalf("expected object item, got %T", item)
|
||||||
}
|
}
|
||||||
id := int64(obj["id"].(float64))
|
idFloat, ok := obj["id"].(float64)
|
||||||
ids[id] = true
|
if !ok {
|
||||||
|
t.Fatalf("expected id to be float64, got %T", obj["id"])
|
||||||
|
}
|
||||||
|
ids[int64(idFloat)] = true
|
||||||
}
|
}
|
||||||
return ids
|
return ids
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user