mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-08 00:26:37 +08:00
test(upload): move storage task fixtures to in-memory mock
This commit is contained in:
@@ -349,7 +349,6 @@ func TestUploadFile(t *testing.T) {
|
|||||||
func TestDownloadFile(t *testing.T) {
|
func TestDownloadFile(t *testing.T) {
|
||||||
dbConn, cleanup := shared.SetupTestEnv(t)
|
dbConn, cleanup := shared.SetupTestEnv(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
defer func() { _ = os.RemoveAll("uploads") }()
|
|
||||||
|
|
||||||
authUser := &contracts.UserDTO{ID: 1001, Username: "test_user"}
|
authUser := &contracts.UserDTO{ID: 1001, Username: "test_user"}
|
||||||
router := setupTestRouter(authUser)
|
router := setupTestRouter(authUser)
|
||||||
@@ -366,15 +365,10 @@ func TestDownloadFile(t *testing.T) {
|
|||||||
Status: models.UploadStatusUsed,
|
Status: models.UploadStatusUsed,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create local file
|
// Seed file content into the in-memory mock storage service.
|
||||||
err := os.MkdirAll("uploads", 0o755)
|
storageSvc := shared.NewMockStorageService()
|
||||||
if err != nil {
|
storageSvc.PutRaw(localUpload.FilePath, []byte("hello download"))
|
||||||
t.Fatalf("failed to create directory: %v", err)
|
shared.SetStorageService(storageSvc)
|
||||||
}
|
|
||||||
err = os.WriteFile(localUpload.FilePath, []byte("hello download"), 0o644)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to write file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dbConn.Create(&localUpload)
|
dbConn.Create(&localUpload)
|
||||||
|
|
||||||
@@ -557,20 +551,15 @@ func TestListFiles(t *testing.T) {
|
|||||||
func TestBatchDownloadFiles(t *testing.T) {
|
func TestBatchDownloadFiles(t *testing.T) {
|
||||||
dbConn, cleanup := shared.SetupTestEnv(t)
|
dbConn, cleanup := shared.SetupTestEnv(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
defer func() { _ = os.RemoveAll("uploads") }()
|
|
||||||
|
|
||||||
authUser := &contracts.UserDTO{ID: 1001, Username: "test_user"}
|
authUser := &contracts.UserDTO{ID: 1001, Username: "test_user"}
|
||||||
router := setupTestRouter(authUser)
|
router := setupTestRouter(authUser)
|
||||||
|
|
||||||
// Create and write files locally
|
storageSvc := shared.NewMockStorageService()
|
||||||
err := os.MkdirAll("uploads", 0o755)
|
storageSvc.PutRaw("uploads/f1.txt", []byte("file1 content"))
|
||||||
if err != nil {
|
storageSvc.PutRaw("uploads/f2.txt", []byte("file2 content"))
|
||||||
t.Fatalf("failed to create local dir: %v", err)
|
storageSvc.PutRaw("uploads/f3.txt", []byte("duplicate name file content"))
|
||||||
}
|
shared.SetStorageService(storageSvc)
|
||||||
|
|
||||||
_ = os.WriteFile("uploads/f1.txt", []byte("file1 content"), 0o644)
|
|
||||||
_ = os.WriteFile("uploads/f2.txt", []byte("file2 content"), 0o644)
|
|
||||||
_ = os.WriteFile("uploads/f3.txt", []byte("duplicate name file content"), 0o644)
|
|
||||||
|
|
||||||
// Seed upload records. Note f2 and f3 have the same FileName "file_a.txt" to trigger name collision resolution.
|
// Seed upload records. Note f2 and f3 have the same FileName "file_a.txt" to trigger name collision resolution.
|
||||||
uploads := []models.Upload{
|
uploads := []models.Upload{
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -128,13 +126,16 @@ func (m *MockStorageService) Put(_ context.Context, key string, body io.Reader,
|
|||||||
return contracts.StoragePutResult{}, err
|
return contracts.StoragePutResult{}, err
|
||||||
}
|
}
|
||||||
m.objects[key] = data
|
m.objects[key] = data
|
||||||
if strings.HasPrefix(key, "uploads/") {
|
|
||||||
_ = os.MkdirAll(filepath.Dir(key), 0o755)
|
|
||||||
_ = os.WriteFile(key, data, 0o644)
|
|
||||||
}
|
|
||||||
return contracts.StoragePutResult{Key: key, Bucket: "test-bucket"}, nil
|
return contracts.StoragePutResult{Key: key, Bucket: "test-bucket"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PutRaw seeds an object directly into the in-memory store (test helper, no I/O).
|
||||||
|
func (m *MockStorageService) PutRaw(key string, data []byte) {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
m.objects[key] = data
|
||||||
|
}
|
||||||
|
|
||||||
// Get retrieves an object from mock storage.
|
// Get retrieves an object from mock storage.
|
||||||
func (m *MockStorageService) Get(_ context.Context, key string) (*contracts.StorageObject, error) {
|
func (m *MockStorageService) Get(_ context.Context, key string) (*contracts.StorageObject, error) {
|
||||||
m.mu.RLock()
|
m.mu.RLock()
|
||||||
@@ -148,15 +149,6 @@ func (m *MockStorageService) Get(_ context.Context, key string) (*contracts.Stor
|
|||||||
ContentType: "application/octet-stream",
|
ContentType: "application/octet-stream",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
if f, err := os.Open(key); err == nil {
|
|
||||||
info, _ := f.Stat()
|
|
||||||
return &contracts.StorageObject{
|
|
||||||
Key: key,
|
|
||||||
Body: f,
|
|
||||||
ContentLength: info.Size(),
|
|
||||||
ContentType: "application/octet-stream",
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return nil, gorm.ErrRecordNotFound
|
return nil, gorm.ErrRecordNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,38 +7,35 @@ import (
|
|||||||
"Wavelet/core/contracts"
|
"Wavelet/core/contracts"
|
||||||
"Wavelet/plugins/domain/upload/models"
|
"Wavelet/plugins/domain/upload/models"
|
||||||
"Wavelet/plugins/domain/upload/shared"
|
"Wavelet/plugins/domain/upload/shared"
|
||||||
|
"Wavelet/plugins/domain/upload/storage"
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
uploadstorage "Wavelet/plugins/domain/upload/storage"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMigrationHandlerExecute(t *testing.T) {
|
func TestMigrationHandlerExecute(t *testing.T) {
|
||||||
dbConn, cleanup := shared.SetupTestEnv(t)
|
dbConn, cleanup := shared.SetupTestEnv(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
sourceRoot := t.TempDir()
|
ctx := context.Background()
|
||||||
sourcePath := filepath.Join(sourceRoot, "uploads", "test.txt")
|
storageSvc, ok := shared.GetStorage(ctx).(*shared.MockStorageService)
|
||||||
if err := os.MkdirAll(filepath.Dir(sourcePath), 0o755); err != nil {
|
if !ok {
|
||||||
t.Fatalf("MkdirAll(%q) returned error: %v", sourcePath, err)
|
t.Fatalf("shared.GetStorage(%T) returned %T, want *shared.MockStorageService", ctx, storageSvc)
|
||||||
}
|
|
||||||
const content = "storage migration"
|
|
||||||
if err := os.WriteFile(sourcePath, []byte(content), 0o644); err != nil {
|
|
||||||
t.Fatalf("WriteFile(%q) returned error: %v", sourcePath, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
const sourcePath = "uploads/test.txt"
|
||||||
|
const content = "storage migration"
|
||||||
|
storageSvc.PutRaw(sourcePath, []byte(content))
|
||||||
|
|
||||||
active := contracts.StorageConfigDTO{
|
active := contracts.StorageConfigDTO{
|
||||||
Driver: contracts.StorageDriverLocal,
|
Driver: contracts.StorageDriverLocal,
|
||||||
Local: contracts.LocalStorageConfigDTO{Root: sourceRoot},
|
Local: contracts.LocalStorageConfigDTO{Root: "unit"},
|
||||||
}
|
}
|
||||||
if err := uploadstorage.SaveActiveConfig(ctx, active); err != nil {
|
if err := storage.SaveActiveConfig(ctx, active); err != nil {
|
||||||
t.Fatalf("SaveActiveConfig() returned error: %v", err)
|
t.Fatalf("SaveActiveConfig() returned error: %v", err)
|
||||||
}
|
}
|
||||||
target := contracts.StorageConfigDTO{
|
target := contracts.StorageConfigDTO{
|
||||||
@@ -85,7 +82,7 @@ func TestMigrationHandlerExecute(t *testing.T) {
|
|||||||
if err := dbConn.First(&migrated, upload.ID).Error; err != nil {
|
if err := dbConn.First(&migrated, upload.ID).Error; err != nil {
|
||||||
t.Fatalf("First(upload) returned error: %v", err)
|
t.Fatalf("First(upload) returned error: %v", err)
|
||||||
}
|
}
|
||||||
current, err := uploadstorage.LoadStorageConfig(ctx)
|
current, err := storage.LoadStorageConfig(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("LoadStorageConfig() returned error: %v", err)
|
t.Fatalf("LoadStorageConfig() returned error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -98,30 +95,28 @@ func TestMigrationHandlerExecuteWithHashValidation(t *testing.T) {
|
|||||||
dbConn, cleanup := shared.SetupTestEnv(t)
|
dbConn, cleanup := shared.SetupTestEnv(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
sourceRoot := t.TempDir()
|
ctx := context.Background()
|
||||||
sourcePath := filepath.Join(sourceRoot, "uploads", "test-hash.txt")
|
storageSvc, ok := shared.GetStorage(ctx).(*shared.MockStorageService)
|
||||||
if err := os.MkdirAll(filepath.Dir(sourcePath), 0o755); err != nil {
|
if !ok {
|
||||||
t.Fatalf("MkdirAll(%q) returned error: %v", sourcePath, err)
|
t.Fatalf("shared.GetStorage(%T) returned %T, want *shared.MockStorageService", ctx, storageSvc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sourcePath = "uploads/test-hash.txt"
|
||||||
const content = "storage migration integrity check content"
|
const content = "storage migration integrity check content"
|
||||||
if err := os.WriteFile(sourcePath, []byte(content), 0o644); err != nil {
|
storageSvc.PutRaw(sourcePath, []byte(content))
|
||||||
t.Fatalf("WriteFile(%q) returned error: %v", sourcePath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate correct SHA-256 hash
|
// Calculate correct SHA-256 hash
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
h.Write([]byte(content))
|
h.Write([]byte(content))
|
||||||
correctHash := hex.EncodeToString(h.Sum(nil))
|
correctHash := hex.EncodeToString(h.Sum(nil))
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
active := contracts.StorageConfigDTO{
|
active := contracts.StorageConfigDTO{
|
||||||
Driver: contracts.StorageDriverLocal,
|
Driver: contracts.StorageDriverLocal,
|
||||||
Local: contracts.LocalStorageConfigDTO{Root: sourceRoot},
|
Local: contracts.LocalStorageConfigDTO{Root: "unit"},
|
||||||
}
|
}
|
||||||
if err := uploadstorage.SaveActiveConfig(ctx, active); err != nil {
|
if err := storage.SaveActiveConfig(ctx, active); err != nil {
|
||||||
t.Fatalf("SaveActiveConfig() returned error: %v", err)
|
t.Fatalf("SaveActiveConfig() returned error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
target := contracts.StorageConfigDTO{
|
target := contracts.StorageConfigDTO{
|
||||||
Driver: contracts.StorageDriverS3,
|
Driver: contracts.StorageDriverS3,
|
||||||
S3: contracts.ObjectStorageConfigDTO{
|
S3: contracts.ObjectStorageConfigDTO{
|
||||||
@@ -200,7 +195,7 @@ func TestMigrationHandlerExecuteWithLock(t *testing.T) {
|
|||||||
active := contracts.StorageConfigDTO{
|
active := contracts.StorageConfigDTO{
|
||||||
Driver: contracts.StorageDriverLocal,
|
Driver: contracts.StorageDriverLocal,
|
||||||
}
|
}
|
||||||
if err := uploadstorage.SaveActiveConfig(ctx, active); err != nil {
|
if err := storage.SaveActiveConfig(ctx, active); err != nil {
|
||||||
t.Fatalf("SaveActiveConfig() returned error: %v", err)
|
t.Fatalf("SaveActiveConfig() returned error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import (
|
|||||||
|
|
||||||
// 上传域任务的通用元数据常量(TaskMetaDTO Category/Queue 复用)
|
// 上传域任务的通用元数据常量(TaskMetaDTO Category/Queue 复用)
|
||||||
const (
|
const (
|
||||||
taskCategoryUpload = "upload"
|
taskCategoryUpload = "upload"
|
||||||
taskQueueDefault = "default"
|
taskQueueDefault = "default"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -7,14 +7,13 @@ import (
|
|||||||
"Wavelet/plugins/domain/upload/filesrv"
|
"Wavelet/plugins/domain/upload/filesrv"
|
||||||
"Wavelet/plugins/domain/upload/models"
|
"Wavelet/plugins/domain/upload/models"
|
||||||
"Wavelet/plugins/domain/upload/shared"
|
"Wavelet/plugins/domain/upload/shared"
|
||||||
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/png"
|
"image/png"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -160,11 +159,19 @@ func TestWarmImageCacheHandlerExecute(t *testing.T) {
|
|||||||
dbConn, cleanup := shared.SetupTestEnv(t)
|
dbConn, cleanup := shared.SetupTestEnv(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
testDir := t.TempDir()
|
ctx := context.Background()
|
||||||
firstPath := filepath.Join(testDir, "first.png")
|
|
||||||
secondPath := filepath.Join(testDir, "second.jpg")
|
firstPath := "uploads/first.png"
|
||||||
writeTaskTestPNG(t, firstPath, color.RGBA{R: 255, A: 255})
|
secondPath := "uploads/second.jpg"
|
||||||
writeTaskTestPNG(t, secondPath, color.RGBA{G: 255, A: 255})
|
firstData := writeTaskTestPNG(t, color.RGBA{R: 255, A: 255})
|
||||||
|
secondData := writeTaskTestPNG(t, color.RGBA{G: 255, A: 255})
|
||||||
|
|
||||||
|
storageSvc, ok := shared.GetStorage(ctx).(*shared.MockStorageService)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("shared.GetStorage(%T) returned %T, want *shared.MockStorageService", ctx, storageSvc)
|
||||||
|
}
|
||||||
|
storageSvc.PutRaw(firstPath, firstData)
|
||||||
|
storageSvc.PutRaw(secondPath, secondData)
|
||||||
|
|
||||||
records := []models.Upload{
|
records := []models.Upload{
|
||||||
{
|
{
|
||||||
@@ -172,8 +179,11 @@ func TestWarmImageCacheHandlerExecute(t *testing.T) {
|
|||||||
UserID: 1001,
|
UserID: 1001,
|
||||||
FileName: "first.png",
|
FileName: "first.png",
|
||||||
FilePath: firstPath,
|
FilePath: firstPath,
|
||||||
|
FileSize: int64(len(firstData)),
|
||||||
MimeType: "image/png",
|
MimeType: "image/png",
|
||||||
Extension: "png",
|
Extension: "png",
|
||||||
|
Hash: "hash1",
|
||||||
|
Type: "attachment",
|
||||||
Status: models.UploadStatusUsed,
|
Status: models.UploadStatusUsed,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -181,17 +191,23 @@ func TestWarmImageCacheHandlerExecute(t *testing.T) {
|
|||||||
UserID: 1001,
|
UserID: 1001,
|
||||||
FileName: "second.jpg",
|
FileName: "second.jpg",
|
||||||
FilePath: secondPath,
|
FilePath: secondPath,
|
||||||
|
FileSize: int64(len(secondData)),
|
||||||
MimeType: "application/octet-stream",
|
MimeType: "application/octet-stream",
|
||||||
Extension: "jpg",
|
Extension: "jpg",
|
||||||
|
Hash: "hash2",
|
||||||
|
Type: "attachment",
|
||||||
Status: models.UploadStatusPending,
|
Status: models.UploadStatusPending,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 4103,
|
ID: 4103,
|
||||||
UserID: 1001,
|
UserID: 1001,
|
||||||
FileName: "notes.txt",
|
FileName: "notes.txt",
|
||||||
FilePath: filepath.Join(testDir, "notes.txt"),
|
FilePath: "uploads/notes.txt",
|
||||||
|
FileSize: 123,
|
||||||
MimeType: "text/plain",
|
MimeType: "text/plain",
|
||||||
Extension: "txt",
|
Extension: "txt",
|
||||||
|
Hash: "hash3",
|
||||||
|
Type: "attachment",
|
||||||
Status: models.UploadStatusUsed,
|
Status: models.UploadStatusUsed,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -199,15 +215,16 @@ func TestWarmImageCacheHandlerExecute(t *testing.T) {
|
|||||||
UserID: 1001,
|
UserID: 1001,
|
||||||
FileName: "deleted.png",
|
FileName: "deleted.png",
|
||||||
FilePath: firstPath,
|
FilePath: firstPath,
|
||||||
|
FileSize: int64(len(firstData)),
|
||||||
MimeType: "image/png",
|
MimeType: "image/png",
|
||||||
Extension: "png",
|
Extension: "png",
|
||||||
|
Hash: "hash4",
|
||||||
|
Type: "attachment",
|
||||||
Status: models.UploadStatusDeleted,
|
Status: models.UploadStatusDeleted,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range records {
|
for i := range records {
|
||||||
if info, err := os.Stat(records[i].FilePath); err == nil {
|
|
||||||
records[i].FileSize = info.Size()
|
|
||||||
}
|
|
||||||
if err := dbConn.Create(&records[i]).Error; err != nil {
|
if err := dbConn.Create(&records[i]).Error; err != nil {
|
||||||
t.Fatalf("failed to create upload %d: %v", records[i].ID, err)
|
t.Fatalf("failed to create upload %d: %v", records[i].ID, err)
|
||||||
}
|
}
|
||||||
@@ -216,7 +233,7 @@ func TestWarmImageCacheHandlerExecute(t *testing.T) {
|
|||||||
handler := &WarmImageCacheHandler{}
|
handler := &WarmImageCacheHandler{}
|
||||||
payload := []byte(`{"quality":"low"}`)
|
payload := []byte(`{"quality":"low"}`)
|
||||||
|
|
||||||
result, err := handler.Execute(context.Background(), payload)
|
result, err := handler.Execute(ctx, payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Execute(%s) returned error: %v", payload, err)
|
t.Fatalf("Execute(%s) returned error: %v", payload, err)
|
||||||
}
|
}
|
||||||
@@ -242,16 +259,17 @@ func TestWarmImageCacheHandlerExecute(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
secondResult, err := handler.Execute(context.Background(), payload)
|
secondResult, err := handler.Execute(ctx, payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("second Execute(%s) returned error: %v", payload, err)
|
t.Fatalf("second Execute(%s) returned error: %v", payload, err)
|
||||||
}
|
}
|
||||||
if secondResult.Message != "图片缓存预热完成,共处理 2 张,生成 0 张,命中 2 张,失败 0 张" {
|
if secondResult.Message != "图片缓存预热完成,共处理 2 张,生成 0 张,命中 2 张,失败 0 张" {
|
||||||
t.Errorf("second Execute() message = %q, want cache-hit summary", secondResult.Message)
|
t.Errorf("second Execute() message = %q, want cache-hit summary", secondResult.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeTaskTestPNG(t *testing.T, path string, fill color.RGBA) {
|
func writeTaskTestPNG(t *testing.T, fill color.RGBA) []byte {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
img := image.NewRGBA(image.Rect(0, 0, 2, 2))
|
img := image.NewRGBA(image.Rect(0, 0, 2, 2))
|
||||||
@@ -265,7 +283,6 @@ func writeTaskTestPNG(t *testing.T, path string, fill color.RGBA) {
|
|||||||
if err := png.Encode(&buf, img); err != nil {
|
if err := png.Encode(&buf, img); err != nil {
|
||||||
t.Fatalf("png.Encode() returned error: %v", err)
|
t.Fatalf("png.Encode() returned error: %v", err)
|
||||||
}
|
}
|
||||||
if err := os.WriteFile(path, buf.Bytes(), 0o600); err != nil {
|
|
||||||
t.Fatalf("os.WriteFile(%q) returned error: %v", path, err)
|
return buf.Bytes()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import (
|
|||||||
|
|
||||||
var db *gorm.DB
|
var db *gorm.DB
|
||||||
|
|
||||||
|
const sqliteDirMode = 0o750
|
||||||
|
|
||||||
// InitDB 初始化主数据库实例(支持 PostgreSQL / SQLite)
|
// InitDB 初始化主数据库实例(支持 PostgreSQL / SQLite)
|
||||||
func InitDB() (*gorm.DB, error) {
|
func InitDB() (*gorm.DB, error) {
|
||||||
if !config.Config.Database.Enabled {
|
if !config.Config.Database.Enabled {
|
||||||
@@ -43,7 +45,7 @@ func initSQLite() (*gorm.DB, error) {
|
|||||||
|
|
||||||
if sqlitePath != ":memory:" && !strings.HasPrefix(sqlitePath, "file:") {
|
if sqlitePath != ":memory:" && !strings.HasPrefix(sqlitePath, "file:") {
|
||||||
if dir := filepath.Dir(sqlitePath); dir != "" && dir != "." {
|
if dir := filepath.Dir(sqlitePath); dir != "" && dir != "." {
|
||||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
if err := os.MkdirAll(dir, sqliteDirMode); err != nil {
|
||||||
return nil, fmt.Errorf("create sqlite directory %q failed: %w", dir, err)
|
return nil, fmt.Errorf("create sqlite directory %q failed: %w", dir, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user