159 lines
4.7 KiB
Go
159 lines
4.7 KiB
Go
package openrouter
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/fs"
|
|
"path"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
func TestCatalogLayoutAndContents(t *testing.T) {
|
|
assets := FS()
|
|
if assets == nil {
|
|
t.Fatal("FS returned nil")
|
|
}
|
|
backendPath := Root + "/backend.yml"
|
|
backendData, err := fs.ReadFile(assets, backendPath)
|
|
if err != nil {
|
|
t.Fatalf("read backend: %v", err)
|
|
}
|
|
assertBackend(t, backendData)
|
|
|
|
profilesRoot := Root + "/profiles"
|
|
ids := make(map[string]string)
|
|
err = fs.WalkDir(assets, Root, func(assetPath string, entry fs.DirEntry, walkErr error) error {
|
|
if walkErr != nil {
|
|
return walkErr
|
|
}
|
|
if assetPath == Root || assetPath == profilesRoot || entry.IsDir() {
|
|
return nil
|
|
}
|
|
if assetPath == backendPath {
|
|
if !entry.Type().IsRegular() {
|
|
return fmt.Errorf("backend asset is not a regular file")
|
|
}
|
|
return nil
|
|
}
|
|
if !strings.HasPrefix(assetPath, profilesRoot+"/") {
|
|
return fmt.Errorf("unexpected catalog entry %q", assetPath)
|
|
}
|
|
if !entry.Type().IsRegular() || !strings.HasSuffix(assetPath, ".yml") {
|
|
return fmt.Errorf("profile asset %q is not a regular .yml file", assetPath)
|
|
}
|
|
data, err := fs.ReadFile(assets, assetPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
id := assertProfile(t, assetPath, data)
|
|
if previous, found := ids[id]; found {
|
|
return fmt.Errorf("duplicate profile ID %q in %s and %s", id, previous, assetPath)
|
|
}
|
|
ids[id] = assetPath
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("validate catalog layout: %v", err)
|
|
}
|
|
if len(ids) != 36 {
|
|
t.Fatalf("profile inventory changed: got %d, want 36", len(ids))
|
|
}
|
|
}
|
|
|
|
func assertBackend(t *testing.T, data []byte) {
|
|
t.Helper()
|
|
root := decodeMapping(t, "backend", data)
|
|
backends := requireSingleMapping(t, "backend", root, "backends")
|
|
if len(backends) != 1 || backends["openrouter"] == nil {
|
|
t.Fatalf("backend asset must define only openrouter: %v", backends)
|
|
}
|
|
definition := mappingFields(t, "backend", backends["openrouter"])
|
|
for field, want := range map[string]string{
|
|
"endpoint": "https://openrouter.ai/api/v1", "api_key_env": "OPENROUTER_API_KEY",
|
|
"concurrency_limit": "16", "queue_capacity": "1024",
|
|
} {
|
|
value := definition[field]
|
|
if value == nil || value.Value != want {
|
|
t.Fatalf("backend %s: got %v, want %q", field, value, want)
|
|
}
|
|
}
|
|
if len(definition) != 4 {
|
|
t.Fatalf("unexpected backend fields: %v", definition)
|
|
}
|
|
}
|
|
|
|
func assertProfile(t *testing.T, assetPath string, data []byte) string {
|
|
t.Helper()
|
|
root := decodeMapping(t, assetPath, data)
|
|
profiles := requireSingleMapping(t, assetPath, root, "profiles")
|
|
if len(profiles) != 1 {
|
|
t.Fatalf("profile asset %s must define exactly one ID", assetPath)
|
|
}
|
|
for id, entry := range profiles {
|
|
if id == "" || id != strings.TrimSuffix(path.Base(assetPath), ".yml") {
|
|
t.Fatalf("profile asset %s has unexpected ID %q", assetPath, id)
|
|
}
|
|
fields := mappingFields(t, assetPath, entry)
|
|
if fields["backend"] == nil || fields["backend"].Value != "openrouter" {
|
|
t.Fatalf("profile %s does not select openrouter", assetPath)
|
|
}
|
|
if fields["model"] == nil || strings.TrimSpace(fields["model"].Value) == "" {
|
|
t.Fatalf("profile %s has no model", assetPath)
|
|
}
|
|
for _, obsolete := range []string{"id", "base_profile"} {
|
|
if fields[obsolete] != nil {
|
|
t.Fatalf("profile %s contains obsolete %s field", assetPath, obsolete)
|
|
}
|
|
}
|
|
return id
|
|
}
|
|
panic("unreachable")
|
|
}
|
|
|
|
func decodeMapping(t *testing.T, name string, data []byte) *yaml.Node {
|
|
t.Helper()
|
|
decoder := yaml.NewDecoder(bytes.NewReader(data))
|
|
var document yaml.Node
|
|
if err := decoder.Decode(&document); err != nil {
|
|
t.Fatalf("decode %s: %v", name, err)
|
|
}
|
|
var trailing yaml.Node
|
|
if err := decoder.Decode(&trailing); !errors.Is(err, io.EOF) {
|
|
t.Fatalf("%s must contain exactly one YAML document: %v", name, err)
|
|
}
|
|
if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode {
|
|
t.Fatalf("%s must contain one mapping document", name)
|
|
}
|
|
return document.Content[0]
|
|
}
|
|
|
|
func requireSingleMapping(t *testing.T, name string, parent *yaml.Node, key string) map[string]*yaml.Node {
|
|
t.Helper()
|
|
fields := mappingFields(t, name, parent)
|
|
if len(fields) != 1 || fields[key] == nil {
|
|
t.Fatalf("%s must contain only %s", name, key)
|
|
}
|
|
return mappingFields(t, name, fields[key])
|
|
}
|
|
|
|
func mappingFields(t *testing.T, name string, node *yaml.Node) map[string]*yaml.Node {
|
|
t.Helper()
|
|
if node.Kind != yaml.MappingNode {
|
|
t.Fatalf("%s must contain a mapping", name)
|
|
}
|
|
fields := make(map[string]*yaml.Node, len(node.Content)/2)
|
|
for index := 0; index+1 < len(node.Content); index += 2 {
|
|
key := node.Content[index].Value
|
|
if _, exists := fields[key]; exists {
|
|
t.Fatalf("%s repeats key %q", name, key)
|
|
}
|
|
fields[key] = node.Content[index+1]
|
|
}
|
|
return fields
|
|
}
|