MCPcopy
hub / github.com/github/github-mcp-server / Test

Function Test

internal/toolsnaps/toolsnaps.go:21–67  ·  view source on GitHub ↗

Test checks that the JSON schema for a tool has not changed unexpectedly. It compares the marshaled JSON of the provided tool against a stored snapshot file. If the UPDATE_TOOLSNAPS environment variable is set to "true", it updates the snapshot file instead. If the snapshot does not exist and not ru

(toolName string, tool any)

Source from the content-addressed store, hash-verified

19// If the snapshot exists, it compares the tool's JSON to the snapshot and returns an error if they differ.
20// Returns an error if marshaling, reading, or comparing fails.
21func Test(toolName string, tool any) error {
22 toolJSON, err := json.MarshalIndent(tool, "", " ")
23 if err != nil {
24 return fmt.Errorf("failed to marshal tool %s: %w", toolName, err)
25 }
26
27 snapPath := fmt.Sprintf("__toolsnaps__/%s.snap", toolName)
28
29 // If UPDATE_TOOLSNAPS is set, then we write the tool JSON to the snapshot file and exit
30 if os.Getenv("UPDATE_TOOLSNAPS") == "true" {
31 return writeSnap(snapPath, toolJSON)
32 }
33
34 snapJSON, err := os.ReadFile(snapPath) //nolint:gosec // filepaths are controlled by the test suite, so this is safe.
35 // If the snapshot file does not exist, this must be the first time this test is run.
36 // We write the tool JSON to the snapshot file and exit.
37 if os.IsNotExist(err) {
38 // If we're running in CI, we will error if there is not snapshot because it's important that snapshots
39 // are committed alongside the tests, rather than just being constructed and not committed during a CI run.
40 if os.Getenv("GITHUB_ACTIONS") == "true" {
41 return fmt.Errorf("tool snapshot does not exist for %s. Please run the tests with UPDATE_TOOLSNAPS=true to create it", toolName)
42 }
43
44 return writeSnap(snapPath, toolJSON)
45 }
46
47 // Otherwise we will compare the tool JSON to the snapshot JSON
48 toolNode, err := jd.ReadJsonString(string(toolJSON))
49 if err != nil {
50 return fmt.Errorf("failed to parse tool JSON for %s: %w", toolName, err)
51 }
52
53 snapNode, err := jd.ReadJsonString(string(snapJSON))
54 if err != nil {
55 return fmt.Errorf("failed to parse snapshot JSON for %s: %w", toolName, err)
56 }
57
58 // jd.Set allows arrays to be compared without order sensitivity,
59 // which is useful because we don't really care about this when exposing tool schemas.
60 diff := toolNode.Diff(snapNode, jd.SET).Render()
61 if diff != "" {
62 // If there is a difference, we return an error with the diff
63 return fmt.Errorf("tool schema for %s has changed unexpectedly:\n%s\nrun with `UPDATE_TOOLSNAPS=true` if this is expected", toolName, diff)
64 }
65
66 return nil
67}
68
69func writeSnap(snapPath string, contents []byte) error {
70 // Sort the JSON keys recursively to ensure consistent output.

Calls 1

writeSnapFunction · 0.85

Tested by

no test coverage detected