Skip to content

Commit 6897c21

Browse files
Add unit tests for Go version detection and fix exception handling
Co-authored-by: tommasodotNET <12819039+tommasodotNET@users.noreply.github.com>
1 parent 2ce0835 commit 6897c21

File tree

3 files changed

+172
-6
lines changed

3 files changed

+172
-6
lines changed

src/CommunityToolkit.Aspire.Hosting.Golang/CommunityToolkit.Aspire.Hosting.Golang.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
<Compile Include="$(SharedDir)\PathNormalizer.cs" Link="Utils\PathNormalizer.cs" />
99
</ItemGroup>
1010

11+
<ItemGroup>
12+
<InternalsVisibleTo Include="CommunityToolkit.Aspire.Hosting.Golang.Tests" />
13+
</ItemGroup>
14+
1115
<ItemGroup>
1216
<PackageReference Include="Aspire.Hosting" />
1317
</ItemGroup>

src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ private static string GetDefaultGoBaseImage(string workingDirectory, IServicePro
147147
/// <param name="workingDirectory">The working directory of the Go project.</param>
148148
/// <param name="logger">The logger for diagnostic messages.</param>
149149
/// <returns>The detected Go version as a string, or <c>null</c> if no version is detected.</returns>
150-
private static string? DetectGoVersion(string workingDirectory, ILogger logger)
150+
internal static string? DetectGoVersion(string workingDirectory, ILogger logger)
151151
{
152152
// Check go.mod file
153153
var goModPath = Path.Combine(workingDirectory, "go.mod");
@@ -171,9 +171,17 @@ private static string GetDefaultGoBaseImage(string workingDirectory, IServicePro
171171
}
172172
}
173173
}
174-
catch (Exception ex)
174+
catch (IOException ex)
175175
{
176-
logger.LogDebug(ex, "Failed to parse go.mod file");
176+
logger.LogDebug(ex, "Failed to parse go.mod file due to IO error");
177+
}
178+
catch (UnauthorizedAccessException ex)
179+
{
180+
logger.LogDebug(ex, "Failed to parse go.mod file due to unauthorized access");
181+
}
182+
catch (RegexMatchTimeoutException ex)
183+
{
184+
logger.LogDebug(ex, "Failed to parse go.mod file due to regex timeout");
177185
}
178186
}
179187

