fix: recognize boolean and varied integer formats for guest exec exited status (#160)

* fix: recognize boolean and varied integer formats for guest exec exited status

The guest-agent schema declares 'exited' as a boolean, but the PVE API
may return it in different formats: as a JSON boolean true, or as integers
1/0, or string '1'/'0'. The cmdlet was only checking for long 1L, causing
it to timeout on any PVE build that passed a boolean true unchanged.

Add ApiValueHelper.IsExited() to normalize these values and recognize
true, 1L, 1, and '1' as exited. Update the polling loop to use it.

* test: add integration tests for ApiValueHelper with real JSON payloads

Add tests that feed JSON data through the actual JsonHelper.ToNative
parsing pipeline to verify ApiValueHelper.IsExited correctly recognizes
boolean true and numeric 1 values as they arrive from the PVE API.
These tests pin the contract between the JSON parsing layer and the
value-recognition logic, ensuring the fix for issue #141 works end-to-end
with real API response shapes.

* fix: restore correct IsExited implementation with type checks

The helper must handle boolean true, long/int 1, and string "1" as the
issue specifies. This restores the correct multi-type check that was
inadvertently reverted.

* fix: correct boolean value handling in IsExited

---------

Co-authored-by: goodolclint-claude[bot] <323206664+goodolclint-claude[bot]@users.noreply.github.com>
This commit is contained in:
goodolclint-claude[bot]
2026-09-02 17:32:09 +00:00
committed by GitHub
parent def8dc6b67
commit 8255e506a6
3 changed files with 92 additions and 1 deletions
@@ -0,0 +1,38 @@
using System;
namespace PSProxmoxVE.Core.Utilities
{
/// <summary>
/// Helper methods for normalizing and checking values received from the Proxmox VE API.
/// The API may return the same logical value in different formats (e.g., boolean true, integer 1, or string "1").
/// </summary>
public static class ApiValueHelper
{
/// <summary>
/// Determines if a value represents a true/exited state.
/// Accepts boolean true, integer 1 (as Int64 or Int32), and string "1" as true.
/// All other values (false, 0, "0", null, etc.) are false.
/// </summary>
/// <param name="value">The value to check, typically from API response data.</param>
/// <returns>True if the value represents an exited/true state, false otherwise.</returns>
public static bool IsExited(object? value)
{
if (value == null)
return false;
if (value is bool b)
return b;
if (value is long l)
return l == 1L;
if (value is int i)
return i == 1;
if (value is string s)
return s == "1";
return false;
}
}
}
@@ -2,6 +2,7 @@ using System;
using System.Diagnostics;
using System.Management.Automation;
using PSProxmoxVE.Core.Services;
using PSProxmoxVE.Core.Utilities;
namespace PSProxmoxVE.Cmdlets.Vms
{
@@ -60,7 +61,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
if (sw.Elapsed >= deadline)
throw new TimeoutException($"Guest command did not complete within {Timeout} seconds.");
result = service.GetGuestExecStatus(session, Node, VmId, pid);
} while (!result.TryGetValue("exited", out var exited) || !Equals(exited, 1L));
} while (!result.TryGetValue("exited", out var exited) || !ApiValueHelper.IsExited(exited));
var output = new PSObject();
output.Properties.Add(new PSNoteProperty("ExitCode", result.TryGetValue("exitcode", out var ec) && ec is long ecl ? (int)ecl : -1));