Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 75 additions & 5 deletions internal/downloader/downloader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,87 @@ func TestDownloadPhpMyAdmin(t *testing.T) {
}

// Verify the file exists
if _, err := os.Stat(downloadedFilePath); err != nil {
t.Fatalf("expected file to exist, but got error: %v", err)
if _, statErr := os.Stat(downloadedFilePath); statErr != nil {
t.Fatalf("expected file to exist, but got error: %v", statErr)
}

// Verify the file content matches mock data
data, err := os.ReadFile(downloadedFilePath)
if err != nil {
t.Fatalf("failed to read downloaded file: %v", err)
data, readErr := os.ReadFile(downloadedFilePath)
if readErr != nil {
t.Fatalf("failed to read downloaded file: %v", readErr)
}

if string(data) != string(mockZipContent) {
t.Errorf("downloaded file content does not match expected mock content")
}
}

func TestDownloadPhpMyAdmin_FailureScenarios(t *testing.T) {
tests := []struct {
name string
serverFunc func() *httptest.Server
setupDir func() (string, error)
expectErr bool
}{
{
name: "http 500 error",
serverFunc: func() *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
http.Error(w, "internal server error", http.StatusInternalServerError)
}))
},
setupDir: func() (string, error) {
return t.TempDir(), nil
},
expectErr: true,
},
{
name: "directory not writable",
serverFunc: func() *httptest.Server {
content := []byte("PK\x03\x04 dummy zip content")
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/zip")
if _, err := w.Write(content); err != nil {
t.Fatalf("failed to write mock zip content: %v", err)
}
}))
},
setupDir: func() (string, error) {
dir := t.TempDir()
if chmodErr := os.Chmod(dir, 0500); chmodErr != nil {
return "", chmodErr
}
return dir, nil
},
expectErr: true,
},
}

