上传文档跨端不可访问修复(ISSUE-20260927-upload-doc-cross-device): - 迁移 00076:freeform_documents 增加 source_filename/mime/size_bytes/asset_id - freedoc:Create/Get/List 读写源文件元数据,负值拒绝 - 前端:注册前全部附件先登记 CAS 并预读文本正文;文本正文嵌入注册 markdown;跨端恢复 sourceType/fileMeta 路由回文件预览器 - 大小显示 formatFileSize(<512B 不再显示 0 KB) - E2E 新增 FS-UPLOAD-02 跨浏览器上下文可访问性用例 回归:go vet/arch-check/go test -short(隔离 PG)+ web npm test/build 全绿; 存量无元数据旧文档不可恢复(重新上传即可)。
164 lines
6.0 KiB
Go
164 lines
6.0 KiB
Go
package freedoc_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"chat-agent-system/internal/docrevision"
|
|
"chat-agent-system/internal/freedoc"
|
|
)
|
|
|
|
func TestCreateDocument_ClientKeyIdempotentAndBootstrapsLedger(t *testing.T) {
|
|
ctx := context.Background()
|
|
rev := docrevision.NewService(nil)
|
|
svc := freedoc.NewService(nil, nil)
|
|
svc.SetDocRevision(rev)
|
|
|
|
detail, err := svc.CreateDocument(ctx, 42, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: 7,
|
|
Title: "超声探头规格.pdf",
|
|
ContentMarkdown: "# 超声探头规格\n\n上传正文基线\n",
|
|
Space: "my_private",
|
|
ClientKey: "doc-upload-1789263145197-0",
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, detail)
|
|
assert.True(t, len(detail.Document.DocID) > 0)
|
|
assert.True(t, detail.Document.DocID[:8] == "doc-free" || detail.Document.DocID[:9] == "doc-free-")
|
|
require.NotNil(t, detail.Document.ClientKey)
|
|
assert.Equal(t, "doc-upload-1789263145197-0", *detail.Document.ClientKey)
|
|
assert.Equal(t, "freeform", detail.Document.GovernanceMode)
|
|
// source_content_sha256 must remain content fingerprint — never client_key prefix
|
|
assert.NotContains(t, detail.Document.SourceContentSHA256, "doc-upload")
|
|
assert.NotContains(t, detail.Document.SourceContentSHA256, "client_key")
|
|
assert.Len(t, detail.Document.SourceContentSHA256, 64)
|
|
|
|
st, err := rev.GetRevisionState(ctx, detail.Document.DocID)
|
|
require.NoError(t, err)
|
|
assert.GreaterOrEqual(t, st.CurrentVersionNo, 1)
|
|
|
|
again, err := svc.CreateDocument(ctx, 42, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: 7,
|
|
Title: "超声探头规格.pdf",
|
|
ContentMarkdown: "# 超声探头规格\n\n上传正文基线\n",
|
|
ClientKey: "doc-upload-1789263145197-0",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, detail.Document.DocID, again.Document.DocID)
|
|
|
|
otherUser, err := svc.CreateDocument(ctx, 99, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: 7,
|
|
Title: "他人同名键",
|
|
ContentMarkdown: "# other\n",
|
|
ClientKey: "doc-upload-1789263145197-0",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotEqual(t, detail.Document.DocID, otherUser.Document.DocID)
|
|
}
|
|
|
|
func TestCreateDocument_AcceptsSnowflakeProjectID(t *testing.T) {
|
|
// projects.id is BIGINT; freeform must accept IDs above int4 max (regression: int4 encode 500).
|
|
const snowflakeProjectID int64 = 1789095399489
|
|
svc := freedoc.NewService(nil, nil)
|
|
detail, err := svc.CreateDocument(context.Background(), 42, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: snowflakeProjectID,
|
|
Title: "snowflake.pdf",
|
|
ContentMarkdown: "# snowflake\n",
|
|
Space: "my_private",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, snowflakeProjectID, detail.Document.ProjectID)
|
|
|
|
list, err := svc.ListDocuments(context.Background(), 42, snowflakeProjectID, "my_private")
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 1)
|
|
assert.Equal(t, snowflakeProjectID, list[0].ProjectID)
|
|
}
|
|
|
|
func TestCreateDocument_RejectsEmptyContent(t *testing.T) {
|
|
svc := freedoc.NewService(nil, nil)
|
|
_, err := svc.CreateDocument(context.Background(), 1, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: 1, Title: "x", ContentMarkdown: " ",
|
|
})
|
|
assert.ErrorIs(t, err, freedoc.ErrInvalidParam)
|
|
}
|
|
|
|
func TestCreateDocument_RequiresProjectIDAndPrivateSpace(t *testing.T) {
|
|
svc := freedoc.NewService(nil, nil)
|
|
_, err := svc.CreateDocument(context.Background(), 1, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: 0, Title: "x", ContentMarkdown: "# x\n",
|
|
})
|
|
assert.ErrorIs(t, err, freedoc.ErrInvalidParam)
|
|
assert.Contains(t, err.Error(), "project_id")
|
|
|
|
_, err = svc.CreateDocument(context.Background(), 1, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: 1, Title: "x", ContentMarkdown: "# x\n", Space: "project_shared",
|
|
})
|
|
assert.ErrorIs(t, err, freedoc.ErrInvalidParam)
|
|
assert.Contains(t, err.Error(), "my_private")
|
|
}
|
|
|
|
func TestCreateDocument_PersistsSourceFileMetadata(t *testing.T) {
|
|
ctx := context.Background()
|
|
svc := freedoc.NewService(nil, nil)
|
|
|
|
detail, err := svc.CreateDocument(ctx, 42, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: 7,
|
|
Title: "upload-note",
|
|
ContentMarkdown: "# upload-note\n\n临床需求摘要占位\n",
|
|
Space: "my_private",
|
|
ClientKey: "doc-upload-meta-1",
|
|
SourceFilename: "upload-note.txt",
|
|
SourceMimeType: "text/plain",
|
|
SourceSizeBytes: 41,
|
|
SourceAssetID: 501,
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, detail)
|
|
assert.Equal(t, "upload-note.txt", detail.Document.SourceFilename)
|
|
assert.Equal(t, "text/plain", detail.Document.SourceMimeType)
|
|
assert.EqualValues(t, 41, detail.Document.SourceSizeBytes)
|
|
assert.EqualValues(t, 501, detail.Document.SourceAssetID)
|
|
|
|
// 列表概要同样带出上传元数据(前端跨端恢复预览路由的事实源)。
|
|
list, err := svc.ListDocuments(ctx, 42, 7, "my_private")
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 1)
|
|
assert.Equal(t, "upload-note.txt", list[0].SourceFilename)
|
|
assert.EqualValues(t, 41, list[0].SourceSizeBytes)
|
|
assert.EqualValues(t, 501, list[0].SourceAssetID)
|
|
|
|
// 非上传文档元数据恒为零值,不影响既有编辑器路径。
|
|
plain, err := svc.CreateDocument(ctx, 42, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: 7,
|
|
Title: "plain-note",
|
|
ContentMarkdown: "# plain\n",
|
|
ClientKey: "doc-upload-meta-2",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Empty(t, plain.Document.SourceFilename)
|
|
assert.EqualValues(t, 0, plain.Document.SourceSizeBytes)
|
|
}
|
|
|
|
func TestCreateDocument_RejectsNegativeSourceMetadata(t *testing.T) {
|
|
ctx := context.Background()
|
|
svc := freedoc.NewService(nil, nil)
|
|
_, err := svc.CreateDocument(ctx, 42, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: 7,
|
|
Title: "bad",
|
|
ContentMarkdown: "# bad\n",
|
|
SourceSizeBytes: -1,
|
|
})
|
|
assert.ErrorIs(t, err, freedoc.ErrInvalidParam)
|
|
_, err = svc.CreateDocument(ctx, 42, freedoc.CreateFreeformDocRequest{
|
|
ProjectID: 7,
|
|
Title: "bad",
|
|
ContentMarkdown: "# bad\n",
|
|
SourceAssetID: -5,
|
|
})
|
|
assert.ErrorIs(t, err, freedoc.ErrInvalidParam)
|
|
}
|