@@ -3,34 +3,54 @@ package internal
33import (
44 "encoding/json"
55 "os"
6+ "sort"
67 "testing"
78
89 "github.com/GoCodeAlone/workflow/plugin"
910)
1011
1112// TestModuleSchemas verifies that the plugin's SchemaProvider returns schema
12- // descriptors for both advertised module types.
13+ // descriptors for both advertised module types and stays in sync with
14+ // ModuleTypes() and plugin.json moduleTypes.
1315func TestModuleSchemas (t * testing.T ) {
1416 p := & githubPlugin {}
1517 schemas := p .ModuleSchemas ()
18+ runtimeTypes := p .ModuleTypes ()
1619
1720 if len (schemas ) != 2 {
1821 t .Fatalf ("expected 2 module schemas, got %d" , len (schemas ))
1922 }
2023
21- byType := make (map [string ]int , len (schemas ))
24+ // Every schema type must appear in the runtime ModuleTypes() list.
25+ runtimeSet := make (map [string ]bool , len (runtimeTypes ))
26+ for _ , mt := range runtimeTypes {
27+ runtimeSet [mt ] = true
28+ }
29+ for _ , s := range schemas {
30+ if ! runtimeSet [s .Type ] {
31+ t .Errorf ("schema type %q is not in githubPlugin.ModuleTypes()" , s .Type )
32+ }
33+ }
34+
35+ // Every runtime module type must have a schema entry.
36+ schemaSet := make (map [string ]int , len (schemas ))
2237 for i , s := range schemas {
23- byType [s .Type ] = i
38+ schemaSet [s .Type ] = i
39+ }
40+ for _ , mt := range runtimeTypes {
41+ if _ , ok := schemaSet [mt ]; ! ok {
42+ t .Errorf ("ModuleTypes() returns %q but no corresponding ModuleSchema exists" , mt )
43+ }
2444 }
2545
2646 for _ , wantType := range []string {"git.webhook" , "github.app" } {
27- if _ , ok := byType [wantType ]; ! ok {
47+ if _ , ok := schemaSet [wantType ]; ! ok {
2848 t .Errorf ("missing module schema for type %q" , wantType )
2949 }
3050 }
3151
32- // git.webhook should have at least the four documented config fields.
33- webhookIdx , ok := byType ["git.webhook" ]
52+ // git.webhook should have the core documented config fields.
53+ webhookIdx , ok := schemaSet ["git.webhook" ]
3454 if ! ok {
3555 t .Fatalf ("git.webhook schema not found" )
3656 }
@@ -41,15 +61,27 @@ func TestModuleSchemas(t *testing.T) {
4161 if webhook .Description == "" {
4262 t .Error ("git.webhook schema: Description must not be empty" )
4363 }
44- if len (webhook .ConfigFields ) < 4 {
45- t .Errorf ("git.webhook schema: expected at least 4 config fields, got %d" , len (webhook .ConfigFields ))
64+ webhookFieldNames := make (map [string ]bool , len (webhook .ConfigFields ))
65+ for _ , f := range webhook .ConfigFields {
66+ webhookFieldNames [f .Name ] = true
67+ }
68+ for _ , want := range []string {"secret" , "events" , "topic" } {
69+ if ! webhookFieldNames [want ] {
70+ t .Errorf ("git.webhook schema: required config field %q is missing" , want )
71+ }
4672 }
4773 if len (webhook .Outputs ) == 0 {
4874 t .Error ("git.webhook schema: expected at least one output" )
4975 }
76+ // raw_payload must be declared as an object (json.RawMessage), not string.
77+ for _ , f := range webhook .Outputs {
78+ if f .Name == "raw_payload" && f .Type != "object" {
79+ t .Errorf ("git.webhook schema: raw_payload output type should be %q, got %q" , "object" , f .Type )
80+ }
81+ }
5082
5183 // github.app should declare the three required config fields.
52- appIdx , ok := byType ["github.app" ]
84+ appIdx , ok := schemaSet ["github.app" ]
5385 if ! ok {
5486 t .Fatalf ("github.app schema not found" )
5587 }
@@ -71,10 +103,37 @@ func TestModuleSchemas(t *testing.T) {
71103 t .Errorf ("github.app schema: field %q should be marked required" , want )
72104 }
73105 }
106+
107+ // Cross-check against plugin.json moduleTypes.
108+ data , err := os .ReadFile ("../plugin.json" )
109+ if err != nil {
110+ t .Fatalf ("plugin.json not found: %v" , err )
111+ }
112+ var manifest struct {
113+ ModuleTypes []string `json:"moduleTypes"`
114+ }
115+ if err := json .Unmarshal (data , & manifest ); err != nil {
116+ t .Fatalf ("parse plugin.json: %v" , err )
117+ }
118+ jsonModuleSet := make (map [string ]bool , len (manifest .ModuleTypes ))
119+ for _ , mt := range manifest .ModuleTypes {
120+ jsonModuleSet [mt ] = true
121+ }
122+ for _ , mt := range runtimeTypes {
123+ if ! jsonModuleSet [mt ] {
124+ t .Errorf ("githubPlugin.ModuleTypes() returns %q but plugin.json moduleTypes does not include it" , mt )
125+ }
126+ }
127+ for _ , mt := range manifest .ModuleTypes {
128+ if ! runtimeSet [mt ] {
129+ t .Errorf ("plugin.json moduleTypes includes %q but githubPlugin.ModuleTypes() does not" , mt )
130+ }
131+ }
74132}
75133
76134// TestPluginStepSchemasJSON verifies that plugin.json can be parsed and that
77- // it declares a stepSchemas entry for every step type the plugin advertises.
135+ // it declares a stepSchemas entry for every step type the plugin advertises,
136+ // and that both are in sync with the runtime StepTypes() list.
78137func TestPluginStepSchemasJSON (t * testing.T ) {
79138 // Locate plugin.json relative to the repository root (one level up from internal/).
80139 data , err := os .ReadFile ("../plugin.json" )
@@ -111,6 +170,40 @@ func TestPluginStepSchemasJSON(t *testing.T) {
111170 t .Errorf ("plugin.json: stepSchemas count (%d) does not match stepTypes count (%d)" ,
112171 len (manifest .StepSchemas ), len (manifest .StepTypes ))
113172 }
173+
174+ // Cross-check JSON manifest against the runtime StepTypes() list.
175+ p := & githubPlugin {}
176+ runtimeTypes := p .StepTypes ()
177+
178+ runtimeSet := make (map [string ]bool , len (runtimeTypes ))
179+ for _ , st := range runtimeTypes {
180+ runtimeSet [st ] = true
181+ }
182+ jsonTypeSet := make (map [string ]bool , len (manifest .StepTypes ))
183+ for _ , st := range manifest .StepTypes {
184+ jsonTypeSet [st ] = true
185+ }
186+
187+ for _ , rt := range runtimeTypes {
188+ if ! jsonTypeSet [rt ] {
189+ t .Errorf ("githubPlugin.StepTypes() returns %q but plugin.json stepTypes does not include it" , rt )
190+ }
191+ }
192+ for _ , jt := range manifest .StepTypes {
193+ if ! runtimeSet [jt ] {
194+ t .Errorf ("plugin.json stepTypes includes %q but githubPlugin.StepTypes() does not return it" , jt )
195+ }
196+ }
197+
198+ // Verify both lists have the same length (no duplicates or gaps).
199+ sortedRuntime := append ([]string (nil ), runtimeTypes ... )
200+ sortedJSON := append ([]string (nil ), manifest .StepTypes ... )
201+ sort .Strings (sortedRuntime )
202+ sort .Strings (sortedJSON )
203+ if len (sortedRuntime ) != len (sortedJSON ) {
204+ t .Errorf ("runtime StepTypes() count (%d) != plugin.json stepTypes count (%d)" ,
205+ len (sortedRuntime ), len (sortedJSON ))
206+ }
114207}
115208
116209// TestPluginManifestEngineValidation verifies that plugin.json is parseable as a
0 commit comments