Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
403
cloud/maplefile-backend/config/config_test.go
Normal file
403
cloud/maplefile-backend/config/config_test.go
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestValidateProduction_AllValid tests that a fully configured production setup passes validation
|
||||
func TestValidateProduction_AllValid(t *testing.T) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: "production",
|
||||
},
|
||||
JWT: JWTConfig{
|
||||
Secret: "this-is-a-very-secure-secret-key-with-more-than-32-characters",
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Hosts: []string{"cassandra1.prod.example.com:9042"},
|
||||
Keyspace: "maplefile_prod",
|
||||
Username: "admin",
|
||||
Password: "secure_password_123",
|
||||
},
|
||||
S3: S3Config{
|
||||
AccessKey: "AKIAIOSFODNN7EXAMPLE",
|
||||
SecretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
||||
BucketName: "maplefile-production",
|
||||
Endpoint: "https://s3.amazonaws.com",
|
||||
},
|
||||
Mailgun: MailgunConfig{
|
||||
APIKey: "key-1234567890abcdef1234567890abcdef",
|
||||
Domain: "mg.example.com",
|
||||
SenderEmail: "noreply@example.com",
|
||||
},
|
||||
Cache: CacheConfig{
|
||||
Host: "redis.prod.example.com",
|
||||
},
|
||||
Security: SecurityConfig{
|
||||
AllowedOrigins: []string{"https://app.example.com"},
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.ValidateProduction()
|
||||
if err != nil {
|
||||
t.Errorf("Expected valid production config to pass validation, got error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateProduction_MissingJWTSecret tests JWT secret validation
|
||||
func TestValidateProduction_MissingJWTSecret(t *testing.T) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: "production",
|
||||
},
|
||||
JWT: JWTConfig{
|
||||
Secret: "", // Missing
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Hosts: []string{"localhost:9042"},
|
||||
Keyspace: "test",
|
||||
},
|
||||
S3: S3Config{
|
||||
AccessKey: "test",
|
||||
SecretKey: "test",
|
||||
BucketName: "test",
|
||||
Endpoint: "http://localhost:9000",
|
||||
},
|
||||
Mailgun: MailgunConfig{
|
||||
APIKey: "test",
|
||||
Domain: "test.com",
|
||||
SenderEmail: "test@test.com",
|
||||
},
|
||||
Cache: CacheConfig{
|
||||
Host: "localhost",
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.ValidateProduction()
|
||||
if err == nil {
|
||||
t.Error("Expected error for missing JWT_SECRET in production")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "JWT_SECRET is required") {
|
||||
t.Errorf("Expected JWT_SECRET error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateProduction_ShortJWTSecret tests JWT secret length validation
|
||||
func TestValidateProduction_ShortJWTSecret(t *testing.T) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: "production",
|
||||
},
|
||||
JWT: JWTConfig{
|
||||
Secret: "short", // Too short (less than 32 chars)
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Hosts: []string{"localhost:9042"},
|
||||
Keyspace: "test",
|
||||
},
|
||||
S3: S3Config{
|
||||
AccessKey: "test",
|
||||
SecretKey: "test",
|
||||
BucketName: "test",
|
||||
Endpoint: "http://localhost:9000",
|
||||
},
|
||||
Mailgun: MailgunConfig{
|
||||
APIKey: "test",
|
||||
Domain: "test.com",
|
||||
SenderEmail: "test@test.com",
|
||||
},
|
||||
Cache: CacheConfig{
|
||||
Host: "localhost",
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.ValidateProduction()
|
||||
if err == nil {
|
||||
t.Error("Expected error for short JWT_SECRET in production")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "at least 32 characters") {
|
||||
t.Errorf("Expected JWT_SECRET length error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateProduction_MissingS3Credentials tests S3 credential validation
|
||||
func TestValidateProduction_MissingS3Credentials(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
accessKey string
|
||||
secretKey string
|
||||
wantError string
|
||||
}{
|
||||
{
|
||||
name: "missing access key",
|
||||
accessKey: "",
|
||||
secretKey: "valid-secret",
|
||||
wantError: "S3_ACCESS_KEY is required",
|
||||
},
|
||||
{
|
||||
name: "missing secret key",
|
||||
accessKey: "valid-access",
|
||||
secretKey: "",
|
||||
wantError: "S3_SECRET_KEY is required",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: "production",
|
||||
},
|
||||
JWT: JWTConfig{
|
||||
Secret: "this-is-a-very-secure-secret-key-with-more-than-32-characters",
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Hosts: []string{"localhost:9042"},
|
||||
Keyspace: "test",
|
||||
},
|
||||
S3: S3Config{
|
||||
AccessKey: tt.accessKey,
|
||||
SecretKey: tt.secretKey,
|
||||
BucketName: "test",
|
||||
Endpoint: "http://localhost:9000",
|
||||
},
|
||||
Mailgun: MailgunConfig{
|
||||
APIKey: "test",
|
||||
Domain: "test.com",
|
||||
SenderEmail: "test@test.com",
|
||||
},
|
||||
Cache: CacheConfig{
|
||||
Host: "localhost",
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.ValidateProduction()
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for %s in production", tt.name)
|
||||
}
|
||||
if !strings.Contains(err.Error(), tt.wantError) {
|
||||
t.Errorf("Expected error containing '%s', got: %v", tt.wantError, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateProduction_MissingMailgunCredentials tests email service validation
|
||||
func TestValidateProduction_MissingMailgunCredentials(t *testing.T) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: "production",
|
||||
},
|
||||
JWT: JWTConfig{
|
||||
Secret: "this-is-a-very-secure-secret-key-with-more-than-32-characters",
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Hosts: []string{"localhost:9042"},
|
||||
Keyspace: "test",
|
||||
},
|
||||
S3: S3Config{
|
||||
AccessKey: "test",
|
||||
SecretKey: "test",
|
||||
BucketName: "test",
|
||||
Endpoint: "http://localhost:9000",
|
||||
},
|
||||
Mailgun: MailgunConfig{
|
||||
APIKey: "", // Missing
|
||||
Domain: "test.com",
|
||||
SenderEmail: "test@test.com",
|
||||
},
|
||||
Cache: CacheConfig{
|
||||
Host: "localhost",
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.ValidateProduction()
|
||||
if err == nil {
|
||||
t.Error("Expected error for missing MAILGUN_API_KEY in production")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "MAILGUN_API_KEY is required") {
|
||||
t.Errorf("Expected MAILGUN_API_KEY error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateProduction_MissingDatabaseConfig tests database configuration validation
|
||||
func TestValidateProduction_MissingDatabaseConfig(t *testing.T) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: "production",
|
||||
},
|
||||
JWT: JWTConfig{
|
||||
Secret: "this-is-a-very-secure-secret-key-with-more-than-32-characters",
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Hosts: []string{}, // Missing
|
||||
Keyspace: "", // Missing
|
||||
},
|
||||
S3: S3Config{
|
||||
AccessKey: "test",
|
||||
SecretKey: "test",
|
||||
BucketName: "test",
|
||||
Endpoint: "http://localhost:9000",
|
||||
},
|
||||
Mailgun: MailgunConfig{
|
||||
APIKey: "test",
|
||||
Domain: "test.com",
|
||||
SenderEmail: "test@test.com",
|
||||
},
|
||||
Cache: CacheConfig{
|
||||
Host: "localhost",
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.ValidateProduction()
|
||||
if err == nil {
|
||||
t.Error("Expected error for missing database configuration in production")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "DATABASE_HOSTS is required") {
|
||||
t.Errorf("Expected DATABASE_HOSTS error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateProduction_UnsafeOrigins tests CORS wildcard detection
|
||||
func TestValidateProduction_UnsafeOrigins(t *testing.T) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: "production",
|
||||
},
|
||||
JWT: JWTConfig{
|
||||
Secret: "this-is-a-very-secure-secret-key-with-more-than-32-characters",
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Hosts: []string{"localhost:9042"},
|
||||
Keyspace: "test",
|
||||
},
|
||||
S3: S3Config{
|
||||
AccessKey: "test",
|
||||
SecretKey: "test",
|
||||
BucketName: "test",
|
||||
Endpoint: "http://localhost:9000",
|
||||
},
|
||||
Mailgun: MailgunConfig{
|
||||
APIKey: "test",
|
||||
Domain: "test.com",
|
||||
SenderEmail: "test@test.com",
|
||||
},
|
||||
Cache: CacheConfig{
|
||||
Host: "localhost",
|
||||
},
|
||||
Security: SecurityConfig{
|
||||
AllowedOrigins: []string{"*"}, // Unsafe wildcard
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.ValidateProduction()
|
||||
if err == nil {
|
||||
t.Error("Expected error for wildcard CORS origin in production")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "SECURITY_ALLOWED_ORIGINS='*'") {
|
||||
t.Errorf("Expected CORS wildcard warning, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateProduction_MultipleErrors tests that all validation errors are collected
|
||||
func TestValidateProduction_MultipleErrors(t *testing.T) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: "production",
|
||||
},
|
||||
JWT: JWTConfig{
|
||||
Secret: "", // Missing
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Hosts: []string{}, // Missing
|
||||
Keyspace: "", // Missing
|
||||
},
|
||||
S3: S3Config{
|
||||
AccessKey: "", // Missing
|
||||
SecretKey: "", // Missing
|
||||
BucketName: "",
|
||||
Endpoint: "",
|
||||
},
|
||||
Mailgun: MailgunConfig{
|
||||
APIKey: "", // Missing
|
||||
Domain: "",
|
||||
SenderEmail: "",
|
||||
},
|
||||
Cache: CacheConfig{
|
||||
Host: "",
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.ValidateProduction()
|
||||
if err == nil {
|
||||
t.Fatal("Expected multiple validation errors")
|
||||
}
|
||||
|
||||
errorMsg := err.Error()
|
||||
expectedErrors := []string{
|
||||
"JWT_SECRET is required",
|
||||
"DATABASE_HOSTS is required",
|
||||
"DATABASE_KEYSPACE is required",
|
||||
"S3_ACCESS_KEY is required",
|
||||
"S3_SECRET_KEY is required",
|
||||
"S3_BUCKET is required",
|
||||
"S3_ENDPOINT is required",
|
||||
"MAILGUN_API_KEY is required",
|
||||
"MAILGUN_DOMAIN is required",
|
||||
"CACHE_HOST is required",
|
||||
}
|
||||
|
||||
for _, expected := range expectedErrors {
|
||||
if !strings.Contains(errorMsg, expected) {
|
||||
t.Errorf("Expected error message to contain '%s', got: %v", expected, errorMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidate_Development tests that development environments use basic validation
|
||||
func TestValidate_Development(t *testing.T) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: "development",
|
||||
},
|
||||
JWT: JWTConfig{
|
||||
Secret: "dev-secret", // Short secret OK in development
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Hosts: []string{"localhost:9042"},
|
||||
Keyspace: "maplefile_dev",
|
||||
},
|
||||
S3: S3Config{
|
||||
AccessKey: "", // OK in development
|
||||
SecretKey: "", // OK in development
|
||||
BucketName: "test",
|
||||
},
|
||||
}
|
||||
|
||||
// Should not fail with lenient development validation
|
||||
err := cfg.Validate()
|
||||
if err != nil {
|
||||
t.Errorf("Development environment should not require strict validation, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidate_ProductionCallsValidateProduction tests integration
|
||||
func TestValidate_ProductionCallsValidateProduction(t *testing.T) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: "production",
|
||||
},
|
||||
JWT: JWTConfig{
|
||||
Secret: "", // This should trigger production validation
|
||||
},
|
||||
}
|
||||
|
||||
err := cfg.Validate()
|
||||
if err == nil {
|
||||
t.Error("Expected production Validate() to call ValidateProduction() and fail")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "JWT_SECRET is required") {
|
||||
t.Errorf("Expected ValidateProduction error, got: %v", err)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue