fix: 记录视频上传预览与入口错误

This commit is contained in:
QiuSW
2026-09-30 09:48:11 +08:00
parent 10b5e23d53
commit e0bedd1cd1
3 changed files with 83 additions and 3 deletions
+7 -2
View File
@@ -960,7 +960,12 @@ func (a *App) DownloadVideos(productIDs []string) error {
// GetUploadPreview 只扫描本地磁盘并执行本地预检;批量确认框不发远端请求。
// 单商品保留 R5 首版的覆盖警告,因此额外读取一次远端当前状态。
func (a *App) GetUploadPreview(productIDs []string) (UploadPreview, error) {
func (a *App) GetUploadPreview(productIDs []string) (preview UploadPreview, previewErr error) {
defer func() {
if previewErr != nil && a.log != nil {
a.log.Error("上传预览失败:%s", uploadRequestSummary(previewErr))
}
}()
if a.db == nil {
return UploadPreview{}, fmt.Errorf("数据库未就绪,请查看运行日志")
}
@@ -968,7 +973,7 @@ func (a *App) GetUploadPreview(productIDs []string) (UploadPreview, error) {
if len(ids) == 0 {
return UploadPreview{}, fmt.Errorf("请先勾选要上传的商品")
}
preview := UploadPreview{Total: len(ids)}
preview = UploadPreview{Total: len(ids)}
var single store.Product
for _, productID := range ids {
product, found, err := a.db.GetProduct(productID)
+19 -1
View File
@@ -16,7 +16,12 @@ import (
)
// UploadVideos 只在使用者确认后逐件执行;未决操作只能查询,不能生成新键重放写入。
func (a *App) UploadVideos(productIDs []string) error {
func (a *App) UploadVideos(productIDs []string) (uploadErr error) {
defer func() {
if uploadErr != nil && a.log != nil {
a.log.Error("启动视频上传失败:%s", uploadRequestSummary(uploadErr))
}
}()
if a.db == nil {
return fmt.Errorf("数据库未就绪,请查看运行日志")
}
@@ -221,6 +226,19 @@ func videoCode(err error) string {
return "VIDEO_REQUEST_FAILED"
}
// 上传入口错误只记稳定字段;尤其不要把原始上游响应、请求地址或凭据写入日志。
func uploadRequestSummary(err error) string {
var videoErr *erpgo.VideoError
if errors.As(err, &videoErr) {
return fmt.Sprintf("%s (HTTP %d, requestId=%s)", videoCode(err), videoErr.Status, videoErr.RequestID)
}
var bridgeErr *erpgo.Error
if errors.As(err, &bridgeErr) {
return erpgo.LogSummary(err)
}
return "LOCAL_UPLOAD_ERROR"
}
func safeUploadCode(value string) bool {
if len(value) == 0 || len(value) > 64 {
return false
+57
View File
@@ -7,6 +7,7 @@ import (
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"cmsp/internal/downloader"
@@ -92,3 +93,59 @@ func TestVideoUploadUsesERPGoAndPersistsOutcome(t *testing.T) {
})
}
}
func TestUploadPreviewFailureIsLoggedWithoutKey(t *testing.T) {
const key = "fictional-secret-key"
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w, `{"code":401,"errorCode":"API_KEY_INVALID","requestId":"fictional-request"}`)
}))
defer server.Close()
db, err := store.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
if err := db.UpsertProducts([]store.Product{{ID: "internal-1", ItemID: "123"}}, "2026-09-30 00:00:00"); err != nil {
t.Fatal(err)
}
a := NewApp()
a.db = db
a.cfg.ERPGo.BaseURL, a.cfg.ERPGo.APIKey = server.URL, key
a.cfg.Download.VideoDir = t.TempDir()
a.probe = func(context.Context, string) (downloader.ProbeResult, error) {
return downloader.ProbeResult{Duration: 20, FormatName: "mp4", Width: 640, Height: 480}, nil
}
dir := filepath.Join(a.cfg.Download.VideoDir, "123")
if err := os.MkdirAll(dir, 0700); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "video.mp4"), []byte("fictional-mp4"), 0600); err != nil {
t.Fatal(err)
}
if _, err := a.GetUploadPreview([]string{"internal-1"}); err == nil {
t.Fatal("expected preview failure")
}
entries := a.GetLogs()
if len(entries) != 1 || !strings.Contains(entries[0].Message, "API_KEY_INVALID") || strings.Contains(entries[0].Message, key) {
t.Fatalf("wrong log: %+v", entries)
}
}
func TestUploadStartFailureIsLogged(t *testing.T) {
a := NewApp()
db, err := store.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
a.db = db
if err := a.UploadVideos([]string{"internal-1"}); err == nil {
t.Fatal("expected unconfigured erpgo")
}
entries := a.GetLogs()
if len(entries) != 1 || !strings.Contains(entries[0].Message, "ERPGo_NOT_CONFIGURED") {
t.Fatalf("wrong log: %+v", entries)
}
}