WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s

This commit is contained in:
yawan
2026-09-22 16:19:06 +08:00
commit f7fc992f57
3929 changed files with 1006607 additions and 0 deletions
@@ -0,0 +1,109 @@
package workbench
import (
"os"
"strings"
"testing"
"time"
"github.com/google/uuid"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// PostgreSQL distinguishes the conflict target from EXCLUDED; SQLite does not
// reject an unqualified status predicate, so this must execute on PostgreSQL.
func TestPostgresContentFeedbackAcceptanceUpsert(t *testing.T) {
dsn := os.Getenv("WORKBENCH_TEST_POSTGRES_DSN")
if dsn == "" {
t.Skip("WORKBENCH_TEST_POSTGRES_DSN is not set")
}
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
if err != nil {
t.Fatal(err)
}
sqlDB, err := db.DB()
if err != nil {
t.Fatal(err)
}
defer sqlDB.Close()
schema := "wb_memory_test_" + strings.ReplaceAll(uuid.NewString(), "-", "")
if err := db.Exec("CREATE SCHEMA " + schema).Error; err != nil {
t.Fatal(err)
}
defer func() {
if err := db.Exec("DROP SCHEMA " + schema + " CASCADE").Error; err != nil {
t.Error(err)
}
}()
testDSN := dsn + " search_path=" + schema
if strings.Contains(dsn, "://") {
separator := "?"
if strings.Contains(dsn, "?") {
separator = "&"
}
testDSN = dsn + separator + "search_path=" + schema
}
testDB, err := gorm.Open(postgres.Open(testDSN), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
if err != nil {
t.Fatal(err)
}
testSQL, err := testDB.DB()
if err != nil {
t.Fatal(err)
}
defer testSQL.Close()
if err := testDB.AutoMigrate(&Resource{}, &Job{}, &Revision{}, &Event{}, &Consumption{}, &PendingMemory{}); err != nil {
t.Fatal(err)
}
s, ctx, resource, job := feedbackHarnessWithService(t, NewService(testDB))
accept := func() PendingMemory {
t.Helper()
version := resource.Version
if err := s.executeTask(ctx, job, resource, ActionRequest{SegmentID: "segment"}); err != nil {
t.Fatal(err)
}
if err := s.save(ctx, resource, version); err != nil {
t.Fatalf("acceptance must commit with its pending feedback: %v", err)
}
var persisted Resource
if err := testDB.First(&persisted, "id = ?", resource.ID).Error; err != nil {
t.Fatal(err)
}
data, err := decode[TaskData](persisted.Data)
if err != nil || persisted.Version != version+1 || data.Segments[0].Status != "accepted" {
t.Fatalf("acceptance was not persisted atomically: %+v %v", persisted, err)
}
var rows []PendingMemory
if err := testDB.Where("tenant_id = ? AND owner_id = ?", resource.TenantID, resource.OwnerID).Find(&rows).Error; err != nil {
t.Fatal(err)
}
if len(rows) != 1 || rows[0].Content != "开场先说结论,再给案例" {
t.Fatalf("feedback lost or duplicated: %+v", rows)
}
return rows[0]
}
first := accept()
if first.Status != "pending" {
t.Fatalf("initial acceptance did not create pending feedback: %+v", first)
}
if repeated := accept(); repeated.ID != first.ID || !repeated.UpdatedAt.Equal(first.UpdatedAt) {
t.Fatalf("repeat acceptance mutated an existing pending candidate: %+v", repeated)
}
for _, state := range []string{"invalidated", "accepted", "rejected"} {
stamp := time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC)
if err := testDB.Model(&PendingMemory{}).Where("id = ?", first.ID).
Updates(map[string]any{"status": state, "updated_at": stamp}).Error; err != nil {
t.Fatal(err)
}
row := accept()
if state == "invalidated" {
if row.Status != "pending" || !row.UpdatedAt.After(stamp) {
t.Fatalf("reacceptance did not restore invalidated feedback: %+v", row)
}
} else if row.Status != state || !row.UpdatedAt.Equal(stamp) {
t.Fatalf("reacceptance changed explicit %s review: %+v", state, row)
}
}
}