Add podman-compose/docker-compose integration tests
This commit is contained in:
234
tests/integration/compose_integration_test.go
Normal file
234
tests/integration/compose_integration_test.go
Normal file
@@ -0,0 +1,234 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// ComposeIntegrationTest runs integration tests against a containerized instance
|
||||
func TestComposeIntegration(t *testing.T) {
|
||||
if os.Getenv("RUN_COMPOSE_TESTS") != "true" {
|
||||
t.Skip("Skipping compose integration tests. Set RUN_COMPOSE_TESTS=true to run")
|
||||
}
|
||||
|
||||
composeCmd := detectComposeCommand(t)
|
||||
projectName := "dyn-test-" + fmt.Sprintf("%d", time.Now().Unix())
|
||||
|
||||
// Cleanup function
|
||||
cleanup := func() {
|
||||
t.Log("Cleaning up containers...")
|
||||
cmd := exec.Command(composeCmd, "-f", "../../docker-compose.yml", "-p", projectName, "down", "-v")
|
||||
cmd.Run()
|
||||
os.Remove(".env.test")
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
// Create test environment
|
||||
envContent := `SERVER_PORT=8080
|
||||
DATABASE_PATH=/data/dyn.db
|
||||
TECHNITIUM_URL=http://mock-dns:8080
|
||||
TECHNITIUM_TOKEN=test-token
|
||||
BASE_DOMAIN=test.rip
|
||||
SPACE_SUBDOMAIN=space
|
||||
RATE_LIMIT_PER_IP=100
|
||||
RATE_LIMIT_PER_TOKEN=100
|
||||
`
|
||||
err := os.WriteFile(".env.test", []byte(envContent), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Start services
|
||||
t.Log("Starting services with", composeCmd)
|
||||
cmd := exec.Command(composeCmd, "-f", "../../docker-compose.yml", "-p", projectName, "--env-file", ".env.test", "up", "-d", "--build")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start services: %v\nOutput: %s", err, output)
|
||||
}
|
||||
|
||||
// Wait for service to be ready
|
||||
baseURL := waitForService(t, "http://localhost:8080", 60)
|
||||
t.Logf("Service ready at %s", baseURL)
|
||||
|
||||
// Run tests
|
||||
t.Run("HealthCheck", func(t *testing.T) {
|
||||
testHealthCheck(t, baseURL)
|
||||
})
|
||||
|
||||
t.Run("CheckSubdomain", func(t *testing.T) {
|
||||
testCheckSubdomain(t, baseURL)
|
||||
})
|
||||
|
||||
t.Run("ClaimSpace", func(t *testing.T) {
|
||||
testClaimSpace(t, baseURL)
|
||||
})
|
||||
|
||||
t.Run("ProfanityFilter", func(t *testing.T) {
|
||||
testProfanityFilterCompose(t, baseURL)
|
||||
})
|
||||
|
||||
t.Run("CustomFilter", func(t *testing.T) {
|
||||
testCustomFilterCompose(t, baseURL)
|
||||
})
|
||||
|
||||
t.Run("DynDNSEndpoint", func(t *testing.T) {
|
||||
testDynDNSEndpoint(t, baseURL)
|
||||
})
|
||||
}
|
||||
|
||||
func detectComposeCommand(t *testing.T) string {
|
||||
// Try podman-compose first
|
||||
if _, err := exec.LookPath("podman-compose"); err == nil {
|
||||
t.Log("Using podman-compose")
|
||||
return "podman-compose"
|
||||
}
|
||||
|
||||
// Try docker-compose
|
||||
if _, err := exec.LookPath("docker-compose"); err == nil {
|
||||
t.Log("Using docker-compose")
|
||||
return "docker-compose"
|
||||
}
|
||||
|
||||
t.Skip("Neither podman-compose nor docker-compose found")
|
||||
return ""
|
||||
}
|
||||
|
||||
func waitForService(t *testing.T, url string, timeout int) string {
|
||||
client := &http.Client{Timeout: 2 * time.Second}
|
||||
|
||||
for i := 0; i < timeout; i++ {
|
||||
resp, err := client.Get(url)
|
||||
if err == nil && resp.StatusCode == http.StatusOK {
|
||||
resp.Body.Close()
|
||||
return url
|
||||
}
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
t.Fatalf("Service did not become ready within %d seconds", timeout)
|
||||
return ""
|
||||
}
|
||||
|
||||
func testHealthCheck(t *testing.T, baseURL string) {
|
||||
resp, err := http.Get(baseURL + "/")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
body := new(bytes.Buffer)
|
||||
body.ReadFrom(resp.Body)
|
||||
assert.Contains(t, body.String(), "DWS Dynamic DNS")
|
||||
}
|
||||
|
||||
func testCheckSubdomain(t *testing.T, baseURL string) {
|
||||
// Test available subdomain
|
||||
resp, err := http.Get(baseURL + "/api/check?subdomain=newspace")
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
var result map[string]interface{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, result["available"].(bool))
|
||||
}
|
||||
|
||||
func testClaimSpace(t *testing.T, baseURL string) string {
|
||||
payload := map[string]string{"subdomain": "testclaim"}
|
||||
body, _ := json.Marshal(payload)
|
||||
|
||||
resp, err := http.Post(baseURL+"/api/claim", "application/json", bytes.NewBuffer(body))
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, http.StatusCreated, resp.StatusCode)
|
||||
|
||||
var result map[string]interface{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
|
||||
token := result["token"].(string)
|
||||
assert.NotEmpty(t, token)
|
||||
assert.Equal(t, "testclaim", result["subdomain"])
|
||||
|
||||
return token
|
||||
}
|
||||
|
||||
func testProfanityFilterCompose(t *testing.T, baseURL string) {
|
||||
profaneWords := []string{"fuck", "shit", "bitch"}
|
||||
|
||||
for _, word := range profaneWords {
|
||||
t.Run(word, func(t *testing.T) {
|
||||
payload := map[string]string{"subdomain": word}
|
||||
body, _ := json.Marshal(payload)
|
||||
|
||||
resp, err := http.Post(baseURL+"/api/claim", "application/json", bytes.NewBuffer(body))
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
var result map[string]string
|
||||
json.NewDecoder(resp.Body).Decode(&result)
|
||||
assert.Contains(t, result["error"], "inappropriate")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testCustomFilterCompose(t *testing.T, baseURL string) {
|
||||
reservedWords := []string{"dws", "dubey", "tanishq"}
|
||||
|
||||
for _, word := range reservedWords {
|
||||
t.Run(word, func(t *testing.T) {
|
||||
payload := map[string]string{"subdomain": word}
|
||||
body, _ := json.Marshal(payload)
|
||||
|
||||
resp, err := http.Post(baseURL+"/api/claim", "application/json", bytes.NewBuffer(body))
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
var result map[string]string
|
||||
json.NewDecoder(resp.Body).Decode(&result)
|
||||
assert.Contains(t, result["error"], "reserved")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testDynDNSEndpoint(t *testing.T, baseURL string) {
|
||||
// First claim a space
|
||||
token := testClaimSpace(t, baseURL)
|
||||
|
||||
// Try DynDNS update
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
req, err := http.NewRequest("GET", baseURL+"/api/nic/update?hostname=testclaim.space.test.rip&myip=192.168.1.100", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Authorization", "Basic "+basicAuth("none", token))
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
// We expect 200 or 503 (since there's no real DNS server)
|
||||
assert.True(t, resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusServiceUnavailable)
|
||||
}
|
||||
|
||||
func basicAuth(username, password string) string {
|
||||
auth := username + ":" + password
|
||||
return base64.StdEncoding.EncodeToString([]byte(auth))
|
||||
}
|
||||
Reference in New Issue
Block a user