Files
Blizzard ec9431bfa4 fix(report): 报告源/产物落 MinIO,去掉 gateway↔mcp-go 本地盘耦合
多机/容器化第一时间断裂的隐患(ARCHITECTURE_REVIEW §7 #1):此前报告
源(reportStore)与 .docx 产物(reportExport/reportRender)都写 mcp-go
本地 SUNDYNIX_REPORTS_DIR,gateway 再按同一路径 c.File 回流——mcp-go
与 gateway 不共享磁盘即断。

- blob 包从 gateway/internal 提到 sundynix-shared/blob,gateway 与 mcp-go
  共用同一 MinIO;新增 PutBytes/GetBytes 走二进制(.docx)。
- mcp-go 注入 blob:report 源/产物优先 Put 到对象存储(键 reports/<id>.{json,docx}),
  导出结果返回 minio://<key>;MinIO 未就绪回退本地盘(单机降级,getSource 兼容旧本地报告)。
- gateway ExportReport 识别 minio:// → GetBytes 流式下载,否则 c.File 本地降级。
- 测试:mcp 本地回落往返单测 + shared/blob 真 MinIO 二进制往返(BLOB_TEST_ENDPOINT 门控)。
  四模块 build 绿,受影响测试全过。
- 附带:go mod tidy 引入 genproto 拆包冲突,四模块统一钉单体 genproto 新版解决
  (注:勿 go work sync,会剪掉 indirect require 回落旧版重现冲突)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 13:29:31 +08:00

58 lines
1.8 KiB
Go

package mcp
import (
"context"
"encoding/json"
"os"
"strings"
"testing"
"github.com/sundynix/sundynix-shared/blob"
"github.com/sundynix/sundynix-shared/contract"
"github.com/sundynix/sundynix-mcp-go/internal/office"
)
// blob 未就绪(MinIO 连不上)时,报告源/产物回落本地盘:
// putSource → getSource 往返一致,putDocx 返回本地路径(非 minio:// 标记)。
// 这是单机/无对象存储的降级路径,必须始终可用。
func TestReport_LocalFallback_WhenBlobNotReady(t *testing.T) {
// 隔离到临时目录,避免污染系统 temp 下的 sundynix-reports。
dir := t.TempDir()
t.Setenv("SUNDYNIX_REPORTS_DIR", dir)
g := &Gateway{blob: &blob.Store{}} // cli=nil → Ready()=false
if g.blob.Ready() {
t.Fatal("裸 blob.Store 应为未就绪")
}
ctx := context.Background()
id := "report_local_fallback"
// 存源 → 取源往返。
src := reportSource{Title: "标题", Sections: []office.Section{{Heading: "H", Body: "B"}}}
data, _ := json.Marshal(src)
if err := g.putSource(ctx, id, data); err != nil {
t.Fatalf("putSource: %v", err)
}
got, err := g.getSource(ctx, id)
if err != nil {
t.Fatalf("getSource: %v", err)
}
var back reportSource
if err := json.Unmarshal(got, &back); err != nil || back.Title != "标题" {
t.Fatalf("源往返不一致: %v / %+v", err, back)
}
// 产物回落本地路径:返回真实路径、无 minio:// 前缀、文件存在。
ref, err := g.putDocx(ctx, id, []byte("PK\x03\x04fake-docx"))
if err != nil {
t.Fatalf("putDocx: %v", err)
}
if strings.HasPrefix(ref, contract.BlobScheme) {
t.Errorf("blob 未就绪不应返回 minio:// 标记,得 %q", ref)
}
if _, serr := os.Stat(ref); serr != nil {
t.Errorf("本地产物应落盘,stat %s: %v", ref, serr)
}
}