Files
dingtalk-workspace-cli/internal/cli/schema_static_test.go
T
玉澜 225a073d89 fix(cli): close tool search self-review findings
- SearchSubqueries returned a nil candidate slice on the
  decomposed_exact_filtered refusal, so that one strategy encoded
  "candidates":null while every other path encoded []; the refusal now
  carries an empty slice and a marshal assertion pins the wire shape
- the memoized delivery engine was never invalidated: it indexes one
  Catalog generation and caches its source/surface hashes, but
  RegisterSchemaSourceRoot -> resetDeliverySchemaCatalogState left the
  memo installed, so a re-registered root could be served stale hashes.
  Catalog delivery reset now clears it, with a ForTest wrapper and a
  regression test for the rebuild
- dangerous filter Unicode is rejected before the effect vocabulary and
  Catalog product checks, so a control/Bidi character returns
  dangerous_filter_unicode instead of being echoed back through
  invalid_effect; the filter list is an ordered slice, not a map, so the
  reported field name is deterministic
- dws schema help and RFC 5.8 record the path-form boundary: multi-token
  args resolve as a CLI path, a canonical path must stay one argument
- --explain and ToolSearchScoreBreakdown declare that the reported score
  is the raw value while ordering uses the quantized key
- --limit/--candidate-limit help state that 0 means "use the default",
  which was already the behavior but read as an asymmetry against the
  rejected negative values
- bootstrap seeds become named constants and are published in both
  evaluation reports (bootstrap_samples/bootstrap_seed/
  recovery_bootstrap_seed) so an interval is reproducible without
  reading the source
- dingtalk-shared documents the cross-product summary --dry-run flag and
  that its command list is a plan, not business data
2026-08-17 17:21:10 +08:00

98 lines
3.3 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
package cli
import (
"bytes"
"encoding/json"
"strings"
"testing"
"github.com/spf13/cobra"
)
func TestSchemaHelpDocumentsCanonicalAndCLIPathForms(t *testing.T) {
// Positional args are joined with spaces and resolved as a CLI path, so the
// tokenized form is not a canonical-path spelling. Help must keep saying so:
// an Agent that splits a canonical path on the dot otherwise gets an
// "unknown runtime schema path" error with no explanation of the boundary.
long := NewSchemaCommand().Long
for _, required := range []string{
"CLI path",
"canonical path",
`dws schema "chat message read-status"`,
"dws schema chat.query_msg_read_status",
} {
if !strings.Contains(long, required) {
t.Fatalf("schema long help omits the path-form boundary %q:\n%s", required, long)
}
}
}
func TestSchemaUsesDeliveryCatalogWithoutRuntimeLoad(t *testing.T) {
root := &cobra.Command{Use: "dws"}
root.AddCommand(NewSchemaCommand())
var stdout bytes.Buffer
root.SetOut(&stdout)
root.SetArgs([]string{"schema"})
if err := root.Execute(); err != nil {
t.Fatalf("schema execute: %v", err)
}
var payload struct {
Count int `json:"count"`
ToolCount int `json:"tool_count"`
}
if err := json.Unmarshal(stdout.Bytes(), &payload); err != nil {
t.Fatalf("decode schema: %v\n%s", err, stdout.String())
}
loaded := deliverySchemaCatalog()
if payload.Count != len(loaded.Registry.Products) || payload.ToolCount != len(loaded.Index.CanonicalPaths()) {
t.Fatalf("schema counts = %d/%d, want %d/%d", payload.Count, payload.ToolCount, len(loaded.Registry.Products), len(loaded.Index.CanonicalPaths()))
}
}
func TestSchemaAllReturnsCompleteDeliveryLeafSchemas(t *testing.T) {
root := &cobra.Command{Use: "dws"}
root.AddCommand(NewSchemaCommand())
var stdout bytes.Buffer
root.SetOut(&stdout)
root.SetArgs([]string{"schema", "--all"})
if err := root.Execute(); err != nil {
t.Fatalf("schema --all execute: %v", err)
}
var payload map[string]any
if err := json.Unmarshal(stdout.Bytes(), &payload); err != nil {
t.Fatalf("decode schema --all: %v", err)
}
expanded := 0
for _, product := range schemaMapSlice(payload["products"]) {
for _, tool := range schemaMapSlice(product["tools"]) {
if _, ok := tool["parameters"].(map[string]any); !ok {
t.Fatalf("schema --all tool %q has no parameters object", schemaString(tool["canonical_path"]))
}
expanded++
}
}
want := len(deliverySchemaCatalog().Index.CanonicalPaths())
if expanded != want {
t.Fatalf("schema --all tools = %d, want %d", expanded, want)
}
}
func TestWalkLeafCommandsTraversesAnnotatedHiddenSubtree(t *testing.T) {
root := &cobra.Command{Use: "dws"}
group := &cobra.Command{Use: "compat", Hidden: true, Run: func(*cobra.Command, []string) {}}
leaf := &cobra.Command{Use: "legacy", Hidden: true, Run: func(*cobra.Command, []string) {}}
AttachRuntimeSchema(leaf, "compat", "legacy", "test")
group.AddCommand(leaf)
root.AddCommand(group)
var got []*cobra.Command
walkLeafCommands(root, func(command *cobra.Command) { got = append(got, command) })
if len(got) != 1 || got[0] != leaf {
t.Fatalf("walked commands = %#v, want annotated hidden leaf", got)
}
}