Checkpoint
This commit is contained in:
370
server/server_test.go
Normal file
370
server/server_test.go
Normal file
@@ -0,0 +1,370 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"git.maze.io/ham/hamview/schema"
|
||||
)
|
||||
|
||||
// setupTestServer creates an Echo instance with routes configured and an in-memory database
|
||||
func setupTestServer(t *testing.T) (*echo.Echo, *Server) {
|
||||
t.Helper()
|
||||
|
||||
logger := logrus.New()
|
||||
logger.SetLevel(logrus.WarnLevel)
|
||||
|
||||
// Initialize in-memory SQLite database
|
||||
if err := schema.Open("sqlite3", ":memory:"); err != nil {
|
||||
t.Fatalf("Failed to open test database: %v", err)
|
||||
}
|
||||
|
||||
// Create server instance
|
||||
server := &Server{
|
||||
listen: "127.0.0.1:0",
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
// Setup Echo with routes
|
||||
e := echo.New()
|
||||
e.HideBanner = true
|
||||
setupRoutes(server, e)
|
||||
|
||||
return e, server
|
||||
}
|
||||
|
||||
// teardownTestServer cleans up test resources
|
||||
func teardownTestServer(t *testing.T) {
|
||||
t.Helper()
|
||||
// Close database connection if needed
|
||||
// schema.Close() // Add this method to schema package if needed
|
||||
}
|
||||
|
||||
// TestRadiosEndpoints tests all radio-related endpoints
|
||||
func TestRadiosEndpoints(t *testing.T) {
|
||||
e, _ := setupTestServer(t)
|
||||
defer teardownTestServer(t)
|
||||
|
||||
t.Run("GET /api/v1/radios", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/radios", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, rec.Code)
|
||||
}
|
||||
|
||||
var radios []*schema.Radio
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &radios); err != nil {
|
||||
t.Errorf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GET /api/v1/radios/:protocol", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/radios/aprs", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, rec.Code)
|
||||
}
|
||||
|
||||
var radios []*schema.Radio
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &radios); err != nil {
|
||||
t.Errorf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestAPRSEndpoints tests all APRS-related endpoints
|
||||
func TestAPRSEndpoints(t *testing.T) {
|
||||
e, _ := setupTestServer(t)
|
||||
defer teardownTestServer(t)
|
||||
|
||||
t.Run("GET /api/v1/aprs/packets", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/aprs/packets", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, rec.Code)
|
||||
}
|
||||
|
||||
var packets []*schema.APRSPacket
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &packets); err != nil {
|
||||
t.Errorf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GET /api/v1/aprs/packets filters", func(t *testing.T) {
|
||||
testCases := []string{
|
||||
"?src=OE1ABC",
|
||||
"?dst=APRS",
|
||||
"?limit=200",
|
||||
}
|
||||
|
||||
for _, query := range testCases {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/aprs/packets"+query, nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK && rec.Code != http.StatusInternalServerError {
|
||||
t.Errorf("Expected status %d or %d, got %d", http.StatusOK, http.StatusInternalServerError, rec.Code)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestMeshCoreEndpoints tests all MeshCore-related endpoints
|
||||
func TestMeshCoreEndpoints(t *testing.T) {
|
||||
e, _ := setupTestServer(t)
|
||||
defer teardownTestServer(t)
|
||||
|
||||
t.Run("GET /api/v1/meshcore", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/meshcore", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, rec.Code)
|
||||
}
|
||||
|
||||
var stats map[string]any
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &stats); err != nil {
|
||||
t.Errorf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GET /api/v1/meshcore/groups", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/meshcore/groups", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, rec.Code)
|
||||
}
|
||||
|
||||
var groups []any
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &groups); err != nil {
|
||||
t.Errorf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GET /api/v1/meshcore/nodes", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/meshcore/nodes", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, rec.Code)
|
||||
}
|
||||
|
||||
var nodes []*schema.MeshCoreNode
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &nodes); err != nil {
|
||||
t.Errorf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GET /api/v1/meshcore/nodes?type=chat", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/meshcore/nodes?type=chat", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, rec.Code)
|
||||
}
|
||||
|
||||
var nodes []*schema.MeshCoreNode
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &nodes); err != nil {
|
||||
t.Errorf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GET /api/v1/meshcore/packets", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/meshcore/packets", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, rec.Code)
|
||||
}
|
||||
|
||||
var packets []*schema.MeshCorePacket
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &packets); err != nil {
|
||||
t.Errorf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestMeshCoreNodesCloseTo tests the close-to endpoint
|
||||
func TestMeshCoreNodesCloseTo(t *testing.T) {
|
||||
e, _ := setupTestServer(t)
|
||||
defer teardownTestServer(t)
|
||||
|
||||
// First, insert a test node if needed
|
||||
// This is a placeholder - you'll need actual test data setup
|
||||
|
||||
t.Run("GET /api/v1/meshcore/nodes/close-to/:publickey", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/meshcore/nodes/close-to/test_key", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
// May return 404 or error if no data exists, which is fine for skeleton test
|
||||
if rec.Code != http.StatusOK && rec.Code != http.StatusNotFound && rec.Code != http.StatusInternalServerError {
|
||||
t.Errorf("Expected status %d, %d, or %d, got %d", http.StatusOK, http.StatusNotFound, http.StatusInternalServerError, rec.Code)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GET /api/v1/meshcore/nodes/close-to/:publickey with radius", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/meshcore/nodes/close-to/test_key?radius=50000", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
// May return 404 or error if no data exists, which is fine for skeleton test
|
||||
if rec.Code != http.StatusOK && rec.Code != http.StatusNotFound && rec.Code != http.StatusInternalServerError {
|
||||
t.Errorf("Expected status %d, %d, or %d, got %d", http.StatusOK, http.StatusNotFound, http.StatusInternalServerError, rec.Code)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestMeshCorePacketsWithFilters tests packet endpoint with various query parameters
|
||||
func TestMeshCorePacketsWithFilters(t *testing.T) {
|
||||
e, _ := setupTestServer(t)
|
||||
defer teardownTestServer(t)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
queryParam string
|
||||
}{
|
||||
{"With hash", "?hash=test_hash"},
|
||||
{"With type", "?type=1"},
|
||||
{"With type and channel_hash", "?type=1&channel_hash=test_channel"},
|
||||
{"No filters", ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/meshcore/packets"+tc.queryParam, nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK && rec.Code != http.StatusInternalServerError {
|
||||
t.Errorf("Expected status %d or %d, got %d", http.StatusOK, http.StatusInternalServerError, rec.Code)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkGetRadios benchmarks the radios endpoint
|
||||
func BenchmarkGetRadios(b *testing.B) {
|
||||
logger := logrus.New()
|
||||
logger.SetLevel(logrus.ErrorLevel)
|
||||
|
||||
if err := schema.Open("sqlite3", ":memory:"); err != nil {
|
||||
b.Fatalf("Failed to open test database: %v", err)
|
||||
}
|
||||
|
||||
server := &Server{
|
||||
listen: "127.0.0.1:0",
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
e := echo.New()
|
||||
e.HideBanner = true
|
||||
setupRoutes(server, e)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/radios", nil)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
rec := httptest.NewRecorder()
|
||||
e.ServeHTTP(rec, req)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkGetMeshCorePackets benchmarks the packets endpoint
|
||||
func BenchmarkGetMeshCorePackets(b *testing.B) {
|
||||
logger := logrus.New()
|
||||
logger.SetLevel(logrus.ErrorLevel)
|
||||
|
||||
if err := schema.Open("sqlite3", ":memory:"); err != nil {
|
||||
b.Fatalf("Failed to open test database: %v", err)
|
||||
}
|
||||
|
||||
server := &Server{
|
||||
listen: "127.0.0.1:0",
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
e := echo.New()
|
||||
e.HideBanner = true
|
||||
setupRoutes(server, e)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/meshcore/packets", nil)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
rec := httptest.NewRecorder()
|
||||
e.ServeHTTP(rec, req)
|
||||
}
|
||||
}
|
||||
|
||||
// Example test showing how to populate test data
|
||||
func TestWithTestData(t *testing.T) {
|
||||
e, _ := setupTestServer(t)
|
||||
defer teardownTestServer(t)
|
||||
|
||||
// Example: Insert test data
|
||||
ctx := context.Background()
|
||||
|
||||
// Example radio insertion (adapt based on your schema package)
|
||||
// radio := &schema.Radio{
|
||||
// ID: "test-radio-1",
|
||||
// Protocol: "aprs",
|
||||
// Name: "Test Radio",
|
||||
// }
|
||||
// if err := schema.InsertRadio(ctx, radio); err != nil {
|
||||
// t.Fatalf("Failed to insert test radio: %v", err)
|
||||
// }
|
||||
|
||||
t.Run("GET /api/v1/radios with data", func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/radios", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
e.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("Expected status %d, got %d", http.StatusOK, rec.Code)
|
||||
}
|
||||
|
||||
var radios []*schema.Radio
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &radios); err != nil {
|
||||
t.Errorf("Failed to unmarshal response: %v", err)
|
||||
}
|
||||
|
||||
// Add assertions about the data
|
||||
// if len(radios) != 1 {
|
||||
// t.Errorf("Expected 1 radio, got %d", len(radios))
|
||||
// }
|
||||
})
|
||||
|
||||
_ = ctx // Use ctx to avoid unused variable error
|
||||
}
|
||||
Reference in New Issue
Block a user