cli/internal/bnp/build_test.go
Alex Dunmow 71d005f1fb feat(bnp): marshal public_routes + sitemap into built manifests (ADR 0026)
pluginsdk v0.2.7. The packer validates public_routes (reserved
prefixes, traversal, duplicates), requires an HTTP handler for routes
or sitemap, and stamps both into manifest.pb; codeless builds reject
them; writeMod round-trips the new plugin.mod keys so a version bump
cannot strip live route claims.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 02:45:58 +08:00

74 lines
2.4 KiB
Go

package bnp
import (
"strings"
"testing"
abiv1 "git.dev.alexdunmow.com/block/pluginsdk/abi/v1"
core "git.dev.alexdunmow.com/block/pluginsdk/plugin"
)
func TestStampPublicRoutes(t *testing.T) {
manifest := &abiv1.PluginManifest{HasHttpHandler: true}
mod := &core.ModFile{Plugin: core.ModPlugin{
PublicRoutes: []core.ModPublicRoute{
{Path: "/area", Prefix: true},
{Path: "/api/semantic-search"},
},
Sitemap: true,
}}
if err := stampPublicRoutes(manifest, mod); err != nil {
t.Fatalf("stampPublicRoutes: %v", err)
}
routes := manifest.GetPublicRoutes()
if len(routes) != 2 {
t.Fatalf("manifest routes len = %d, want 2", len(routes))
}
if routes[0].GetPath() != "/area" || !routes[0].GetPrefix() {
t.Errorf("routes[0] = %+v, want /area prefix", routes[0])
}
if routes[1].GetPath() != "/api/semantic-search" || routes[1].GetPrefix() {
t.Errorf("routes[1] = %+v, want exact /api/semantic-search", routes[1])
}
if !manifest.GetSitemap() {
t.Errorf("manifest sitemap not stamped")
}
}
func TestStampPublicRoutes_RejectsReservedPrefix(t *testing.T) {
manifest := &abiv1.PluginManifest{HasHttpHandler: true}
mod := &core.ModFile{Plugin: core.ModPlugin{
PublicRoutes: []core.ModPublicRoute{{Path: "/api/plugins/mine", Prefix: true}},
}}
err := stampPublicRoutes(manifest, mod)
if err == nil {
t.Fatal("reserved prefix accepted; want error")
}
if !strings.Contains(err.Error(), "public_routes") || !strings.Contains(err.Error(), "reserved prefix") {
t.Errorf("error %q should name public_routes and the reserved prefix", err.Error())
}
}
func TestStampPublicRoutes_RequiresHTTPHandler(t *testing.T) {
mod := &core.ModFile{Plugin: core.ModPlugin{
PublicRoutes: []core.ModPublicRoute{{Path: "/area"}},
}}
if err := stampPublicRoutes(&abiv1.PluginManifest{}, mod); err == nil {
t.Error("public_routes without HTTP handler accepted; want error")
}
sitemapOnly := &core.ModFile{Plugin: core.ModPlugin{Sitemap: true}}
if err := stampPublicRoutes(&abiv1.PluginManifest{}, sitemapOnly); err == nil {
t.Error("sitemap without HTTP handler accepted; want error")
}
}
func TestStampPublicRoutes_NoDeclarationIsNoop(t *testing.T) {
manifest := &abiv1.PluginManifest{}
if err := stampPublicRoutes(manifest, &core.ModFile{}); err != nil {
t.Fatalf("empty declaration: %v", err)
}
if len(manifest.GetPublicRoutes()) != 0 || manifest.GetSitemap() {
t.Errorf("manifest gained routes from an empty mod: %+v", manifest)
}
}