-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathunmatched_client_test.go
More file actions
72 lines (62 loc) · 2.53 KB
/
Copy pathunmatched_client_test.go
File metadata and controls
72 lines (62 loc) · 2.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package engine
// flagUnmatchedRoutes tags each client call site that resolves to no loaded server
// route with unmatched_by_server + a reason, so the aggregate coverage count becomes
// a queryable per-call list. This is the observability half of the coverage pass.
import (
"testing"
"github.com/enola-labs/enola/internal/config"
"github.com/enola-labs/enola/internal/facts"
)
func clientRouteFact(repo, name, method string) facts.Fact {
return facts.Fact{Kind: facts.KindRoute, Name: name, Repo: repo,
Props: map[string]any{"role": "client", "method": method}}
}
func TestFlagUnmatchedRoutes_ClientSide(t *testing.T) {
eng, err := New(config.Default())
if err != nil {
t.Fatalf("New: %v", err)
}
eng.store.Add(
clientRouteFact("app", "/api/items/{id}", "GET"), // resolves to backend
clientRouteFact("app", "/api/unknown/{id}", "GET"), // no server serves it -> path_unknown
clientRouteFact("app", "/api/orders/{id}", "POST"), // path served, wrong verb -> method_mismatch
clientRouteFact("app", "/health", "GET"), // sub-2-segment path -> generic_path
facts.Fact{Kind: facts.KindRoute, Name: "/api/items/{itemId}", Repo: "backend",
Props: map[string]any{"role": "server", "method": "GET"}},
facts.Fact{Kind: facts.KindRoute, Name: "/api/orders/{orderId}", Repo: "backend",
Props: map[string]any{"role": "server", "method": "GET"}},
)
eng.flagUnmatchedRoutes()
props := map[string]map[string]any{}
for _, f := range eng.store.All() {
if f.Kind == facts.KindRoute {
props[f.Name] = f.Props
}
}
// Each reason the resolver can emit for an unresolved client call, asserted by name
// so the value set stays pinned to the crossrepo.Reason* constants.
for _, tc := range []struct {
name, wantReason string
}{
{"/api/unknown/{id}", "path_unknown"},
{"/api/orders/{id}", "method_mismatch"},
{"/health", "generic_path"},
} {
got := props[tc.name]
if e, _ := got["unmatched_by_server"].(bool); !e {
t.Errorf("%s should be unmatched_by_server; got %+v", tc.name, got)
}
if got["unmatched_reason"] != tc.wantReason {
t.Errorf("%s reason = %v, want %s", tc.name, got["unmatched_reason"], tc.wantReason)
}
}
items := props["/api/items/{id}"]
if _, has := items["unmatched_by_server"]; has {
t.Errorf("resolved client call must not be flagged; got %+v", items)
}
// The server route must never carry the client-side flag.
server := props["/api/items/{itemId}"]
if _, has := server["unmatched_by_server"]; has {
t.Errorf("server route must not carry unmatched_by_server; got %+v", server)
}
}