diff --git a/.gitignore b/.gitignore index fb29651..418d6a6 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ Thumbs.db *.exe *.test *.out + +/test_data/tmp diff --git a/internal/backer/newServer_test.go b/internal/backer/newServer_test.go index d901135..85a65c1 100644 --- a/internal/backer/newServer_test.go +++ b/internal/backer/newServer_test.go @@ -4,6 +4,8 @@ import ( "archive/tar" "compress/gzip" "context" + "crypto/tls" + "errors" "io" "net/http" "net/http/httptest" @@ -11,6 +13,166 @@ import ( "testing" ) +// TestIsTLSError tests the isTLSError function. +func TestIsTLSError(t *testing.T) { + tests := []struct { + name string + err error + expected bool + }{ + { + name: "nil error", + err: nil, + expected: false, + }, + { + name: "regular error", + err: errors.New("some random error"), + expected: false, + }, + { + name: "TLS prefix error", + err: errors.New("tls: handshake failure"), + expected: true, + }, + { + name: "TLS AlertError", + err: tls.AlertError(80), + expected: true, + }, + { + name: "TLS CertificateVerificationError", + err: &tls.CertificateVerificationError{}, + expected: true, + }, + { + name: "TLS ECHRejectionError", + err: &tls.ECHRejectionError{RetryConfigList: []byte("rejected")}, + expected: true, + }, + { + name: "TLS RecordHeaderError", + err: &tls.RecordHeaderError{}, + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := isTLSError(tt.err) + if result != tt.expected { + t.Errorf("isTLSError(%v) = %v, expected %v", tt.err, result, tt.expected) + } + }) + } +} + +// TestGetClientIP tests the getClientIP function. +func TestGetClientIP(t *testing.T) { + tests := []struct { + name string + xffHeader string + remoteAddr string + expectedIP string + }{ + { + name: "no X-Forwarded-For", + xffHeader: "", + remoteAddr: "192.168.1.100:12345", + expectedIP: "192.168.1.100", + }, + { + name: "single IP in X-Forwarded-For", + xffHeader: "10.0.0.1", + remoteAddr: "192.168.1.100:12345", + expectedIP: "10.0.0.1", + }, + { + name: "multiple IPs in X-Forwarded-For", + xffHeader: "10.0.0.1, 192.168.1.100, 172.16.0.1", + remoteAddr: "192.168.1.100:12345", + expectedIP: "10.0.0.1", + }, + { + name: "X-Forwarded-For with spaces", + xffHeader: " 10.0.0.1 , 192.168.1.100 ", + remoteAddr: "192.168.1.100:12345", + expectedIP: "10.0.0.1", + }, + { + name: "invalid RemoteAddr", + xffHeader: "", + remoteAddr: "invalid", + expectedIP: "invalid", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := httptest.NewRequest("GET", "/archive", nil) + if tt.xffHeader != "" { + req.Header.Set("X-Forwarded-For", tt.xffHeader) + } + req.RemoteAddr = tt.remoteAddr + + result := getClientIP(req) + if result != tt.expectedIP { + t.Errorf("getClientIP() = %q, expected %q", result, tt.expectedIP) + } + }) + } +} + +// TestGetCompressionAlgorithm tests the getCompressionAlgorithm function. +func TestGetCompressionAlgorithm(t *testing.T) { + tests := []struct { + name string + ext string + expected string + }{ + { + name: "tar.bz2", + ext: "tar.bz2", + expected: "bzip2", + }, + { + name: "tar.zst", + ext: "tar.zst", + expected: "zstd", + }, + { + name: "tar.lz4", + ext: "tar.lz4", + expected: "lz4", + }, + { + name: "tar.xz", + ext: "tar.xz", + expected: "xz", + }, + { + name: "tar.gz", + ext: "tar.gz", + expected: "pgzip", + }, + { + name: "default with gzip config", + ext: "", + expected: "gzip", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + C = Config{DefaultCompression: "gzip"} + result := getCompressionAlgorithm(tt.ext) + if result != tt.expected { + t.Errorf("getCompressionAlgorithm(%q) = %q, expected %q", tt.ext, result, tt.expected) + } + }) + } +} + // TestNewServerSuccess tests successful server creation. func TestNewServerSuccess(t *testing.T) { C = Config{} // Reset global config. diff --git a/internal/log/main_test.go b/internal/log/main_test.go index bcdbcb0..5a25415 100644 --- a/internal/log/main_test.go +++ b/internal/log/main_test.go @@ -354,4 +354,35 @@ func TestCloseStderr(t *testing.T) { } } +// TestDebugLogger tests that DebugLogger returns a working *log.Logger. +func TestDebugLogger(t *testing.T) { + tmpFile, err := os.CreateTemp(t.TempDir(), "test_log_*.log") + if err != nil { + t.Fatal(err) + } + logFilePath := tmpFile.Name() + tmpFile.Close() + + if err := Init("info", logFilePath); err != nil { + t.Fatal(err) + } + defer Close() + + logger := DebugLogger() + if logger == nil { + t.Error("DebugLogger returned nil") + } + + logger.Print("test debug message") + + content, err := os.ReadFile(logFilePath) + if err != nil { + t.Fatal(err) + } + + if !strings.Contains(string(content), "test debug message") { + t.Error("Expected debug message in log") + } +} + /* vim: setlocal ft=go noet ai ts=4 sw=4 sts=4: */ diff --git a/test_data/test_config.json b/test_data/test_config.json index 693073c..a0b749e 100644 --- a/test_data/test_config.json +++ b/test_data/test_config.json @@ -24,7 +24,7 @@ "password": "SharpShooter", /* Where to store logs. */ - "log": "/var/log/backer.log", + "log": "../../test_data/tmp/backer.log", /* Verbosity of logs */ "loglevel": "info", @@ -39,5 +39,5 @@ "backup_timeout": 60, /* Gzip compression level (1-9, where 9 is best compression). */ - "compression_level": 6 + "compression_level": 3 }