From 8b638275b8358700869135d99e172f16ad75cb31 Mon Sep 17 00:00:00 2001 From: skidoodle Date: Sun, 18 Jan 2026 21:19:42 +0100 Subject: [PATCH] fix: unhandled errors Signed-off-by: skidoodle --- internal/app/db.go | 2 +- internal/app/db_test.go | 12 ++++- internal/app/server_test.go | 95 ++++++++++++++++++++++++++-------- internal/app/storage_test.go | 78 +++++++++++++++++++++------- internal/crypto/crypto_test.go | 20 +++++-- 5 files changed, 160 insertions(+), 47 deletions(-) diff --git a/internal/app/db.go b/internal/app/db.go index 6e974ed..317e040 100644 --- a/internal/app/db.go +++ b/internal/app/db.go @@ -27,7 +27,7 @@ func InitDB(storageDir string) (*bbolt.DB, error) { }) if err != nil { - db.Close() + _ = db.Close() return nil, err } diff --git a/internal/app/db_test.go b/internal/app/db_test.go index 2dd0278..b57acd3 100644 --- a/internal/app/db_test.go +++ b/internal/app/db_test.go @@ -17,7 +17,11 @@ func TestInitDB(t *testing.T) { if err != nil { t.Fatalf("InitDB failed: %v", err) } - defer db.Close() + defer func() { + if err := db.Close(); err != nil { + t.Errorf("Failed to close DB: %v", err) + } + }() dbPath := filepath.Join(tmpDir, DBFileName) if _, err := os.Stat(dbPath); os.IsNotExist(err) { @@ -42,7 +46,11 @@ func TestDB_MetadataLifecycle(t *testing.T) { if err != nil { t.Fatal(err) } - defer db.Close() + defer func() { + if err := db.Close(); err != nil { + t.Errorf("Failed to close DB: %v", err) + } + }() app := &App{ Conf: Config{StorageDir: tmpDir, MaxMB: 100}, diff --git a/internal/app/server_test.go b/internal/app/server_test.go index 0565b0e..7f774df 100644 --- a/internal/app/server_test.go +++ b/internal/app/server_test.go @@ -16,13 +16,21 @@ import ( func setupTestApp(t *testing.T) (*App, string) { storageDir := t.TempDir() - os.MkdirAll(filepath.Join(storageDir, TempDirName), 0700) + if err := os.MkdirAll(filepath.Join(storageDir, TempDirName), 0700); err != nil { + t.Fatalf("Failed to create temp dir: %v", err) + } webDir := filepath.Join(storageDir, "web") - os.MkdirAll(webDir, 0700) + if err := os.MkdirAll(webDir, 0700); err != nil { + t.Fatalf("Failed to create web dir: %v", err) + } - os.WriteFile(filepath.Join(webDir, "layout.html"), []byte(`{{define "layout"}}{{template "content" .}}{{end}}`), 0600) - os.WriteFile(filepath.Join(webDir, "home.html"), []byte(`{{define "content"}}OK{{end}}`), 0600) + if err := os.WriteFile(filepath.Join(webDir, "layout.html"), []byte(`{{define "layout"}}{{template "content" .}}{{end}}`), 0600); err != nil { + t.Fatalf("Failed to write layout.html: %v", err) + } + if err := os.WriteFile(filepath.Join(webDir, "home.html"), []byte(`{{define "content"}}OK{{end}}`), 0600); err != nil { + t.Fatalf("Failed to write home.html: %v", err) + } testFS := os.DirFS(webDir) tmpl := ParseTemplates(testFS) @@ -31,7 +39,11 @@ func setupTestApp(t *testing.T) (*App, string) { if err != nil { t.Fatalf("Failed to init db: %v", err) } - t.Cleanup(func() { db.Close() }) + t.Cleanup(func() { + if err := db.Close(); err != nil { + t.Errorf("Failed to close DB: %v", err) + } + }) app := &App{ Conf: Config{ @@ -58,10 +70,17 @@ func TestIntegration_StandardUploadAndDownload(t *testing.T) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - part, _ := writer.CreateFormFile("file", "test.txt") + part, err := writer.CreateFormFile("file", "test.txt") + if err != nil { + t.Fatalf("CreateFormFile failed: %v", err) + } content := []byte("Hello Safebin") - part.Write(content) - writer.Close() + if _, err := part.Write(content); err != nil { + t.Fatalf("Write part failed: %v", err) + } + if err := writer.Close(); err != nil { + t.Fatalf("Writer close failed: %v", err) + } req, _ := http.NewRequest("POST", server.URL+"/", body) req.Header.Set("Content-Type", writer.FormDataContentType()) @@ -70,7 +89,11 @@ func TestIntegration_StandardUploadAndDownload(t *testing.T) { if err != nil { t.Fatalf("Upload request failed: %v", err) } - defer resp.Body.Close() + defer func() { + if err := resp.Body.Close(); err != nil { + t.Errorf("Failed to close response body: %v", err) + } + }() if resp.StatusCode != http.StatusOK { t.Fatalf("Upload failed status: %d", resp.StatusCode) @@ -86,7 +109,11 @@ func TestIntegration_StandardUploadAndDownload(t *testing.T) { if err != nil { t.Fatalf("Download request failed: %v", err) } - defer resp.Body.Close() + defer func() { + if err := resp.Body.Close(); err != nil { + t.Errorf("Failed to close download response body: %v", err) + } + }() if resp.StatusCode != http.StatusOK { t.Fatalf("Download failed status: %d", resp.StatusCode) @@ -119,7 +146,11 @@ func TestIntegration_ChunkedUpload(t *testing.T) { } resp := postForm(t, finishURL, form) - defer resp.Body.Close() + defer func() { + if err := resp.Body.Close(); err != nil { + t.Errorf("Failed to close finish response body: %v", err) + } + }() if resp.StatusCode != http.StatusOK { t.Fatalf("Finish failed: %d", resp.StatusCode) @@ -131,9 +162,14 @@ func TestIntegration_ChunkedUpload(t *testing.T) { slugWithExt := parts[len(parts)-1] downloadURL := fmt.Sprintf("%s/%s", server.URL, slugWithExt) - dlResp, _ := http.Get(downloadURL) + dlResp, err := http.Get(downloadURL) + if err != nil { + t.Fatalf("Download request failed: %v", err) + } dlBytes, _ := io.ReadAll(dlResp.Body) - dlResp.Body.Close() + if err := dlResp.Body.Close(); err != nil { + t.Errorf("Failed to close download response body: %v", err) + } if !bytes.Equal(content, dlBytes) { t.Errorf("Chunked reassembly failed. Want %s, got %s", content, dlBytes) @@ -143,11 +179,22 @@ func TestIntegration_ChunkedUpload(t *testing.T) { func uploadChunk(t *testing.T, baseURL, uid string, idx int, data []byte) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - writer.WriteField("upload_id", uid) - writer.WriteField("index", fmt.Sprintf("%d", idx)) - part, _ := writer.CreateFormFile("chunk", "blob") - part.Write(data) - writer.Close() + if err := writer.WriteField("upload_id", uid); err != nil { + t.Fatalf("WriteField upload_id failed: %v", err) + } + if err := writer.WriteField("index", fmt.Sprintf("%d", idx)); err != nil { + t.Fatalf("WriteField index failed: %v", err) + } + part, err := writer.CreateFormFile("chunk", "blob") + if err != nil { + t.Fatalf("CreateFormFile failed: %v", err) + } + if _, err := part.Write(data); err != nil { + t.Fatalf("Write part failed: %v", err) + } + if err := writer.Close(); err != nil { + t.Fatalf("Writer close failed: %v", err) + } req, _ := http.NewRequest("POST", baseURL+"/upload/chunk", body) req.Header.Set("Content-Type", writer.FormDataContentType()) @@ -155,16 +202,22 @@ func uploadChunk(t *testing.T, baseURL, uid string, idx int, data []byte) { if err != nil || resp.StatusCode != http.StatusOK { t.Fatalf("Chunk %d upload failed: %v", idx, err) } - resp.Body.Close() + if err := resp.Body.Close(); err != nil { + t.Errorf("Failed to close chunk response body: %v", err) + } } func postForm(t *testing.T, url string, fields map[string]string) *http.Response { body := &bytes.Buffer{} writer := multipart.NewWriter(body) for k, v := range fields { - writer.WriteField(k, v) + if err := writer.WriteField(k, v); err != nil { + t.Fatalf("WriteField %s failed: %v", k, err) + } + } + if err := writer.Close(); err != nil { + t.Fatalf("Writer close failed: %v", err) } - writer.Close() req, _ := http.NewRequest("POST", url, body) req.Header.Set("Content-Type", writer.FormDataContentType()) diff --git a/internal/app/storage_test.go b/internal/app/storage_test.go index 5e72409..24463c4 100644 --- a/internal/app/storage_test.go +++ b/internal/app/storage_test.go @@ -13,10 +13,19 @@ import ( func TestCleanup_AbandonedMerge(t *testing.T) { tmpDir := t.TempDir() tmpStorage := filepath.Join(tmpDir, TempDirName) - os.MkdirAll(tmpStorage, 0700) + if err := os.MkdirAll(tmpStorage, 0700); err != nil { + t.Fatalf("MkdirAll failed: %v", err) + } - db, _ := InitDB(tmpDir) - defer db.Close() + db, err := InitDB(tmpDir) + if err != nil { + t.Fatalf("InitDB failed: %v", err) + } + defer func() { + if err := db.Close(); err != nil { + t.Errorf("Failed to close DB: %v", err) + } + }() app := &App{ Conf: Config{StorageDir: tmpDir}, @@ -44,10 +53,19 @@ func TestCleanup_AbandonedMerge(t *testing.T) { func TestCleanup_AbandonedChunks(t *testing.T) { tmpDir := t.TempDir() tmpStorage := filepath.Join(tmpDir, TempDirName) - os.MkdirAll(tmpStorage, 0700) + if err := os.MkdirAll(tmpStorage, 0700); err != nil { + t.Fatalf("MkdirAll failed: %v", err) + } - db, _ := InitDB(tmpDir) - defer db.Close() + db, err := InitDB(tmpDir) + if err != nil { + t.Fatalf("InitDB failed: %v", err) + } + defer func() { + if err := db.Close(); err != nil { + t.Errorf("Failed to close DB: %v", err) + } + }() app := &App{ Conf: Config{StorageDir: tmpDir}, @@ -56,11 +74,17 @@ func TestCleanup_AbandonedChunks(t *testing.T) { } chunkDir := filepath.Join(tmpStorage, "some_upload_id") - os.MkdirAll(chunkDir, 0700) - os.WriteFile(filepath.Join(chunkDir, "0"), []byte("chunk data"), 0600) + if err := os.MkdirAll(chunkDir, 0700); err != nil { + t.Fatalf("MkdirAll chunkDir failed: %v", err) + } + if err := os.WriteFile(filepath.Join(chunkDir, "0"), []byte("chunk data"), 0600); err != nil { + t.Fatalf("WriteFile chunk failed: %v", err) + } oldTime := time.Now().Add(-TempExpiry - time.Hour) - os.Chtimes(chunkDir, oldTime, oldTime) + if err := os.Chtimes(chunkDir, oldTime, oldTime); err != nil { + t.Fatalf("Chtimes failed: %v", err) + } app.CleanTemp(tmpStorage) @@ -71,8 +95,15 @@ func TestCleanup_AbandonedChunks(t *testing.T) { func TestCleanup_ExpiredStorage(t *testing.T) { storageDir := t.TempDir() - db, _ := InitDB(storageDir) - defer db.Close() + db, err := InitDB(storageDir) + if err != nil { + t.Fatalf("InitDB failed: %v", err) + } + defer func() { + if err := db.Close(); err != nil { + t.Errorf("Failed to close DB: %v", err) + } + }() app := &App{ Conf: Config{ @@ -85,9 +116,16 @@ func TestCleanup_ExpiredStorage(t *testing.T) { filename := "large_file_id" path := filepath.Join(storageDir, filename) - f, _ := os.Create(path) - f.Truncate(100 * MegaByte) - f.Close() + f, err := os.Create(path) + if err != nil { + t.Fatalf("Create file failed: %v", err) + } + if err := f.Truncate(100 * MegaByte); err != nil { + t.Fatalf("Truncate failed: %v", err) + } + if err := f.Close(); err != nil { + t.Fatalf("Close file failed: %v", err) + } expiredMeta := FileMeta{ ID: filename, @@ -96,11 +134,13 @@ func TestCleanup_ExpiredStorage(t *testing.T) { ExpiresAt: time.Now().Add(-time.Hour), } - app.DB.Update(func(tx *bbolt.Tx) error { + if err := app.DB.Update(func(tx *bbolt.Tx) error { b := tx.Bucket([]byte(DBBucketName)) data, _ := json.Marshal(expiredMeta) return b.Put([]byte(filename), data) - }) + }); err != nil { + t.Fatalf("DB Update failed: %v", err) + } app.CleanStorage() @@ -108,11 +148,13 @@ func TestCleanup_ExpiredStorage(t *testing.T) { t.Error("Cleanup failed to remove expired large file") } - app.DB.View(func(tx *bbolt.Tx) error { + if err := app.DB.View(func(tx *bbolt.Tx) error { b := tx.Bucket([]byte(DBBucketName)) if v := b.Get([]byte(filename)); v != nil { t.Error("Cleanup failed to remove metadata") } return nil - }) + }); err != nil { + t.Fatalf("DB View failed: %v", err) + } } diff --git a/internal/crypto/crypto_test.go b/internal/crypto/crypto_test.go index 0e9200b..badf90c 100644 --- a/internal/crypto/crypto_test.go +++ b/internal/crypto/crypto_test.go @@ -22,7 +22,9 @@ func TestDeriveKey(t *testing.T) { t.Errorf("Expected key length 16, got %d", len(key1)) } - reader.Seek(0, 0) + if _, err := reader.Seek(0, 0); err != nil { + t.Fatalf("Seek failed: %v", err) + } key2, err := crypto.DeriveKey(reader) if err != nil { t.Fatalf("DeriveKey failed second time: %v", err) @@ -51,10 +53,14 @@ func TestGetID(t *testing.T) { func TestEncryptDecryptStream(t *testing.T) { payloadSize := (64 * 1024) * 3 payload := make([]byte, payloadSize) - rand.Read(payload) + if _, err := rand.Read(payload); err != nil { + t.Fatalf("rand.Read payload failed: %v", err) + } key := make([]byte, 16) - rand.Read(key) + if _, err := rand.Read(key); err != nil { + t.Fatalf("rand.Read key failed: %v", err) + } var encryptedBuf bytes.Buffer streamer, err := crypto.NewGCMStreamer(key) @@ -92,11 +98,15 @@ func TestDecryptorSeeking(t *testing.T) { } key := make([]byte, 16) - rand.Read(key) + if _, err := rand.Read(key); err != nil { + t.Fatalf("rand.Read key failed: %v", err) + } var encryptedBuf bytes.Buffer streamer, _ := crypto.NewGCMStreamer(key) - streamer.EncryptStream(&encryptedBuf, bytes.NewReader(payload)) + if err := streamer.EncryptStream(&encryptedBuf, bytes.NewReader(payload)); err != nil { + t.Fatalf("EncryptStream failed: %v", err) + } r := bytes.NewReader(encryptedBuf.Bytes()) d := crypto.NewDecryptor(r, streamer.AEAD, int64(encryptedBuf.Len()))