feat: implement core Go application with web server
- Add Go modules with required dependencies (Gin, UUID, JWT, etc.) - Implement main web server with landing page endpoint - Add comprehensive API endpoints for health and status - Include proper error handling and request validation - Set up CORS middleware and security headers
This commit is contained in:
294
output/tests/business_logic_test.go
Normal file
294
output/tests/business_logic_test.go
Normal file
@@ -0,0 +1,294 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDomainValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
domain string
|
||||
valid bool
|
||||
reason string
|
||||
}{
|
||||
{"example.com", true, "Valid domain"},
|
||||
{"sub.example.com", true, "Valid subdomain"},
|
||||
{"test.co.uk", true, "Valid domain with multiple TLDs"},
|
||||
{"", false, "Empty domain"},
|
||||
{"invalid", false, "No TLD"},
|
||||
{".com", false, "Starts with dot"},
|
||||
{"com.", false, "Ends with dot"},
|
||||
{"..double.com", false, "Double dots"},
|
||||
{"toolong" + string(make([]byte, 300)) + ".com", false, "Too long domain"},
|
||||
{"valid-domain.com", true, "Valid domain with hyphen"},
|
||||
{"-invalid.com", false, "Starts with hyphen"},
|
||||
{"invalid-.com", false, "Ends with hyphen"},
|
||||
{"valid123.com", true, "Valid domain with numbers"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.reason, func(t *testing.T) {
|
||||
// Simple domain validation logic
|
||||
valid := isValidDomain(test.domain)
|
||||
assert.Equal(t, test.valid, valid, "Domain: %s", test.domain)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmailValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
email string
|
||||
valid bool
|
||||
reason string
|
||||
}{
|
||||
{"test@example.com", true, "Valid email"},
|
||||
{"user.name@domain.co.uk", true, "Valid email with subdomain"},
|
||||
{"user+tag@example.org", true, "Valid email with plus tag"},
|
||||
{"", false, "Empty email"},
|
||||
{"invalid", false, "No @ symbol"},
|
||||
{"@domain.com", false, "No local part"},
|
||||
{"user@", false, "No domain part"},
|
||||
{"user..name@example.com", false, "Double dots in local part"},
|
||||
{"user@.com", false, "Domain starts with dot"},
|
||||
{"user@com.", false, "Domain ends with dot"},
|
||||
{"user@toolong" + string(make([]byte, 300)) + ".com", false, "Too long email"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.reason, func(t *testing.T) {
|
||||
// Simple email validation logic
|
||||
valid := isValidEmail(test.email)
|
||||
assert.Equal(t, test.valid, valid, "Email: %s", test.email)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreditCardValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
cardNumber string
|
||||
valid bool
|
||||
reason string
|
||||
}{
|
||||
{"4242424242424242", true, "Valid Visa test card"},
|
||||
{"5555555555554444", true, "Valid Mastercard test card"},
|
||||
{"378282246310005", true, "Valid Amex test card"},
|
||||
{"", false, "Empty card number"},
|
||||
{"4111", false, "Too short"},
|
||||
{"42424242424242424242", false, "Too long"},
|
||||
{"abcdabcdabcdabcd", false, "Non-numeric"},
|
||||
{"4242-4242-4242-4242", false, "Contains dashes"},
|
||||
{"4242 4242 4242 4242", false, "Contains spaces"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.reason, func(t *testing.T) {
|
||||
// Simple credit card validation logic
|
||||
valid := isValidCreditCard(test.cardNumber)
|
||||
assert.Equal(t, test.valid, valid, "Card: %s", test.cardNumber)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBusinessLogic(t *testing.T) {
|
||||
t.Run("Customer ID generation", func(t *testing.T) {
|
||||
// Test that customer IDs are unique
|
||||
id1 := generateCustomerID()
|
||||
id2 := generateCustomerID()
|
||||
|
||||
assert.NotEmpty(t, id1)
|
||||
assert.NotEmpty(t, id2)
|
||||
assert.NotEqual(t, id1, id2)
|
||||
})
|
||||
|
||||
t.Run("Pricing calculation", func(t *testing.T) {
|
||||
// Test pricing logic
|
||||
assert.Equal(t, 250.0, calculateMonthlyPrice())
|
||||
assert.Equal(t, 3000.0, calculateYearlyPrice())
|
||||
})
|
||||
|
||||
t.Run("Provisioning steps", func(t *testing.T) {
|
||||
// Test provisioning workflow
|
||||
steps := getProvisioningSteps()
|
||||
|
||||
expectedSteps := []string{
|
||||
"Domain Registration",
|
||||
"VPS Provisioning",
|
||||
"Cloudron Installation",
|
||||
"DNS Configuration",
|
||||
"Business Setup",
|
||||
}
|
||||
|
||||
assert.Equal(t, len(expectedSteps), len(steps))
|
||||
|
||||
for i, expected := range expectedSteps {
|
||||
assert.Equal(t, expected, steps[i].Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestProvisioningProgress(t *testing.T) {
|
||||
t.Run("Initial progress", func(t *testing.T) {
|
||||
progress := calculateProgress(0) // No steps completed
|
||||
assert.Equal(t, 0, progress)
|
||||
})
|
||||
|
||||
t.Run("Partial progress", func(t *testing.T) {
|
||||
progress := calculateProgress(2) // 2 of 5 steps completed
|
||||
assert.Equal(t, 40, progress)
|
||||
})
|
||||
|
||||
t.Run("Complete progress", func(t *testing.T) {
|
||||
progress := calculateProgress(5) // All 5 steps completed
|
||||
assert.Equal(t, 100, progress)
|
||||
})
|
||||
|
||||
t.Run("Invalid progress", func(t *testing.T) {
|
||||
progress := calculateProgress(10) // More than total steps
|
||||
assert.Equal(t, 100, progress) // Should cap at 100
|
||||
})
|
||||
}
|
||||
|
||||
func TestErrorHandling(t *testing.T) {
|
||||
t.Run("Empty request validation", func(t *testing.T) {
|
||||
err := validateLaunchRequest("", "", "")
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "required")
|
||||
})
|
||||
|
||||
t.Run("Valid request", func(t *testing.T) {
|
||||
err := validateLaunchRequest("example.com", "test@example.com", "4242424242424242")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Invalid domain", func(t *testing.T) {
|
||||
err := validateLaunchRequest("invalid", "test@example.com", "4242424242424242")
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("Invalid email", func(t *testing.T) {
|
||||
err := validateLaunchRequest("example.com", "invalid", "4242424242424242")
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("Invalid card", func(t *testing.T) {
|
||||
err := validateLaunchRequest("example.com", "test@example.com", "invalid")
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
// Helper functions for testing
|
||||
|
||||
func isValidDomain(domain string) bool {
|
||||
if domain == "" || len(domain) > 253 {
|
||||
return false
|
||||
}
|
||||
// Simple validation - in production, use more robust validation
|
||||
return len(domain) > 3 && contains(domain, ".")
|
||||
}
|
||||
|
||||
func isValidEmail(email string) bool {
|
||||
if email == "" || len(email) > 254 {
|
||||
return false
|
||||
}
|
||||
// Simple validation - in production, use more robust validation
|
||||
return contains(email, "@") && contains(email, ".")
|
||||
}
|
||||
|
||||
func isValidCreditCard(cardNumber string) bool {
|
||||
if cardNumber == "" {
|
||||
return false
|
||||
}
|
||||
// Simple validation - in production, use Luhn algorithm and proper card validation
|
||||
return len(cardNumber) >= 13 && len(cardNumber) <= 19 && isNumeric(cardNumber)
|
||||
}
|
||||
|
||||
func contains(s, substr string) bool {
|
||||
return len(s) >= len(substr) && s[len(s)-len(substr):] == substr ||
|
||||
(len(s) > len(substr) && s[:len(substr)] == substr) ||
|
||||
(len(s) > len(substr) && findInString(s, substr))
|
||||
}
|
||||
|
||||
func findInString(s, substr string) bool {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isNumeric(s string) bool {
|
||||
for _, c := range s {
|
||||
if c < '0' || c > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func generateCustomerID() string {
|
||||
// Mock implementation
|
||||
return "cust_" + string(rune(len("test") * 1000))
|
||||
}
|
||||
|
||||
func calculateMonthlyPrice() float64 {
|
||||
return 250.0
|
||||
}
|
||||
|
||||
func calculateYearlyPrice() float64 {
|
||||
return calculateMonthlyPrice() * 12
|
||||
}
|
||||
|
||||
type ProvisioningStep struct {
|
||||
Name string
|
||||
Status string
|
||||
}
|
||||
|
||||
func getProvisioningSteps() []ProvisioningStep {
|
||||
return []ProvisioningStep{
|
||||
{Name: "Domain Registration", Status: "pending"},
|
||||
{Name: "VPS Provisioning", Status: "pending"},
|
||||
{Name: "Cloudron Installation", Status: "pending"},
|
||||
{Name: "DNS Configuration", Status: "pending"},
|
||||
{Name: "Business Setup", Status: "pending"},
|
||||
}
|
||||
}
|
||||
|
||||
func calculateProgress(completedSteps int) int {
|
||||
totalSteps := len(getProvisioningSteps())
|
||||
if completedSteps >= totalSteps {
|
||||
return 100
|
||||
}
|
||||
return (completedSteps * 100) / totalSteps
|
||||
}
|
||||
|
||||
func validateLaunchRequest(domain, email, cardNumber string) error {
|
||||
if domain == "" {
|
||||
return &ValidationError{Message: "domain is required"}
|
||||
}
|
||||
if email == "" {
|
||||
return &ValidationError{Message: "email is required"}
|
||||
}
|
||||
if cardNumber == "" {
|
||||
return &ValidationError{Message: "card number is required"}
|
||||
}
|
||||
if !isValidDomain(domain) {
|
||||
return &ValidationError{Message: "invalid domain"}
|
||||
}
|
||||
if !isValidEmail(email) {
|
||||
return &ValidationError{Message: "invalid email"}
|
||||
}
|
||||
if !isValidCreditCard(cardNumber) {
|
||||
return &ValidationError{Message: "invalid credit card"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ValidationError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *ValidationError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
Reference in New Issue
Block a user