@@ -193,8 +201,11 @@ private static string GetDefaultGoBaseImage(string workingDirectory, IServicePro
193201
using var process = Process.Start(startInfo);
194202
if (process != null)
195203
{
196-
var output = process.StandardOutput.ReadToEnd();
204+
// Read both output and error asynchronously to avoid deadlock
205+
var outputTask = process.StandardOutput.ReadToEndAsync();
206+
var errorTask = process.StandardError.ReadToEndAsync();
197207
process.WaitForExit();
208+
var output = outputTask.GetAwaiter().GetResult();
198209

199210
if (process.ExitCode == 0)
200211
{
@@ -209,9 +220,13 @@ private static string GetDefaultGoBaseImage(string workingDirectory, IServicePro
209220
}
210221
}
211222
}
212-
catch (Exception ex)
223+
catch (IOException ex)
224+
{
225+
logger.LogDebug(ex, "Failed to detect Go version from installed toolchain due to IO error");
226+
}
227+
catch (System.ComponentModel.Win32Exception ex)
213228
{
214-
logger.LogDebug(ex, "Failed to detect Go version from installed toolchain");
229+
logger.LogDebug(ex, "Failed to detect Go version from installed toolchain - go command not found or not executable");
215230
}
216231

217232
logger.LogDebug("No Go version detected, will use default version");
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using Aspire.Hosting;
2+
using Microsoft.Extensions.Logging.Abstractions;
3+
4+
namespace CommunityToolkit.Aspire.Hosting.Golang.Tests;
5+
6+
public class GoVersionDetectionTests
7+
{
8+
[Fact]
9+
public void DetectGoVersionFromGoMod()
10+
{
11+
// Arrange
12+
var workingDirectory = Path.GetFullPath(Path.Combine("..", "..", "..", "..", "..", "examples", "golang", "gin-api"));
13+
var logger = NullLogger.Instance;
14+
15+
// Act
16+
var version = GolangAppHostingExtension.DetectGoVersion(workingDirectory, logger);
17+
18+
// Assert
19+
Assert.NotNull(version);
20+
Assert.Equal("1.22", version);
21+
}
22+
23+
[Fact]
24+
public void DetectGoVersionFromGoMod_NonExistentDirectory()
25+
{
26+
// Arrange
27+
var workingDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
28+
var logger = NullLogger.Instance;
29+
30+
// Act
31+
var version = GolangAppHostingExtension.DetectGoVersion(workingDirectory, logger);
32+
33+
// Assert - should fall back to checking installed toolchain or return null
34+
// We don't assert a specific value because it depends on the system's Go installation
35+
Assert.True(version == null || !string.IsNullOrEmpty(version));
36+
}
37+
38+
[Fact]
39+
public void DetectGoVersionFromGoMod_WithPatchVersion()
40+
{
41+
// Arrange - Create a temporary directory with a go.mod file
42+
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
43+
Directory.CreateDirectory(tempDir);
44+
try
45+
{
46+
var goModPath = Path.Combine(tempDir, "go.mod");
47+
File.WriteAllText(goModPath, @"module testmodule
48+
49+
go 1.21.5
50+
51+
require (
52+
github.com/example/package v1.0.0
53+
)
54+
");
55+
56+
var logger = NullLogger.Instance;
57+
58+
// Act
59+
var version = GolangAppHostingExtension.DetectGoVersion(tempDir, logger);
60+
61+
// Assert
62+
Assert.NotNull(version);
63+
Assert.Equal("1.21", version);
64+
}
65+
finally
66+
{
67+
// Cleanup
68+
if (Directory.Exists(tempDir))
69+
{
70+
Directory.Delete(tempDir, true);
71+
}
72+
}
73+
}
74+
75+
[Fact]
76+
public void DetectGoVersionFromGoMod_WithMajorMinorOnly()
77+
{
78+
// Arrange - Create a temporary directory with a go.mod file
79+
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
80+
Directory.CreateDirectory(tempDir);
81+
try
82+
{
83+
var goModPath = Path.Combine(tempDir, "go.mod");
84+
File.WriteAllText(goModPath, @"module testmodule
85+
86+
go 1.20
87+
88+
require (
89+
github.com/example/package v1.0.0
90+
)
91+
");
92+
93+
var logger = NullLogger.Instance;
94+
95+
// Act
96+
var version = GolangAppHostingExtension.DetectGoVersion(tempDir, logger);
97+
98+
// Assert
99+
Assert.NotNull(version);
100+
Assert.Equal("1.20", version);
101+
}
102+
finally
103+
{
104+
// Cleanup
105+
if (Directory.Exists(tempDir))
106+
{
107+
Directory.Delete(tempDir, true);
108+
}
109+
}
110+
}
111+
112+
[Fact]
113+
public void DetectGoVersionFromGoMod_InvalidFormat()
114+
{
115+
// Arrange - Create a temporary directory with an invalid go.mod file
116+
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
117+
Directory.CreateDirectory(tempDir);
118+
try
119+
{
120+
var goModPath = Path.Combine(tempDir, "go.mod");
121+
File.WriteAllText(goModPath, @"module testmodule
122+
123+
go invalid
124+
125+
require (
126+
github.com/example/package v1.0.0
127+
)
128+
");
129+
130+
var logger = NullLogger.Instance;
131+
132+
// Act
133+
var version = GolangAppHostingExtension.DetectGoVersion(tempDir, logger);
134+
135+
// Assert - should fall back to checking installed toolchain or return null
136+
Assert.True(version == null || !string.IsNullOrEmpty(version));
137+
}
138+
finally
139+
{
140+
// Cleanup
141+
if (Directory.Exists(tempDir))
142+
{
143+
Directory.Delete(tempDir, true);
144+
}
145+
}
146+
}
147+
}

0 commit comments

Comments
 (0)