Files
goyco/internal/e2e/version_test.go

193 lines
5.0 KiB
Go

package e2e
import (
"encoding/json"
"net/http"
"regexp"
"testing"
"goyco/internal/testutils"
)
func TestE2E_VersionEndpoint(t *testing.T) {
ctx := setupTestContext(t)
t.Run("version_in_api_info", func(t *testing.T) {
req, err := http.NewRequest("GET", ctx.baseURL+"/api", nil)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
testutils.WithStandardHeaders(req)
resp, err := ctx.client.Do(req)
if err != nil {
t.Fatalf("Request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("Expected status 200 for /api endpoint, got %d", resp.StatusCode)
return
}
var apiInfo map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&apiInfo); err != nil {
t.Fatalf("Failed to decode API info response: %v", err)
}
data, ok := apiInfo["data"].(map[string]interface{})
if !ok {
t.Fatalf("API info data is not a map")
}
version, ok := data["version"].(string)
if !ok {
t.Error("Version field missing or not a string in API info")
return
}
if version == "" {
t.Error("Version is empty")
}
versionPattern := regexp.MustCompile(`^\d+\.\d+\.\d+`)
if !versionPattern.MatchString(version) {
t.Errorf("Version format invalid, expected semantic version (x.y.z), got: %s", version)
}
})
t.Run("version_in_health_endpoint", func(t *testing.T) {
req, err := http.NewRequest("GET", ctx.baseURL+"/health", nil)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
testutils.WithStandardHeaders(req)
resp, err := ctx.client.Do(req)
if err != nil {
t.Fatalf("Request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("Expected status 200 for /health endpoint, got %d", resp.StatusCode)
return
}
var healthInfo map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&healthInfo); err != nil {
t.Fatalf("Failed to decode health response: %v", err)
}
data, ok := healthInfo["data"].(map[string]interface{})
if !ok {
t.Fatalf("Health data is not a map")
}
version, ok := data["version"].(string)
if !ok {
t.Error("Version field missing or not a string in health info")
return
}
if version == "" {
t.Error("Version is empty")
}
versionPattern := regexp.MustCompile(`^\d+\.\d+\.\d+`)
if !versionPattern.MatchString(version) {
t.Errorf("Version format invalid, expected semantic version (x.y.z), got: %s", version)
}
})
t.Run("version_consistency", func(t *testing.T) {
apiReq, err := http.NewRequest("GET", ctx.baseURL+"/api", nil)
if err != nil {
t.Fatalf("Failed to create API request: %v", err)
}
testutils.WithStandardHeaders(apiReq)
apiResp, err := ctx.client.Do(apiReq)
if err != nil {
t.Fatalf("API request failed: %v", err)
}
defer apiResp.Body.Close()
healthReq, err := http.NewRequest("GET", ctx.baseURL+"/health", nil)
if err != nil {
t.Fatalf("Failed to create health request: %v", err)
}
testutils.WithStandardHeaders(healthReq)
healthResp, err := ctx.client.Do(healthReq)
if err != nil {
t.Fatalf("Health request failed: %v", err)
}
defer healthResp.Body.Close()
if apiResp.StatusCode != http.StatusOK || healthResp.StatusCode != http.StatusOK {
t.Skip("One or both endpoints unavailable")
return
}
var apiInfo map[string]interface{}
if err := json.NewDecoder(apiResp.Body).Decode(&apiInfo); err != nil {
t.Fatalf("Failed to decode API info: %v", err)
}
var healthInfo map[string]interface{}
if err := json.NewDecoder(healthResp.Body).Decode(&healthInfo); err != nil {
t.Fatalf("Failed to decode health info: %v", err)
}
apiData, _ := apiInfo["data"].(map[string]interface{})
healthData, _ := healthInfo["data"].(map[string]interface{})
apiVersion, apiOk := apiData["version"].(string)
healthVersion, healthOk := healthData["version"].(string)
if apiOk && healthOk && apiVersion != healthVersion {
t.Errorf("Version mismatch: /api has %s, /health has %s", apiVersion, healthVersion)
}
})
t.Run("version_format_validation", func(t *testing.T) {
req, err := http.NewRequest("GET", ctx.baseURL+"/api", nil)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
testutils.WithStandardHeaders(req)
resp, err := ctx.client.Do(req)
if err != nil {
t.Fatalf("Request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Skip("API endpoint unavailable")
return
}
var apiInfo map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&apiInfo); err != nil {
t.Fatalf("Failed to decode API info: %v", err)
}
data, ok := apiInfo["data"].(map[string]interface{})
if !ok {
return
}
version, ok := data["version"].(string)
if !ok || version == "" {
return
}
semverPattern := regexp.MustCompile(`^\d+\.\d+\.\d+(-[a-zA-Z0-9-]+)?(\+[a-zA-Z0-9-]+)?$`)
if !semverPattern.MatchString(version) {
t.Logf("Version '%s' does not strictly follow semantic versioning (acceptable)", version)
}
})
}