clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

feat/ui-updates
tinyrelay / protocol / dependencies_test.go
dependencies_test.go 2.9K
1package protocol_test23import (4 "go/ast"5 "go/parser"6 "go/token"7 "os/exec"8 "path/filepath"9 "runtime"10 "slices"11 "strings"12 "testing"13)1415func TestPublicProtocolDependencyGraph(t *testing.T) {16 for _, name := range []string{"nostr", "auth"} {17 t.Run(name, func(t *testing.T) {18 cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), "list", "-deps", "-f", "{{.ImportPath}}", "./"+name)19 out, err := cmd.CombinedOutput()20 if err != nil {21 t.Fatalf("dependency graph: %v\n%s", err, out)22 }23 found := false24 for _, dependency := range strings.Fields(string(out)) {25 if dependency == modulePath+"/protocol/"+name {26 found = true27 }28 if strings.HasPrefix(dependency, modulePath+"/") && dependency != modulePath+"/protocol/nostr" && dependency != modulePath+"/protocol/auth" {29 t.Errorf("protocol/%s depends on host package %s", name, dependency)30 }31 for _, forbidden := range []string{"modernc.org/sqlite", "github.com/prometheus/", "go.opentelemetry.io/"} {32 if strings.HasPrefix(dependency, forbidden) {33 t.Errorf("protocol/%s depends on host infrastructure %s", name, dependency)34 }35 }36 }37 if !found {38 t.Fatal("dependency graph omitted target package")39 }40 })41 }42}4344// Keep this generic package's public surface deliberate: feature-specific45// kind constants, private-kind classification and room/job semantics belong46// to their owning packages, not the Nostr wire model.47func TestNostrPublicSurface(t *testing.T) {48 want := strings.Fields("Event EventRef Filter Validate Parse Canonical Tag TagValues Expiration Difficulty CommittedDifficulty Sign GenerateKey PublicKey IsEphemeral IsReplaceable IsAddressable ParseFilter Matches SearchTerms Filter.MarshalJSON")49 var got []string50 files, err := filepath.Glob("nostr/*.go")51 if err != nil {52 t.Fatal(err)53 }54 for _, path := range files {55 if strings.HasSuffix(path, "_test.go") {56 continue57 }58 file, err := parser.ParseFile(token.NewFileSet(), path, nil, 0)59 if err != nil {60 t.Fatal(err)61 }62 for _, decl := range file.Decls {63 switch decl := decl.(type) {64 case *ast.FuncDecl:65 if !decl.Name.IsExported() {66 continue67 }68 name := decl.Name.Name69 if decl.Recv != nil {70 receiver := decl.Recv.List[0].Type71 if pointer, ok := receiver.(*ast.StarExpr); ok {72 receiver = pointer.X73 }74 name = receiver.(*ast.Ident).Name + "." + name75 }76 got = append(got, name)77 case *ast.GenDecl:78 for _, spec := range decl.Specs {79 switch spec := spec.(type) {80 case *ast.TypeSpec:81 if spec.Name.IsExported() {82 got = append(got, spec.Name.Name)83 }84 case *ast.ValueSpec:85 for _, name := range spec.Names {86 if name.IsExported() {87 got = append(got, name.Name)88 }89 }90 }91 }92 }93 }94 }95 slices.Sort(got)96 slices.Sort(want)97 if !slices.Equal(got, want) {98 t.Fatalf("Nostr public API changed; review protocol scope\ngot: %v\nwant: %v", got, want)99 }100}