yao/openapi/openapi_test.go
Max 517a4cf5b0 Implement OAuth endpoint logic and enhance test setup
- Added core functionality for OAuth authorization, token handling, and user info retrieval, including error handling and response generation.
- Introduced helper functions for managing different grant types, improving code organization and clarity.
- Enhanced the test setup with a new Prepare function to initialize the OpenAPI test environment and a Clean function for proper resource management.
- Updated tests to ensure the OpenAPI server is correctly loaded and operational during testing.
2025-07-21 15:34:13 +08:00

170 lines
5.2 KiB
Go

package openapi
import (
"context"
"fmt"
"net"
"net/http"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/test"
)
// testServer holds the test HTTP server instance
var testServer *http.Server
// Prepare initializes the OpenAPI test environment and starts a mock HTTP server.
//
// AI ASSISTANT INSTRUCTIONS:
// All tests in the openapi package MUST use these utility functions for proper test environment setup.
// This is a preparation utility function, NOT an actual test case.
//
// Usage pattern for ALL openapi tests:
//
// func TestYourFunction(t *testing.T) {
// serverURL := Prepare(t)
// defer Clean()
//
// // Get base URL from server config for correct path construction
// baseURL := ""
// if Server != nil && Server.Config != nil {
// baseURL = Server.Config.BaseURL
// }
//
// // Your actual test code here...
// // Use serverURL + baseURL + endpoint to make HTTP requests
// // Example: http.Get(serverURL + baseURL + "/helloworld/hello")
// // The OpenAPI server will be available as the global Server variable
// }
//
// PREREQUISITES:
// Before running any tests in this package, you MUST execute the following command in your terminal:
//
// source $YAO_SOURCE_ROOT/env.local.sh
//
// This loads the required environment variables for the test environment.
//
// WHAT THIS FUNCTION DOES:
// Step 1: Calls test.Prepare(t, config.Conf) to initialize the base Yao test environment
//
// This sets up database connections, configurations, and other core dependencies
//
// Step 2: Calls Load(config.Conf) to initialize the OpenAPI server instance
//
// This creates the global Server variable that contains the Gin router and all endpoints
//
// Step 3: Creates a Gin router and attaches the OpenAPI server to it
//
// The server uses Server.Config.BaseURL as the base path for all endpoints
//
// Step 4: Starts an HTTP server on a random available port (127.0.0.1:xxxxx)
//
// This allows actual HTTP testing of the OpenAPI endpoints
//
// RETURN VALUE:
// Returns the server URL in format "http://127.0.0.1:xxxxx" where xxxxx is the random port
// NOTE: You need to append Server.Config.BaseURL to construct the full endpoint URL
//
// ERROR HANDLING:
// If any step fails, the test will fail immediately with a descriptive error message.
func Prepare(t *testing.T) string {
// Step 1: Initialize base test environment with all Yao dependencies
test.Prepare(t, config.Conf)
// Step 2: Initialize OpenAPI server and make it available globally
_, err := Load(config.Conf)
if err != nil {
t.Fatalf("Failed to load OpenAPI server: %v", err)
}
// Step 3: Create Gin router and attach OpenAPI server
gin.SetMode(gin.TestMode)
router := gin.New()
// Attach the OpenAPI server to the router
if Server != nil {
Server.Attach(router)
}
// Step 4: Start HTTP server on random available port
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("Failed to create listener: %v", err)
}
testServer = &http.Server{
Handler: router,
}
// Start server in background
go func() {
if err := testServer.Serve(listener); err != nil && err != http.ErrServerClosed {
t.Errorf("Failed to start test server: %v", err)
}
}()
// Wait a moment for server to start
time.Sleep(10 * time.Millisecond)
// Return server URL
serverURL := fmt.Sprintf("http://%s", listener.Addr().String())
return serverURL
}
// Clean cleans up the OpenAPI test environment and shuts down the test server.
//
// AI ASSISTANT INSTRUCTIONS:
// This function MUST be called with defer in every test that uses Prepare().
// This is a cleanup utility function, NOT an actual test case.
// Always use: defer Clean()
//
// WHAT THIS FUNCTION DOES:
// Step 1: Gracefully shutdown the HTTP test server if it exists
//
// This ensures all pending requests are completed and resources are freed
//
// Step 2: Reset the global Server variable to nil
//
// This ensures no state leakage between tests and prevents memory leaks
//
// Step 3: Calls test.Clean() to clean up the base test environment
//
// This closes database connections, cleans up temporary files, and resets global state
//
// IMPORTANT NOTES:
// - This function should ALWAYS be called with defer to ensure cleanup happens even if tests panic
// - Proper cleanup prevents test interference and resource leaks
// - The order of cleanup steps is important: HTTP server first, then OpenAPI cleanup, then base cleanup
// - Server shutdown has a 5-second timeout to prevent hanging tests
func Clean() {
// Step 1: Gracefully shutdown the HTTP test server
if testServer != nil {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := testServer.Shutdown(ctx); err != nil {
// Force close if graceful shutdown fails
testServer.Close()
}
testServer = nil
}
// Step 2: Reset OpenAPI server instance to prevent state leakage
Server = nil
// Step 3: Clean up base test environment and all dependencies
test.Clean()
}
func TestLoad(t *testing.T) {
serverURL := Prepare(t)
defer Clean()
assert.NotNil(t, Server)
assert.NotEmpty(t, serverURL)
assert.Contains(t, serverURL, "http://127.0.0.1:")
}