Skip to content

Commit bcd84a2

Browse files
Test registry-enabled plugins depend on registry-enabled plugins (#2368)
We want to ensure that any plugin that ends up with registry configuration only depends on plugins that also have registry configuration (for that same registry). This caught a few past plugins that violate that (b9abdd2), that we aren't planning to go back and update at this point, to demonstrate that the test works.
1 parent 3ab1507 commit bcd84a2

1 file changed

Lines changed: 84 additions & 0 deletions

File tree

tests/plugins_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"os"
1515
"os/exec"
1616
"path/filepath"
17+
"reflect"
1718
"strconv"
1819
"strings"
1920
"testing"
@@ -84,6 +85,13 @@ exec docker run --log-driver=none --rm -i {{.ImageName}}:{{.Version}} "$@"
8485
"buf.build/community/mercari-grpc-federation": {"eliza": true, "petapis": true},
8586
"buf.build/googlecloudplatform/bq-schema": {"eliza": true, "petapis": true},
8687
}
88+
// allowedMissingRegistryDeps lists dependencies that are known to lack a registry config for
89+
// a given registry type. The key is "pluginRef -> depRef" (e.g. "buf.build/grpc/python:v1.59.1 -> buf.build/protocolbuffers/python:v24.4").
90+
// Only add entries here for old plugin versions where the dep predates registry config support.
91+
allowedMissingRegistryDeps = map[string]bool{
92+
"buf.build/grpc/python:v1.59.1 -> buf.build/protocolbuffers/python:v24.4": true,
93+
"buf.build/grpc/python:v1.59.2 -> buf.build/protocolbuffers/python:v24.4": true,
94+
}
8795
)
8896

8997
func TestGeneration(t *testing.T) {
@@ -455,6 +463,82 @@ func TestPyPIDependencies(t *testing.T) {
455463
}
456464
}
457465

466+
func TestRegistryDepsHaveRegistryConfig(t *testing.T) {
467+
t.Parallel()
468+
plugins := loadAllPlugins(t)
469+
// Build a lookup map by "name:version".
470+
pluginByRef := make(map[string]*plugin.Plugin, len(plugins))
471+
for _, p := range plugins {
472+
pluginByRef[p.String()] = p
473+
}
474+
// registryType returns a string identifying which registry type is configured,
475+
// or "" if no registry is configured. Fails the test if any pointer field on
476+
// the registry struct is non-nil but not handled by the switch, so this test
477+
// stays up to date when new registry types are added to ExternalRegistryConfig.
478+
registryType := func(t *testing.T, p *plugin.Plugin) string {
479+
t.Helper()
480+
switch {
481+
case p.Registry.Go != nil:
482+
return "go"
483+
case p.Registry.NPM != nil:
484+
return "npm"
485+
case p.Registry.Maven != nil:
486+
return "maven"
487+
case p.Registry.Swift != nil:
488+
return "swift"
489+
case p.Registry.Python != nil:
490+
return "python"
491+
case p.Registry.Cargo != nil:
492+
return "cargo"
493+
case p.Registry.Nuget != nil:
494+
return "nuget"
495+
case p.Registry.Cmake != nil:
496+
return "cmake"
497+
default:
498+
rv := reflect.ValueOf(p.Registry)
499+
rt := reflect.TypeFor[bufremotepluginconfig.ExternalRegistryConfig]()
500+
for i := range rt.NumField() {
501+
field := rt.Field(i)
502+
if field.Type.Kind() == reflect.Pointer && !rv.Field(i).IsNil() {
503+
assert.Failf(t, "unrecognized registry type", "plugin %q has unrecognized registry type field %q - update registryType() in this test", p.String(), field.Name)
504+
}
505+
}
506+
return ""
507+
}
508+
}
509+
// checkDeps recursively verifies that all transitive dependencies of p have the expected registry type.
510+
var checkDeps func(t *testing.T, p *plugin.Plugin, want string, visited map[string]bool)
511+
checkDeps = func(t *testing.T, p *plugin.Plugin, want string, visited map[string]bool) {
512+
t.Helper()
513+
for _, dep := range p.Deps {
514+
if visited[dep.Plugin] {
515+
continue
516+
}
517+
visited[dep.Plugin] = true
518+
depPlugin, ok := pluginByRef[dep.Plugin]
519+
require.Truef(t, ok, "dependency %q not found", dep.Plugin)
520+
key := fmt.Sprintf("%s -> %s", p.String(), dep.Plugin)
521+
if registryType(t, depPlugin) != want && !allowedMissingRegistryDeps[key] {
522+
assert.Failf(t, "missing registry config",
523+
"dependency %q of plugin %q has registry type %q, want %q",
524+
dep.Plugin, p.String(), registryType(t, depPlugin), want,
525+
)
526+
}
527+
checkDeps(t, depPlugin, want, visited)
528+
}
529+
}
530+
for _, p := range plugins {
531+
rt := registryType(t, p)
532+
if rt == "" {
533+
continue
534+
}
535+
t.Run(fmt.Sprintf("%s/%s@%s", p.Identity.Owner(), p.Identity.Plugin(), p.PluginVersion), func(t *testing.T) {
536+
t.Parallel()
537+
checkDeps(t, p, rt, make(map[string]bool))
538+
})
539+
}
540+
}
541+
458542
func runPluginWithImage(ctx context.Context, t *testing.T, basedir string, pluginMeta *plugin.Plugin, image string, goPkgPrefix string) string {
459543
t.Helper()
460544
gendir := filepath.Join(basedir, "gen")

0 commit comments

Comments
 (0)