Coverage priorities 1-5: test pure functions, extract interfaces, mock-based handler tests
- Priority 1: Test NewSendEmailTask + NewSendPushTask (5 tests) - Priority 2: Test customHTTPErrorHandler — all 15+ branches (21 tests) - Priority 3: Extract Enqueuer interface + payload builders in worker pkg (5 tests) - Priority 4: Extract ClassifyFile/ComputeRelPath in migrate-encrypt (6 tests) - Priority 5: Define Handler interfaces, refactor to accept them, mock-based tests (14 tests) - Fix .gitignore: /worker instead of worker to stop ignoring internal/worker/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
50
cmd/migrate-encrypt/helpers.go
Normal file
50
cmd/migrate-encrypt/helpers.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// isEncrypted checks if a file path ends with .enc
|
||||
func isEncrypted(path string) bool {
|
||||
return strings.HasSuffix(path, ".enc")
|
||||
}
|
||||
|
||||
// encryptedPath appends .enc to the file path.
|
||||
func encryptedPath(path string) string {
|
||||
return path + ".enc"
|
||||
}
|
||||
|
||||
// shouldProcessFile returns true if the file should be encrypted.
|
||||
func shouldProcessFile(isDir bool, path string) bool {
|
||||
return !isDir && !isEncrypted(path)
|
||||
}
|
||||
|
||||
// FileAction represents the decision about what to do with a file during encryption migration.
|
||||
type FileAction int
|
||||
|
||||
const (
|
||||
ActionSkipDir FileAction = iota // Directory, skip
|
||||
ActionSkipEncrypted // Already encrypted, skip
|
||||
ActionDryRun // Would encrypt (dry run mode)
|
||||
ActionEncrypt // Should encrypt
|
||||
)
|
||||
|
||||
// ClassifyFile determines what action to take for a file during the walk.
|
||||
func ClassifyFile(isDir bool, path string, dryRun bool) FileAction {
|
||||
if isDir {
|
||||
return ActionSkipDir
|
||||
}
|
||||
if isEncrypted(path) {
|
||||
return ActionSkipEncrypted
|
||||
}
|
||||
if dryRun {
|
||||
return ActionDryRun
|
||||
}
|
||||
return ActionEncrypt
|
||||
}
|
||||
|
||||
// ComputeRelPath computes the relative path from base to path.
|
||||
func ComputeRelPath(base, path string) (string, error) {
|
||||
return filepath.Rel(base, path)
|
||||
}
|
||||
96
cmd/migrate-encrypt/helpers_test.go
Normal file
96
cmd/migrate-encrypt/helpers_test.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestIsEncrypted_EncFile_True(t *testing.T) {
|
||||
if !isEncrypted("photo.jpg.enc") {
|
||||
t.Error("expected true for .enc file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsEncrypted_PdfFile_False(t *testing.T) {
|
||||
if isEncrypted("doc.pdf") {
|
||||
t.Error("expected false for .pdf file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsEncrypted_DotEncOnly_True(t *testing.T) {
|
||||
if !isEncrypted(".enc") {
|
||||
t.Error("expected true for '.enc'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptedPath_AppendsDotEnc(t *testing.T) {
|
||||
got := encryptedPath("uploads/photo.jpg")
|
||||
want := "uploads/photo.jpg.enc"
|
||||
if got != want {
|
||||
t.Errorf("got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldProcessFile_RegularFile_True(t *testing.T) {
|
||||
if !shouldProcessFile(false, "photo.jpg") {
|
||||
t.Error("expected true for regular file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldProcessFile_Directory_False(t *testing.T) {
|
||||
if shouldProcessFile(true, "uploads") {
|
||||
t.Error("expected false for directory")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldProcessFile_AlreadyEncrypted_False(t *testing.T) {
|
||||
if shouldProcessFile(false, "photo.jpg.enc") {
|
||||
t.Error("expected false for already encrypted file")
|
||||
}
|
||||
}
|
||||
|
||||
// --- ClassifyFile ---
|
||||
|
||||
func TestClassifyFile_Directory_SkipDir(t *testing.T) {
|
||||
if got := ClassifyFile(true, "uploads", false); got != ActionSkipDir {
|
||||
t.Errorf("got %d, want ActionSkipDir", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClassifyFile_EncryptedFile_SkipEncrypted(t *testing.T) {
|
||||
if got := ClassifyFile(false, "photo.jpg.enc", false); got != ActionSkipEncrypted {
|
||||
t.Errorf("got %d, want ActionSkipEncrypted", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClassifyFile_DryRun_DryRun(t *testing.T) {
|
||||
if got := ClassifyFile(false, "photo.jpg", true); got != ActionDryRun {
|
||||
t.Errorf("got %d, want ActionDryRun", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClassifyFile_Normal_Encrypt(t *testing.T) {
|
||||
if got := ClassifyFile(false, "photo.jpg", false); got != ActionEncrypt {
|
||||
t.Errorf("got %d, want ActionEncrypt", got)
|
||||
}
|
||||
}
|
||||
|
||||
// --- ComputeRelPath ---
|
||||
|
||||
func TestComputeRelPath_Valid(t *testing.T) {
|
||||
got, err := ComputeRelPath("/uploads", "/uploads/photo.jpg")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if got != "photo.jpg" {
|
||||
t.Errorf("got %q, want %q", got, "photo.jpg")
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeRelPath_NestedPath(t *testing.T) {
|
||||
got, err := ComputeRelPath("/uploads", "/uploads/2024/01/photo.jpg")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
want := "2024/01/photo.jpg"
|
||||
if got != want {
|
||||
t.Errorf("got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
@@ -87,13 +86,11 @@ func main() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Skip directories
|
||||
if info.IsDir() {
|
||||
action := ClassifyFile(info.IsDir(), path, *dryRun)
|
||||
switch action {
|
||||
case ActionSkipDir:
|
||||
return nil
|
||||
}
|
||||
|
||||
// Skip files already encrypted
|
||||
if strings.HasSuffix(path, ".enc") {
|
||||
case ActionSkipEncrypted:
|
||||
skipped++
|
||||
return nil
|
||||
}
|
||||
@@ -101,14 +98,14 @@ func main() {
|
||||
totalFiles++
|
||||
|
||||
// Compute the relative path from upload dir
|
||||
relPath, err := filepath.Rel(absUploadDir, path)
|
||||
relPath, err := ComputeRelPath(absUploadDir, path)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Str("path", path).Msg("Failed to compute relative path")
|
||||
errCount++
|
||||
return nil
|
||||
}
|
||||
|
||||
if *dryRun {
|
||||
if action == ActionDryRun {
|
||||
log.Info().Str("file", relPath).Msg("[DRY RUN] Would encrypt")
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user