diff --git a/src/Servers/IIS/IIS/test/IIS.FunctionalTests/ShadowCopyTests.cs b/src/Servers/IIS/IIS/test/IIS.FunctionalTests/ShadowCopyTests.cs index 1a449c9bf991..375bf607eaed 100644 --- a/src/Servers/IIS/IIS/test/IIS.FunctionalTests/ShadowCopyTests.cs +++ b/src/Servers/IIS/IIS/test/IIS.FunctionalTests/ShadowCopyTests.cs @@ -172,6 +172,91 @@ public async Task ShadowCopyE2EWorksWithFolderPresent() Assert.True(response.IsSuccessStatusCode); } + [ConditionalFact] + public async Task ShadowCopyE2EWorksWithOldFoldersPresent() + { + using var directory = TempDirectory.Create(); + var deploymentParameters = Fixture.GetBaseDeploymentParameters(); + deploymentParameters.HandlerSettings["experimentalEnableShadowCopy"] = "true"; + deploymentParameters.HandlerSettings["shadowCopyDirectory"] = directory.DirectoryPath; + var deploymentResult = await DeployAsync(deploymentParameters); + + // Start with 1 to exercise the incremental logic + DirectoryCopy(deploymentResult.ContentRoot, Path.Combine(directory.DirectoryPath, "1"), copySubDirs: true); + + var response = await deploymentResult.HttpClient.GetAsync("Wow!"); + Assert.True(response.IsSuccessStatusCode); + + using var secondTempDir = TempDirectory.Create(); + + // copy back and forth to cause file change notifications. + DirectoryCopy(deploymentResult.ContentRoot, secondTempDir.DirectoryPath, copySubDirs: true); + DirectoryCopy(secondTempDir.DirectoryPath, deploymentResult.ContentRoot, copySubDirs: true); + + response = await deploymentResult.HttpClient.GetAsync("Wow!"); + Assert.False(Directory.Exists(Path.Combine(directory.DirectoryPath, "0")), "Expected 0 shadow copy directory to be skipped"); + + // Depending on timing, this could result in a shutdown failure, but sometimes it succeeds, handle both situations + if (!response.IsSuccessStatusCode) + { + Assert.Equal("Application Shutting Down", response.ReasonPhrase); + } + + // This shutdown should trigger a copy to the next highest directory, which will be 2 + await deploymentResult.AssertRecycledAsync(); + + Assert.True(Directory.Exists(Path.Combine(directory.DirectoryPath, "2")), "Expected 2 shadow copy directory"); + + response = await deploymentResult.HttpClient.GetAsync("Wow!"); + Assert.True(response.IsSuccessStatusCode); + } + + [ConditionalFact] + public async Task ShadowCopyCleansUpOlderFolders() + { + using var directory = TempDirectory.Create(); + var deploymentParameters = Fixture.GetBaseDeploymentParameters(); + deploymentParameters.HandlerSettings["experimentalEnableShadowCopy"] = "true"; + deploymentParameters.HandlerSettings["shadowCopyDirectory"] = directory.DirectoryPath; + var deploymentResult = await DeployAsync(deploymentParameters); + + // Start with a bunch of junk + DirectoryCopy(deploymentResult.ContentRoot, Path.Combine(directory.DirectoryPath, "1"), copySubDirs: true); + DirectoryCopy(deploymentResult.ContentRoot, Path.Combine(directory.DirectoryPath, "3"), copySubDirs: true); + DirectoryCopy(deploymentResult.ContentRoot, Path.Combine(directory.DirectoryPath, "10"), copySubDirs: true); + + var response = await deploymentResult.HttpClient.GetAsync("Wow!"); + Assert.True(response.IsSuccessStatusCode); + + using var secondTempDir = TempDirectory.Create(); + + // copy back and forth to cause file change notifications. + DirectoryCopy(deploymentResult.ContentRoot, secondTempDir.DirectoryPath, copySubDirs: true); + DirectoryCopy(secondTempDir.DirectoryPath, deploymentResult.ContentRoot, copySubDirs: true); + + response = await deploymentResult.HttpClient.GetAsync("Wow!"); + Assert.False(Directory.Exists(Path.Combine(directory.DirectoryPath, "0")), "Expected 0 shadow copy directory to be skipped"); + + // Depending on timing, this could result in a shutdown failure, but sometimes it succeeds, handle both situations + if (!response.IsSuccessStatusCode) + { + Assert.Equal("Application Shutting Down", response.ReasonPhrase); + } + + // This shutdown should trigger a copy to the next highest directory, which will be 11 + await deploymentResult.AssertRecycledAsync(); + + Assert.True(Directory.Exists(Path.Combine(directory.DirectoryPath, "11")), "Expected 11 shadow copy directory"); + + response = await deploymentResult.HttpClient.GetAsync("Wow!"); + Assert.True(response.IsSuccessStatusCode); + + // Verify old directories were cleaned up + Assert.False(Directory.Exists(Path.Combine(directory.DirectoryPath, "1")), "Expected 1 shadow copy directory to be deleted"); + Assert.False(Directory.Exists(Path.Combine(directory.DirectoryPath, "3")), "Expected 3 shadow copy directory to be deleted"); + } + + [ConditionalFact] [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_20H2, SkipReason = "Shutdown hangs https://github.com/dotnet/aspnetcore/issues/25107")] public async Task ShadowCopyIgnoresItsOwnDirectoryWithRelativePathSegmentWhenCopying()