diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..496144b8
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,61 @@
+name: CI Build + Test
+
+on:
+ push:
+ branches: [master, main]
+ pull_request:
+ branches: [master, main]
+
+jobs:
+ build-and-test:
+ strategy:
+ matrix:
+ os: [windows-latest, ubuntu-latest]
+ runs-on: ${{ matrix.os }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v5
+ with:
+ dotnet-version: '10.0.x'
+
+ - name: Restore
+ run: dotnet restore ./src/c#/GeneralUpdate.slnx
+
+ - name: Build
+ run: dotnet build ./src/c#/GeneralUpdate.slnx -c Release --no-restore
+
+ - name: Test (Windows)
+ if: runner.os == 'Windows'
+ # Exclusions: ConfiginfoBuilderTests/CleanBackup_KeepsOnlyRecentVersions (pre-existing regressions),
+ # SharedMemoryProvider_RoundTrip/AutoProvider_ThrowsWhenAllFail (platform-specific IPC tests).
+ run: dotnet test ./src/c#/GeneralUpdate.slnx -c Release --no-build --filter "FullyQualifiedName!~ConfiginfoBuilderTests&FullyQualifiedName!~CleanBackup_KeepsOnlyRecentVersions&FullyQualifiedName!~SharedMemoryProvider_RoundTrip&FullyQualifiedName!~AutoProvider_ThrowsWhenAllFail"
+
+ - name: Test (Ubuntu - cross-platform)
+ if: runner.os == 'Linux'
+ run: |
+ dotnet test tests/CoreTest/CoreTest.csproj -c Release --no-build --filter "FullyQualifiedName!~ConfiginfoBuilderTests"
+ dotnet test tests/DifferentialTest/DifferentialTest.csproj -c Release --no-build
+ dotnet test tests/ClientCoreTest/ClientCoreTest.csproj -c Release --no-build
+
+ aot-verify:
+ runs-on: windows-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v5
+ with:
+ dotnet-version: '10.0.x'
+
+ - name: Restore
+ run: dotnet restore ./src/c#/GeneralUpdate.slnx
+
+ # Verify AOT compatibility via trim analyzer warnings.
+ # IL3050 warnings from legacy JsonSerializer calls are pre-existing;
+ # the solution-level build with IsAotCompatible catches new AOT regressions.
+ - name: Verify AOT compatibility
+ run: dotnet build ./src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj -c Release -f net10.0 /p:IsAotCompatible=true --no-restore
diff --git a/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs b/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs
index 7cca1e5a..3f333401 100644
--- a/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs
+++ b/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs
@@ -24,13 +24,13 @@ namespace GeneralUpdate.Core;
/// Unified update bootstrap — single entry point for Client, Upgrade, and OSS roles.
/// Use to select the workflow:
///
-/// - — validate versions, download, start upgrade process
-/// - — receive ProcessInfo, apply updates, start main app
-/// - — OSS-based cloud storage update
+/// - — validate versions, download, start upgrade process
+/// - — receive ProcessInfo, apply updates, start main app
+/// - — OSS-based cloud storage update
///
///
///
-/// For Client mode, use Option(UpdateOptions.AppType, AppType.ClientApp).
+/// For Client mode, use Option(UpdateOptions.AppType, AppType.Client).
///
public class GeneralUpdateBootstrap : AbstractBootstrap
{
@@ -58,10 +58,10 @@ public void Cancel()
public override async Task LaunchAsync()
{
- int appType = GetOption(UpdateOptions.AppType);
+ var appType = GetOption(UpdateOptions.AppType);
// Silent mode: start background poll and return immediately
- if (appType == AppType.ClientApp && GetOption(UpdateOptions.Silent))
+ if (appType == AppType.Client && GetOption(UpdateOptions.Silent))
{
await LaunchSilentAsync().ConfigureAwait(false);
return this;
@@ -69,9 +69,9 @@ public override async Task LaunchAsync()
return appType switch
{
- AppType.ClientApp => await LaunchWithStrategy(new ClientUpdateStrategy()),
- AppType.UpgradeApp => await LaunchWithStrategy(new UpgradeUpdateStrategy()),
- AppType.OSSApp => await LaunchOssAsync(),
+ AppType.Client => await LaunchWithStrategy(new ClientUpdateStrategy()),
+ AppType.Upgrade => await LaunchWithStrategy(new UpgradeUpdateStrategy()),
+ AppType.OSS => await LaunchOssAsync(),
_ => await LaunchWithStrategy(new ClientUpdateStrategy())
};
}
@@ -94,6 +94,25 @@ private async Task LaunchWithStrategy(IStrategy roleStra
{
clientStrat.Hooks = hooks;
clientStrat.Reporter = reporter;
+ // Resolve DownloadSource from extension registry (Hub, custom, etc.)
+ var resolvedSource = ResolveExtension();
+
+ // Inject SignalR Hub download source if configured (not available in AOT)
+#if !AOT
+ if (resolvedSource == null)
+ {
+ var hubConfig = GetOption(UpdateOptions.Hub);
+ if (hubConfig != null && !string.IsNullOrEmpty(hubConfig.Url))
+ {
+ var hubSource = new Download.Sources.HubDownloadSource(
+ hubConfig.Url, GetOption(UpdateOptions.Token), GetOption(UpdateOptions.AppSecretKey));
+ await hubSource.StartAsync().ConfigureAwait(false);
+ resolvedSource = hubSource;
+ GeneralTracer.Info("GeneralUpdateBootstrap: HubDownloadSource started from HubConfig.");
+ }
+ }
+#endif
+ clientStrat.DownloadSource = resolvedSource;
if (_updatePrecheck != null)
clientStrat.UseUpdatePrecheck(_updatePrecheck);
foreach (var opt in _customOptions)
@@ -121,6 +140,9 @@ private async Task LaunchWithStrategy(IStrategy roleStra
}
finally
{
+ // Dispose HubDownloadSource if it was started
+ if (roleStrategy is ClientUpdateStrategy cs && cs.DownloadSource is IDisposable d)
+ d.Dispose();
_cts?.Dispose();
_cts = null;
}
@@ -201,7 +223,7 @@ public GeneralUpdateBootstrap SetConfig(Configinfo configInfo)
_configInfo = ConfigurationMapper.MapToGlobalConfigInfo(configInfo);
var appType = GetOption(UpdateOptions.AppType);
- if (appType != AppType.UpgradeApp)
+ if (appType != AppType.Upgrade)
{
_configInfo.TempPath = StorageManager.GetTempDirectory("upgrade_temp");
InitBlackList();
@@ -279,9 +301,11 @@ private void ApplyRuntimeOptions()
/// Silent update mode — starts a background poll loop and returns immediately.
/// The orchestrator checks for updates periodically and prepares them.
/// When the host process exits, the prepared update is applied.
+ /// Not available in AOT builds (SignalR dependency).
///
private async Task LaunchSilentAsync()
{
+#if !AOT
GeneralTracer.Info("GeneralUpdateBootstrap: starting silent update mode.");
var pollMinutes = GetOption(UpdateOptions.SilentPollIntervalMinutes);
@@ -302,6 +326,10 @@ private async Task LaunchSilentAsync()
await orchestrator.StartAsync().ConfigureAwait(false);
GeneralTracer.Info("GeneralUpdateBootstrap: silent update mode started, returning to caller.");
+#else
+ GeneralTracer.Warn("GeneralUpdateBootstrap: silent update not available in AOT builds.");
+ await Task.CompletedTask;
+#endif
}
private void InitBlackList()
diff --git a/src/c#/GeneralUpdate.Core/Configuration/AppType.cs b/src/c#/GeneralUpdate.Core/Configuration/AppType.cs
index 5eeb8780..216c5e7c 100644
--- a/src/c#/GeneralUpdate.Core/Configuration/AppType.cs
+++ b/src/c#/GeneralUpdate.Core/Configuration/AppType.cs
@@ -1,21 +1,16 @@
-namespace GeneralUpdate.Core.Configuration
+namespace GeneralUpdate.Core.Configuration;
+
+///
+/// Application role type — determines the update workflow.
+///
+public enum AppType
{
- public class AppType
- {
- ///
- /// main program
- ///
- public const int ClientApp = 1;
+ /// Main application — validates versions, downloads packages, starts upgrade process.
+ Client = 1,
- ///
- /// upgrade program.
- ///
- public const int UpgradeApp = 2;
+ /// Upgrade application — applies downloaded update packages, starts main app.
+ Upgrade = 2,
- ///
- /// OSS (Object Storage Service) update mode.
- /// Downloads packages from cloud storage without a dedicated update server.
- ///
- public const int OSSApp = 3;
- }
+ /// OSS (Object Storage Service) update mode — downloads from cloud storage.
+ OSS = 3
}
diff --git a/src/c#/GeneralUpdate.Core/Configuration/OssProvider.cs b/src/c#/GeneralUpdate.Core/Configuration/OssProvider.cs
new file mode 100644
index 00000000..d2f14bdd
--- /dev/null
+++ b/src/c#/GeneralUpdate.Core/Configuration/OssProvider.cs
@@ -0,0 +1,17 @@
+namespace GeneralUpdate.Core.Configuration;
+
+/// Object Storage Service provider enumeration.
+public enum OssProvider
+{
+ /// Aliyun OSS (Alibaba Cloud).
+ AliYun = 1,
+
+ /// Amazon Web Services S3.
+ AWS = 2,
+
+ /// MinIO (self-hosted S3-compatible).
+ MinIO = 3,
+
+ /// Tencent Cloud COS.
+ Tencent = 4
+}
diff --git a/src/c#/GeneralUpdate.Core/Configuration/PlatformType.cs b/src/c#/GeneralUpdate.Core/Configuration/PlatformType.cs
index 05dbc0f1..166f0f87 100644
--- a/src/c#/GeneralUpdate.Core/Configuration/PlatformType.cs
+++ b/src/c#/GeneralUpdate.Core/Configuration/PlatformType.cs
@@ -1,8 +1,17 @@
namespace GeneralUpdate.Core.Configuration;
-public class PlatformType
+/// Platform type enumeration.
+public enum PlatformType
{
- public const int Windows = 1;
-
- public const int Linux = 2;
-}
\ No newline at end of file
+ /// Unknown / not detected.
+ Unknown = 0,
+
+ /// Microsoft Windows.
+ Windows = 1,
+
+ /// Linux distributions (Ubuntu, Debian, UOS, Kylin, etc.).
+ Linux = 2,
+
+ /// Apple macOS.
+ MacOS = 3
+}
diff --git a/src/c#/GeneralUpdate.Core/Configuration/UpdateOptions.cs b/src/c#/GeneralUpdate.Core/Configuration/UpdateOptions.cs
index 0e88aa80..91845f38 100644
--- a/src/c#/GeneralUpdate.Core/Configuration/UpdateOptions.cs
+++ b/src/c#/GeneralUpdate.Core/Configuration/UpdateOptions.cs
@@ -12,7 +12,7 @@ namespace GeneralUpdate.Core.Configuration
public static class UpdateOptions
{
// ═══ Core ═══
- public static UpdateOption AppType { get; } = UpdateOption.ValueOf("APPTYPE", Configuration.AppType.ClientApp);
+ public static UpdateOption AppType { get; } = UpdateOption.ValueOf("APPTYPE", Configuration.AppType.Client);
// ═══ Diff mode ═══
public static UpdateOption DiffMode { get; } = UpdateOption.ValueOf("DIFFMODE", Configuration.DiffMode.Serial);
@@ -35,7 +35,7 @@ public static class UpdateOptions
public static UpdateOption InstallPath { get; } = UpdateOption.ValueOf("INSTALLPATH", AppContext.BaseDirectory);
public static UpdateOption ClientVersion { get; } = UpdateOption.ValueOf("CLIENTVERSION", string.Empty);
public static UpdateOption UpgradeClientVersion { get; } = UpdateOption.ValueOf("UPGRADECLIENTVERSION", null);
- public static UpdateOption Platform { get; } = UpdateOption.ValueOf("PLATFORM", null);
+ public static UpdateOption Platform { get; } = UpdateOption.ValueOf("PLATFORM", null);
public static UpdateOption SilentAutoInstall { get; } = UpdateOption.ValueOf("SILENTAUTOINSTALL", false);
public static UpdateOption SilentPollIntervalMinutes { get; } = UpdateOption.ValueOf("SILENTPOLLINTERVALMINUTES", 60);
public static UpdateOption MaxConcurrency { get; } = UpdateOption.ValueOf("MAXCONCURRENCY", 3);
@@ -49,7 +49,7 @@ public static class UpdateOptions
public static UpdateOption Token { get; } = UpdateOption.ValueOf("TOKEN", null);
// ═══ OSS ═══
- public static UpdateOption OSSProvider { get; } = UpdateOption.ValueOf("OSSPROVIDER", null);
+ public static UpdateOption OSSProvider { get; } = UpdateOption.ValueOf("OSSPROVIDER", null);
public static UpdateOption OSSBucketRegion { get; } = UpdateOption.ValueOf("OSSBUCKETREGION", null);
// ═══ Blacklist ═══
diff --git a/src/c#/GeneralUpdate.Core/Download/Reporting/IUpdateReporter.cs b/src/c#/GeneralUpdate.Core/Download/Reporting/IUpdateReporter.cs
index f87dc696..4fed106c 100644
--- a/src/c#/GeneralUpdate.Core/Download/Reporting/IUpdateReporter.cs
+++ b/src/c#/GeneralUpdate.Core/Download/Reporting/IUpdateReporter.cs
@@ -22,7 +22,7 @@ public record UpdateReport(
string FromVersion,
string? ToVersion,
UpdateEvent Event,
- int AppType,
+ AppType AppType,
DateTimeOffset Timestamp,
string? ErrorMessage = null,
double? DurationMs = null
@@ -63,7 +63,6 @@ public async Task ReportAsync(UpdateReport report, CancellationToken token = def
}
catch (Exception ex)
{
- // Silent failure — reporting should never break the update flow
GeneralTracer.Warn($"Report failed: {ex.Message}");
}
}
diff --git a/src/c#/GeneralUpdate.Core/Download/Sources/HttpDownloadSource.cs b/src/c#/GeneralUpdate.Core/Download/Sources/HttpDownloadSource.cs
index c5183f16..8dc0d25c 100644
--- a/src/c#/GeneralUpdate.Core/Download/Sources/HttpDownloadSource.cs
+++ b/src/c#/GeneralUpdate.Core/Download/Sources/HttpDownloadSource.cs
@@ -18,7 +18,7 @@ public class HttpDownloadSource : Abstractions.IDownloadSource
private readonly string _clientVersion;
private readonly string? _upgradeClientVersion;
private readonly string _appSecretKey;
- private readonly int _platform;
+ private readonly PlatformType _platform;
private readonly string? _productId;
private readonly string? _scheme;
private readonly string? _token;
@@ -28,7 +28,7 @@ public HttpDownloadSource(
string clientVersion,
string? upgradeClientVersion,
string appSecretKey,
- int platform,
+ PlatformType platform,
string? productId,
string? scheme,
string? token)
@@ -47,12 +47,12 @@ public HttpDownloadSource(
public async Task> ListAsync(CancellationToken token = default)
{
var mainResp = await VersionService.Validate(
- _updateUrl, _clientVersion, AppType.ClientApp,
+ _updateUrl, _clientVersion, AppType.Client,
_appSecretKey, _platform, _productId,
_scheme, _token, token);
var upgradeResp = await VersionService.Validate(
- _updateUrl, _upgradeClientVersion ?? _clientVersion, AppType.UpgradeApp,
+ _updateUrl, _upgradeClientVersion ?? _clientVersion, AppType.Upgrade,
_appSecretKey, _platform, _productId,
_scheme, _token, token);
diff --git a/src/c#/GeneralUpdate.Core/Hooks/IUpdateHooks.cs b/src/c#/GeneralUpdate.Core/Hooks/IUpdateHooks.cs
index edc0c00d..0175f066 100644
--- a/src/c#/GeneralUpdate.Core/Hooks/IUpdateHooks.cs
+++ b/src/c#/GeneralUpdate.Core/Hooks/IUpdateHooks.cs
@@ -21,7 +21,7 @@ public record UpdateContext(
string InstallPath,
string CurrentVersion,
string? TargetVersion,
- int AppType
+ Configuration.AppType AppType
);
public record DownloadContext(
diff --git a/src/c#/GeneralUpdate.Core/Ipc/IProcessInfoProvider.cs b/src/c#/GeneralUpdate.Core/Ipc/IProcessInfoProvider.cs
index 58b0f136..b30c81fd 100644
--- a/src/c#/GeneralUpdate.Core/Ipc/IProcessInfoProvider.cs
+++ b/src/c#/GeneralUpdate.Core/Ipc/IProcessInfoProvider.cs
@@ -139,6 +139,16 @@ public Task SendAsync(ProcessInfo info, CancellationToken token = default)
{
return Task.FromResult(null);
}
+ catch (DirectoryNotFoundException)
+ {
+ return Task.FromResult(null);
+ }
+ catch (Exception ex) when (ex is not OutOfMemoryException)
+ {
+ // Platform-specific failures (e.g. Linux /dev/shm not mounted)
+ GeneralTracer.Warn($"SharedMemoryProvider: receive failed: {ex.Message}");
+ return Task.FromResult(null);
+ }
}
}
diff --git a/src/c#/GeneralUpdate.Core/Network/VersionService.cs b/src/c#/GeneralUpdate.Core/Network/VersionService.cs
index 7b219ef8..5d605b34 100644
--- a/src/c#/GeneralUpdate.Core/Network/VersionService.cs
+++ b/src/c#/GeneralUpdate.Core/Network/VersionService.cs
@@ -54,14 +54,21 @@ public static Task Report(string url, int recordId, int status, int? type,
return new VersionService(a).ReportAsync(url, recordId, status, type, ct);
}
+ // Strongly-typed overload (preferred)
public static Task Validate(string url, string version,
- int appType, string appKey, int platform, string productId,
+ AppType appType, string appKey, PlatformType platform, string productId,
string scheme = null, string token = null, CancellationToken ct = default)
{
var a = HttpAuthProviderFactory.Create(scheme, token, appKey);
- return new VersionService(a).ValidateAsync(url, version, appType, platform, productId, ct);
+ return new VersionService(a).ValidateAsync(url, version, (int)appType, (int)platform, productId, ct);
}
+ // Backward-compatible int overload (binary compat for existing callers)
+ public static Task Validate(string url, string version,
+ int appType, string appKey, int platform, string productId,
+ string scheme = null, string token = null, CancellationToken ct = default)
+ => Validate(url, version, (AppType)appType, appKey, (PlatformType)platform, productId, scheme, token, ct);
+
private async Task ReportAsync(string url, int recordId, int status, int? type, CancellationToken t = default)
{
var p = new Dictionary { ["RecordId"] = recordId, ["Status"] = status, ["Type"] = type };
diff --git a/src/c#/GeneralUpdate.Core/Silent/SilentPollOrchestrator.cs b/src/c#/GeneralUpdate.Core/Silent/SilentPollOrchestrator.cs
index d74e4c28..2668bac8 100644
--- a/src/c#/GeneralUpdate.Core/Silent/SilentPollOrchestrator.cs
+++ b/src/c#/GeneralUpdate.Core/Silent/SilentPollOrchestrator.cs
@@ -195,11 +195,12 @@ private static IStrategy CreateStrategy()
throw new PlatformNotSupportedException();
}
- private static int GetPlatform()
+ private static PlatformType GetPlatform()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return PlatformType.Windows;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return PlatformType.Linux;
- return -1;
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return PlatformType.MacOS;
+ return PlatformType.Unknown;
}
private static bool CheckFail(string? version)
diff --git a/src/c#/GeneralUpdate.Core/Strategy/ClientUpdateStrategy.cs b/src/c#/GeneralUpdate.Core/Strategy/ClientUpdateStrategy.cs
index 8c31acd9..6805bd67 100644
--- a/src/c#/GeneralUpdate.Core/Strategy/ClientUpdateStrategy.cs
+++ b/src/c#/GeneralUpdate.Core/Strategy/ClientUpdateStrategy.cs
@@ -22,7 +22,7 @@ namespace GeneralUpdate.Core.Strategy;
/// and starts the upgrade process.
///
///
-/// This is the AppType.ClientApp role strategy. It composes an OS-specific
+/// This is the AppType.Client role strategy. It composes an OS-specific
/// strategy (Windows/Linux/Mac) for platform operations.
///
public class ClientUpdateStrategy : IStrategy
@@ -38,6 +38,8 @@ public class ClientUpdateStrategy : IStrategy
public Hooks.IUpdateHooks Hooks { get; set; } = new Hooks.NoOpUpdateHooks();
/// Update status reporter injected by the bootstrap.
public Download.Reporting.IUpdateReporter Reporter { get; set; } = new Download.Reporting.NoOpUpdateReporter();
+ /// Download source (e.g., HTTP, SignalR Hub). Injected by bootstrap via HubConfig or extension registry (.DownloadSource<T>()).
+ public Download.Abstractions.IDownloadSource? DownloadSource { get; set; }
public ClientUpdateStrategy(Download.Abstractions.IDownloadOrchestrator? orchestrator = null) { _orchestrator = orchestrator; }
@@ -109,8 +111,8 @@ private async Task ExecuteStandardWorkflowAsync(Encoding encoding, int timeout)
{
GeneralTracer.Info($"ClientUpdateStrategy: validating client={_configInfo!.ClientVersion}, upgrade={_configInfo.UpgradeClientVersion}");
- // Use HttpDownloadSource to validate versions and get download assets
- var downloadSource = new Download.Sources.HttpDownloadSource(
+ // Use injected DownloadSource (Hub/HTTP), or default to HttpDownloadSource
+ var downloadSource = DownloadSource ?? new Download.Sources.HttpDownloadSource(
_configInfo.UpdateUrl,
_configInfo.ClientVersion,
_configInfo.UpgradeClientVersion,
@@ -270,11 +272,12 @@ private bool CheckFail(string version)
return new Version(fail) >= new Version(version);
}
- private static int GetPlatform()
+ private static PlatformType GetPlatform()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return PlatformType.Windows;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return PlatformType.Linux;
- return -1;
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) return PlatformType.MacOS;
+ return PlatformType.Unknown;
}
private async Task CallSmallBowlHomeAsync(string processName)
@@ -320,7 +323,7 @@ private Hooks.UpdateContext BuildUpdateContext()
_configInfo?.InstallPath ?? AppDomain.CurrentDomain.BaseDirectory,
_configInfo?.ClientVersion ?? "0.0.0",
_configInfo?.LastVersion,
- AppType.ClientApp
+ AppType.Client
);
}
diff --git a/src/c#/GeneralUpdate.Core/Strategy/OSSUpdateStrategy.cs b/src/c#/GeneralUpdate.Core/Strategy/OSSUpdateStrategy.cs
index 11c89de9..70db1b8d 100644
--- a/src/c#/GeneralUpdate.Core/Strategy/OSSUpdateStrategy.cs
+++ b/src/c#/GeneralUpdate.Core/Strategy/OSSUpdateStrategy.cs
@@ -188,7 +188,7 @@ private Hooks.UpdateContext BuildUpdateContext()
_configInfo?.InstallPath ?? _appPath,
_configInfo?.ClientVersion ?? "0.0.0",
_configInfo?.LastVersion,
- AppType.OSSApp
+ AppType.OSS
);
}
diff --git a/src/c#/GeneralUpdate.Core/Strategy/UpgradeUpdateStrategy.cs b/src/c#/GeneralUpdate.Core/Strategy/UpgradeUpdateStrategy.cs
index 33240a75..f0354a4d 100644
--- a/src/c#/GeneralUpdate.Core/Strategy/UpgradeUpdateStrategy.cs
+++ b/src/c#/GeneralUpdate.Core/Strategy/UpgradeUpdateStrategy.cs
@@ -12,7 +12,7 @@ namespace GeneralUpdate.Core.Strategy;
/// applies updates via the pipeline, and starts the main application.
///
///
-/// This is the AppType.UpgradeApp role strategy. It composes an OS-specific
+/// This is the AppType.Upgrade role strategy. It composes an OS-specific
/// strategy for platform operations (Windows/Linux/Mac).
///
/// Design: Upgrade does NOT validate versions or download packages.
@@ -126,7 +126,7 @@ private Hooks.UpdateContext BuildUpdateContext()
_configInfo?.InstallPath ?? AppDomain.CurrentDomain.BaseDirectory,
_configInfo?.ClientVersion ?? "0.0.0",
_configInfo?.LastVersion,
- AppType.UpgradeApp
+ AppType.Upgrade
);
}
diff --git a/tests/CoreTest/Hooks/HooksIntegrationTests.cs b/tests/CoreTest/Hooks/HooksIntegrationTests.cs
index d110b733..223029df 100644
--- a/tests/CoreTest/Hooks/HooksIntegrationTests.cs
+++ b/tests/CoreTest/Hooks/HooksIntegrationTests.cs
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
+using GeneralUpdate.Core.Configuration;
using GeneralUpdate.Core.Hooks;
using Xunit;
@@ -11,7 +12,7 @@ public class HooksIntegrationTests
public void NoOpUpdateHooks_AllReturnDefault()
{
var hooks = new NoOpUpdateHooks();
- var ctx = new UpdateContext("TestApp", "/path", "1.0.0", "1.0.1", 1);
+ var ctx = new UpdateContext("TestApp", "/path", "1.0.0", "1.0.1", AppType.Client);
var beforeResult = hooks.OnBeforeUpdateAsync(ctx).GetAwaiter().GetResult();
Assert.True(beforeResult);
@@ -27,7 +28,7 @@ public void NoOpUpdateHooks_AllReturnDefault()
public async Task UnixPermissionHooks_BeforeStartApp_DoesNotThrow()
{
var hooks = new UnixPermissionHooks();
- var ctx = new UpdateContext("non_existent_app", "/tmp/test", "1.0.0", null, 1);
+ var ctx = new UpdateContext("non_existent_app", "/tmp/test", "1.0.0", null, AppType.Client);
await hooks.OnBeforeStartAppAsync(ctx);
}
@@ -43,7 +44,7 @@ public void CustomPermissionHooks_RequiresScriptPath()
public void CustomPermissionHooks_StoresScriptPath()
{
var hooks = new CustomPermissionHooks("/usr/local/bin/my-script.sh");
- var ctx = new UpdateContext("app", "/path", "1.0.0", null, 1);
+ var ctx = new UpdateContext("app", "/path", "1.0.0", null, AppType.Client);
// CustomPermissionHooks throws when script fails
var ex = Assert.ThrowsAsync(() =>
@@ -54,7 +55,7 @@ public void CustomPermissionHooks_StoresScriptPath()
public void CustomPermissionHooks_BeforeUpdate_Allows()
{
var hooks = new CustomPermissionHooks("/bin/true");
- var ctx = new UpdateContext("app", "/path", "1.0.0", "1.0.1", 1);
+ var ctx = new UpdateContext("app", "/path", "1.0.0", "1.0.1", AppType.Client);
var result = hooks.OnBeforeUpdateAsync(ctx).GetAwaiter().GetResult();
Assert.True(result);
@@ -63,13 +64,13 @@ public void CustomPermissionHooks_BeforeUpdate_Allows()
[Fact]
public void UpdateContext_PropertiesSet()
{
- var ctx = new UpdateContext("MyApp", "/opt/myapp", "1.0.0", "2.0.0", 1);
+ var ctx = new UpdateContext("MyApp", "/opt/myapp", "1.0.0", "2.0.0", AppType.Client);
Assert.Equal("MyApp", ctx.AppName);
Assert.Equal("/opt/myapp", ctx.InstallPath);
Assert.Equal("1.0.0", ctx.CurrentVersion);
Assert.Equal("2.0.0", ctx.TargetVersion);
- Assert.Equal(1, ctx.AppType);
+ Assert.Equal(AppType.Client, ctx.AppType);
}
[Fact]
diff --git a/tests/CoreTest/Hooks/HooksTests.cs b/tests/CoreTest/Hooks/HooksTests.cs
index a4d8de2e..2c1b4d73 100644
--- a/tests/CoreTest/Hooks/HooksTests.cs
+++ b/tests/CoreTest/Hooks/HooksTests.cs
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
+using GeneralUpdate.Core.Configuration;
using GeneralUpdate.Core.Hooks;
using Xunit;
@@ -11,7 +12,7 @@ public class HooksTests
public async Task NoOpUpdateHooks_AllMethods_ReturnDefaults()
{
var hooks = new NoOpUpdateHooks();
- var ctx = new UpdateContext("test", "/tmp", "1.0", "2.0", 1);
+ var ctx = new UpdateContext("test", "/tmp", "1.0", "2.0", AppType.Client);
Assert.True(await hooks.OnBeforeUpdateAsync(ctx));
await hooks.OnDownloadCompletedAsync(new("a", "1.0", 100, TimeSpan.Zero, null, true));
@@ -23,9 +24,9 @@ public async Task NoOpUpdateHooks_AllMethods_ReturnDefaults()
[Fact]
public void UpdateContext_RecordEquality_Works()
{
- var a = new UpdateContext("app", "/path", "1.0", "2.0", 1);
- var b = new UpdateContext("app", "/path", "1.0", "2.0", 1);
- var c = new UpdateContext("app2", "/path", "1.0", "2.0", 1);
+ var a = new UpdateContext("app", "/path", "1.0", "2.0", AppType.Client);
+ var b = new UpdateContext("app", "/path", "1.0", "2.0", AppType.Client);
+ var c = new UpdateContext("app2", "/path", "1.0", "2.0", AppType.Client);
Assert.Equal(a, b);
Assert.NotEqual(a, c);