for _, tt := range tests {
tt := tt // capture range variable
t.Run(tt.name, func(t *testing.T) {
server := tt.serverFunc()
defer server.Close()

tempDir, dirErr := tt.setupDir()
if dirErr != nil {
t.Fatalf("failed to setup dir: %v", dirErr)
}
defer func() {
// restore permission so tempdir can be cleaned up
_ = os.Chmod(tempDir, 0700)
}()

version := "5.2.2"
mockDownloadURL := fmt.Sprintf("%s/phpMyAdmin-%s-all-languages.zip", server.URL, version)

_, downloadErr := DownloadPhpMyAdmin(mockDownloadURL, tempDir, version)
if tt.expectErr && downloadErr == nil {
t.Errorf("expected error but got none")
}
if !tt.expectErr && downloadErr != nil {
t.Errorf("unexpected error: %v", downloadErr)
}
})
}
}
52 changes: 40 additions & 12 deletions internal/extractor/extractor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,30 @@ import (
func TestExtractZip(t *testing.T) {
tempDir := t.TempDir()

// Create a test zip file with sample files
// Create test zip file
zipPath := filepath.Join(tempDir, "test.zip")
testFiles := map[string]string{
"folder1/file1.txt": "content1",
"folder2/file2.txt": "content2",
}

if err := createTestZip(t, zipPath, testFiles); err != nil {
t.Fatalf("failed to create test zip: %v", err)
createErr := createTestZip(t, zipPath, testFiles)
if createErr != nil {
t.Fatalf("failed to create test zip: %v", createErr)
}

extractDir := filepath.Join(tempDir, "extracted")

// Execute extraction
if err := ExtractZip(zipPath, extractDir); err != nil {
t.Fatalf("ExtractZip failed: %v", err)
extractErr := ExtractZip(zipPath, extractDir)
if extractErr != nil {
t.Fatalf("ExtractZip failed: %v", extractErr)
}

// Validate that extracted files match expected contents
for name, content := range testFiles {
extractedPath := filepath.Join(extractDir, name)
data, err := os.ReadFile(extractedPath)
if err != nil {
t.Errorf("failed to read extracted file %s: %v", name, err)
data, readErr := os.ReadFile(extractedPath)
if readErr != nil {
t.Errorf("failed to read extracted file %s: %v", name, readErr)
continue
}
if string(data) != content {
Expand All @@ -42,7 +42,35 @@ func TestExtractZip(t *testing.T) {
}
}

// createTestZip creates a zip file at the given path with provided files and contents.
func TestExtractZip_FailureScenarios(t *testing.T) {
tempDir := t.TempDir()

t.Run("file not found", func(t *testing.T) {
invalidPath := filepath.Join(tempDir, "nonexistent.zip")
extractDir := filepath.Join(tempDir, "extracted1")

err := ExtractZip(invalidPath, extractDir)
if err == nil {
t.Errorf("expected error when opening nonexistent file, got nil")
}
})

t.Run("corrupted zip file", func(t *testing.T) {
badZipPath := filepath.Join(tempDir, "bad.zip")
writeErr := os.WriteFile(badZipPath, []byte("not a real zip content"), 0644)
if writeErr != nil {
t.Fatalf("failed to write corrupted zip: %v", writeErr)
}

extractDir := filepath.Join(tempDir, "extracted2")
err := ExtractZip(badZipPath, extractDir)
if err == nil {
t.Errorf("expected error when extracting corrupted zip, got nil")
}
})
}

// Hardening helper - fully linter safe
func createTestZip(t *testing.T, zipPath string, files map[string]string) error {
zipFile, err := os.Create(zipPath)
if err != nil {
Expand All @@ -66,7 +94,7 @@ func createTestZip(t *testing.T, zipPath string, files map[string]string) error
if err != nil {
return err
}
if _, err = writer.Write([]byte(content)); err != nil {
if _, err := writer.Write([]byte(content)); err != nil {
return err
}
}
Expand Down
75 changes: 63 additions & 12 deletions internal/fs/fs_test.go
Original file line number Diff line number Diff line change
@@ -1,67 +1,85 @@
package fs

import (
"fmt"
"os"
"path/filepath"
"testing"
)

func TestCopyFile(t *testing.T) {
var renameFunc = os.Rename

func TestCopyFile_Success(t *testing.T) {
tempDir := t.TempDir()

srcFile := filepath.Join(tempDir, "source.txt")
dstFile := filepath.Join(tempDir, "dest.txt")

content := []byte("test file content")

// Create source file
if err := os.WriteFile(srcFile, content, 0644); err != nil {
t.Fatalf("failed to write source file: %v", err)
}

// Perform copy operation
if err := CopyFile(srcFile, dstFile); err != nil {
t.Fatalf("CopyFile failed: %v", err)
}

// Verify destination file content
read, err := os.ReadFile(dstFile)
if err != nil {
t.Fatalf("failed to read destination file: %v", err)
t.Fatalf("failed to read dest file: %v", err)
}

if string(read) != string(content) {
t.Errorf("content mismatch: expected %q, got %q", content, read)
}
}

func TestMoveDir(t *testing.T) {
func TestCopyFile_FailureScenarios(t *testing.T) {
tempDir := t.TempDir()

t.Run("source does not exist", func(t *testing.T) {
err := CopyFile(filepath.Join(tempDir, "no-source.txt"), filepath.Join(tempDir, "dest.txt"))
if err == nil {
t.Errorf("expected error for missing source file, got nil")
}
})

t.Run("source is not regular file", func(t *testing.T) {
dirPath := filepath.Join(tempDir, "some-dir")
if err := os.Mkdir(dirPath, 0755); err != nil {
t.Fatalf("failed to create dir: %v", err)
}
err := CopyFile(dirPath, filepath.Join(tempDir, "dest.txt"))
if err == nil {
t.Errorf("expected error for non-regular source file, got nil")
}
})
}

func TestMoveDir_Success(t *testing.T) {
tempDir := t.TempDir()

sourceDir := filepath.Join(tempDir, "source")
destDir := filepath.Join(tempDir, "dest")

// Create source directory
if err := os.MkdirAll(sourceDir, 0755); err != nil {
t.Fatalf("failed to create source directory: %v", err)
t.Fatalf("failed to create source dir: %v", err)
}

testFile := filepath.Join(sourceDir, "test.txt")
if err := os.WriteFile(testFile, []byte("move test"), 0644); err != nil {
t.Fatalf("failed to write test file: %v", err)
}

// Perform move operation
if err := MoveDir(sourceDir, destDir); err != nil {
t.Fatalf("MoveDir failed: %v", err)
}

// Verify source directory was removed
if _, err := os.Stat(sourceDir); !os.IsNotExist(err) {
t.Errorf("source directory still exists after move")
t.Errorf("source dir still exists after move")
}

// Verify file was moved correctly
read, err := os.ReadFile(filepath.Join(destDir, "test.txt"))
if err != nil {
t.Fatalf("failed to read moved file: %v", err)
Expand All @@ -71,3 +89,36 @@ func TestMoveDir(t *testing.T) {
t.Errorf("content mismatch: expected 'move test', got %q", string(read))
}
}

// simulate copyDir failure by mocking filepath.Walk (advanced scenario - optional in real pipelines)

func TestMoveDir_FallbackCrossDevice(t *testing.T) {
// here we simulate EXDEV manually to trigger the fallback
tempDir := t.TempDir()

sourceDir := filepath.Join(tempDir, "source")
destDir := filepath.Join(tempDir, "dest")

if err := os.MkdirAll(sourceDir, 0755); err != nil {
t.Fatalf("failed to create source dir: %v", err)
}

testFile := filepath.Join(sourceDir, "test.txt")
if err := os.WriteFile(testFile, []byte("move test"), 0644); err != nil {
t.Fatalf("failed to write test file: %v", err)
}

// replace os.Rename temporarily to simulate EXDEV
originalRename := renameFunc
defer func() { renameFunc = originalRename }()
renameFunc = func(_, _ string) error {
return fmt.Errorf("simulated rename error")
}
if err := MoveDir(sourceDir, destDir); err != nil {
t.Fatalf("MoveDir fallback failed: %v", err)
}

if _, err := os.Stat(sourceDir); !os.IsNotExist(err) {
t.Errorf("source dir still exists after fallback move")
}
}
Loading
Loading