1c80b07f2c
build / build (push) Successful in 1m59s
Dockerfile 运行阶段补齐 dws_dingtalk_scan(F12),并新增 runtime-scripts 门禁 做脚本依赖闭包正负例;就绪探测每次解析当前端点/绑定/凭据并区分 404、未配置、 不可达(F13);路由写入来源路径与父目录,历史空值仅按同连接同 item 的意图读时 补齐(F14);目标筛选显示短 ID 与当前绑定/历史并提供快捷筛选(F15);刷新终态 移除后台运行、展示失败时间/旧快照/脱敏原因/作业 ID 与重试(F16)。 验证:make verify 17 项全过(identity 本地按设计 skipped);一次性 schema 的 Monitor 目录/路由集成用例通过;8088 部署与真实 UI 验收仍由父会话执行。
91 lines
3.3 KiB
Go
91 lines
3.3 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
postgresstore "knowledge-governance/internal/platform/postgres"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
type monitorTasksTestStore struct {
|
|
fakeJobStore
|
|
filter postgresstore.MonitorTaskFilter
|
|
}
|
|
|
|
func (s *monitorTasksTestStore) ListMonitorTasks(_ context.Context, f postgresstore.MonitorTaskFilter) (postgresstore.MonitorTaskPage, error) {
|
|
s.filter = f
|
|
return postgresstore.MonitorTaskPage{Items: []postgresstore.MonitorTask{}, Total: 145, Limit: f.Limit, Offset: f.Offset}, nil
|
|
}
|
|
func TestMonitorTasksRoute(t *testing.T) {
|
|
s := &monitorTasksTestStore{}
|
|
req := httptest.NewRequest("GET", "/api/v1/monitor/tasks?status=active&limit=20&offset=40", nil)
|
|
req = req.WithContext(context.WithValue(req.Context(), sessionKey{}, sessionIdentity{Username: "tester", Role: roleViewer}))
|
|
w := httptest.NewRecorder()
|
|
h, err := NewHandler(Config{Store: s})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
h.ServeHTTP(w, req)
|
|
if w.Code != 200 {
|
|
t.Fatalf("status %d: %s", w.Code, w.Body.String())
|
|
}
|
|
if s.filter.Status != "active" || s.filter.Offset != 40 {
|
|
t.Fatalf("filter %#v", s.filter)
|
|
}
|
|
for _, query := range []string{"status=garbage", "stage=internal&scope=internal", "limit=101", "offset=-1", "since=bad"} {
|
|
r := httptest.NewRequest("GET", "/api/v1/monitor/tasks?"+query, nil).WithContext(req.Context())
|
|
rr := httptest.NewRecorder()
|
|
h.ServeHTTP(rr, r)
|
|
if rr.Code != 400 {
|
|
t.Fatalf("invalid %s: %d", query, rr.Code)
|
|
}
|
|
}
|
|
unauth := httptest.NewRecorder()
|
|
h.ServeHTTP(unauth, httptest.NewRequest("GET", "/api/v1/monitor/tasks", nil))
|
|
if unauth.Code != 401 {
|
|
t.Fatalf("unauthenticated %d", unauth.Code)
|
|
}
|
|
removal := httptest.NewRecorder()
|
|
h.ServeHTTP(removal, httptest.NewRequest("POST", "/api/v1/test-publications/example/removal-retry", nil).WithContext(req.Context()))
|
|
if removal.Code != 403 {
|
|
t.Fatalf("viewer removal %d", removal.Code)
|
|
}
|
|
}
|
|
|
|
// F15:筛选里的“当前绑定”必须来自持久化绑定(与业务同一真源),不是 env 旧值,
|
|
// 也不能让前端拿本页数据猜全局。
|
|
func TestMonitorTasksReportsEffectiveTargetBindings(t *testing.T) {
|
|
store := &monitorTasksTestStore{}
|
|
handler, err := NewHandler(Config{
|
|
Store: store,
|
|
InternalRoutingKnowledgeBaseID: "env-old-internal",
|
|
ExternalRoutingKnowledgeBaseID: "env-old-external",
|
|
RoutingBindings: &bindingStoreFake{internal: "current-internal", external: "current-external"},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
req := httptest.NewRequest("GET", "/api/v1/monitor/tasks?limit=20", nil)
|
|
req = req.WithContext(context.WithValue(req.Context(), sessionKey{}, sessionIdentity{Username: "tester", Role: roleViewer}))
|
|
recorder := httptest.NewRecorder()
|
|
handler.ServeHTTP(recorder, req)
|
|
if recorder.Code != 200 {
|
|
t.Fatalf("status %d: %s", recorder.Code, recorder.Body.String())
|
|
}
|
|
var payload struct {
|
|
Data struct {
|
|
Bindings struct {
|
|
Internal string `json:"internal"`
|
|
External string `json:"external"`
|
|
} `json:"bindings"`
|
|
} `json:"data"`
|
|
}
|
|
if err := json.Unmarshal(recorder.Body.Bytes(), &payload); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if payload.Data.Bindings.Internal != "current-internal" || payload.Data.Bindings.External != "current-external" {
|
|
t.Fatalf("bindings = %#v, want the persisted current bindings", payload.Data.Bindings)
|
|
}
|
|
}
|