| File: DevTunnelExpirationTests.cs | Web Access |
| Project: src\tests\Aspire.Hosting.DevTunnels.Tests\Aspire.Hosting.DevTunnels.Tests.csproj (Aspire.Hosting.DevTunnels.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Utils; using Microsoft.Extensions.Configuration; namespace Aspire.Hosting.DevTunnels.Tests; public class DevTunnelExpirationTests { [Fact] public void ExpirationHours_DefaultsToNullAndCanBeCleared() { var options = new DevTunnelOptions(); Assert.Null(options.ExpirationHours); options.ExpirationHours = 24; options.ExpirationHours = null; Assert.Null(options.ExpirationHours); } [Theory] [InlineData(1)] [InlineData(25)] [InlineData(720)] public void ExpirationHours_AcceptsValuesWithinRange(int hours) { var options = new DevTunnelOptions { ExpirationHours = hours }; Assert.Equal(hours, options.ExpirationHours); } [Theory] [InlineData(int.MinValue)] [InlineData(0)] [InlineData(721)] [InlineData(int.MaxValue)] public void ExpirationHours_RejectsInvalidValuesWithoutChangingOptions(int hours) { var options = new DevTunnelOptions { ExpirationHours = 24 }; var exception = Assert.Throws<ArgumentOutOfRangeException>(() => options.ExpirationHours = hours); Assert.Equal("value", exception.ParamName); Assert.Equal(hours, exception.ActualValue); Assert.Equal(24, options.ExpirationHours); } [Theory] [InlineData(false, 1)] [InlineData(true, 24)] [InlineData(false, 720)] public void WithExpiration_ConfiguresOptions(bool polyglot, int hours) { using var builder = TestDistributedApplicationBuilder.Create(); var tunnel = polyglot ? builder.AddDevTunnelForPolyglot("tunnel") : builder.AddDevTunnel("tunnel"); var result = tunnel.WithExpiration(hours); Assert.Same(tunnel, result); Assert.Equal(hours, tunnel.Resource.Options.ExpirationHours); } [Fact] public void WithExpiration_RejectsNullBuilder() { IResourceBuilder<DevTunnelResource> builder = null!; var exception = Assert.Throws<ArgumentNullException>(() => builder.WithExpiration(24)); Assert.Equal("tunnelBuilder", exception.ParamName); } [Theory] [InlineData(int.MinValue)] [InlineData(0)] [InlineData(721)] [InlineData(int.MaxValue)] public void WithExpiration_RejectsInvalidExpiration(int hours) { using var builder = TestDistributedApplicationBuilder.Create(); var tunnel = builder.AddDevTunnel("tunnel"); var exception = Assert.Throws<ArgumentOutOfRangeException>(() => tunnel.WithExpiration(hours)); Assert.Equal("expirationHours", exception.ParamName); Assert.Null(tunnel.Resource.Options.ExpirationHours); } [Theory] [InlineData(null)] [InlineData(1)] [InlineData(24)] [InlineData(25)] [InlineData(720)] public async Task CreateAndUpdate_PassExpirationInHours(int? hours) { var cli = new TestDevTunnelCli(); cli.EnqueueCreateResult(0); cli.EnqueueUpdateResult(0); var options = new DevTunnelOptions { ExpirationHours = hours }; await cli.CreateTunnelAsync("mytunnel", options); await cli.UpdateTunnelAsync("mytunnel", options); await Verify(cli.Calls.Select(call => call.Arguments)).UseParameters(hours); } [Fact] public async Task CreateAndUpdate_WithNullOptions_OmitExpiration() { var cli = new TestDevTunnelCli(); cli.EnqueueCreateResult(0); cli.EnqueueUpdateResult(0); await cli.CreateTunnelAsync("mytunnel"); await cli.UpdateTunnelAsync("mytunnel"); await Verify(cli.Calls.Select(call => call.Arguments)); } [Fact] public async Task CreateAndUpdate_FormatExpirationInvariantly() { var originalCulture = CultureInfo.CurrentCulture; try { CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("ar-SA"); var cli = new TestDevTunnelCli(); cli.EnqueueCreateResult(0); cli.EnqueueUpdateResult(0); var options = new DevTunnelOptions { ExpirationHours = 25 }; await cli.CreateTunnelAsync("mytunnel", options); await cli.UpdateTunnelAsync("mytunnel", options); await Verify(cli.Calls.Select(call => call.Arguments)); } finally { CultureInfo.CurrentCulture = originalCulture; } } [Theory] [InlineData(null)] [InlineData(24)] public async Task CreateTunnelAsync_WhenTunnelExists_PassesExpirationToUpdate(int? hours) { var cli = new TestDevTunnelCli(); cli.EnqueueCreateResult(DevTunnelCli.ResourceConflictsWithExistingExitCode); cli.EnqueueUpdateResult(0, """{"tunnelId":"mytunnel.eun1"}"""); cli.EnqueueResetAccessResult(0, """{"accessControlEntries":[]}"""); var client = new DevTunnelCliClient(new ConfigurationBuilder().Build(), cli); var options = new DevTunnelOptions { Region = DevTunnelRegion.NorthEurope, ExpirationHours = hours }; var tunnel = await client.CreateTunnelAsync("mytunnel", options); Assert.Equal("mytunnel.eun1", tunnel.TunnelId); await Verify(cli.Calls).UseParameters(hours); } [Fact] public async Task ToLoggerString_IncludesExpiration() { var options = new DevTunnelOptions { ExpirationHours = 24 }; await Verify(options.ToLoggerString()); } }