@@ -68,6 +68,133 @@ func TestListLaunchesTool(t *testing.T) {
6868 assert .Equal (t , string (launches ), text )
6969}
7070
71+ // TestRunAutoAnalysisTool tests the run_auto_analysis tool to ensure:
72+ // 1. The tool schema correctly includes the "items" property for array parameters
73+ // (critical for GitHub Copilot compatibility - fixes "array type must have items" error)
74+ // 2. The enum values for analyzer_item_modes are correctly defined
75+ // 3. The tool handler correctly processes requests and calls the ReportPortal API
76+ func TestRunAutoAnalysisTool (t * testing.T ) {
77+ ctx := context .Background ()
78+ testProject := "test-project"
79+ launchID := 123
80+ expectedMessage := "Auto analysis started successfully"
81+
82+ // Track the request payload to verify correct parameters
83+ var capturedRequest * openapi.AnalyzeLaunchRQ
84+ mockServer := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
85+ assert .Equal (t , fmt .Sprintf ("/api/v1/%s/launch/analyze" , testProject ), r .URL .Path )
86+ assert .Equal (t , http .MethodPost , r .Method )
87+
88+ // Parse request body
89+ var reqBody openapi.AnalyzeLaunchRQ
90+ err := json .NewDecoder (r .Body ).Decode (& reqBody )
91+ require .NoError (t , err )
92+ capturedRequest = & reqBody
93+
94+ // Return success response - using map to match actual API response structure
95+ response := map [string ]interface {}{
96+ "message" : expectedMessage ,
97+ }
98+ w .Header ().Set ("Content-Type" , "application/json" )
99+ w .WriteHeader (http .StatusOK )
100+ _ = json .NewEncoder (w ).Encode (response )
101+ }))
102+ defer mockServer .Close ()
103+
104+ srv := mcptest .NewUnstartedServer (t )
105+
106+ serverURL , _ := url .Parse (mockServer .URL )
107+ launchTools := NewLaunchResources (gorp .NewClient (serverURL , "" ), nil , "" )
108+ tool , handler := launchTools .toolRunAutoAnalysis ()
109+ srv .AddTool (tool , handler )
110+
111+ // Verify the tool schema includes items property for array parameter
112+ // This is critical for GitHub Copilot compatibility
113+ toolSchema := tool .InputSchema
114+ require .NotNil (t , toolSchema )
115+ require .NotNil (t , toolSchema .Properties )
116+
117+ analyzerItemModesProp , exists := toolSchema .Properties ["analyzer_item_modes" ]
118+ require .True (t , exists , "analyzer_item_modes parameter should exist in schema" )
119+
120+ // Verify it's an array type with items property (critical for GitHub Copilot compatibility)
121+ // Properties are stored as map[string]any, so we need to check the JSON schema structure
122+ propMap , ok := analyzerItemModesProp .(map [string ]interface {})
123+ require .True (t , ok , "analyzer_item_modes property should be a map" )
124+ require .Equal (t , "array" , propMap ["type" ], "analyzer_item_modes should be an array type" )
125+ require .NotNil (
126+ t ,
127+ propMap ["items" ],
128+ "analyzer_item_modes must have items property for GitHub Copilot compatibility" ,
129+ )
130+
131+ // Verify items have enum values
132+ itemsMap , ok := propMap ["items" ].(map [string ]interface {})
133+ require .True (t , ok , "items should be a map" )
134+ require .NotNil (t , itemsMap ["enum" ], "items should have enum values" )
135+
136+ // Enum can be stored as []interface{} or []string, handle both cases
137+ enumValue := itemsMap ["enum" ]
138+ var enumValues []interface {}
139+ switch v := enumValue .(type ) {
140+ case []interface {}:
141+ enumValues = v
142+ case []string :
143+ enumValues = make ([]interface {}, len (v ))
144+ for i , s := range v {
145+ enumValues [i ] = s
146+ }
147+ default :
148+ require .Fail (t , "enum should be an array" , "got type: %T" , enumValue )
149+ }
150+
151+ expectedEnumValues := []string {"to_investigate" , "auto_analyzed" , "manually_analyzed" }
152+ actualEnumValues := make ([]string , len (enumValues ))
153+ for i , v := range enumValues {
154+ actualEnumValues [i ] = v .(string )
155+ }
156+ assert .Equal (
157+ t ,
158+ expectedEnumValues ,
159+ actualEnumValues ,
160+ "enum values should match expected values" ,
161+ )
162+
163+ err := srv .Start (ctx )
164+ require .NoError (t , err )
165+ defer srv .Close ()
166+
167+ client := srv .Client ()
168+
169+ // Test with valid enum values
170+ var req mcp.CallToolRequest
171+ req .Params .Name = "run_auto_analysis"
172+ req .Params .Arguments = map [string ]any {
173+ "project" : testProject ,
174+ "launch_id" : launchID ,
175+ "analyzer_mode" : "current_launch" ,
176+ "analyzer_type" : "autoAnalyzer" ,
177+ "analyzer_item_modes" : []string {"to_investigate" , "auto_analyzed" },
178+ }
179+
180+ result , err := client .CallTool (ctx , req )
181+ require .NoError (t , err )
182+ require .NotNil (t , result )
183+ require .Len (t , result .Content , 1 )
184+
185+ var textContent mcp.TextContent
186+ require .IsType (t , textContent , result .Content [0 ])
187+ text := result .Content [0 ].(mcp.TextContent ).Text
188+ assert .Equal (t , expectedMessage , text )
189+
190+ // Verify the API was called with correct parameters
191+ require .NotNil (t , capturedRequest )
192+ assert .Equal (t , int64 (launchID ), capturedRequest .LaunchId )
193+ assert .Equal (t , "CURRENT_LAUNCH" , capturedRequest .AnalyzerMode )
194+ assert .Equal (t , "AUTOANALYZER" , capturedRequest .AnalyzerTypeName )
195+ assert .Equal (t , []string {"to_investigate" , "auto_analyzed" }, capturedRequest .AnalyzeItemsMode )
196+ }
197+
71198func testLaunches () * openapi.PageLaunchResource {
72199 launches := openapi .NewPageLaunchResource ()
73200 launches .SetContent ([]openapi.LaunchResource {
0 commit comments