diff --git a/src/CommunityToolkit.Aspire.Hosting.Perl/PerlAppResourceBuilderExtensions.PackageManager.cs b/src/CommunityToolkit.Aspire.Hosting.Perl/PerlAppResourceBuilderExtensions.PackageManager.cs index c85dfb502..cabde12ec 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Perl/PerlAppResourceBuilderExtensions.PackageManager.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Perl/PerlAppResourceBuilderExtensions.PackageManager.cs @@ -382,7 +382,7 @@ private static void AddPackageInstaller( return; } - var installerName = $"{packageName}-installer"; + var installerName = $"{resource.Resource.Name}-{packageName}-installer"; resource.ApplicationBuilder.TryCreateResourceBuilder( installerName, out var existingResource); diff --git a/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/ApplicationModelCompositionTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/ApplicationModelCompositionTests.cs index 355a022e0..9b6a3fa15 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/ApplicationModelCompositionTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/ApplicationModelCompositionTests.cs @@ -22,4 +22,32 @@ public void MultipleResourcesCanBeAddedToModel() Assert.Contains(resources, r => r.Name == "script-app"); Assert.Contains(resources, r => r.Name == "api-app"); } + + [Fact] + public void MultipleResourcesWithSharedPackages_ModelBuildsSuccessfully() + { + var builder = DistributedApplication.CreateBuilder(); + + builder.AddPerlScript("script-app", "scripts", "worker.pl") + .WithCpanMinus() + .WithPackage("OpenTelemetry::SDK") + .WithPackage("DBI"); + + builder.AddPerlApi("api-app", "api", "server.pl") + .WithCpanMinus() + .WithPackage("OpenTelemetry::SDK") + .WithPackage("Mojolicious"); + + using var app = builder.Build(); + + var appModel = app.Services.GetRequiredService(); + var perlResources = appModel.Resources.OfType().ToList(); + var installers = appModel.Resources.OfType().ToList(); + + Assert.Equal(2, perlResources.Count); + Assert.Equal(4, installers.Count); + + var installerNames = installers.Select(i => i.Name).ToList(); + Assert.Equal(installerNames.Count, installerNames.Distinct(StringComparer.OrdinalIgnoreCase).Count()); + } } diff --git a/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/InstallerIntegrationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/InstallerIntegrationTests.cs index b9b856406..9d2df8df9 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/InstallerIntegrationTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/InstallerIntegrationTests.cs @@ -70,4 +70,29 @@ public void WithPerlbrewEnvironmentAndCpanm_ModuleInstallerDoesNotWaitForBootstr moduleInstaller.Annotations.OfType(), wait => wait.Resource.Name == "perl-app-perlbrew-cpanm-installer" && wait.WaitType == WaitType.WaitForCompletion); } + + [Fact, RequiresLinux] + public void TwoResourcesWithPerlbrewAndSamePackage_CreatesSeparateInstallers() + { + var builder = DistributedApplication.CreateBuilder(); + + builder.AddPerlScript("worker", "scripts", "workerService.pl") + .WithPerlbrewEnvironment("5.38.0", perlbrewRoot: "/tmp/ctaspire-missing-perlbrew-root") + .WithCpanMinus() + .WithPackage("OpenTelemetry::SDK"); + + builder.AddPerlApi("api", "scripts", "apiService.pl") + .WithPerlbrewEnvironment("5.38.0", perlbrewRoot: "/tmp/ctaspire-missing-perlbrew-root") + .WithCpanMinus() + .WithPackage("OpenTelemetry::SDK"); + + using var app = builder.Build(); + + var appModel = app.Services.GetRequiredService(); + var installers = appModel.Resources.OfType().ToList(); + + Assert.Equal(2, installers.Count); + Assert.Contains(installers, i => i.Name == "worker-OpenTelemetry88SDK-installer"); + Assert.Contains(installers, i => i.Name == "api-OpenTelemetry88SDK-installer"); + } } diff --git a/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/WithLocalLibTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/WithLocalLibTests.cs index 8d70cd0ef..d0379dd07 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/WithLocalLibTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/WithLocalLibTests.cs @@ -87,7 +87,7 @@ public async Task WithLocalLib_CalledTwice_DoesNotDuplicateResourceEnvironmentCa } [Theory] - [InlineData("specificLocal", "packageName", "packageName-installer")] + [InlineData("specificLocal", "packageName", "perl-app-packageName-installer")] public void WithPackageAndLocalLib_InstallerAndPackageAndLocalLibCorrectlyConfigured( string expectedLocalLibPath, string packageName, diff --git a/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/WithPackageTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/WithPackageTests.cs index 4493a1aeb..98788d5c5 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/WithPackageTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/WithPackageTests.cs @@ -8,8 +8,8 @@ namespace CommunityToolkit.Aspire.Hosting.Perl.Tests; public class WithPackageTests { [Theory] - [InlineData("Mojolicious", "Mojolicious-installer")] - [InlineData("OpenTelemetry::SDK", "OpenTelemetry88SDK-installer")] + [InlineData("Mojolicious", "perl-app-Mojolicious-installer")] + [InlineData("OpenTelemetry::SDK", "perl-app-OpenTelemetry88SDK-installer")] public void WithPackage_CreatesInstallerWithCorrectName(string moduleName, string expectedInstallerName) { var builder = DistributedApplication.CreateBuilder(); @@ -118,4 +118,87 @@ public void AddPerlApiWithCpanMinusAndPackage() Assert.Equal("Mojolicious", moduleAnnotation.Name); Assert.True(moduleAnnotation.SkipTest); } + + [Fact] + public void TwoResourcesWithSamePackage_CreatesSeparateInstallers() + { + var builder = DistributedApplication.CreateBuilder(); + + builder.AddPerlScript("worker", "scripts", "workerService.pl") + .WithCpanMinus() + .WithPackage("OpenTelemetry::SDK"); + + builder.AddPerlApi("api", "scripts", "apiService.pl") + .WithCpanMinus() + .WithPackage("OpenTelemetry::SDK"); + + using var app = builder.Build(); + + var appModel = app.Services.GetRequiredService(); + var installers = appModel.Resources.OfType().ToList(); + + Assert.Equal(2, installers.Count); + Assert.Contains(installers, i => i.Name == "worker-OpenTelemetry88SDK-installer"); + Assert.Contains(installers, i => i.Name == "api-OpenTelemetry88SDK-installer"); + } + + [Fact] + public void TwoResourcesWithMultipleSharedPackages_CreatesIndependentInstallers() + { + var builder = DistributedApplication.CreateBuilder(); + + builder.AddPerlScript("worker", "scripts", "workerService.pl") + .WithCpanMinus() + .WithPackage("OpenTelemetry::SDK") + .WithPackage("DBI"); + + builder.AddPerlApi("api", "scripts", "apiService.pl") + .WithCpanMinus() + .WithPackage("OpenTelemetry::SDK") + .WithPackage("Mojolicious"); + + using var app = builder.Build(); + + var appModel = app.Services.GetRequiredService(); + var installers = appModel.Resources.OfType().ToList(); + + Assert.Equal(4, installers.Count); + Assert.Contains(installers, i => i.Name == "worker-OpenTelemetry88SDK-installer"); + Assert.Contains(installers, i => i.Name == "worker-DBI-installer"); + Assert.Contains(installers, i => i.Name == "api-OpenTelemetry88SDK-installer"); + Assert.Contains(installers, i => i.Name == "api-Mojolicious-installer"); + } + + [Fact] + public void TwoResourcesWithSamePackage_InstallersAreParentedCorrectly() + { + var builder = DistributedApplication.CreateBuilder(); + + builder.AddPerlScript("worker", "scripts", "workerService.pl") + .WithCpanMinus() + .WithPackage("DBI"); + + builder.AddPerlApi("api", "scripts", "apiService.pl") + .WithCpanMinus() + .WithPackage("DBI"); + + using var app = builder.Build(); + + var appModel = app.Services.GetRequiredService(); + + var workerInstaller = appModel.Resources.OfType() + .Single(i => i.Name == "worker-DBI-installer"); + var apiInstaller = appModel.Resources.OfType() + .Single(i => i.Name == "api-DBI-installer"); + + var workerParent = workerInstaller.Annotations + .OfType() + .Single(a => a.Type == "Parent"); + var apiParent = apiInstaller.Annotations + .OfType() + .Single(a => a.Type == "Parent"); + + Assert.Equal("worker", workerParent.Resource.Name); + Assert.Equal("api", apiParent.Resource.Name); + } }