Files
wehub-resource-sync f36e2104d8
tests / ragflow_tests_infinity (push) Has been cancelled
tests / ragflow_tests_elasticsearch (push) Has been cancelled
sep-tests / ragflow_preflight (push) Has been cancelled
sep-tests / ragflow_tests_infinity (push) Has been cancelled
sep-tests / ragflow_tests_elasticsearch (push) Has been cancelled
tests / ragflow_preflight (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:16:49 +08:00

235 lines
8.5 KiB
Go

//
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package dsl
import (
"reflect"
"testing"
)
// TestResetForCanvas_ClearsPerRunState asserts the four top-level
// accumulators are reset to fresh empty slices, matching the Python
// `self.history = []` / `self.retrieval = []` / `self.memory = []`
// and the parent `Graph.reset()` `self.path = []` branches.
func TestResetForCanvas_ClearsPerRunState(t *testing.T) {
in := map[string]any{
"history": []any{"m1", "m2"},
"retrieval": []any{map[string]any{"doc": "x"}},
"memory": []any{"mem"},
"path": []any{"begin", "llm"},
}
got := ResetForCanvas(in)
if v, ok := got["history"].([]any); !ok || len(v) != 0 {
t.Errorf("history = %v (%T), want empty []any", got["history"], got["history"])
}
if v, ok := got["retrieval"].([]any); !ok || len(v) != 0 {
t.Errorf("retrieval = %v (%T), want empty []any", got["retrieval"], got["retrieval"])
}
if v, ok := got["memory"].([]any); !ok || len(v) != 0 {
t.Errorf("memory = %v (%T), want empty []any", got["memory"], got["memory"])
}
if v, ok := got["path"].([]any); !ok || len(v) != 0 {
t.Errorf("path = %v (%T), want empty []any", got["path"], got["path"])
}
}
// TestResetForCanvas_ZeroesSysGlobals walks every Python reset()
// branch for sys.* keys (string/int/float/list/dict/other).
func TestResetForCanvas_ZeroesSysGlobals(t *testing.T) {
in := map[string]any{
"globals": map[string]any{
"sys.query": "hello",
"sys.conversation": 7,
"sys.score": 0.85,
"sys.history": []any{"a", "b"},
"sys.session_meta": map[string]any{"k": "v"},
"sys.unknown_kind": struct{ X int }{X: 1},
"user.preserve_me": "leave alone",
// env.* is reset, not preserved: there is no matching
// variables["preserve_me"] declaration, so the helper
// falls into the "no declared default" branch and
// zeroes the key to "" — matching the Python
// `else: self.globals[k] = ""` line.
"env.preserve_me": "leave alone",
},
}
got := ResetForCanvas(in)
g, ok := got["globals"].(map[string]any)
if !ok {
t.Fatalf("globals missing or wrong type: %T", got["globals"])
}
if g["sys.query"] != "" {
t.Errorf("sys.query = %v, want \"\"", g["sys.query"])
}
// int / float → 0
if v, ok := g["sys.conversation"].(int); !ok || v != 0 {
t.Errorf("sys.conversation = %v (%T), want 0", g["sys.conversation"], g["sys.conversation"])
}
if v, ok := g["sys.score"].(float64); !ok || v != 0 {
t.Errorf("sys.score = %v (%T), want 0", g["sys.score"], g["sys.score"])
}
if v, ok := g["sys.history"].([]any); !ok || len(v) != 0 {
t.Errorf("sys.history = %v (%T), want []any{}", g["sys.history"], g["sys.history"])
}
if v, ok := g["sys.session_meta"].(map[string]any); !ok || len(v) != 0 {
t.Errorf("sys.session_meta = %v (%T), want map[string]any{}", g["sys.session_meta"], g["sys.session_meta"])
}
if g["sys.unknown_kind"] != nil {
t.Errorf("sys.unknown_kind = %v, want nil", g["sys.unknown_kind"])
}
// Non-sys./env. keys must NOT be touched.
if g["user.preserve_me"] != "leave alone" {
t.Errorf("user.preserve_me = %v, want \"leave alone\"", g["user.preserve_me"])
}
// env.preserve_me has no variables["preserve_me"] entry, so it
// falls through to the Python `else: self.globals[k] = ""` line.
if g["env.preserve_me"] != "" {
t.Errorf("env.preserve_me = %v, want \"\"", g["env.preserve_me"])
}
}
// TestResetForCanvas_RestoresEnvFromVariables covers the env.* branch:
// - declared variable with value → globals restored to that value
// - declared variable without value + numeric type → 0
// - declared variable without value + boolean type → false
// - declared variable without value + object type → {}
// - declared variable without value + array type → []
// - declared variable without value + string type → ""
// - undeclared env.* key → ""
func TestResetForCanvas_RestoresEnvFromVariables(t *testing.T) {
in := map[string]any{
"variables": map[string]any{
"with_value": map[string]any{
"type": "string",
"value": "default-val",
},
"numeric": map[string]any{"type": "number"},
"boolean": map[string]any{"type": "boolean"},
"object": map[string]any{"type": "object"},
"arr": map[string]any{"type": "array[string]"},
"str": map[string]any{"type": "string"},
},
"globals": map[string]any{
"env.with_value": "stale",
"env.numeric": 42,
"env.boolean": true,
"env.object": map[string]any{"k": "v"},
"env.arr": []any{"stale"},
"env.str": "stale",
"env.undeclared": "stale",
},
}
got := ResetForCanvas(in)
g := got["globals"].(map[string]any)
if g["env.with_value"] != "default-val" {
t.Errorf("env.with_value = %v, want \"default-val\"", g["env.with_value"])
}
if v, ok := g["env.numeric"].(int); !ok || v != 0 {
t.Errorf("env.numeric = %v (%T), want 0", g["env.numeric"], g["env.numeric"])
}
if v, ok := g["env.boolean"].(bool); !ok || v != false {
t.Errorf("env.boolean = %v (%T), want false", g["env.boolean"], g["env.boolean"])
}
if v, ok := g["env.object"].(map[string]any); !ok || len(v) != 0 {
t.Errorf("env.object = %v (%T), want empty map", g["env.object"], g["env.object"])
}
if v, ok := g["env.arr"].([]any); !ok || len(v) != 0 {
t.Errorf("env.arr = %v (%T), want empty slice", g["env.arr"], g["env.arr"])
}
if v, _ := g["env.str"].(string); v != "" {
t.Errorf("env.str = %v, want \"\"", g["env.str"])
}
if g["env.undeclared"] != "" {
t.Errorf("env.undeclared = %v, want \"\"", g["env.undeclared"])
}
}
// TestResetForCanvas_PreservesGraphAndComponents asserts the
// "anything else in the DSL is left untouched" contract: graph,
// components, and other top-level keys are passed through to the
// returned DSL so a reset is non-destructive on structure.
func TestResetForCanvas_PreservesGraphAndComponents(t *testing.T) {
graph := map[string]any{
"nodes": []any{map[string]any{"id": "begin"}},
"edges": []any{},
}
comps := map[string]any{
"begin": map[string]any{"obj": map[string]any{"component_name": "Begin"}},
}
in := map[string]any{
"graph": graph,
"components": comps,
"messages": []any{"leave me alone"},
"title": "Untouched",
}
got := ResetForCanvas(in)
if !reflect.DeepEqual(got["graph"], graph) {
t.Errorf("graph mutated: got %v, want %v", got["graph"], graph)
}
if !reflect.DeepEqual(got["components"], comps) {
t.Errorf("components mutated: got %v, want %v", got["components"], comps)
}
if !reflect.DeepEqual(got["messages"], []any{"leave me alone"}) {
t.Errorf("messages mutated: got %v", got["messages"])
}
if got["title"] != "Untouched" {
t.Errorf("title = %v, want \"Untouched\"", got["title"])
}
}
// TestResetForCanvas_DefensiveCopy makes sure the input map is not
// mutated. The service layer feeds `row.DSL` straight from GORM into
// ResetForCanvas; mutating that in place would corrupt the entity in
// the calling goroutine and any in-flight readers of the same row.
func TestResetForCanvas_DefensiveCopy(t *testing.T) {
in := map[string]any{
"history": []any{"x"},
"globals": map[string]any{
"sys.query": "hello",
},
}
_ = ResetForCanvas(in)
if v, _ := in["history"].([]any); len(v) != 1 || v[0] != "x" {
t.Errorf("input history mutated: %v", in["history"])
}
if g, _ := in["globals"].(map[string]any); g["sys.query"] != "hello" {
t.Errorf("input globals mutated: %v", g["sys.query"])
}
}
// TestResetForCanvas_NilAndEmptyDSL covers the safe-default branches:
// a nil input returns an empty map, and an input without a globals
// block is passed through without an injected nil/empty globals.
func TestResetForCanvas_NilAndEmptyDSL(t *testing.T) {
if got := ResetForCanvas(nil); got == nil {
t.Errorf("ResetForCanvas(nil) = nil, want non-nil empty map")
}
in := map[string]any{
"graph": map[string]any{"nodes": []any{}},
"components": map[string]any{},
}
got := ResetForCanvas(in)
if _, hasGlobals := got["globals"]; hasGlobals {
t.Errorf("globals key injected: %v", got["globals"])
}
}