@@ -266,6 +266,106 @@ func (s *HelmSuite) TestHelmUninstallDenied() {
266266 })
267267}
268268
269+ func (s * HelmSuite ) TestHelmHistoryNoReleases () {
270+ s .InitMcpClient ()
271+ s .Run ("helm_history(name=non-existent-release) with no releases" , func () {
272+ toolResult , err := s .CallTool ("helm_history" , map [string ]interface {}{
273+ "name" : "non-existent-release" ,
274+ })
275+ s .Run ("has error" , func () {
276+ s .Truef (toolResult .IsError , "call tool should fail for non-existent release" )
277+ s .Nilf (err , "call tool should not return error object" )
278+ })
279+ s .Run ("describes error" , func () {
280+ s .Truef (strings .Contains (toolResult .Content [0 ].(mcp.TextContent ).Text , "failed to retrieve helm history" ), "expected descriptive error, got %v" , toolResult .Content [0 ].(mcp.TextContent ).Text )
281+ })
282+ })
283+ }
284+
285+ func (s * HelmSuite ) TestHelmHistory () {
286+ kc := kubernetes .NewForConfigOrDie (envTestRestConfig )
287+ // Create multiple revisions of a release
288+ for i := 1 ; i <= 3 ; i ++ {
289+ _ , err := kc .CoreV1 ().Secrets ("default" ).Create (s .T ().Context (), & corev1.Secret {
290+ ObjectMeta : metav1.ObjectMeta {
291+ Name : "sh.helm.release.v1.release-with-history.v" + string (rune ('0' + i )),
292+ Labels : map [string ]string {"owner" : "helm" , "name" : "release-with-history" , "version" : string (rune ('0' + i ))},
293+ },
294+ Data : map [string ][]byte {
295+ "release" : []byte (base64 .StdEncoding .EncodeToString ([]byte ("{" +
296+ "\" name\" :\" release-with-history\" ," +
297+ "\" version\" :" + string (rune ('0' + i )) + "," +
298+ "\" info\" :{\" status\" :\" superseded\" ,\" last_deployed\" :\" 2024-01-01T00:00:00Z\" ,\" description\" :\" Upgrade complete\" }," +
299+ "\" chart\" :{\" metadata\" :{\" name\" :\" test-chart\" ,\" version\" :\" 1.0.0\" ,\" appVersion\" :\" 1.0.0\" }}" +
300+ "}" ))),
301+ },
302+ }, metav1.CreateOptions {})
303+ s .Require ().NoError (err )
304+ }
305+ s .InitMcpClient ()
306+ s .Run ("helm_history(name=release-with-history) with multiple revisions" , func () {
307+ toolResult , err := s .CallTool ("helm_history" , map [string ]interface {}{
308+ "name" : "release-with-history" ,
309+ })
310+ s .Run ("no error" , func () {
311+ s .Nilf (err , "call tool failed %v" , err )
312+ s .Falsef (toolResult .IsError , "call tool failed" )
313+ })
314+ s .Run ("returns history" , func () {
315+ var decoded []map [string ]interface {}
316+ err = yaml .Unmarshal ([]byte (toolResult .Content [0 ].(mcp.TextContent ).Text ), & decoded )
317+ s .Run ("has yaml content" , func () {
318+ s .Nilf (err , "invalid tool result content %v" , err )
319+ })
320+ s .Run ("has 3 items" , func () {
321+ s .Lenf (decoded , 3 , "invalid helm history count, expected 3, got %v" , len (decoded ))
322+ })
323+ s .Run ("has valid revision numbers" , func () {
324+ for i , item := range decoded {
325+ expectedRevision := float64 (i + 1 )
326+ s .Equalf (expectedRevision , item ["revision" ], "invalid revision for item %d, expected %v, got %v" , i , expectedRevision , item ["revision" ])
327+ }
328+ })
329+ s .Run ("has valid status" , func () {
330+ s .Equalf ("superseded" , decoded [0 ]["status" ], "invalid status, expected superseded, got %v" , decoded [0 ]["status" ])
331+ })
332+ s .Run ("has valid chart" , func () {
333+ s .Equalf ("test-chart-1.0.0" , decoded [0 ]["chart" ], "invalid chart, expected test-chart-1.0.0, got %v" , decoded [0 ]["chart" ])
334+ })
335+ s .Run ("has valid appVersion" , func () {
336+ s .Equalf ("1.0.0" , decoded [0 ]["appVersion" ], "invalid appVersion, expected 1.0.0, got %v" , decoded [0 ]["appVersion" ])
337+ })
338+ s .Run ("has valid description" , func () {
339+ s .Equalf ("Upgrade complete" , decoded [0 ]["description" ], "invalid description, expected 'Upgrade complete', got %v" , decoded [0 ]["description" ])
340+ })
341+ })
342+ })
343+ s .Run ("helm_history(name=release-with-history, max=2) with max limit" , func () {
344+ toolResult , err := s .CallTool ("helm_history" , map [string ]interface {}{
345+ "name" : "release-with-history" ,
346+ "max" : 2 ,
347+ })
348+ s .Run ("no error" , func () {
349+ s .Nilf (err , "call tool failed %v" , err )
350+ s .Falsef (toolResult .IsError , "call tool failed" )
351+ })
352+ s .Run ("returns limited history" , func () {
353+ var decoded []map [string ]interface {}
354+ err = yaml .Unmarshal ([]byte (toolResult .Content [0 ].(mcp.TextContent ).Text ), & decoded )
355+ s .Run ("has yaml content" , func () {
356+ s .Nilf (err , "invalid tool result content %v" , err )
357+ })
358+ s .Run ("has 2 items" , func () {
359+ s .Lenf (decoded , 2 , "invalid helm history count with max=2, expected 2, got %v" , len (decoded ))
360+ })
361+ s .Run ("returns most recent revisions" , func () {
362+ s .Equalf (float64 (2 ), decoded [0 ]["revision" ], "expected revision 2, got %v" , decoded [0 ]["revision" ])
363+ s .Equalf (float64 (3 ), decoded [1 ]["revision" ], "expected revision 3, got %v" , decoded [1 ]["revision" ])
364+ })
365+ })
366+ })
367+ }
368+
269369func clearHelmReleases (ctx context.Context , kc * kubernetes.Clientset ) {
270370 secrets , _ := kc .CoreV1 ().Secrets ("default" ).List (ctx , metav1.ListOptions {})
271371 for _ , secret := range secrets .Items {
0 commit comments