mirror of
https://github.com/freedbygrace/PSOPNSenseAPI.git
synced 2026-08-21 07:37:34 +00:00
Rename Upgrade-OPNSenseFirmware to Start-OPNSenseFirmwareUpgrade to resolve cmdlet name conflict
This commit is contained in:
+5
-1
@@ -5,7 +5,11 @@ All notable changes to the PSOPNSenseAPI module will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [2025.04.15.0739] - 2025-04-15
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Renamed `Upgrade-OPNSenseFirmware` to `Start-OPNSenseFirmwareUpgrade` to resolve cmdlet name conflict
|
||||||
|
- Added unit tests for firmware management cmdlets
|
||||||
|
|
||||||
## [0.6.0] - 2025-04-14
|
## [0.6.0] - 2025-04-14
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,9 @@ Invoke-OPNSenseNetworkCalculation -Network "10.0.0.0/24" -Operation SupernetSumm
|
|||||||
# Firmware management
|
# Firmware management
|
||||||
Update-OPNSenseFirmware -Wait
|
Update-OPNSenseFirmware -Wait
|
||||||
|
|
||||||
|
# Major firmware upgrade
|
||||||
|
Start-OPNSenseFirmwareUpgrade -Wait -Timeout 1200
|
||||||
|
|
||||||
# Reboot firewall
|
# Reboot firewall
|
||||||
Restart-OPNSenseFirewall -Wait -Timeout 300
|
Restart-OPNSenseFirewall -Wait -Timeout 300
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ Write-Output "Firmware updated successfully"
|
|||||||
|
|
||||||
# Upgrade firmware (major version upgrade)
|
# Upgrade firmware (major version upgrade)
|
||||||
# Note: This will restart the firewall
|
# Note: This will restart the firewall
|
||||||
# Upgrade-OPNSenseFirmware -Wait -Timeout 1200
|
Start-OPNSenseFirmwareUpgrade -Wait -Timeout 1200
|
||||||
|
Write-Output "Firmware upgraded successfully"
|
||||||
|
|
||||||
# Restart the firewall
|
# Restart the firewall
|
||||||
Restart-OPNSenseFirewall -Wait -Timeout 300
|
Restart-OPNSenseFirewall -Wait -Timeout 300
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@{
|
@{
|
||||||
RootModule = 'PSOPNSenseAPI.psm1'
|
RootModule = 'PSOPNSenseAPI.psm1'
|
||||||
ModuleVersion = '2025.04.14.2340'
|
ModuleVersion = '2025.04.15.0739'
|
||||||
GUID = '1f0e4b77-cc7c-4a1e-b45a-d7c51a3c562e'
|
GUID = '1f0e4b77-cc7c-4a1e-b45a-d7c51a3c562e'
|
||||||
Author = 'PSOPNSenseAPI Contributors'
|
Author = 'PSOPNSenseAPI Contributors'
|
||||||
CompanyName = 'PSOPNSenseAPI'
|
CompanyName = 'PSOPNSenseAPI'
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
RootModule = 'PSOPNSenseAPI.psm1'
|
RootModule = 'PSOPNSenseAPI.psm1'
|
||||||
|
|
||||||
# Version number of this module.
|
# Version number of this module.
|
||||||
ModuleVersion = '2025.04.14.2340'
|
ModuleVersion = '2025.04.15.0739'
|
||||||
|
|
||||||
# Supported PSEditions
|
# Supported PSEditions
|
||||||
CompatiblePSEditions = @('Desktop', 'Core')
|
CompatiblePSEditions = @('Desktop', 'Core')
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
using PSOPNSenseAPI.Cmdlets;
|
||||||
|
using PSOPNSenseAPI.Services;
|
||||||
|
using PSOPNSenseAPI.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace PSOPNSenseAPI.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class FirmwareCmdletTests
|
||||||
|
{
|
||||||
|
private Mock<OPNSenseApiClient> _mockApiClient;
|
||||||
|
private Mock<ILogger> _mockLogger;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_mockApiClient = new Mock<OPNSenseApiClient>("https://example.com", "key", "secret", false, Mock.Of<ILogger>());
|
||||||
|
_mockLogger = new Mock<ILogger>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UpdateOPNSenseFirmwareCmdlet_ProcessRecord_CallsUpdateAsync()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_mockApiClient.Setup(c => c.PostAsync<dynamic>("core/firmware/update", It.IsAny<object>()))
|
||||||
|
.ReturnsAsync(new { status = "ok" });
|
||||||
|
|
||||||
|
// Create and configure the cmdlet
|
||||||
|
var cmdlet = new UpdateOPNSenseFirmwareCmdlet();
|
||||||
|
|
||||||
|
// Use reflection to set the protected properties
|
||||||
|
SetProtectedProperty(cmdlet, "ApiClient", _mockApiClient.Object);
|
||||||
|
SetProtectedProperty(cmdlet, "Logger", _mockLogger.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
InvokeMethod(cmdlet, "ProcessRecord");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockApiClient.Verify(c => c.PostAsync<dynamic>("core/firmware/update", It.IsAny<object>()), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void StartOPNSenseFirmwareUpgradeCmdlet_ProcessRecord_CallsUpgradeAsync()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_mockApiClient.Setup(c => c.PostAsync<dynamic>("core/firmware/upgrade", It.IsAny<object>()))
|
||||||
|
.ReturnsAsync(new { status = "ok" });
|
||||||
|
|
||||||
|
// Create and configure the cmdlet
|
||||||
|
var cmdlet = new UpgradeOPNSenseFirmwareCmdlet();
|
||||||
|
|
||||||
|
// Use reflection to set the protected properties
|
||||||
|
SetProtectedProperty(cmdlet, "ApiClient", _mockApiClient.Object);
|
||||||
|
SetProtectedProperty(cmdlet, "Logger", _mockLogger.Object);
|
||||||
|
|
||||||
|
// Set Force parameter to skip confirmation
|
||||||
|
typeof(UpgradeOPNSenseFirmwareCmdlet).GetProperty("Force").SetValue(cmdlet, new SwitchParameter(true));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
InvokeMethod(cmdlet, "ProcessRecord");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockApiClient.Verify(c => c.PostAsync<dynamic>("core/firmware/upgrade", It.IsAny<object>()), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetOPNSenseFirmwareCmdlet_ProcessRecord_CallsGetStatusAsync()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/status"))
|
||||||
|
.ReturnsAsync(new { status = "ok" });
|
||||||
|
|
||||||
|
// Create and configure the cmdlet
|
||||||
|
var cmdlet = new GetOPNSenseFirmwareCmdlet();
|
||||||
|
|
||||||
|
// Use reflection to set the protected properties
|
||||||
|
SetProtectedProperty(cmdlet, "ApiClient", _mockApiClient.Object);
|
||||||
|
SetProtectedProperty(cmdlet, "Logger", _mockLogger.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
InvokeMethod(cmdlet, "ProcessRecord");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/status"), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetOPNSenseFirmwareCmdlet_WithChangelog_CallsGetChangelogAsync()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/changelog"))
|
||||||
|
.ReturnsAsync(new { changelog = "Changes in version X.Y.Z" });
|
||||||
|
|
||||||
|
// Create and configure the cmdlet
|
||||||
|
var cmdlet = new GetOPNSenseFirmwareCmdlet();
|
||||||
|
|
||||||
|
// Use reflection to set the protected properties
|
||||||
|
SetProtectedProperty(cmdlet, "ApiClient", _mockApiClient.Object);
|
||||||
|
SetProtectedProperty(cmdlet, "Logger", _mockLogger.Object);
|
||||||
|
|
||||||
|
// Set Changelog parameter
|
||||||
|
typeof(GetOPNSenseFirmwareCmdlet).GetProperty("Changelog").SetValue(cmdlet, new SwitchParameter(true));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
InvokeMethod(cmdlet, "ProcessRecord");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/changelog"), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void GetOPNSenseFirmwareCmdlet_WithAudit_CallsGetAuditAsync()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/audit"))
|
||||||
|
.ReturnsAsync(new { audit = new[] { new { name = "package1", version = "1.0.0" } } });
|
||||||
|
|
||||||
|
// Create and configure the cmdlet
|
||||||
|
var cmdlet = new GetOPNSenseFirmwareCmdlet();
|
||||||
|
|
||||||
|
// Use reflection to set the protected properties
|
||||||
|
SetProtectedProperty(cmdlet, "ApiClient", _mockApiClient.Object);
|
||||||
|
SetProtectedProperty(cmdlet, "Logger", _mockLogger.Object);
|
||||||
|
|
||||||
|
// Set Audit parameter
|
||||||
|
typeof(GetOPNSenseFirmwareCmdlet).GetProperty("Audit").SetValue(cmdlet, new SwitchParameter(true));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
InvokeMethod(cmdlet, "ProcessRecord");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/audit"), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetProtectedProperty(object obj, string propertyName, object value)
|
||||||
|
{
|
||||||
|
var propertyInfo = obj.GetType().BaseType.GetProperty(
|
||||||
|
propertyName,
|
||||||
|
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||||
|
|
||||||
|
if (propertyInfo == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Property {propertyName} not found on {obj.GetType().FullName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var backingField = obj.GetType().BaseType.GetField(
|
||||||
|
$"<{propertyName}>k__BackingField",
|
||||||
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
if (backingField != null)
|
||||||
|
{
|
||||||
|
backingField.SetValue(obj, value);
|
||||||
|
}
|
||||||
|
else if (propertyInfo.CanWrite)
|
||||||
|
{
|
||||||
|
propertyInfo.SetValue(obj, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Cannot set property {propertyName} on {obj.GetType().FullName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InvokeMethod(object obj, string methodName)
|
||||||
|
{
|
||||||
|
var methodInfo = obj.GetType().GetMethod(
|
||||||
|
methodName,
|
||||||
|
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||||
|
|
||||||
|
if (methodInfo == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Method {methodName} not found on {obj.GetType().FullName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
methodInfo.Invoke(obj, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Moq;
|
||||||
|
using PSOPNSenseAPI.Cmdlets;
|
||||||
|
using PSOPNSenseAPI.Services;
|
||||||
|
using PSOPNSenseAPI.Logging;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace PSOPNSenseAPI.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class FirmwareServiceTests
|
||||||
|
{
|
||||||
|
private Mock<OPNSenseApiClient> _mockApiClient;
|
||||||
|
private Mock<ILogger> _mockLogger;
|
||||||
|
private FirmwareService _firmwareService;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_mockApiClient = new Mock<OPNSenseApiClient>("https://example.com", "key", "secret", false, Mock.Of<ILogger>());
|
||||||
|
_mockLogger = new Mock<ILogger>();
|
||||||
|
_firmwareService = new FirmwareService(_mockApiClient.Object, _mockLogger.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task GetStatusAsync_ReturnsStatus()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedResponse = new { status = "ok" };
|
||||||
|
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/status"))
|
||||||
|
.ReturnsAsync(expectedResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _firmwareService.GetStatusAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.AreEqual("ok", result.Status);
|
||||||
|
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/status"), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task UpdateAsync_CallsCorrectEndpoint()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedResponse = new { status = "ok" };
|
||||||
|
_mockApiClient.Setup(c => c.PostAsync<dynamic>("core/firmware/update", It.IsAny<object>()))
|
||||||
|
.ReturnsAsync(expectedResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _firmwareService.UpdateAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.AreEqual("ok", result.Status);
|
||||||
|
_mockApiClient.Verify(c => c.PostAsync<dynamic>("core/firmware/update", It.IsAny<object>()), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task UpgradeAsync_CallsCorrectEndpoint()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedResponse = new { status = "ok" };
|
||||||
|
_mockApiClient.Setup(c => c.PostAsync<dynamic>("core/firmware/upgrade", It.IsAny<object>()))
|
||||||
|
.ReturnsAsync(expectedResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _firmwareService.UpgradeAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.AreEqual("ok", result.Status);
|
||||||
|
_mockApiClient.Verify(c => c.PostAsync<dynamic>("core/firmware/upgrade", It.IsAny<object>()), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task GetChangelogAsync_ReturnsChangelog()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedResponse = new { changelog = "Changes in version X.Y.Z" };
|
||||||
|
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/changelog"))
|
||||||
|
.ReturnsAsync(expectedResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _firmwareService.GetChangelogAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.AreEqual("Changes in version X.Y.Z", result.Changelog);
|
||||||
|
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/changelog"), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task GetHealthAsync_ReturnsHealth()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedResponse = new { health = "healthy" };
|
||||||
|
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/health"))
|
||||||
|
.ReturnsAsync(expectedResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _firmwareService.GetHealthAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.AreEqual("healthy", result.Health);
|
||||||
|
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/health"), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task GetAuditAsync_ReturnsAudit()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedResponse = new { audit = new[] { new { name = "package1", version = "1.0.0" } } };
|
||||||
|
_mockApiClient.Setup(c => c.GetAsync<dynamic>("core/firmware/audit"))
|
||||||
|
.ReturnsAsync(expectedResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _firmwareService.GetAuditAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsNotNull(result.Audit);
|
||||||
|
_mockApiClient.Verify(c => c.GetAsync<dynamic>("core/firmware/audit"), Times.Once);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user