From bff07e30b8f8ddb8172c3ced41f8e549ba074d5c Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 24 Dec 2022 15:30:37 +0300 Subject: [PATCH 01/33] Add OC.Testing project --- OrchardCore.sln | 17 +++++++------- .../OrchardCore.Testing.csproj | 23 +++++++++++++++++++ 2 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj diff --git a/OrchardCore.sln b/OrchardCore.sln index 79af47faa79..a12c41d4d4f 100644 --- a/OrchardCore.sln +++ b/OrchardCore.sln @@ -440,7 +440,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OrchardCore.Themes", "Orcha EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Autoroute.Core", "src\OrchardCore\OrchardCore.Autoroute.Core\OrchardCore.Autoroute.Core.csproj", "{7F31D1A5-2B6F-448A-9337-482F876B85EF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCore.Security", "src\OrchardCore.Modules\OrchardCore.Security\OrchardCore.Security.csproj", "{B02C00A7-33C2-4FEE-9D0F-B14C349ADB68}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Security", "src\OrchardCore.Modules\OrchardCore.Security\OrchardCore.Security.csproj", "{B02C00A7-33C2-4FEE-9D0F-B14C349ADB68}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Abstractions.Tests", "test\OrchardCore.Abstractions.Tests\OrchardCore.Abstractions.Tests.csproj", "{FE8011DE-D917-4F74-9955-238B2BBA9165}" EndProject @@ -480,10 +480,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Media.AmazonS3" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.ArchiveLater", "src\OrchardCore.Modules\OrchardCore.ArchiveLater\OrchardCore.ArchiveLater.csproj", "{190C4BEB-C506-4F7F-BDCA-93F3C1C221BC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCore.Features.Core", "src\OrchardCore\OrchardCore.Features.Core\OrchardCore.Features.Core.csproj", "{122EC0DA-A593-4038-BD21-2D4A7061F348}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Features.Core", "src\OrchardCore\OrchardCore.Features.Core\OrchardCore.Features.Core.csproj", "{122EC0DA-A593-4038-BD21-2D4A7061F348}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Search", "src\OrchardCore.Modules\OrchardCore.Search\OrchardCore.Search.csproj", "{7BDF280B-70B7-4AFC-A6F7-B5759DCA2A2C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCore.Testing", "src\OrchardCore\OrchardCore.Testing\OrchardCore.Testing.csproj", "{C3DA562E-7B0B-455E-87FF-FF3E1D31A400}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1272,10 +1274,6 @@ Global {FF1C550C-6D30-499A-AF11-68DE7C8B6869}.Debug|Any CPU.Build.0 = Debug|Any CPU {FF1C550C-6D30-499A-AF11-68DE7C8B6869}.Release|Any CPU.ActiveCfg = Release|Any CPU {FF1C550C-6D30-499A-AF11-68DE7C8B6869}.Release|Any CPU.Build.0 = Release|Any CPU - {A6563050-EE6D-4E7C-81AA-C383DB3ED124}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A6563050-EE6D-4E7C-81AA-C383DB3ED124}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A6563050-EE6D-4E7C-81AA-C383DB3ED124}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A6563050-EE6D-4E7C-81AA-C383DB3ED124}.Release|Any CPU.Build.0 = Release|Any CPU {190C4BEB-C506-4F7F-BDCA-93F3C1C221BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {190C4BEB-C506-4F7F-BDCA-93F3C1C221BC}.Debug|Any CPU.Build.0 = Debug|Any CPU {190C4BEB-C506-4F7F-BDCA-93F3C1C221BC}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -1288,7 +1286,10 @@ Global {7BDF280B-70B7-4AFC-A6F7-B5759DCA2A2C}.Debug|Any CPU.Build.0 = Debug|Any CPU {7BDF280B-70B7-4AFC-A6F7-B5759DCA2A2C}.Release|Any CPU.ActiveCfg = Release|Any CPU {7BDF280B-70B7-4AFC-A6F7-B5759DCA2A2C}.Release|Any CPU.Build.0 = Release|Any CPU - + {C3DA562E-7B0B-455E-87FF-FF3E1D31A400}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3DA562E-7B0B-455E-87FF-FF3E1D31A400}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3DA562E-7B0B-455E-87FF-FF3E1D31A400}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3DA562E-7B0B-455E-87FF-FF3E1D31A400}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1513,7 +1514,7 @@ Global {190C4BEB-C506-4F7F-BDCA-93F3C1C221BC} = {90030E85-0C4F-456F-B879-443E8A3F220D} {122EC0DA-A593-4038-BD21-2D4A7061F348} = {F23AC6C2-DE44-4699-999D-3C478EF3D691} {7BDF280B-70B7-4AFC-A6F7-B5759DCA2A2C} = {90030E85-0C4F-456F-B879-443E8A3F220D} - + {C3DA562E-7B0B-455E-87FF-FF3E1D31A400} = {F23AC6C2-DE44-4699-999D-3C478EF3D691} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {46A1D25A-78D1-4476-9CBF-25B75E296341} diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj new file mode 100644 index 00000000000..f3a9b5ef9ae --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -0,0 +1,23 @@ + + + + + OrchardCore Testing + + $(OCFrameworkDescription) + + Implementation of OrchardCore testing APIs + + $(PackageTags) OrchardCoreFramework + + + + + + + + + + + + From 8e77805107cf45800ad3cd55ff133304fd92f1f7 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 24 Dec 2022 16:44:48 +0300 Subject: [PATCH 02/33] Add UseCultureAttribute --- OrchardCore.sln | 7 ++ src/OrchardCore.Build/Dependencies.props | 1 + .../OrchardCore.Testing.csproj | 1 + .../UseCultureAttribute.cs | 72 +++++++++++++++++++ .../OrchardCore.Testing.Tests.csproj | 28 ++++++++ .../UseCultureAttributeTests.cs | 64 +++++++++++++++++ test/OrchardCore.Testing.Tests/Usings.cs | 1 + 7 files changed, 174 insertions(+) create mode 100644 src/OrchardCore/OrchardCore.Testing/UseCultureAttribute.cs create mode 100644 test/OrchardCore.Testing.Tests/OrchardCore.Testing.Tests.csproj create mode 100644 test/OrchardCore.Testing.Tests/UseCultureAttributeTests.cs create mode 100644 test/OrchardCore.Testing.Tests/Usings.cs diff --git a/OrchardCore.sln b/OrchardCore.sln index a12c41d4d4f..43ac767a7e9 100644 --- a/OrchardCore.sln +++ b/OrchardCore.sln @@ -486,6 +486,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Search", "src\O EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCore.Testing", "src\OrchardCore\OrchardCore.Testing\OrchardCore.Testing.csproj", "{C3DA562E-7B0B-455E-87FF-FF3E1D31A400}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCore.Testing.Tests", "test\OrchardCore.Testing.Tests\OrchardCore.Testing.Tests.csproj", "{841FF342-25ED-487E-8EA4-65C015545F3E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1290,6 +1292,10 @@ Global {C3DA562E-7B0B-455E-87FF-FF3E1D31A400}.Debug|Any CPU.Build.0 = Debug|Any CPU {C3DA562E-7B0B-455E-87FF-FF3E1D31A400}.Release|Any CPU.ActiveCfg = Release|Any CPU {C3DA562E-7B0B-455E-87FF-FF3E1D31A400}.Release|Any CPU.Build.0 = Release|Any CPU + {841FF342-25ED-487E-8EA4-65C015545F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {841FF342-25ED-487E-8EA4-65C015545F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {841FF342-25ED-487E-8EA4-65C015545F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {841FF342-25ED-487E-8EA4-65C015545F3E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1515,6 +1521,7 @@ Global {122EC0DA-A593-4038-BD21-2D4A7061F348} = {F23AC6C2-DE44-4699-999D-3C478EF3D691} {7BDF280B-70B7-4AFC-A6F7-B5759DCA2A2C} = {90030E85-0C4F-456F-B879-443E8A3F220D} {C3DA562E-7B0B-455E-87FF-FF3E1D31A400} = {F23AC6C2-DE44-4699-999D-3C478EF3D691} + {841FF342-25ED-487E-8EA4-65C015545F3E} = {B8D16C60-99B4-43D5-A3AD-4CD89AF39B25} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {46A1D25A-78D1-4476-9CBF-25B75E296341} diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index 5166ac0d4ae..0437bb7a1a1 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -55,6 +55,7 @@ + diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index f3a9b5ef9ae..791c779ae2e 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -18,6 +18,7 @@ + diff --git a/src/OrchardCore/OrchardCore.Testing/UseCultureAttribute.cs b/src/OrchardCore/OrchardCore.Testing/UseCultureAttribute.cs new file mode 100644 index 00000000000..64e62df89e1 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/UseCultureAttribute.cs @@ -0,0 +1,72 @@ +using System; +using System.Globalization; +using System.Reflection; +using System.Threading; +using Xunit.Sdk; + +namespace OrchardCore.Testing; + +/// +/// Represents an attribute to be used in test method to replace the +/// and +/// with another culture(s). +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] +public class UseCultureAttribute : BeforeAfterTestAttribute +{ + private readonly Lazy _culture; + private readonly Lazy _uiCulture; + + private CultureInfo _originalCulture; + private CultureInfo _originalUICulture; + + /// + /// Creates an instance of with culture. + /// + /// The name of the culture to replace the current thread culture with. + public UseCultureAttribute(string culture) : this(culture, culture) + { + } + + /// + /// Creates an instance of with culture and UI culture. + /// + /// >The name of the culture to replace the current thread culture with. + /// >The name of the UI culture to replace the current thread UI culture with. + public UseCultureAttribute(string culture, string uiCulture) + { + _culture = new Lazy(() => new CultureInfo(culture, false)); + _uiCulture = new Lazy(() => new CultureInfo(uiCulture, false)); + } + + /// + /// Gets the culture. + /// + public CultureInfo Culture => _culture.Value; + + /// + /// Gets the UI culture. + /// + public CultureInfo UICulture => _uiCulture.Value; + + /// + public override void Before(MethodInfo methodUnderTest) + { + _originalCulture = Thread.CurrentThread.CurrentCulture; + _originalUICulture = Thread.CurrentThread.CurrentUICulture; + + SetCultures(Culture, UICulture); + } + + /// + public override void After(MethodInfo methodUnderTest) => SetCultures(_originalCulture, _originalUICulture); + + private static void SetCultures(CultureInfo culture, CultureInfo uiCulture) + { + Thread.CurrentThread.CurrentCulture = culture; + Thread.CurrentThread.CurrentUICulture = uiCulture; + + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + } +} diff --git a/test/OrchardCore.Testing.Tests/OrchardCore.Testing.Tests.csproj b/test/OrchardCore.Testing.Tests/OrchardCore.Testing.Tests.csproj new file mode 100644 index 00000000000..90d6e0511a3 --- /dev/null +++ b/test/OrchardCore.Testing.Tests/OrchardCore.Testing.Tests.csproj @@ -0,0 +1,28 @@ + + + + + + $(CommonTargetFrameworks) + true + + + + + + + + + + + + + + + + + + + + + diff --git a/test/OrchardCore.Testing.Tests/UseCultureAttributeTests.cs b/test/OrchardCore.Testing.Tests/UseCultureAttributeTests.cs new file mode 100644 index 00000000000..1f8b85b25ce --- /dev/null +++ b/test/OrchardCore.Testing.Tests/UseCultureAttributeTests.cs @@ -0,0 +1,64 @@ +using System.Globalization; + +namespace OrchardCore.Testing.Tests; + +public class UseCultureAttributeTests +{ + [Fact] + public void UsesSuppliedCultureAndUICulture() + { + // Arrange + var culture = "de-DE"; + var uiCulture = "fr-CA"; + + // Act + var usedCulture = new UseCultureAttribute(culture, uiCulture); + + // Assert + Assert.Equal(new CultureInfo(culture), usedCulture.Culture); + Assert.Equal(new CultureInfo(uiCulture), usedCulture.UICulture); + } + + [Fact] + public void UseCulture_BeforeAndAfterTest() + { + // Arrange + var originalCulture = CultureInfo.CurrentCulture; + var originalUICulture = CultureInfo.CurrentUICulture; + var culture = "de-DE"; + var uiCulture = "fr-CA"; + var usedCulture = new UseCultureAttribute(culture, uiCulture); + + // Act + usedCulture.Before(methodUnderTest: null); + + // Assert + Assert.Equal(new CultureInfo(culture), CultureInfo.CurrentCulture); + Assert.Equal(new CultureInfo(uiCulture), CultureInfo.CurrentUICulture); + + // Act + usedCulture.After(methodUnderTest: null); + + // Assert + Assert.Equal(originalCulture, CultureInfo.CurrentCulture); + Assert.Equal(originalUICulture, CultureInfo.CurrentUICulture); + } + + [Fact] + [UseCulture("ar-YE")] + public void UseCultureAttribute_UsesSuppliedCulture() + { + // Assert + Assert.Equal(new CultureInfo("ar-YE"), CultureInfo.CurrentCulture); + Assert.Equal(new CultureInfo("ar-YE"), CultureInfo.CurrentUICulture); + } + + [Fact] + [UseCulture("ar-YE", "ar-SA")] + public void UseCultureAttribute_UsesSuppliedCultureAndUICulture() + { + // Assert + Assert.Equal(new CultureInfo("ar-YE"), CultureInfo.CurrentCulture); + Assert.Equal(new CultureInfo("ar-SA"), CultureInfo.CurrentUICulture); + } +} diff --git a/test/OrchardCore.Testing.Tests/Usings.cs b/test/OrchardCore.Testing.Tests/Usings.cs new file mode 100644 index 00000000000..8c927eb747a --- /dev/null +++ b/test/OrchardCore.Testing.Tests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file From aa81d4685c99539fd67f296f18052600b08529f2 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 24 Dec 2022 17:24:46 +0300 Subject: [PATCH 03/33] Add overload that accepts CultureInfo --- .../OrchardCore.Testing/UseCultureAttribute.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Testing/UseCultureAttribute.cs b/src/OrchardCore/OrchardCore.Testing/UseCultureAttribute.cs index 64e62df89e1..e8a4982730d 100644 --- a/src/OrchardCore/OrchardCore.Testing/UseCultureAttribute.cs +++ b/src/OrchardCore/OrchardCore.Testing/UseCultureAttribute.cs @@ -24,7 +24,8 @@ public class UseCultureAttribute : BeforeAfterTestAttribute /// Creates an instance of with culture. /// /// The name of the culture to replace the current thread culture with. - public UseCultureAttribute(string culture) : this(culture, culture) + public UseCultureAttribute(string culture) + : this(culture, culture) { } @@ -34,9 +35,19 @@ public UseCultureAttribute(string culture) : this(culture, culture) /// >The name of the culture to replace the current thread culture with. /// >The name of the UI culture to replace the current thread UI culture with. public UseCultureAttribute(string culture, string uiCulture) + : this(new CultureInfo(culture), new CultureInfo(uiCulture)) { - _culture = new Lazy(() => new CultureInfo(culture, false)); - _uiCulture = new Lazy(() => new CultureInfo(uiCulture, false)); + } + + /// + /// Creates an instance of with culture and UI culture. + /// + /// >The culture to replace the current thread culture with. + /// >The UI culture to replace the current thread UI culture with. + public UseCultureAttribute(CultureInfo culture, CultureInfo uiCulture) + { + _culture = new Lazy(() => culture); + _uiCulture = new Lazy(() => uiCulture); } /// From 49faca3c455334d98302a543d5122877add09ad4 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 24 Dec 2022 17:52:50 +0300 Subject: [PATCH 04/33] Use UseCultureAttribute --- .../PortableObjectStringLocalizerTests.cs | 156 ++++++++---------- .../OrchardCore.Tests.csproj | 1 + 2 files changed, 71 insertions(+), 86 deletions(-) diff --git a/test/OrchardCore.Tests/Localization/PortableObjectStringLocalizerTests.cs b/test/OrchardCore.Tests/Localization/PortableObjectStringLocalizerTests.cs index 6b3b30928b7..cf58dc99c44 100644 --- a/test/OrchardCore.Tests/Localization/PortableObjectStringLocalizerTests.cs +++ b/test/OrchardCore.Tests/Localization/PortableObjectStringLocalizerTests.cs @@ -15,6 +15,7 @@ using Moq; using OrchardCore.Localization; using OrchardCore.Localization.PortableObject; +using OrchardCore.Testing; using Xunit; namespace OrchardCore.Tests.Localization @@ -31,6 +32,7 @@ public PortableObjectStringLocalizerTests() } [Fact] + [UseCulture("cs")] public void LocalizerReturnsTranslationsFromProvidedDictionary() { SetupDictionary("cs", new[] { @@ -38,16 +40,14 @@ public void LocalizerReturnsTranslationsFromProvidedDictionary() }); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs")) - { - var translation = localizer["ball"]; + var translation = localizer["ball"]; - Assert.Equal("míč", translation); - } + Assert.Equal("míč", translation); } [Fact] + [UseCulture("cs")] public void LocalizerReturnsOriginalTextIfTranslationsDoesntExistInProvidedDictionary() { SetupDictionary("cs", new[] { @@ -55,29 +55,27 @@ public void LocalizerReturnsOriginalTextIfTranslationsDoesntExistInProvidedDicti }); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs")) - { - var translation = localizer["car"]; - Assert.Equal("car", translation); - } + var translation = localizer["car"]; + + Assert.Equal("car", translation); } [Fact] + [UseCulture("cs")] public void LocalizerReturnsOriginalTextIfDictionaryIsEmpty() { SetupDictionary("cs", Array.Empty()); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs")) - { - var translation = localizer["car"]; - Assert.Equal("car", translation); - } + var translation = localizer["car"]; + + Assert.Equal("car", translation); } [Fact] + [UseCulture("cs-CZ")] public void LocalizerFallbacksToParentCultureIfTranslationDoesntExistInSpecificCulture() { SetupDictionary("cs", new[] { @@ -89,15 +87,14 @@ public void LocalizerFallbacksToParentCultureIfTranslationDoesntExistInSpecificC }); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs-cz")) - { - var translation = localizer["ball"]; - Assert.Equal("míč", translation); - } + var translation = localizer["ball"]; + + Assert.Equal("míč", translation); } [Fact] + [UseCulture("cs-CZ")] public void LocalizerReturnsTranslationFromSpecificCultureIfItExists() { SetupDictionary("cs", new[] { @@ -109,15 +106,14 @@ public void LocalizerReturnsTranslationFromSpecificCultureIfItExists() }); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs-CZ")) - { - var translation = localizer["ball"]; - Assert.Equal("balón", translation); - } + var translation = localizer["ball"]; + + Assert.Equal("balón", translation); } [Fact] + [UseCulture("cs")] public void LocalizerReturnsTranslationWithSpecificContext() { SetupDictionary("cs", new[] { @@ -126,15 +122,14 @@ public void LocalizerReturnsTranslationWithSpecificContext() }); var localizer = new PortableObjectStringLocalizer("small", _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs")) - { - var translation = localizer["ball"]; - Assert.Equal("míček", translation); - } + var translation = localizer["ball"]; + + Assert.Equal("míček", translation); } [Fact] + [UseCulture("cs")] public void LocalizerReturnsTranslationWithoutContextIfTranslationWithContextDoesntExist() { SetupDictionary("cs", new[] { @@ -143,15 +138,14 @@ public void LocalizerReturnsTranslationWithoutContextIfTranslationWithContextDoe }); var localizer = new PortableObjectStringLocalizer("small", _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs")) - { - var translation = localizer["ball"]; - Assert.Equal("míč", translation); - } + var translation = localizer["ball"]; + + Assert.Equal("míč", translation); } [Fact] + [UseCulture("cs")] public void LocalizerReturnsFormattedTranslation() { SetupDictionary("cs", new[] { @@ -159,15 +153,14 @@ public void LocalizerReturnsFormattedTranslation() }); var localizer = new PortableObjectStringLocalizer("small", _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs")) - { - var translation = localizer["The page (ID:{0}) was deleted.", 1]; - Assert.Equal("Stránka (ID:1) byla smazána.", translation); - } + var translation = localizer["The page (ID:{0}) was deleted.", 1]; + + Assert.Equal("Stránka (ID:1) byla smazána.", translation); } [Fact] + [UseCulture("cs")] public void HtmlLocalizerDoesNotFormatTwiceIfFormattedTranslationContainsCurlyBraces() { SetupDictionary("cs", new[] { @@ -175,29 +168,27 @@ public void HtmlLocalizerDoesNotFormatTwiceIfFormattedTranslationContainsCurlyBr }); var localizer = new PortableObjectStringLocalizer("small", _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs")) - { - var htmlLocalizer = new PortableObjectHtmlLocalizer(localizer); - var unformatted = htmlLocalizer["The page (ID:{0}) was deleted.", "{1}"]; - var memStream = new MemoryStream(); - var textWriter = new StreamWriter(memStream); - var textReader = new StreamReader(memStream); + var htmlLocalizer = new PortableObjectHtmlLocalizer(localizer); + var unformatted = htmlLocalizer["The page (ID:{0}) was deleted.", "{1}"]; + var memStream = new MemoryStream(); + var textWriter = new StreamWriter(memStream); + var textReader = new StreamReader(memStream); - unformatted.WriteTo(textWriter, HtmlEncoder.Default); + unformatted.WriteTo(textWriter, HtmlEncoder.Default); - textWriter.Flush(); - memStream.Seek(0, SeekOrigin.Begin); - var formatted = textReader.ReadToEnd(); + textWriter.Flush(); + memStream.Seek(0, SeekOrigin.Begin); + var formatted = textReader.ReadToEnd(); - textWriter.Dispose(); - textReader.Dispose(); - memStream.Dispose(); + textWriter.Dispose(); + textReader.Dispose(); + memStream.Dispose(); - Assert.Equal("Stránka (ID:{1}) byla smazána.", formatted); - } + Assert.Equal("Stránka (ID:{1}) byla smazána.", formatted); } [Theory] + [UseCulture("cs")] [InlineData("car", 1)] [InlineData("cars", 2)] public void LocalizerReturnsOriginalTextForPluralIfTranslationDoesntExist(string expected, int count) @@ -207,11 +198,9 @@ public void LocalizerReturnsOriginalTextForPluralIfTranslationDoesntExist(string }); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs")) - { - var translation = localizer.Plural(count, "car", "cars"); - Assert.Equal(expected, translation); - } + + var translation = localizer.Plural(count, "car", "cars"); + Assert.Equal(expected, translation); } [Theory] @@ -236,6 +225,7 @@ public void LocalizerReturnsCorrectTranslationForPluralIfNoPluralFormsSpecified( } [Theory] + [UseCulture("cs")] [InlineData("míč", 1)] [InlineData("2 míče", 2)] [InlineData("5 míčů", 5)] @@ -246,15 +236,14 @@ public void LocalizerReturnsTranslationInCorrectPluralForm(string expected, int }); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("cs")) - { - var translation = localizer.Plural(count, "ball", "{0} balls", count); - Assert.Equal(expected, translation); - } + var translation = localizer.Plural(count, "ball", "{0} balls", count); + + Assert.Equal(expected, translation); } [Theory] + [UseCulture("en")] [InlineData("míč", 1)] [InlineData("2 míče", 2)] [InlineData("5 míčů", 5)] @@ -263,15 +252,14 @@ public void LocalizerReturnsOriginalValuesIfTranslationDoesntExistAndMultiplePlu SetupDictionary("en", Array.Empty()); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("en")) - { - var translation = localizer.Plural(count, new[] { "míč", "{0} míče", "{0} míčů" }, count); - Assert.Equal(expected, translation); - } + var translation = localizer.Plural(count, new[] { "míč", "{0} míče", "{0} míčů" }, count); + + Assert.Equal(expected, translation); } [Theory] + [UseCulture("en")] [InlineData("ball", 1)] [InlineData("2 balls", 2)] public void LocalizerReturnsCorrectPluralFormIfMultiplePluraflFormsAreSpecified(string expected, int count) @@ -282,15 +270,14 @@ public void LocalizerReturnsCorrectPluralFormIfMultiplePluraflFormsAreSpecified( }, PluralizationRule.English); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, true, _logger.Object); - using (CultureScope.Create("en")) - { - var translation = localizer.Plural(count, new[] { "míč", "{0} míče", "{0} míčů" }, count); - Assert.Equal(expected, translation); - } + var translation = localizer.Plural(count, new[] { "míč", "{0} míče", "{0} míčů" }, count); + + Assert.Equal(expected, translation); } [Theory] + [UseCulture("ar-YE")] [InlineData(false, "hello", "hello")] [InlineData(true, "hello", "مرحبا")] public void LocalizerFallBackToParentCultureIfFallBackToParentUICulturesIsTrue(bool fallBackToParentCulture, string resourceKey, string expected) @@ -303,15 +290,14 @@ public void LocalizerFallBackToParentCultureIfFallBackToParentUICulturesIsTrue(b SetupDictionary("ar-YE", Array.Empty(), PluralizationRule.Arabic); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, fallBackToParentCulture, _logger.Object); - using (CultureScope.Create("ar-YE")) - { - var translation = localizer[resourceKey]; - Assert.Equal(expected, translation); - } + var translation = localizer[resourceKey]; + + Assert.Equal(expected, translation); } [Theory] + [UseCulture("ar-YE")] [InlineData(false, new[] { "مدونة", "منتج" })] [InlineData(true, new[] { "مدونة", "منتج", "قائمة", "صفحة", "مقالة" })] public void LocalizerReturnsGetAllStrings(bool includeParentCultures, string[] expected) @@ -331,12 +317,10 @@ public void LocalizerReturnsGetAllStrings(bool includeParentCultures, string[] e }, PluralizationRule.Arabic); var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, false, _logger.Object); - using (CultureScope.Create("ar-YE")) - { - var translations = localizer.GetAllStrings(includeParentCultures).Select(l => l.Value).ToArray(); - Assert.Equal(expected.Length, translations.Length); - } + var translations = localizer.GetAllStrings(includeParentCultures).Select(l => l.Value).ToArray(); + + Assert.Equal(expected.Length, translations.Length); } [Fact] diff --git a/test/OrchardCore.Tests/OrchardCore.Tests.csproj b/test/OrchardCore.Tests/OrchardCore.Tests.csproj index 1fb053a61fd..5f58cb74ca1 100644 --- a/test/OrchardCore.Tests/OrchardCore.Tests.csproj +++ b/test/OrchardCore.Tests/OrchardCore.Tests.csproj @@ -48,6 +48,7 @@ + From e4a039cd46892250192b04d10dcc86b8190cc6d1 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 24 Dec 2022 18:01:51 +0300 Subject: [PATCH 05/33] Replace xunit.extensibility.core with xunit package --- src/OrchardCore.Build/Dependencies.props | 1 - src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index 0437bb7a1a1..5166ac0d4ae 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -55,7 +55,6 @@ - diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index 791c779ae2e..c635445b6a9 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -18,7 +18,7 @@ - + From a247ce102b495e8623cead0957caf350f9baf6ab Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 25 Dec 2022 00:48:26 +0300 Subject: [PATCH 06/33] Move stubs to OC.Testing --- .../OrchardCore.Testing.csproj | 5 ++ .../ShapeBindingsDictionary.cs | 13 +++++ .../Stubs/HostingEnvironmentStub.cs | 40 +++++++++++++ .../Stubs/MemoryFileBuilder.cs | 32 +++++++++++ .../Stubs/NullExtensionManager.cs | 29 ++++++++++ .../Stubs/PoFileLocationProviderStub.cs | 29 ++++++++++ .../Stubs/ShapeBindingResolverStub.cs | 27 +++++++++ .../Stubs/ShapeTableManagerStub.cs | 15 +++++ .../Stubs/ThemeManagerStub.cs | 16 ++++++ .../ShapeFactoryBenchmark.cs | 6 +- .../DefaultShapeTableManagerTests.cs | 4 +- .../DefaultDisplayManagerTests.cs | 17 +++--- .../DisplayManagement/ShapeFactoryTests.cs | 6 +- .../DisplayManagement/ShapeHelperTests.cs | 6 +- .../DisplayManagement/ShapeSerializerTests.cs | 6 +- .../Extensions/ExtensionManagerTests.cs | 5 +- ...rtableObjectStringLocalizerFactoryTests.cs | 3 +- .../OpenIdServerDeploymentSourceTests.cs | 2 +- .../Shell/ShellContainerFactoryTests.cs | 3 +- .../Stubs/MemoryFileBuilder.cs | 36 ------------ .../Stubs/StubExtensionManager.cs | 57 ------------------- .../Stubs/StubHostingEnvironment.cs | 41 ------------- .../Stubs/StubPoFileLocationProvider.cs | 28 --------- .../Stubs/TestShapeBindingResolver.cs | 36 ------------ .../Stubs/TestShapeTableManager.cs | 35 ------------ 25 files changed, 236 insertions(+), 261 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/ShapeBindingsDictionary.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/HostingEnvironmentStub.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/MemoryFileBuilder.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/NullExtensionManager.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/PoFileLocationProviderStub.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/ShapeBindingResolverStub.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/ShapeTableManagerStub.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/ThemeManagerStub.cs delete mode 100644 test/OrchardCore.Tests/Stubs/MemoryFileBuilder.cs delete mode 100644 test/OrchardCore.Tests/Stubs/StubExtensionManager.cs delete mode 100644 test/OrchardCore.Tests/Stubs/StubHostingEnvironment.cs delete mode 100644 test/OrchardCore.Tests/Stubs/StubPoFileLocationProvider.cs delete mode 100644 test/OrchardCore.Tests/Stubs/TestShapeBindingResolver.cs delete mode 100644 test/OrchardCore.Tests/Stubs/TestShapeTableManager.cs diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index c635445b6a9..9ed707c93a2 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -21,4 +21,9 @@ + + + + + diff --git a/src/OrchardCore/OrchardCore.Testing/ShapeBindingsDictionary.cs b/src/OrchardCore/OrchardCore.Testing/ShapeBindingsDictionary.cs new file mode 100644 index 00000000000..23468e20dba --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/ShapeBindingsDictionary.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using OrchardCore.DisplayManagement.Descriptors; + +namespace OrchardCore.Testing; + +public class ShapeBindingsDictionary : Dictionary +{ + public ShapeBindingsDictionary() + : base(StringComparer.OrdinalIgnoreCase) + { + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/HostingEnvironmentStub.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/HostingEnvironmentStub.cs new file mode 100644 index 00000000000..7d284543104 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/HostingEnvironmentStub.cs @@ -0,0 +1,40 @@ +using System.IO; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; + +namespace OrchardCore.Testing.Stubs; + +public class HostingEnvironmentStub : IHostEnvironment +{ + private string _rootPath; + private IFileProvider _contentRootFileProvider; + + public HostingEnvironmentStub() + { + ApplicationName = GetType().Assembly.GetName().Name; + } + + public string EnvironmentName { get; set; } = "Testing"; + + public string ApplicationName { get; set; } + + public string WebRootPath { get; set; } + + public IFileProvider WebRootFileProvider { get; set; } + + public string ContentRootPath + { + get => _rootPath ?? Directory.GetCurrentDirectory(); + set + { + _contentRootFileProvider = new PhysicalFileProvider(value); + _rootPath = value; + } + } + + public IFileProvider ContentRootFileProvider + { + get => _contentRootFileProvider; + set => _contentRootFileProvider = value; + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/MemoryFileBuilder.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/MemoryFileBuilder.cs new file mode 100644 index 00000000000..e55a07d38cd --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/MemoryFileBuilder.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using OrchardCore.Deployment; + +namespace OrchardCore.Testing.Stubs; +/// +/// Represents In memory file builder that uses a dictionary as virtual file system. +/// +public class MemoryFileBuilder : IFileBuilder +{ + private readonly Dictionary _virtualFiles = new(); + + /// + public async Task SetFileAsync(string subpath, Stream stream) + { + using var memoryStream = new MemoryStream(); + + await stream.CopyToAsync(memoryStream); + + _virtualFiles[subpath] = memoryStream.ToArray(); + } + + /// + /// Read the contents of a file using the specified encoding. + /// + /// The file path. + /// The encoding used to convert the byte array to string. + /// + public string GetFileContents(string subpath, Encoding encoding) => encoding.GetString(_virtualFiles[subpath]); +} diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/NullExtensionManager.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/NullExtensionManager.cs new file mode 100644 index 00000000000..34850341303 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/NullExtensionManager.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using OrchardCore.Environment.Extensions; +using OrchardCore.Environment.Extensions.Features; + +namespace OrchardCore.Testing.Stubs; + +public class NullExtensionManager : IExtensionManager +{ + public IEnumerable GetDependentFeatures(string featureId) => Enumerable.Empty(); + + public IExtensionInfo GetExtension(string extensionId) => null; + + public IEnumerable GetExtensions() => Enumerable.Empty(); + + public IEnumerable GetFeatureDependencies(string featureId) => Enumerable.Empty(); + + public IEnumerable GetFeatures() => Enumerable.Empty(); + + public IEnumerable GetFeatures(string[] featureIdsToLoad) => Enumerable.Empty(); + + public Task LoadExtensionAsync(IExtensionInfo extensionInfo) => Task.FromResult(new ExtensionEntry()); + + public Task> LoadFeaturesAsync() => Task.FromResult(Enumerable.Empty()); + + public Task> LoadFeaturesAsync(string[] featureIdsToLoad) + => Task.FromResult(Enumerable.Empty()); +} diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/PoFileLocationProviderStub.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/PoFileLocationProviderStub.cs new file mode 100644 index 00000000000..e6c30809b84 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/PoFileLocationProviderStub.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.IO; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using OrchardCore.Localization; + +namespace OrchardCore.Testing.Stubs; + +public class PoFileLocationProviderStub : ILocalizationFileLocationProvider +{ + private readonly IFileProvider _fileProvider; + private readonly string _resourcesPath; + + public PoFileLocationProviderStub(IHostEnvironment hostingEnvironment, IOptions localizationOptions) + { + var rootPath = new DirectoryInfo(hostingEnvironment.ContentRootPath).Parent.Parent.Parent.FullName; + _fileProvider = new PhysicalFileProvider(rootPath); + _resourcesPath = localizationOptions.Value.ResourcesPath; + } + + public IEnumerable GetLocations(string cultureName) + { + var resourcePath = Path.Combine(_resourcesPath, cultureName + ".po"); + + yield return _fileProvider.GetFileInfo(resourcePath); + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/ShapeBindingResolverStub.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/ShapeBindingResolverStub.cs new file mode 100644 index 00000000000..a6b5baa2d4d --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/ShapeBindingResolverStub.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using OrchardCore.DisplayManagement; +using OrchardCore.DisplayManagement.Descriptors; + +namespace OrchardCore.Testing.Stubs; + +public class ShapeBindingResolverStub : IShapeBindingResolver +{ + private readonly ShapeBindingsDictionary _shapeBindings; + + public ShapeBindingResolverStub(ShapeBindingsDictionary shapeBindings) + { + _shapeBindings = shapeBindings; + } + + public Task GetShapeBindingAsync(string shapeType) + { + if (_shapeBindings.TryGetValue(shapeType, out var binding)) + { + return Task.FromResult(binding); + } + else + { + return Task.FromResult(null); + } + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/ShapeTableManagerStub.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/ShapeTableManagerStub.cs new file mode 100644 index 00000000000..2081fec7752 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/ShapeTableManagerStub.cs @@ -0,0 +1,15 @@ +using OrchardCore.DisplayManagement.Descriptors; + +namespace OrchardCore.Testing.Stubs; + +public class ShapeTableManagerStub : IShapeTableManager +{ + private readonly ShapeTable _defaultShapeTable; + + public ShapeTableManagerStub(ShapeTable defaultShapeTable) + { + _defaultShapeTable = defaultShapeTable; + } + + public ShapeTable GetShapeTable(string themeId) => _defaultShapeTable; +} diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/ThemeManagerStub.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/ThemeManagerStub.cs new file mode 100644 index 00000000000..8165c7dea41 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/ThemeManagerStub.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using OrchardCore.DisplayManagement.Theming; +using OrchardCore.Environment.Extensions; + +namespace OrchardCore.Testing.Stubs; + +public class ThemeManagerStub : IThemeManager +{ + private IExtensionInfo _extensionInfo; + public ThemeManagerStub(IExtensionInfo extensionInfo) + { + _extensionInfo = extensionInfo; + } + + public Task GetThemeAsync() => Task.FromResult(_extensionInfo); +} diff --git a/test/OrchardCore.Benchmarks/ShapeFactoryBenchmark.cs b/test/OrchardCore.Benchmarks/ShapeFactoryBenchmark.cs index 3bc865ec6d4..177d17f90b1 100644 --- a/test/OrchardCore.Benchmarks/ShapeFactoryBenchmark.cs +++ b/test/OrchardCore.Benchmarks/ShapeFactoryBenchmark.cs @@ -15,7 +15,7 @@ using OrchardCore.Environment.Extensions.Features; using OrchardCore.Environment.Extensions.Manifests; using OrchardCore.Modules.Manifest; -using OrchardCore.Tests.Stubs; +using OrchardCore.Testing.Stubs; namespace OrchardCore.Benchmark { @@ -38,8 +38,8 @@ static ShapeFactoryBenchmark() var shapeFactory = new DefaultShapeFactory( serviceProvider: new ServiceCollection().BuildServiceProvider(), events: Enumerable.Empty(), - shapeTableManager: new TestShapeTableManager(defaultShapeTable), - themeManager: new MockThemeManager(new ExtensionInfo("path", new ManifestInfo(new ModuleAttribute()), (x, y) => Enumerable.Empty()))); + shapeTableManager: new ShapeTableManagerStub(defaultShapeTable), + themeManager: new ThemeManagerStub(new ExtensionInfo("path", new ManifestInfo(new ModuleAttribute()), (x, y) => Enumerable.Empty()))); _templateContext.AmbientValues["DisplayHelper"] = new DisplayHelper(null, shapeFactory, null); } diff --git a/test/OrchardCore.Tests/DisplayManagement/Decriptors/DefaultShapeTableManagerTests.cs b/test/OrchardCore.Tests/DisplayManagement/Decriptors/DefaultShapeTableManagerTests.cs index ab5299ee784..203d732c554 100644 --- a/test/OrchardCore.Tests/DisplayManagement/Decriptors/DefaultShapeTableManagerTests.cs +++ b/test/OrchardCore.Tests/DisplayManagement/Decriptors/DefaultShapeTableManagerTests.cs @@ -16,7 +16,7 @@ using OrchardCore.Environment.Extensions.Manifests; using OrchardCore.Environment.Shell; using OrchardCore.Modules.Manifest; -using OrchardCore.Tests.Stubs; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.DisplayManagement.Decriptors @@ -129,7 +129,7 @@ public DefaultShapeTableManagerTests() serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(new StubHostingEnvironment()); + serviceCollection.AddSingleton(new HostingEnvironmentStub()); var testFeatureExtensionInfo = new TestModuleExtensionInfo("Testing"); var theme1FeatureExtensionInfo = new TestThemeExtensionInfo("Theme1"); diff --git a/test/OrchardCore.Tests/DisplayManagement/DefaultDisplayManagerTests.cs b/test/OrchardCore.Tests/DisplayManagement/DefaultDisplayManagerTests.cs index 0c65cd22830..a53fa338dd8 100644 --- a/test/OrchardCore.Tests/DisplayManagement/DefaultDisplayManagerTests.cs +++ b/test/OrchardCore.Tests/DisplayManagement/DefaultDisplayManagerTests.cs @@ -11,16 +11,17 @@ using OrchardCore.DisplayManagement.Theming; using OrchardCore.Environment.Extensions; using OrchardCore.Localization; -using OrchardCore.Tests.Stubs; +using OrchardCore.Testing; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.DisplayManagement { public class DefaultDisplayManagerTests { - private ShapeTable _defaultShapeTable; - private TestShapeBindingsDictionary _additionalBindings; - private IServiceProvider _serviceProvider; + private readonly ShapeTable _defaultShapeTable; + private readonly ShapeBindingsDictionary _additionalBindings; + private readonly IServiceProvider _serviceProvider; public DefaultDisplayManagerTests() { @@ -29,16 +30,16 @@ public DefaultDisplayManagerTests() new Dictionary(StringComparer.OrdinalIgnoreCase), new Dictionary(StringComparer.OrdinalIgnoreCase) ); - _additionalBindings = new TestShapeBindingsDictionary(); + _additionalBindings = new ShapeBindingsDictionary(); IServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); + serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); serviceCollection.AddSingleton(); serviceCollection.AddTransient(typeof(IStringLocalizer<>), typeof(StringLocalizer<>)); diff --git a/test/OrchardCore.Tests/DisplayManagement/ShapeFactoryTests.cs b/test/OrchardCore.Tests/DisplayManagement/ShapeFactoryTests.cs index 38c0bdf70b2..b2e1043794f 100644 --- a/test/OrchardCore.Tests/DisplayManagement/ShapeFactoryTests.cs +++ b/test/OrchardCore.Tests/DisplayManagement/ShapeFactoryTests.cs @@ -10,7 +10,7 @@ using OrchardCore.DisplayManagement.Shapes; using OrchardCore.DisplayManagement.Theming; using OrchardCore.Environment.Extensions; -using OrchardCore.Tests.Stubs; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.DisplayManagement @@ -27,8 +27,8 @@ public ShapeFactoryTests() serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); + serviceCollection.AddScoped(); _shapeTable = new ShapeTable ( diff --git a/test/OrchardCore.Tests/DisplayManagement/ShapeHelperTests.cs b/test/OrchardCore.Tests/DisplayManagement/ShapeHelperTests.cs index 17041859f7b..7bd4d547fde 100644 --- a/test/OrchardCore.Tests/DisplayManagement/ShapeHelperTests.cs +++ b/test/OrchardCore.Tests/DisplayManagement/ShapeHelperTests.cs @@ -7,7 +7,7 @@ using OrchardCore.DisplayManagement.Implementation; using OrchardCore.DisplayManagement.Theming; using OrchardCore.Environment.Extensions; -using OrchardCore.Tests.Stubs; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.DisplayManagement @@ -22,10 +22,10 @@ public ShapeHelperTests() serviceCollection.AddLogging(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); var defaultShapeTable = new ShapeTable ( diff --git a/test/OrchardCore.Tests/DisplayManagement/ShapeSerializerTests.cs b/test/OrchardCore.Tests/DisplayManagement/ShapeSerializerTests.cs index 925db9b2a0b..33bc41e5384 100644 --- a/test/OrchardCore.Tests/DisplayManagement/ShapeSerializerTests.cs +++ b/test/OrchardCore.Tests/DisplayManagement/ShapeSerializerTests.cs @@ -7,7 +7,7 @@ using OrchardCore.DisplayManagement.Implementation; using OrchardCore.DisplayManagement.Theming; using OrchardCore.Environment.Extensions; -using OrchardCore.Tests.Stubs; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.DisplayManagement @@ -22,10 +22,10 @@ public ShapeSerializerTests() serviceCollection.AddLogging(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); var defaultShapeTable = new ShapeTable ( diff --git a/test/OrchardCore.Tests/Extensions/ExtensionManagerTests.cs b/test/OrchardCore.Tests/Extensions/ExtensionManagerTests.cs index 45974d56c45..76063dc75de 100644 --- a/test/OrchardCore.Tests/Extensions/ExtensionManagerTests.cs +++ b/test/OrchardCore.Tests/Extensions/ExtensionManagerTests.cs @@ -7,15 +7,14 @@ using OrchardCore.Environment.Extensions; using OrchardCore.Environment.Extensions.Features; using OrchardCore.Modules; -using OrchardCore.Tests.Stubs; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.Extensions { public class ExtensionManagerTests { - private static IHostEnvironment HostingEnvironment - = new StubHostingEnvironment(); + private static IHostEnvironment HostingEnvironment = new HostingEnvironmentStub(); private static IApplicationContext ApplicationContext = new ModularApplicationContext(HostingEnvironment, new List() diff --git a/test/OrchardCore.Tests/Localization/PortableObjectStringLocalizerFactoryTests.cs b/test/OrchardCore.Tests/Localization/PortableObjectStringLocalizerFactoryTests.cs index 6d0e3c4de99..e6af9d7499d 100644 --- a/test/OrchardCore.Tests/Localization/PortableObjectStringLocalizerFactoryTests.cs +++ b/test/OrchardCore.Tests/Localization/PortableObjectStringLocalizerFactoryTests.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Localization; using OrchardCore.Localization; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.Localization @@ -24,7 +25,7 @@ public void ConfigureServices(IServiceCollection services) services.AddMvc(); services.AddLocalization(); services.AddPortableObjectLocalization(options => options.ResourcesPath = "Localization/PoFiles"); - services.Replace(ServiceDescriptor.Singleton()); + services.Replace(ServiceDescriptor.Singleton()); } public void Configure( diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.OpenId/OpenIdServerDeploymentSourceTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.OpenId/OpenIdServerDeploymentSourceTests.cs index d31b0f35f37..bcc185d1e08 100644 --- a/test/OrchardCore.Tests/Modules/OrchardCore.OpenId/OpenIdServerDeploymentSourceTests.cs +++ b/test/OrchardCore.Tests/Modules/OrchardCore.OpenId/OpenIdServerDeploymentSourceTests.cs @@ -10,7 +10,7 @@ using OrchardCore.OpenId.Services; using OrchardCore.OpenId.Settings; using OrchardCore.Recipes.Models; -using OrchardCore.Tests.Stubs; +using OrchardCore.Testing.Stubs; using Xunit; using static OrchardCore.OpenId.Settings.OpenIdServerSettings; diff --git a/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs b/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs index 8d471809ea9..0f540601d06 100644 --- a/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs +++ b/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs @@ -10,6 +10,7 @@ using OrchardCore.Environment.Shell.Builders.Models; using OrchardCore.Environment.Shell.Descriptor.Models; using OrchardCore.Modules; +using OrchardCore.Testing.Stubs; using OrchardCore.Tests.Stubs; using Xunit; @@ -36,7 +37,7 @@ public ShellContainerFactoryTests() applicationServices.AddScoped(); _shellContainerFactory = new ShellContainerFactory( - new StubHostingEnvironment(), + new HostingEnvironmentStub(), new StubExtensionManager(), _applicationServiceProvider = applicationServices.BuildServiceProvider(), applicationServices diff --git a/test/OrchardCore.Tests/Stubs/MemoryFileBuilder.cs b/test/OrchardCore.Tests/Stubs/MemoryFileBuilder.cs deleted file mode 100644 index 45bd78ab262..00000000000 --- a/test/OrchardCore.Tests/Stubs/MemoryFileBuilder.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Threading.Tasks; -using OrchardCore.Deployment; - -namespace OrchardCore.Tests.Stubs -{ - /// - /// In memory file builder that uses a dictionary as virtual file system. - /// Intended for unit testing. - /// - public class MemoryFileBuilder - : IFileBuilder - { - public Dictionary VirtualFiles { get; private set; } = new Dictionary(); - - public async Task SetFileAsync(string subpath, Stream stream) - { - using var ms = new MemoryStream(); - await stream.CopyToAsync(ms); - VirtualFiles[subpath] = ms.ToArray(); - } - - /// - /// Read the contents of a file built with this file builder, using the specified encoding. - /// - /// Path and/or file name - /// Encoding used to convert the byte array to string - /// - public string GetFileContents(string subpath, Encoding encoding) - { - return encoding.GetString(VirtualFiles[subpath]); - } - } -} diff --git a/test/OrchardCore.Tests/Stubs/StubExtensionManager.cs b/test/OrchardCore.Tests/Stubs/StubExtensionManager.cs deleted file mode 100644 index e4ea4eca4d6..00000000000 --- a/test/OrchardCore.Tests/Stubs/StubExtensionManager.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using OrchardCore.Environment.Extensions; -using OrchardCore.Environment.Extensions.Features; - -namespace OrchardCore.Tests.Stubs -{ - public class StubExtensionManager : IExtensionManager - { - public IEnumerable GetDependentFeatures(string featureId) - { - throw new NotImplementedException(); - } - - public IExtensionInfo GetExtension(string extensionId) - { - throw new NotImplementedException(); - } - - public IEnumerable GetExtensions() - { - throw new NotImplementedException(); - } - - public IEnumerable GetFeatureDependencies(string featureId) - { - throw new NotImplementedException(); - } - - public IEnumerable GetFeatures() - { - return Enumerable.Empty(); - } - - public IEnumerable GetFeatures(string[] featureIdsToLoad) - { - throw new NotImplementedException(); - } - - public Task LoadExtensionAsync(IExtensionInfo extensionInfo) - { - throw new NotImplementedException(); - } - - public Task> LoadFeaturesAsync() - { - throw new NotImplementedException(); - } - - public Task> LoadFeaturesAsync(string[] featureIdsToLoad) - { - throw new NotImplementedException(); - } - } -} diff --git a/test/OrchardCore.Tests/Stubs/StubHostingEnvironment.cs b/test/OrchardCore.Tests/Stubs/StubHostingEnvironment.cs deleted file mode 100644 index f27120a4749..00000000000 --- a/test/OrchardCore.Tests/Stubs/StubHostingEnvironment.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.IO; -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Hosting; - -namespace OrchardCore.Tests.Stubs -{ - public class StubHostingEnvironment : IHostEnvironment - { - private string _rootPath; - private IFileProvider _contentRootFileProvider; - - public StubHostingEnvironment() - { - ApplicationName = GetType().Assembly.GetName().Name; - } - - public string EnvironmentName { get; set; } = "Stub"; - - public string ApplicationName { get; set; } - - public string WebRootPath { get; set; } - - public IFileProvider WebRootFileProvider { get; set; } - - public string ContentRootPath - { - get { return _rootPath ?? Directory.GetCurrentDirectory(); } - set - { - _contentRootFileProvider = new PhysicalFileProvider(value); - _rootPath = value; - } - } - - public IFileProvider ContentRootFileProvider - { - get { return _contentRootFileProvider; } - set { _contentRootFileProvider = value; } - } - } -} diff --git a/test/OrchardCore.Tests/Stubs/StubPoFileLocationProvider.cs b/test/OrchardCore.Tests/Stubs/StubPoFileLocationProvider.cs deleted file mode 100644 index 4a97d18067c..00000000000 --- a/test/OrchardCore.Tests/Stubs/StubPoFileLocationProvider.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Options; -using OrchardCore.Localization; - -namespace OrchardCore.Tests -{ - public class StubPoFileLocationProvider : ILocalizationFileLocationProvider - { - private readonly IFileProvider _fileProvider; - private readonly string _resourcesContainer; - - public StubPoFileLocationProvider(IHostEnvironment hostingEnvironment, IOptions localizationOptions) - { - var rootPath = new DirectoryInfo(hostingEnvironment.ContentRootPath).Parent.Parent.Parent.FullName; - _fileProvider = new PhysicalFileProvider(rootPath); - _resourcesContainer = localizationOptions.Value.ResourcesPath; - } - - public IEnumerable GetLocations(string cultureName) - { - yield return _fileProvider.GetFileInfo(Path.Combine(_resourcesContainer, cultureName + ".po")); - } - } -} diff --git a/test/OrchardCore.Tests/Stubs/TestShapeBindingResolver.cs b/test/OrchardCore.Tests/Stubs/TestShapeBindingResolver.cs deleted file mode 100644 index 53e822a8a34..00000000000 --- a/test/OrchardCore.Tests/Stubs/TestShapeBindingResolver.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using OrchardCore.DisplayManagement; -using OrchardCore.DisplayManagement.Descriptors; - -namespace OrchardCore.Tests.Stubs -{ - public class TestShapeBindingsDictionary : Dictionary - { - public TestShapeBindingsDictionary() - : base(StringComparer.OrdinalIgnoreCase) { } - } - - public class TestShapeBindingResolver : IShapeBindingResolver - { - private readonly TestShapeBindingsDictionary _shapeBindings; - - public TestShapeBindingResolver(TestShapeBindingsDictionary shapeBindings) - { - _shapeBindings = shapeBindings; - } - - public Task GetShapeBindingAsync(string shapeType) - { - if (_shapeBindings.TryGetValue(shapeType, out var binding)) - { - return Task.FromResult(binding); - } - else - { - return Task.FromResult(null); - } - } - } -} diff --git a/test/OrchardCore.Tests/Stubs/TestShapeTableManager.cs b/test/OrchardCore.Tests/Stubs/TestShapeTableManager.cs deleted file mode 100644 index 0b9a95c4010..00000000000 --- a/test/OrchardCore.Tests/Stubs/TestShapeTableManager.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Threading.Tasks; -using OrchardCore.DisplayManagement.Descriptors; -using OrchardCore.DisplayManagement.Theming; -using OrchardCore.Environment.Extensions; - -namespace OrchardCore.Tests.Stubs -{ - public class TestShapeTableManager : IShapeTableManager - { - private readonly ShapeTable _defaultShapeTable; - - public TestShapeTableManager(ShapeTable defaultShapeTable) - { - _defaultShapeTable = defaultShapeTable; - } - - public ShapeTable GetShapeTable(string themeId) - { - return _defaultShapeTable; - } - } - - public class MockThemeManager : IThemeManager - { - private IExtensionInfo _dec; - public MockThemeManager(IExtensionInfo des) - { - _dec = des; - } - public Task GetThemeAsync() - { - return Task.FromResult(_dec); - } - } -} From c7dfd508aa2b192f0c4bd3340369a369e67ad605 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 25 Dec 2022 01:23:03 +0300 Subject: [PATCH 07/33] Fix broken test --- test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs b/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs index 0f540601d06..ccd357beec1 100644 --- a/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs +++ b/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs @@ -11,7 +11,6 @@ using OrchardCore.Environment.Shell.Descriptor.Models; using OrchardCore.Modules; using OrchardCore.Testing.Stubs; -using OrchardCore.Tests.Stubs; using Xunit; namespace OrchardCore.Tests.Shell @@ -38,7 +37,7 @@ public ShellContainerFactoryTests() _shellContainerFactory = new ShellContainerFactory( new HostingEnvironmentStub(), - new StubExtensionManager(), + new NullExtensionManager(), _applicationServiceProvider = applicationServices.BuildServiceProvider(), applicationServices ); From bdd6714565de5c79af5fef4b66ea41ab61841d99 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 25 Dec 2022 01:31:11 +0300 Subject: [PATCH 08/33] Add OrchardCoreMock.CreateSmtpService() --- .../OrchardCore.Testing.csproj | 1 + .../OrchardCore.Testing/OrchardCoreMock.cs | 29 +++++++++++++++++++ test/OrchardCore.Tests/Email/EmailTests.cs | 24 +++------------ 3 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/OrchardCoreMock.cs diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index 9ed707c93a2..ea88227eba9 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -23,6 +23,7 @@ + diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCoreMock.cs b/src/OrchardCore/OrchardCore.Testing/OrchardCoreMock.cs new file mode 100644 index 00000000000..23f680664e0 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCoreMock.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using OrchardCore.Email; +using OrchardCore.Email.Services; + +namespace OrchardCore.Testing; + +public static class OrchardCoreMock +{ + public static ISmtpService CreateSmtpService(SmtpSettings settings) + { + var smtpSettings = new Mock>(); + smtpSettings + .Setup(o => o.Value) + .Returns(settings); + + var logger = new Mock>(); + var localizer = new Mock>(); + + return new SmtpService(smtpSettings.Object, logger.Object, localizer.Object); + } +} diff --git a/test/OrchardCore.Tests/Email/EmailTests.cs b/test/OrchardCore.Tests/Email/EmailTests.cs index 80029071aa2..3c3c3822aae 100644 --- a/test/OrchardCore.Tests/Email/EmailTests.cs +++ b/test/OrchardCore.Tests/Email/EmailTests.cs @@ -1,13 +1,9 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using MimeKit; -using Moq; using OrchardCore.Email; -using OrchardCore.Email.Services; +using OrchardCore.Testing; using Xunit; namespace OrchardCore.Tests.Email @@ -205,7 +201,7 @@ public async Task SendEmail_WithoutToAndCcAndBccHeaders_ShouldThrowsException() DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory }; - var smtp = CreateSmtpService(settings); + var smtp = OrchardCoreMock.CreateSmtpService(settings); // Act var result = await smtp.SendAsync(message); @@ -229,7 +225,7 @@ public async Task SendOfflineEmailHasNoResponse() DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory }; - var smtp = CreateSmtpService(settings); + var smtp = OrchardCoreMock.CreateSmtpService(settings); // Act var result = await smtp.SendAsync(message); @@ -256,7 +252,7 @@ private async Task SendEmailAsync(MailMessage message, string defaultSen DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory, PickupDirectoryLocation = pickupDirectoryPath }; - var smtp = CreateSmtpService(settings); + var smtp = OrchardCoreMock.CreateSmtpService(settings); var result = await smtp.SendAsync(message); @@ -270,17 +266,5 @@ private async Task SendEmailAsync(MailMessage message, string defaultSen return content; } - - private static ISmtpService CreateSmtpService(SmtpSettings settings) - { - var options = new Mock>(); - options.Setup(o => o.Value).Returns(settings); - - var logger = new Mock>(); - var localizer = new Mock>(); - var smtp = new SmtpService(options.Object, logger.Object, localizer.Object); - - return smtp; - } } } From 2d178b681107b430c78df653e8149fb6c33966db Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 25 Dec 2022 01:54:46 +0300 Subject: [PATCH 09/33] Add OrchardCoreWorkflowMocks --- .../OrchardCoreEmailMocks.cs} | 9 +-- .../Mocks/OrchardCoreWorkflowMocks.cs | 77 +++++++++++++++++++ .../OrchardCore.Testing.csproj | 3 + test/OrchardCore.Tests/Email/EmailTests.cs | 2 +- .../Workflows/WorkflowManagerTests.cs | 67 +--------------- 5 files changed, 86 insertions(+), 72 deletions(-) rename src/OrchardCore/OrchardCore.Testing/{OrchardCoreMock.cs => Mocks/OrchardCoreEmailMocks.cs} (77%) create mode 100644 src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreWorkflowMocks.cs diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCoreMock.cs b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreEmailMocks.cs similarity index 77% rename from src/OrchardCore/OrchardCore.Testing/OrchardCoreMock.cs rename to src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreEmailMocks.cs index 23f680664e0..7d16ab2e519 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCoreMock.cs +++ b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreEmailMocks.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -10,9 +5,9 @@ using OrchardCore.Email; using OrchardCore.Email.Services; -namespace OrchardCore.Testing; +namespace OrchardCore.Testing.Mocks; -public static class OrchardCoreMock +public static partial class OrchardCoreMock { public static ISmtpService CreateSmtpService(SmtpSettings settings) { diff --git a/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreWorkflowMocks.cs b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreWorkflowMocks.cs new file mode 100644 index 00000000000..0b5aecae4a0 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreWorkflowMocks.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using Moq; +using OrchardCore.Locking.Distributed; +using OrchardCore.Modules; +using OrchardCore.Scripting; +using OrchardCore.Scripting.JavaScript; +using OrchardCore.Workflows.Activities; +using OrchardCore.Workflows.Evaluators; +using OrchardCore.Workflows.Models; +using OrchardCore.Workflows.Services; + +namespace OrchardCore.Testing.Mocks; + +public static partial class OrchardCoreMock +{ + public static WorkflowManager CreateWorkflowManager( + IServiceProvider serviceProvider, + IEnumerable activities, + WorkflowType workflowType) + { + var workflowValueSerializers = new Resolver>(serviceProvider); + var activityLibrary = new Mock(); + var workflowTypeStore = new Mock(); + var workflowStore = new Mock(); + var workflowIdGenerator = new Mock(); + workflowIdGenerator + .Setup(x => x.GenerateUniqueId(It.IsAny())) + .Returns(IdGenerator.GenerateId()); + + var distributedLock = new Mock(); + var workflowManagerLogger = new Mock>(); + var workflowContextLogger = new Mock>(); + var missingActivityLogger = new Mock>(); + var missingActivityLocalizer = new Mock>(); + var clock = new Mock(); + var workflowManager = new WorkflowManager( + activityLibrary.Object, + workflowTypeStore.Object, + workflowStore.Object, + workflowIdGenerator.Object, + workflowValueSerializers, + distributedLock.Object, + workflowManagerLogger.Object, + missingActivityLogger.Object, + missingActivityLocalizer.Object, + clock.Object); + + foreach (var activity in activities) + { + activityLibrary.Setup(x => x.InstantiateActivity(activity.Name)).Returns(activity); + } + + workflowTypeStore.Setup(x => x.GetAsync(workflowType.Id)).Returns(Task.FromResult(workflowType)); + + return workflowManager; + } + + public static IWorkflowScriptEvaluator CreateWorkflowScriptEvaluator(IServiceProvider serviceProvider) + { + var memoryCache = new MemoryCache(new MemoryCacheOptions()); + var javaScriptEngine = new JavaScriptEngine(memoryCache); + var workflowContextHandlers = new Resolver>(serviceProvider); + var globalMethodProviders = new IGlobalMethodProvider[0]; + var scriptingManager = new DefaultScriptingManager(new[] { javaScriptEngine }, globalMethodProviders); + + return new JavaScriptWorkflowScriptEvaluator( + scriptingManager, + workflowContextHandlers.Resolve(), + new Mock>().Object + ); + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index ea88227eba9..11726e538d4 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -22,9 +22,12 @@ + + + diff --git a/test/OrchardCore.Tests/Email/EmailTests.cs b/test/OrchardCore.Tests/Email/EmailTests.cs index 3c3c3822aae..30e098ca262 100644 --- a/test/OrchardCore.Tests/Email/EmailTests.cs +++ b/test/OrchardCore.Tests/Email/EmailTests.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; using MimeKit; using OrchardCore.Email; -using OrchardCore.Testing; +using OrchardCore.Testing.Mocks; using Xunit; namespace OrchardCore.Tests.Email diff --git a/test/OrchardCore.Tests/Workflows/WorkflowManagerTests.cs b/test/OrchardCore.Tests/Workflows/WorkflowManagerTests.cs index 0e7ffd1fbd0..59007259b3a 100644 --- a/test/OrchardCore.Tests/Workflows/WorkflowManagerTests.cs +++ b/test/OrchardCore.Tests/Workflows/WorkflowManagerTests.cs @@ -5,20 +5,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Localization; using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Logging; using Moq; using Newtonsoft.Json.Linq; using OrchardCore.DisplayManagement; -using OrchardCore.Locking.Distributed; -using OrchardCore.Modules; -using OrchardCore.Scripting; -using OrchardCore.Scripting.JavaScript; +using OrchardCore.Testing.Mocks; using OrchardCore.Tests.Workflows.Activities; using OrchardCore.Workflows.Activities; -using OrchardCore.Workflows.Evaluators; using OrchardCore.Workflows.Models; using OrchardCore.Workflows.Services; using OrchardCore.Workflows.WorkflowContextProviders; @@ -32,7 +26,7 @@ public class WorkflowManagerTests public async Task CanExecuteSimpleWorkflow() { var serviceProvider = CreateServiceProvider(); - var scriptEvaluator = CreateWorkflowScriptEvaluator(serviceProvider); + var scriptEvaluator = OrchardCoreMock.CreateWorkflowScriptEvaluator(serviceProvider); var localizer = new Mock>(); var stringBuilder = new StringBuilder(); @@ -61,7 +55,7 @@ public async Task CanExecuteSimpleWorkflow() } }; - var workflowManager = CreateWorkflowManager(serviceProvider, new IActivity[] { addTask, writeLineTask, setOutputTask }, workflowType); + var workflowManager = OrchardCoreMock.CreateWorkflowManager(serviceProvider, new IActivity[] { addTask, writeLineTask, setOutputTask }, workflowType); var a = 10d; var b = 22d; var expectedSum = a + b; @@ -85,60 +79,5 @@ private IServiceProvider CreateServiceProvider() return services.BuildServiceProvider(); } - - private IWorkflowScriptEvaluator CreateWorkflowScriptEvaluator(IServiceProvider serviceProvider) - { - var memoryCache = new MemoryCache(new MemoryCacheOptions()); - var javaScriptEngine = new JavaScriptEngine(memoryCache); - var workflowContextHandlers = new Resolver>(serviceProvider); - var globalMethodProviders = new IGlobalMethodProvider[0]; - var scriptingManager = new DefaultScriptingManager(new[] { javaScriptEngine }, globalMethodProviders); - - return new JavaScriptWorkflowScriptEvaluator( - scriptingManager, - workflowContextHandlers.Resolve(), - new Mock>().Object - ); - } - - private WorkflowManager CreateWorkflowManager( - IServiceProvider serviceProvider, - IEnumerable activities, - WorkflowType workflowType - ) - { - var workflowValueSerializers = new Resolver>(serviceProvider); - var activityLibrary = new Mock(); - var workflowTypeStore = new Mock(); - var workflowStore = new Mock(); - var workflowIdGenerator = new Mock(); - workflowIdGenerator.Setup(x => x.GenerateUniqueId(It.IsAny())).Returns(IdGenerator.GenerateId()); - var distributedLock = new Mock(); - var workflowManagerLogger = new Mock>(); - var workflowContextLogger = new Mock>(); - var missingActivityLogger = new Mock>(); - var missingActivityLocalizer = new Mock>(); - var clock = new Mock(); - var workflowManager = new WorkflowManager( - activityLibrary.Object, - workflowTypeStore.Object, - workflowStore.Object, - workflowIdGenerator.Object, - workflowValueSerializers, - distributedLock.Object, - workflowManagerLogger.Object, - missingActivityLogger.Object, - missingActivityLocalizer.Object, - clock.Object); - - foreach (var activity in activities) - { - activityLibrary.Setup(x => x.InstantiateActivity(activity.Name)).Returns(activity); - } - - workflowTypeStore.Setup(x => x.GetAsync(workflowType.Id)).Returns(Task.FromResult(workflowType)); - - return workflowManager; - } } } From 753b2bf57cfdb3b5780be27912be88a31f369460 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 25 Dec 2022 02:10:52 +0300 Subject: [PATCH 10/33] Move PermissionHandlerHelper to OC.Testing.Security --- .../Fakes/FakePermissionHandler.cs | 27 ++++++++ .../Security/PermissionHandlerHelper.cs | 39 ++++++++++++ .../Security/PermissionHandlerTests.cs | 8 ++- .../RolesPermissionsHandlerTests.cs | 2 +- .../Security/PermissionHandlerHelper.cs | 61 ------------------- 5 files changed, 74 insertions(+), 63 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/Fakes/FakePermissionHandler.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Security/PermissionHandlerHelper.cs rename test/{OrchardCore.Tests => OrchardCore.Testing.Tests}/Security/PermissionHandlerTests.cs (98%) delete mode 100644 test/OrchardCore.Tests/Security/PermissionHandlerHelper.cs diff --git a/src/OrchardCore/OrchardCore.Testing/Fakes/FakePermissionHandler.cs b/src/OrchardCore/OrchardCore.Testing/Fakes/FakePermissionHandler.cs new file mode 100644 index 00000000000..256fdb29ffc --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Fakes/FakePermissionHandler.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using OrchardCore.Security; + +namespace OrchardCore.Testing.Fakes; + +internal class FakePermissionHandler : AuthorizationHandler +{ + private readonly HashSet _permissionNames; + + public FakePermissionHandler(string[] permissionNames) + { + _permissionNames = new HashSet(permissionNames, StringComparer.OrdinalIgnoreCase); + } + + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) + { + if (_permissionNames.Contains(requirement.Permission.Name)) + { + context.Succeed(requirement); + } + + return Task.CompletedTask; + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/Security/PermissionHandlerHelper.cs b/src/OrchardCore/OrchardCore.Testing/Security/PermissionHandlerHelper.cs new file mode 100644 index 00000000000..e7db6ee1df1 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Security/PermissionHandlerHelper.cs @@ -0,0 +1,39 @@ +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using OrchardCore.Security.Permissions; +using OrchardCore.Security; +using OrchardCore.Testing.Fakes; + +namespace OrchardCore.Testing.Security; + +public static class PermissionHandlerHelper +{ + public static AuthorizationHandlerContext CreateTestAuthorizationHandlerContext(Permission required, string[] allowed = null, bool authenticated = false) + { + var identity = authenticated + ? new ClaimsIdentity("Testing") + : new ClaimsIdentity(); + + if (allowed != null) + { + foreach (var permissionName in allowed) + { + var permission = new Permission(permissionName); + identity.AddClaim(permission); + } + + } + + var principal = new ClaimsPrincipal(identity); + + return new AuthorizationHandlerContext(new[] { new PermissionRequirement(required) }, principal, null); + } + + public static async Task SuccessAsync(this AuthorizationHandlerContext context, params string[] permissionNames) + { + var handler = new FakePermissionHandler(permissionNames); + + await handler.HandleAsync(context); + } +} diff --git a/test/OrchardCore.Tests/Security/PermissionHandlerTests.cs b/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs similarity index 98% rename from test/OrchardCore.Tests/Security/PermissionHandlerTests.cs rename to test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs index 38b87759b91..cfb6c9f9988 100644 --- a/test/OrchardCore.Tests/Security/PermissionHandlerTests.cs +++ b/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs @@ -2,7 +2,7 @@ using OrchardCore.Security; using OrchardCore.Security.AuthorizationHandlers; using OrchardCore.Security.Permissions; -using Xunit; +using OrchardCore.Testing.Security; namespace OrchardCore.Tests.Security { @@ -15,6 +15,7 @@ public async Task GrantsClaimsPermissions(string required, bool success) { // Arrange var context = PermissionHandlerHelper.CreateTestAuthorizationHandlerContext(new Permission(required), new[] { "Allowed" }, true); + var permissionHandler = CreatePermissionHandler(); // Act @@ -29,6 +30,7 @@ public async Task DontRevokeExistingGrants() { // Arrange var context = PermissionHandlerHelper.CreateTestAuthorizationHandlerContext(new Permission("Required"), new[] { "Other" }, true); + var permissionHandler = CreatePermissionHandler(); await context.SuccessAsync("Required"); @@ -45,6 +47,7 @@ public async Task DontHandleNonAuthenticated() { // Arrange var context = PermissionHandlerHelper.CreateTestAuthorizationHandlerContext(new Permission("Allowed"), new[] { "Allowed" }); + var permissionHandler = CreatePermissionHandler(); // Act @@ -63,6 +66,7 @@ public async Task GrantsInheritedPermissions() var required = new Permission("Required", "Foo", new[] { level1 }); var context = PermissionHandlerHelper.CreateTestAuthorizationHandlerContext(required, new[] { "Implicit2" }, true); + var permissionHandler = CreatePermissionHandler(); // Act @@ -79,6 +83,7 @@ public async Task IsCaseInsensitive() var required = new Permission("required"); var context = PermissionHandlerHelper.CreateTestAuthorizationHandlerContext(required, new[] { "ReQuIrEd" }, true); + var permissionHandler = CreatePermissionHandler(); // Act @@ -91,6 +96,7 @@ public async Task IsCaseInsensitive() private static PermissionHandler CreatePermissionHandler() { var permissionGrantingService = new DefaultPermissionGrantingService(); + return new PermissionHandler(permissionGrantingService); } } diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs index 320acbecf0b..e164d8f4642 100644 --- a/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs +++ b/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs @@ -4,7 +4,7 @@ using OrchardCore.Roles; using OrchardCore.Security; using OrchardCore.Security.Permissions; -using OrchardCore.Tests.Security; +using OrchardCore.Testing.Security; using Xunit; namespace OrchardCore.Tests.Modules.OrchardCore.Roles diff --git a/test/OrchardCore.Tests/Security/PermissionHandlerHelper.cs b/test/OrchardCore.Tests/Security/PermissionHandlerHelper.cs deleted file mode 100644 index 2d72b94be83..00000000000 --- a/test/OrchardCore.Tests/Security/PermissionHandlerHelper.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Security.Claims; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using OrchardCore.Security; -using OrchardCore.Security.Permissions; - -namespace OrchardCore.Tests.Security -{ - public static class PermissionHandlerHelper - { - public static AuthorizationHandlerContext CreateTestAuthorizationHandlerContext(Permission required, string[] allowed = null, bool authenticated = false) - { - var identity = authenticated ? new ClaimsIdentity("Test") : new ClaimsIdentity(); - - if (allowed != null) - { - foreach (var permissionName in allowed) - { - var permission = new Permission(permissionName); - identity.AddClaim(permission); - } - - } - - var principal = new ClaimsPrincipal(identity); - - return new AuthorizationHandlerContext( - new[] { new PermissionRequirement(required) }, - principal, - null); - } - - public static async Task SuccessAsync(this AuthorizationHandlerContext context, params string[] permissionNames) - { - var handler = new FakePermissionHandler(permissionNames); - await handler.HandleAsync(context); - } - - private class FakePermissionHandler : AuthorizationHandler - { - private readonly HashSet _permissionNames; - - public FakePermissionHandler(string[] permissionNames) - { - _permissionNames = new HashSet(permissionNames, StringComparer.OrdinalIgnoreCase); - } - - protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) - { - if (_permissionNames.Contains(requirement.Permission.Name)) - { - context.Succeed(requirement); - } - - return Task.CompletedTask; - } - } - } -} From 03c771cb492b3ebe2201bac55912eddc40b98a0a Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 25 Dec 2022 17:29:51 +0300 Subject: [PATCH 11/33] Move AutorouteEntriesStub to OC.Testing --- .../OrchardCore.Testing.csproj | 1 + .../Stubs/AutorouteEntriesStub.cs | 19 ++++++++ .../Stubs/IAutorouteEntriesStub.cs | 11 +++++ .../Routing/AutorouteEntriesTests.cs | 43 +++++++------------ 4 files changed, 46 insertions(+), 28 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/AutorouteEntriesStub.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/IAutorouteEntriesStub.cs diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index 11726e538d4..231b159254c 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -23,6 +23,7 @@ + diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/AutorouteEntriesStub.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/AutorouteEntriesStub.cs new file mode 100644 index 00000000000..9f5ee7f727a --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/AutorouteEntriesStub.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using OrchardCore.Autoroute.Core.Services; +using OrchardCore.ContentManagement.Routing; + +namespace OrchardCore.Testing.Stubs; + +public class AutorouteEntriesStub : AutorouteEntries, IAutorouteEntriesStub +{ + public AutorouteEntriesStub() : base(null) + { + } + + public new void AddEntries(IEnumerable entries) => base.AddEntries(entries); + + public new void RemoveEntries(IEnumerable entries) => base.RemoveEntries(entries); + + protected override Task InitializeEntriesAsync() => Task.CompletedTask; +} diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/IAutorouteEntriesStub.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/IAutorouteEntriesStub.cs new file mode 100644 index 00000000000..eb73c24f4dc --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/IAutorouteEntriesStub.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using OrchardCore.ContentManagement.Routing; + +namespace OrchardCore.Testing.Stubs; + +public interface IAutorouteEntriesStub : IAutorouteEntries +{ + void AddEntries(IEnumerable entries); + + void RemoveEntries(IEnumerable entries); +} diff --git a/test/OrchardCore.Tests/Routing/AutorouteEntriesTests.cs b/test/OrchardCore.Tests/Routing/AutorouteEntriesTests.cs index 08593418100..69f793173e6 100644 --- a/test/OrchardCore.Tests/Routing/AutorouteEntriesTests.cs +++ b/test/OrchardCore.Tests/Routing/AutorouteEntriesTests.cs @@ -2,13 +2,13 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -using OrchardCore.Autoroute.Core.Services; using OrchardCore.ContentManagement.Routing; using OrchardCore.Environment.Shell; using OrchardCore.Environment.Shell.Builders; using OrchardCore.Environment.Shell.Models; using OrchardCore.Locking; using OrchardCore.Locking.Distributed; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.Routing @@ -23,7 +23,7 @@ public async Task ShouldGetContainedEntryByPath() await shellContext.CreateScope().UsingAsync(scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Act var initialEntries = new List() @@ -39,7 +39,7 @@ await shellContext.CreateScope().UsingAsync(scope => await shellContext.CreateScope().UsingAsync(async scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Test (var result, var containedEntry) = await entries.TryGetEntryByPathAsync("/contained-path"); @@ -57,7 +57,7 @@ public async Task ShouldGetEntryByContainedContentItemId() await shellContext.CreateScope().UsingAsync(scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Act var initialEntries = new List() @@ -73,7 +73,7 @@ await shellContext.CreateScope().UsingAsync(scope => await shellContext.CreateScope().UsingAsync(async scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Test (var result, var containedEntry) = await entries.TryGetEntryByContentItemIdAsync("contained"); @@ -91,7 +91,7 @@ public async Task RemovesContainedEntriesWhenContainerRemoved() await shellContext.CreateScope().UsingAsync(scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Act var initialEntries = new List() @@ -109,7 +109,7 @@ await shellContext.CreateScope().UsingAsync(scope => await shellContext.CreateScope().UsingAsync(async scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Test (var result, var containedEntry) = await entries.TryGetEntryByPathAsync("/contained-path"); @@ -126,7 +126,7 @@ public async Task RemovesContainedEntriesWhenDeleted() await shellContext.CreateScope().UsingAsync(scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Act var initialEntries = new List() @@ -151,7 +151,7 @@ await shellContext.CreateScope().UsingAsync(scope => await shellContext.CreateScope().UsingAsync(async scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Test (var result, var containedEntry) = await entries.TryGetEntryByPathAsync("/contained-path2"); @@ -168,7 +168,7 @@ public async Task RemovesOldContainedPaths() await shellContext.CreateScope().UsingAsync(scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Act var initialEntries = new List() @@ -192,7 +192,7 @@ await shellContext.CreateScope().UsingAsync(scope => await shellContext.CreateScope().UsingAsync(async scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Test (var result, var containedEntry) = await entries.TryGetEntryByPathAsync("/contained-path-old"); @@ -209,7 +209,7 @@ public async Task RemovesOldPaths() await shellContext.CreateScope().UsingAsync(scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Act entries.AddEntries(new[] { new AutorouteEntry("container", "container-path", null, null) }); @@ -221,7 +221,7 @@ await shellContext.CreateScope().UsingAsync(scope => await shellContext.CreateScope().UsingAsync(async scope => { - var entries = scope.ServiceProvider.GetRequiredService(); + var entries = scope.ServiceProvider.GetRequiredService(); // Test (var result, var containedEntry) = await entries.TryGetEntryByPathAsync("/container-path"); @@ -242,23 +242,10 @@ private static ShellContext CreateShellContext() private static IServiceProvider CreateServiceProvider() { var services = new ServiceCollection(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); - return services.AddLogging().BuildServiceProvider(); - } - public interface IStubAutorouteEntries : IAutorouteEntries - { - void AddEntries(IEnumerable entries); - void RemoveEntries(IEnumerable entries); - } - - private class StubAutorouteEntries : AutorouteEntries, IStubAutorouteEntries - { - public StubAutorouteEntries() : base(null) { } - public new void AddEntries(IEnumerable entries) => base.AddEntries(entries); - public new void RemoveEntries(IEnumerable entries) => base.RemoveEntries(entries); - protected override Task InitializeEntriesAsync() => Task.CompletedTask; + return services.AddLogging().BuildServiceProvider(); } } } From 12069e808f207a770ec3b7ded6805ce2529a50b3 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 25 Dec 2022 18:02:59 +0300 Subject: [PATCH 12/33] Move FileVersionProviderStub to OC.Testing --- .../Stubs/FileVersionProviderStub.cs | 9 ++ .../ResourceDefinitionTests.cs | 46 ++++------ .../ResourceManagerTests.cs | 85 +++++++------------ 3 files changed, 55 insertions(+), 85 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/FileVersionProviderStub.cs diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/FileVersionProviderStub.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/FileVersionProviderStub.cs new file mode 100644 index 00000000000..72098c31e61 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/FileVersionProviderStub.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.ViewFeatures; + +namespace OrchardCore.Testing.Stubs; + +public class FileVersionProviderStub : IFileVersionProvider +{ + public string AddFileVersionToPath(PathString requestPathBase, string path) => path; +} diff --git a/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs b/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs index 2c37f15b5f8..8deccab496e 100644 --- a/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs +++ b/test/OrchardCore.Tests/ResourceManagement/ResourceDefinitionTests.cs @@ -2,15 +2,16 @@ using System.IO; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Html; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc.ViewFeatures; using OrchardCore.ResourceManagement; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.ResourceManagement { public class ResourceDefinitionTests { + private readonly static FileVersionProviderStub _fileVersionProviderStub = new(); + private readonly ResourceManifest _resourceManifest; public ResourceDefinitionTests() @@ -31,7 +32,7 @@ public void GetScriptResourceWithUrl(string applicationPath) .SetCdn("https://cdn.tld/foo.js", "https://cdn.tld/foo.debug.js"); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("script", tagBuilder.TagName); Assert.Equal($"{applicationPath}/foo.js", tagBuilder.Attributes["src"]); @@ -46,7 +47,7 @@ public void GetScriptResourceWithBasePath(string basePath) .SetBasePath(basePath); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, String.Empty, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, String.Empty, _fileVersionProviderStub); Assert.Equal("script", tagBuilder.TagName); Assert.Equal($"{basePath}/foo.js", tagBuilder.Attributes["src"]); @@ -63,7 +64,7 @@ public void GetScriptResourceWithDebugUrl(string applicationPath) .SetCdn("https://cdn.tld/foo.js", "https://cdn.tld/foo.debug.js"); var requireSettings = new RequireSettings { DebugMode = true, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("script", tagBuilder.TagName); Assert.Equal($"{applicationPath}/foo.debug.js", tagBuilder.Attributes["src"]); @@ -80,7 +81,7 @@ public void GetScriptResourceWithCdnUrl(string applicationPath) .SetCdn("https://cdn.tld/foo.js", "https://cdn.tld/foo.debug.js"); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = true }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("script", tagBuilder.TagName); Assert.Equal("https://cdn.tld/foo.js", tagBuilder.Attributes["src"]); @@ -97,7 +98,7 @@ public void GetScriptResourceWithDebugCdnUrl(string applicationPath) .SetCdn("https://cdn.tld/foo.js", "https://cdn.tld/foo.debug.js"); var requireSettings = new RequireSettings { DebugMode = true, CdnMode = true, CdnBaseUrl = "https://hostcdn.net" }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("script", tagBuilder.TagName); Assert.Equal("https://cdn.tld/foo.debug.js", tagBuilder.Attributes["src"]); @@ -118,7 +119,7 @@ public void GetLocalScriptResourceWithCdnBaseUrl(string applicationPath, string .SetUrl(url, url); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = true, CdnBaseUrl = "https://hostcdn.net" }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("script", tagBuilder.TagName); Assert.Equal(expected, tagBuilder.Attributes["src"]); @@ -135,7 +136,7 @@ public void GetScriptResourceWithInlineContent(string applicationPath) var requireSettings = new RequireSettings() .UseCdnBaseUrl("https://hostcdn.net"); - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("script", tagBuilder.TagName); Assert.Equal("console.log('foo');", ReadIHtmlContent(tagBuilder.InnerHtml)); @@ -152,7 +153,7 @@ public void GetStyleResourceWithUrl(string applicationPath) .SetCdn("https://cdn.tld/foo.css", "https://cdn.tld/foo.debug.css"); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); @@ -171,7 +172,7 @@ public void GetStyleResourceWithDebugUrl(string applicationPath) .SetCdn("https://cdn.tld/foo.css", "https://cdn.tld/foo.debug.css"); var requireSettings = new RequireSettings { DebugMode = true, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); @@ -190,7 +191,7 @@ public void GetStyleResourceWithCdnUrl(string applicationPath) .SetCdn("https://cdn.tld/foo.css", "https://cdn.tld/foo.debug.css"); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = true }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); @@ -213,7 +214,7 @@ public void GetLocalStyleResourceWithCdnBaseUrl(string applicationPath, string u .SetUrl(url, url); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = true, CdnBaseUrl = "https://hostcdn.net" }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); @@ -232,7 +233,7 @@ public void GetStyleResourceWithDebugCdnUrl(string applicationPath) .SetCdn("https://cdn.tld/foo.css", "https://cdn.tld/foo.debug.css"); var requireSettings = new RequireSettings { DebugMode = true, CdnMode = true }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); @@ -252,7 +253,7 @@ public void GetStyleResourceWithAttributes(string applicationPath) .SetAttribute("media", "all"); var requireSettings = new RequireSettings { DebugMode = false, CdnMode = false }; - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("link", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); @@ -272,7 +273,7 @@ public void GetStyleResourceWithInlineContent(string applicationPath) var requireSettings = new RequireSettings() .UseCdnBaseUrl("https://cdn.net"); - var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, StubFileVersionProvider.Instance); + var tagBuilder = resourceDefinition.GetTagBuilder(requireSettings, applicationPath, _fileVersionProviderStub); Assert.Equal("style", tagBuilder.TagName); Assert.Equal("text/css", tagBuilder.Attributes["type"]); @@ -290,18 +291,5 @@ private static string ReadIHtmlContent(IHtmlContent content) } #endregion - - #region Stubs - private class StubFileVersionProvider : IFileVersionProvider - { - public static StubFileVersionProvider Instance { get; } = new StubFileVersionProvider(); - - public string AddFileVersionToPath(PathString requestPathBase, string path) - { - return path; - } - } - - #endregion } } diff --git a/test/OrchardCore.Tests/ResourceManagement/ResourceManagerTests.cs b/test/OrchardCore.Tests/ResourceManagement/ResourceManagerTests.cs index 03653837312..d2a5d24cdcf 100644 --- a/test/OrchardCore.Tests/ResourceManagement/ResourceManagerTests.cs +++ b/test/OrchardCore.Tests/ResourceManagement/ResourceManagerTests.cs @@ -8,10 +8,9 @@ using AngleSharp.Dom; using AngleSharp.Html.Dom; using Microsoft.AspNetCore.Html; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.Options; using OrchardCore.ResourceManagement; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.ResourceManagement @@ -20,6 +19,8 @@ public class ResourceManagerTests { private const string basePath = "http://host"; + private readonly static FileVersionProviderStub _fileVersionProviderStub = new(); + private readonly IBrowsingContext browsingContext; public ResourceManagerTests() @@ -41,7 +42,7 @@ public void FindResourceFromManifestProviders() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); var resourceDefinition = resourceManager.FindResource(new RequireSettings { Type = "foo", Name = "bar2" }); @@ -58,7 +59,7 @@ public void RegisterResouceUrl() { var resourceManager = new ResourceManager( new OptionsWrapper(new ResourceManagementOptions()), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); var requireSetting = resourceManager.RegisterUrl("foo", "schema://domain.ext/resource", "schema://domain.ext/resource.debug"); @@ -75,7 +76,7 @@ public void RegisteredResouceUrlIsRequired() { var resourceManager = new ResourceManager( new OptionsWrapper(new ResourceManagementOptions()), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterUrl("foo", "schema://domain.ext/resource", "schema://domain.ext/resource.debug"); @@ -101,7 +102,7 @@ public void RegisteredResouceNameIsRequired() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterResource("foo", "bar"); @@ -144,7 +145,7 @@ public void RequireDependencies() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterResource("foo", "last-resource"); @@ -193,7 +194,7 @@ public void RequireCircularDependenciesShouldThrowException() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterResource("foo", "required"); @@ -219,7 +220,7 @@ public void RequireCircularNestedDependencyShouldThrowException() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterResource("foo", "requires-indirect-dependency"); @@ -244,7 +245,7 @@ public void RequireByDependencyResourceThatDependsOnLastPositionedResourceShould var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterResource("foo", "resource"); @@ -278,7 +279,7 @@ public void RequireFirstPositionedResourceThatDependsOnByDependencyResourceShoul var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterResource("foo", "first-resource"); @@ -315,7 +316,7 @@ public void RequireFirstPositionedResourceWithDependencyToResourcePositionedLast var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterResource("foo", "first-resource"); @@ -339,7 +340,7 @@ public void RemoveRequiredResource() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterResource("foo", "required"); @@ -372,7 +373,7 @@ public void RemoveRequiredResourceDependency() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterResource("foo", "required"); @@ -395,7 +396,7 @@ public void RegisterHeadScript() { var resourceManager = new ResourceManager( new OptionsWrapper(new ResourceManagementOptions()), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); var customScript = ""; @@ -411,7 +412,7 @@ public void RegisterFootScript() { var resourceManager = new ResourceManager( new OptionsWrapper(new ResourceManagementOptions()), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); var customScript = ""; @@ -427,7 +428,7 @@ public void RegisterStyle() { var resourceManager = new ResourceManager( new OptionsWrapper(new ResourceManagementOptions()), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); var customStyle = ""; @@ -443,7 +444,7 @@ public void RegisterLink() { var resourceManager = new ResourceManager( new OptionsWrapper(new ResourceManagementOptions()), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); var linkEntry = new LinkEntry @@ -464,7 +465,7 @@ public void RegisterMeta() { var resourceManager = new ResourceManager( new OptionsWrapper(new ResourceManagementOptions()), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); var metaEntry = new MetaEntry(name: "foo", content: "bar"); @@ -481,7 +482,7 @@ public async Task AppendMeta() { var resourceManager = new ResourceManager( new OptionsWrapper(new ResourceManagementOptions()), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); var first = new MetaEntry(name: "keywords", content: "bar") @@ -509,7 +510,7 @@ public async Task RenderMeta() { var resourceManager = new ResourceManager( new OptionsWrapper(new ResourceManagementOptions()), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterMeta(new MetaEntry { Charset = "utf-8" }); @@ -536,7 +537,7 @@ public async Task RenderHeadLink() { var resourceManager = new ResourceManager( new OptionsWrapper(new ResourceManagementOptions()), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterUrl("stylesheet", "other.min.css", "other.css"); // Should not be rendered @@ -572,7 +573,7 @@ public async Task RenderStylesheet() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); resourceManager.RegisterLink(new LinkEntry { Rel = "icon", Href = "/favicon.ico" }); // Should not be rendered @@ -629,7 +630,7 @@ public async Task RenderHeadScript() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); // Require resource @@ -681,7 +682,7 @@ public async Task RenderFootScript() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); // Require resource @@ -743,7 +744,7 @@ public async Task RenderHeadAndFootScriptWithSameDependency() var resourceManager = new ResourceManager ( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); // Require resource. @@ -801,7 +802,7 @@ public async Task RenderLocalScript() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); var requireSetting = resourceManager.RegisterResource("script", "required"); @@ -841,7 +842,7 @@ public async Task RenderLocalStyle() var resourceManager = new ResourceManager( new OptionsWrapper(options), - StubFileVersionProvider.Instance + _fileVersionProviderStub ); var requireSetting = resourceManager.RegisterResource("stylesheet", "required").AtLocation(ResourceLocation.Inline); @@ -877,33 +878,5 @@ private async Task ParseHtmlAsync(IHtmlContent content) } #endregion - - #region Stubs - private class StubResourceManifestProvider : IConfigureOptions - { - private readonly Action _configureManifestAction; - - public StubResourceManifestProvider(Action configureManifestAction) - { - _configureManifestAction = configureManifestAction; - } - - public void Configure(ResourceManagementOptions options) - { - _configureManifestAction?.Invoke(options); - } - } - - private class StubFileVersionProvider : IFileVersionProvider - { - public static StubFileVersionProvider Instance { get; } = new StubFileVersionProvider(); - - public string AddFileVersionToPath(PathString requestPathBase, string path) - { - return path; - } - } - - #endregion } } From 55ee921406989d16f2c616dcefce21a7bde0a1a9 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 25 Dec 2022 18:14:35 +0300 Subject: [PATCH 13/33] Move UsersMockHelpers to OrchardCore.SecurityMocks --- .../Mocks/OrchardCoreSecurityMocks.cs | 79 +++++++++++++++++++ .../OrchardCore.Testing.csproj | 1 + ...UserClaimsPrincipalProviderFactoryTests.cs | 5 +- .../RegistrationControllerTests.cs | 26 +----- .../OrchardCore.Users/UserValidatorTests.cs | 13 +-- .../OrchardCore.Users/UsersMockHelper.cs | 33 -------- 6 files changed, 93 insertions(+), 64 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs delete mode 100644 test/OrchardCore.Tests/OrchardCore.Users/UsersMockHelper.cs diff --git a/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs new file mode 100644 index 00000000000..917a06af6b3 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using Moq; +using OrchardCore.Users; + +namespace OrchardCore.Testing.Mocks; + +public static partial class OrchardCoreMock +{ + public static SignInManager CreateSignInManager(UserManager userManager = null) where TUser : class, IUser + { + var context = new Mock(); + var manager = userManager ?? CreateUserManagerMock().Object; + + var signInManager = new Mock>( + manager, + new HttpContextAccessor { HttpContext = context.Object }, + Mock.Of>(), + null, + null, + null, + null) + { + CallBase = true + }; + + signInManager + .Setup(x => x.SignInAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask); + + return signInManager.Object; + } + + public static Mock> CreateUserManagerMock() where TUser : class + { + var userStore = new Mock>(); + var identityOptions = new IdentityOptions(); + identityOptions.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._+"; + identityOptions.User.RequireUniqueEmail = true; + + var userManagerMock = new Mock>( + userStore.Object, + Options.Create(identityOptions), + null, + null, + null, + null, + null, + null, + null); + + userManagerMock.Object.UserValidators.Add(new UserValidator(new IdentityErrorDescriber())); + + userManagerMock.Object.PasswordValidators.Add(new PasswordValidator()); + + return userManagerMock; + } + + public static RoleManager CreateRoleManager() where TRole : class + { + var roleStoreMock = new Mock>().Object; + var rolesValidators = new List> + { + new RoleValidator() + }; + + var roleManagerMock = new Mock>( + roleStoreMock, + rolesValidators, + new UpperInvariantLookupNormalizer(), + new IdentityErrorDescriber(), + null); + + return roleManagerMock.Object; + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index 231b159254c..13b15b0f7cc 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -29,6 +29,7 @@ + diff --git a/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs b/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs index f81b2cb9ef7..afecaa78d71 100644 --- a/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs +++ b/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Options; using Moq; using OrchardCore.Security; +using OrchardCore.Testing.Mocks; using OrchardCore.Users; using OrchardCore.Users.Models; using OrchardCore.Users.Services; @@ -22,7 +23,7 @@ public class DefaultUserClaimsPrincipalProviderFactoryTests public async Task EnsurePrincipalHasExpectedClaims(bool emailVerified) { //Arrange - var userManager = UsersMockHelper.MockUserManager(); + var userManager = OrchardCoreMock.CreateUserManagerMock(); var user = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo", Email = "foo@foo.com" }; userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.UserId); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); @@ -33,7 +34,7 @@ public async Task EnsurePrincipalHasExpectedClaims(bool emailVerified) userManager.Setup(m => m.IsEmailConfirmedAsync(user)).ReturnsAsync(emailVerified); } - var roleManager = UsersMockHelper.MockRoleManager().Object; + var roleManager = OrchardCoreMock.CreateRoleManager(); var options = new Mock>(); options.Setup(a => a.Value).Returns(new IdentityOptions()); diff --git a/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs b/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs index 7a1d7120524..256861e5ebc 100644 --- a/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs +++ b/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs @@ -20,6 +20,7 @@ using OrchardCore.DisplayManagement.Notify; using OrchardCore.Email; using OrchardCore.Settings; +using OrchardCore.Testing.Mocks; using OrchardCore.Users; using OrchardCore.Users.Controllers; using OrchardCore.Users.Events; @@ -117,27 +118,6 @@ public async Task UsersCanRequireEmailConfirmation() Assert.Equal("ConfirmEmailSent", ((RedirectToActionResult)result).ActionName); } - private static Mock> MockSignInManager(UserManager userManager = null) where TUser : class, IUser - { - var context = new Mock(); - var manager = userManager ?? UsersMockHelper.MockUserManager().Object; - - var signInManager = new Mock>( - manager, - new HttpContextAccessor { HttpContext = context.Object }, - Mock.Of>(), - null, - null, - null, - null) - { CallBase = true }; - - signInManager.Setup(x => x.SignInAsync(It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(Task.CompletedTask); - - return signInManager; - } - private static RegistrationController SetupRegistrationController() => SetupRegistrationController(new RegistrationSettings { @@ -147,7 +127,7 @@ private static RegistrationController SetupRegistrationController() private static RegistrationController SetupRegistrationController(RegistrationSettings registrationSettings) { var users = new List(); - var mockUserManager = UsersMockHelper.MockUserManager(); + var mockUserManager = OrchardCoreMock.CreateUserManagerMock(); mockUserManager.Setup(um => um.FindByEmailAsync(It.IsAny())) .Returns(e => { @@ -212,7 +192,7 @@ private static RegistrationController SetupRegistrationController(RegistrationSe .Returns(userService.Object); mockServiceProvider .Setup(x => x.GetService(typeof(SignInManager))) - .Returns(MockSignInManager(mockUserManager.Object).Object); + .Returns(OrchardCoreMock.CreateSignInManager(mockUserManager.Object)); mockServiceProvider .Setup(x => x.GetService(typeof(ITempDataDictionaryFactory))) .Returns(Mock.Of()); diff --git a/test/OrchardCore.Tests/OrchardCore.Users/UserValidatorTests.cs b/test/OrchardCore.Tests/OrchardCore.Users/UserValidatorTests.cs index 8707ea7df50..3a48207ea9b 100644 --- a/test/OrchardCore.Tests/OrchardCore.Users/UserValidatorTests.cs +++ b/test/OrchardCore.Tests/OrchardCore.Users/UserValidatorTests.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Moq; +using OrchardCore.Testing.Mocks; using OrchardCore.Users; using OrchardCore.Users.Models; using Xunit; @@ -15,7 +16,7 @@ public class UserValidatorTests public async Task CanValidateUser() { // Arrange - var userManager = UsersMockHelper.MockUserManager(); + var userManager = OrchardCoreMock.CreateUserManagerMock(); var user = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo", Email = "foo@foo.com" }; userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.UserId); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); @@ -34,7 +35,7 @@ public async Task ShouldRequireEmail() { // Arrange var describer = new IdentityErrorDescriber(); - var userManager = UsersMockHelper.MockUserManager(); + var userManager = OrchardCoreMock.CreateUserManagerMock(); var user = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo" }; userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.UserId); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); @@ -54,7 +55,7 @@ public async Task ShouldRequireValidEmail() { // Arrange var describer = new IdentityErrorDescriber(); - var userManager = UsersMockHelper.MockUserManager(); + var userManager = OrchardCoreMock.CreateUserManagerMock(); var user = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo", Email = "foo" }; userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.UserId); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); @@ -74,7 +75,7 @@ public async Task ShouldRequireUniqueEmail() { // Arrange var describer = new IdentityErrorDescriber(); - var userManager = UsersMockHelper.MockUserManager(); + var userManager = OrchardCoreMock.CreateUserManagerMock(); var existingUser = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo", Email = "foo@foo.com" }; userManager.Setup(m => m.GetUserIdAsync(existingUser)).ReturnsAsync(existingUser.UserId); userManager.Setup(m => m.GetUserNameAsync(existingUser)).ReturnsAsync(existingUser.UserName); @@ -101,7 +102,7 @@ public async Task ShouldRequireUserNameIsNotAnEmailAddress() { // Arrange var describer = new IdentityErrorDescriber(); - var userManager = UsersMockHelper.MockUserManager(); + var userManager = OrchardCoreMock.CreateUserManagerMock(); var user = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "foo@foo.com", Email = "foo" }; userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.UserId); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); @@ -121,7 +122,7 @@ public async Task ShouldRequireUniqueUserName() { // Arrange var describer = new IdentityErrorDescriber(); - var userManager = UsersMockHelper.MockUserManager(); + var userManager = OrchardCoreMock.CreateUserManagerMock(); var existingUser = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo", Email = "bar@bar.com" }; userManager.Setup(m => m.GetUserIdAsync(existingUser)).ReturnsAsync(existingUser.UserId); userManager.Setup(m => m.GetUserNameAsync(existingUser)).ReturnsAsync(existingUser.UserName); diff --git a/test/OrchardCore.Tests/OrchardCore.Users/UsersMockHelper.cs b/test/OrchardCore.Tests/OrchardCore.Users/UsersMockHelper.cs deleted file mode 100644 index fe913e95e11..00000000000 --- a/test/OrchardCore.Tests/OrchardCore.Users/UsersMockHelper.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.Options; -using Moq; - -namespace OrchardCore.Tests.OrchardCore.Users -{ - public static class UsersMockHelper - { - public static Mock> MockUserManager() where TUser : class - { - var store = new Mock>(); - var identityOptions = new IdentityOptions(); - identityOptions.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._+"; - identityOptions.User.RequireUniqueEmail = true; - - var mgr = new Mock>(store.Object, Options.Create(identityOptions), null, null, null, null, null, null, null); - mgr.Object.UserValidators.Add(new UserValidator(new IdentityErrorDescriber())); - mgr.Object.PasswordValidators.Add(new PasswordValidator()); - - return mgr; - } - - public static Mock> MockRoleManager() where TRole : class - { - var store = new Mock>().Object; - var roles = new List>(); - roles.Add(new RoleValidator()); - - return new Mock>(store, roles, new UpperInvariantLookupNormalizer(), new IdentityErrorDescriber(), null); - } - } -} From 2886364ef380274ca2f2a21554d8d5ed45eef2ae Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 31 Dec 2022 19:27:42 +0300 Subject: [PATCH 14/33] Move HttpContentExtensions & HttpRequestExtensions to OC.Testing --- .../Extensions/HttpContentExtensions.cs | 5 +- .../Extensions/HttpRequestExtensions.cs | 109 ++++++++++ .../BlogPostApiControllerTests.cs | 1 + .../BlogPostCreateDeploymentPlanTests.cs | 1 + .../BlogPostUpdateDeploymentPlanTests.cs | 1 + .../Context/BlogPostApiControllerContext.cs | 1 + .../Extensions/HttpRequestExtensions.cs | 200 ------------------ .../Apis/Lucene/LuceneQueryTests.cs | 1 + 8 files changed, 116 insertions(+), 203 deletions(-) rename {test/OrchardCore.Tests/Apis/Context => src/OrchardCore/OrchardCore.Testing}/Extensions/HttpContentExtensions.cs (92%) create mode 100644 src/OrchardCore/OrchardCore.Testing/Extensions/HttpRequestExtensions.cs delete mode 100644 test/OrchardCore.Tests/Apis/Context/Extensions/HttpRequestExtensions.cs diff --git a/test/OrchardCore.Tests/Apis/Context/Extensions/HttpContentExtensions.cs b/src/OrchardCore/OrchardCore.Testing/Extensions/HttpContentExtensions.cs similarity index 92% rename from test/OrchardCore.Tests/Apis/Context/Extensions/HttpContentExtensions.cs rename to src/OrchardCore/OrchardCore.Testing/Extensions/HttpContentExtensions.cs index 22c2e697e5e..673432f1ad3 100644 --- a/test/OrchardCore.Tests/Apis/Context/Extensions/HttpContentExtensions.cs +++ b/src/OrchardCore/OrchardCore.Testing/Extensions/HttpContentExtensions.cs @@ -1,12 +1,11 @@ using System.IO; -using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace OrchardCore.Tests.Apis.Context +namespace System.Net.Http { - internal static class HttpContentExtensions + public static class HttpContentExtensions { public static async Task ReadAsAsync(this HttpContent content, JsonConverter jsonConverter) { diff --git a/src/OrchardCore/OrchardCore.Testing/Extensions/HttpRequestExtensions.cs b/src/OrchardCore/OrchardCore.Testing/Extensions/HttpRequestExtensions.cs new file mode 100644 index 00000000000..92da57e30fb --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Extensions/HttpRequestExtensions.cs @@ -0,0 +1,109 @@ +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace System.Net.Http +{ + /// + /// The http request extensions. + /// + public static class HttpRequestExtensions + { + private readonly static JsonSerializerSettings JsonSettings = new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore + }; + + public static Task PatchAsJsonAsync( + this HttpClient client, + string requestUri, + T value, + JsonSerializerSettings settings = null) + { + var content = new StringContent( + JsonConvert.SerializeObject(value, settings ?? JsonSettings), + Encoding.UTF8, + "application/json"); + + return PatchAsync(client, requestUri, content); + } + + public static Task PatchAsync(this HttpClient client, string requestUri, HttpContent content) + { + var request = new HttpRequestMessage + { + Method = new HttpMethod("PATCH"), + RequestUri = new Uri(client.BaseAddress + requestUri), + Content = content + }; + + request.Headers.ExpectContinue = false; + + return client.SendAsync(request); + } + + public static Task PutAsJsonAsync( + this HttpClient client, + string requestUri, + T value, + JsonSerializerSettings settings = null) + { + var content = new StringContent( + JsonConvert.SerializeObject(value, settings ?? JsonSettings), + Encoding.UTF8, + "application/json"); + + return client.PutAsync(requestUri, content); + } + + public static Task PostAsJsonAsync( + this HttpClient client, + string requestUri, + T value, + JsonSerializerSettings settings = null) + { + var content = new StringContent( + JsonConvert.SerializeObject(value, settings ?? JsonSettings), + Encoding.UTF8, + "application/json"); + + var request = new HttpRequestMessage(HttpMethod.Post, requestUri) + { + Content = content + }; + + request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + + return client.SendAsync(request); + } + + public static Task PostJsonAsync(this HttpClient client, string requestUri, string json) + { + var content = new StringContent(json, Encoding.UTF8, "application/json"); + + var request = new HttpRequestMessage(HttpMethod.Post, requestUri) + { + Content = content + }; + + request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + + return client.SendAsync(request); + } + + public static Task PostJsonApiAsync(this HttpClient client, string requestUri, string json) + { + var content = new StringContent(json, Encoding.UTF8, "application/vnd.api+json"); + + var request = new HttpRequestMessage(HttpMethod.Post, requestUri) + { + Content = content + }; + + request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.api+json")); + + return client.SendAsync(request); + } + } +} diff --git a/test/OrchardCore.Tests/Apis/ContentManagement/ContentApiController/BlogPostApiControllerTests.cs b/test/OrchardCore.Tests/Apis/ContentManagement/ContentApiController/BlogPostApiControllerTests.cs index ae2d561ecf1..ae3a386edcd 100644 --- a/test/OrchardCore.Tests/Apis/ContentManagement/ContentApiController/BlogPostApiControllerTests.cs +++ b/test/OrchardCore.Tests/Apis/ContentManagement/ContentApiController/BlogPostApiControllerTests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; diff --git a/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostCreateDeploymentPlanTests.cs b/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostCreateDeploymentPlanTests.cs index 122ea8d937a..86e3acaaaa4 100644 --- a/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostCreateDeploymentPlanTests.cs +++ b/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostCreateDeploymentPlanTests.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json.Linq; diff --git a/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostUpdateDeploymentPlanTests.cs b/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostUpdateDeploymentPlanTests.cs index 088bef378c2..986aa44ab8c 100644 --- a/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostUpdateDeploymentPlanTests.cs +++ b/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostUpdateDeploymentPlanTests.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using OrchardCore.ContentManagement; diff --git a/test/OrchardCore.Tests/Apis/Context/BlogPostApiControllerContext.cs b/test/OrchardCore.Tests/Apis/Context/BlogPostApiControllerContext.cs index fd353d4bb52..c97981128af 100644 --- a/test/OrchardCore.Tests/Apis/Context/BlogPostApiControllerContext.cs +++ b/test/OrchardCore.Tests/Apis/Context/BlogPostApiControllerContext.cs @@ -1,3 +1,4 @@ +using System.Net.Http; using System.Threading.Tasks; using OrchardCore.Apis.GraphQL.Client; using OrchardCore.ContentManagement; diff --git a/test/OrchardCore.Tests/Apis/Context/Extensions/HttpRequestExtensions.cs b/test/OrchardCore.Tests/Apis/Context/Extensions/HttpRequestExtensions.cs deleted file mode 100644 index 958120df4ca..00000000000 --- a/test/OrchardCore.Tests/Apis/Context/Extensions/HttpRequestExtensions.cs +++ /dev/null @@ -1,200 +0,0 @@ -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace OrchardCore.Tests.Apis.Context -{ - /// - /// The http request extensions. - /// - internal static class HttpRequestExtensions - { - private readonly static JsonSerializerSettings JsonSettings = new JsonSerializerSettings() - { - NullValueHandling = NullValueHandling.Ignore - }; - - /// - /// The patch as json async. - /// - /// - /// The client. - /// - /// - /// The request uri. - /// - /// - /// The value. - /// - /// - /// The formatter. - /// - /// - /// - /// - /// The . - /// - public static Task PatchAsJsonAsync( - this HttpClient client, - string requestUri, - T value, - JsonSerializerSettings settings = null) - { - var content = new StringContent( - JsonConvert.SerializeObject(value, settings ?? JsonSettings), - Encoding.UTF8, - "application/json"); - - return HttpRequestExtensions.PatchAsync(client, requestUri, content); - } - - /// - /// The patch async. - /// - /// - /// The client. - /// - /// - /// The request uri. - /// - /// - /// The content. - /// - /// - /// The . - /// - public static Task PatchAsync( - this HttpClient client, - string requestUri, - HttpContent content) - { - var request = new HttpRequestMessage - { - Method = new HttpMethod("PATCH"), - RequestUri = new Uri(client.BaseAddress + requestUri), - Content = content - }; - - request.Headers.ExpectContinue = false; - return client.SendAsync(request); - } - - /// - /// The put as json async. - /// - /// - /// The client. - /// - /// - /// The request uri. - /// - /// - /// The value. - /// - /// - /// The formatter. - /// - /// - /// - /// - /// The . - /// - public static Task PutAsJsonAsync( - this HttpClient client, - string requestUri, - T value, - JsonSerializerSettings settings = null) - { - var content = new StringContent( - JsonConvert.SerializeObject(value, settings ?? JsonSettings), - Encoding.UTF8, - "application/json"); - - return client.PutAsync(requestUri, content); - } - - /// - /// PostAsJsonAsync - /// - /// - /// The client. - /// - /// - /// The request uri. - /// - /// - /// The value. - /// - /// - /// The formatter. - /// - /// - /// - /// - /// The . - /// - public static Task PostAsJsonAsync( - this HttpClient client, - string requestUri, - T value, - JsonSerializerSettings settings = null) - { - var content = new StringContent( - JsonConvert.SerializeObject(value, settings ?? JsonSettings), - Encoding.UTF8, - "application/json"); - - var request = new HttpRequestMessage(HttpMethod.Post, requestUri); - request.Content = content; - - request.Headers - .Accept - .Add(new MediaTypeWithQualityHeaderValue("application/json")); - - return client.SendAsync(request); - } - - public static Task PostJsonAsync( - this HttpClient client, - string requestUri, - string json) - { - var content = new StringContent( - json, - Encoding.UTF8, - "application/json"); - - var request = new HttpRequestMessage(HttpMethod.Post, requestUri); - request.Content = content; - - request.Headers - .Accept - .Add(new MediaTypeWithQualityHeaderValue("application/json")); - - return client.SendAsync(request); - } - - public static Task PostJsonApiAsync( - this HttpClient client, - string requestUri, - string json) - { - var content = new StringContent( - json, - Encoding.UTF8, - "application/vnd.api+json"); - - var request = new HttpRequestMessage(HttpMethod.Post, requestUri); - request.Content = content; - - request.Headers - .Accept - .Add(new MediaTypeWithQualityHeaderValue("application/vnd.api+json")); - - return client.SendAsync(request); - } - } -} diff --git a/test/OrchardCore.Tests/Apis/Lucene/LuceneQueryTests.cs b/test/OrchardCore.Tests/Apis/Lucene/LuceneQueryTests.cs index 8b782f82f43..db0bba23e0f 100644 --- a/test/OrchardCore.Tests/Apis/Lucene/LuceneQueryTests.cs +++ b/test/OrchardCore.Tests/Apis/Lucene/LuceneQueryTests.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; From 336b5744581cc7ab0c2b6ed7875e84238c31da76 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 31 Dec 2022 19:32:12 +0300 Subject: [PATCH 15/33] Move TablePrefixGenerator to OC.Testing --- .../Data}/TablePrefixGenerator.cs | 13 +++++++------ .../OrchardCore.Testing/OrchardCore.Testing.csproj | 5 +++++ .../Data}/TablePrefixGeneratorTests.cs | 5 +++-- test/OrchardCore.Tests/Apis/Context/SiteContext.cs | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) rename {test/OrchardCore.Tests/Apis/Context => src/OrchardCore/OrchardCore.Testing/Data}/TablePrefixGenerator.cs (67%) rename test/{OrchardCore.Tests/Apis/Context => OrchardCore.Testing.Tests/Data}/TablePrefixGeneratorTests.cs (91%) diff --git a/test/OrchardCore.Tests/Apis/Context/TablePrefixGenerator.cs b/src/OrchardCore/OrchardCore.Testing/Data/TablePrefixGenerator.cs similarity index 67% rename from test/OrchardCore.Tests/Apis/Context/TablePrefixGenerator.cs rename to src/OrchardCore/OrchardCore.Testing/Data/TablePrefixGenerator.cs index 9f4ab5a6fd5..8a3ffde0180 100644 --- a/test/OrchardCore.Tests/Apis/Context/TablePrefixGenerator.cs +++ b/src/OrchardCore/OrchardCore.Testing/Data/TablePrefixGenerator.cs @@ -1,8 +1,8 @@ -using System; +using System; using System.Text; using System.Threading.Tasks; -namespace OrchardCore.Tests.Apis.Context +namespace OrchardCore.Testing.Data { /// /// This is an internal table prefix generator which uses a timestamp to generate a table prefix @@ -13,9 +13,9 @@ namespace OrchardCore.Tests.Apis.Context /// internal class TablePrefixGenerator { - private static readonly char[] CharList = "abcdefghijklmnopqrstuvwxyz".ToCharArray(); + private static readonly char[] _charList = "abcdefghijklmnopqrstuvwxyz".ToCharArray(); - internal async Task GeneratePrefixAsync() + public async Task GeneratePrefixAsync() { await Task.Delay(1); var ticks = DateTime.Now.Ticks; @@ -23,8 +23,9 @@ internal async Task GeneratePrefixAsync() var result = new StringBuilder(); while (ticks != 0) { - result.Append(CharList[ticks % CharList.Length]); - ticks /= CharList.Length; + result.Append(_charList[ticks % _charList.Length]); + + ticks /= _charList.Length; } return result.ToString(); diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index 13b15b0f7cc..291fe240b3a 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -15,6 +15,11 @@ + + + + + diff --git a/test/OrchardCore.Tests/Apis/Context/TablePrefixGeneratorTests.cs b/test/OrchardCore.Testing.Tests/Data/TablePrefixGeneratorTests.cs similarity index 91% rename from test/OrchardCore.Tests/Apis/Context/TablePrefixGeneratorTests.cs rename to test/OrchardCore.Testing.Tests/Data/TablePrefixGeneratorTests.cs index 37b58629ff7..fe4f2e202a1 100644 --- a/test/OrchardCore.Tests/Apis/Context/TablePrefixGeneratorTests.cs +++ b/test/OrchardCore.Testing.Tests/Data/TablePrefixGeneratorTests.cs @@ -1,8 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; -using Xunit; -namespace OrchardCore.Tests.Apis.Context +namespace OrchardCore.Testing.Data.Tests { public class TablePrefixGeneratorTests { @@ -15,7 +14,9 @@ public async Task TenantPrefixShouldBeUnique() for (var i = 0; i < 200; i++) { var prefix = await tablePrefixGenerator.GeneratePrefixAsync(); + Assert.DoesNotContain(prefix, prefixes); + prefixes.Add(prefix); } } diff --git a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs index cf6348e2b83..450ed423f24 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs @@ -10,10 +10,10 @@ using OrchardCore.BackgroundTasks; using OrchardCore.ContentManagement; using OrchardCore.Environment.Shell; -using OrchardCore.Environment.Shell.Builders; using OrchardCore.Environment.Shell.Scope; using OrchardCore.Recipes.Services; using OrchardCore.Search.Lucene; +using OrchardCore.Testing.Data; namespace OrchardCore.Tests.Apis.Context { From 78bc2b6b7227808eec36c6db38fb4f876cd37c3e Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 31 Dec 2022 19:39:48 +0300 Subject: [PATCH 16/33] Move secutity classes to OC.Testing --- .../PermissionContextAuthorizationHandler.cs | 21 ++----------------- .../Apis/Security/PermissionsContext.cs | 18 ++++++++++++++++ .../OrchardCore.Testing/Stubs/IdentityStub.cs | 13 ++++++++++++ .../Apis/Context/SiteContext.cs | 1 + .../Apis/Context/SiteStartup.cs | 12 +++++------ .../Apis/GraphQL/Blog/BlogPostTests.cs | 1 + .../RequiresPermissionValidationRuleTests.cs | 5 +++-- 7 files changed, 44 insertions(+), 27 deletions(-) rename test/OrchardCore.Tests/Apis/Context/AuthenticationContext.cs => src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionContextAuthorizationHandler.cs (84%) create mode 100644 src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionsContext.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Stubs/IdentityStub.cs diff --git a/test/OrchardCore.Tests/Apis/Context/AuthenticationContext.cs b/src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionContextAuthorizationHandler.cs similarity index 84% rename from test/OrchardCore.Tests/Apis/Context/AuthenticationContext.cs rename to src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionContextAuthorizationHandler.cs index 96705dd44ed..d9bf6400722 100644 --- a/test/OrchardCore.Tests/Apis/Context/AuthenticationContext.cs +++ b/src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionContextAuthorizationHandler.cs @@ -1,16 +1,15 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Security.Principal; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using OrchardCore.Security; using OrchardCore.Security.Permissions; -namespace OrchardCore.Tests.Apis.Context +namespace OrchardCore.Testing.Apis.Security { - internal class PermissionContextAuthorizationHandler : AuthorizationHandler + public class PermissionContextAuthorizationHandler : AuthorizationHandler { private readonly PermissionsContext _permissionsContext; @@ -95,20 +94,4 @@ private void GetGrantingNamesInternal(Permission permission, HashSet sta } } } - - public class PermissionsContext - { - public IEnumerable AuthorizedPermissions { get; set; } = Enumerable.Empty(); - - public bool UsePermissionsContext { get; set; } = false; - } - - internal class StubIdentity : IIdentity - { - public string AuthenticationType => "TEST TEST"; - - public bool IsAuthenticated => true; - - public string Name => "Mr Robot"; - } } diff --git a/src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionsContext.cs b/src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionsContext.cs new file mode 100644 index 00000000000..717f023ef30 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionsContext.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Linq; +using OrchardCore.Security.Permissions; + +namespace OrchardCore.Testing.Apis.Security +{ + public class PermissionsContext + { + public PermissionsContext() + { + AuthorizedPermissions = Enumerable.Empty(); + UsePermissionsContext = false; + } + public IEnumerable AuthorizedPermissions { get; set; } + + public bool UsePermissionsContext { get; set; } + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/IdentityStub.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/IdentityStub.cs new file mode 100644 index 00000000000..e7132acbdc7 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/IdentityStub.cs @@ -0,0 +1,13 @@ +using System.Security.Principal; + +namespace OrchardCore.Testing.Stubs +{ + public class IdentityStub : IIdentity + { + public string AuthenticationType => "Testing"; + + public bool IsAuthenticated => true; + + public string Name => "OrchardCore"; + } +} diff --git a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs index 450ed423f24..63eca38cbc6 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs @@ -13,6 +13,7 @@ using OrchardCore.Environment.Shell.Scope; using OrchardCore.Recipes.Services; using OrchardCore.Search.Lucene; +using OrchardCore.Testing.Apis.Security; using OrchardCore.Testing.Data; namespace OrchardCore.Tests.Apis.Context diff --git a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs index 883088f9ed4..6f1816f1296 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs @@ -11,12 +11,13 @@ using OrchardCore.Modules; using OrchardCore.Modules.Manifest; using OrchardCore.Recipes.Services; +using OrchardCore.Testing.Apis.Security; namespace OrchardCore.Tests.Apis.Context { public class SiteStartup { - public static ConcurrentDictionary PermissionsContexts; + public readonly static ConcurrentDictionary PermissionsContexts; static SiteStartup() { @@ -32,14 +33,13 @@ public void ConfigureServices(IServiceCollection services) .AddTenantFeatures( "OrchardCore.Apis.GraphQL" ) - .ConfigureServices(collection => + .ConfigureServices(serviceCollection => { collection.AddScoped(); - collection.AddScoped(sp => - { - return new PermissionContextAuthorizationHandler(sp.GetRequiredService(), PermissionsContexts); - }); + serviceCollection.AddScoped(sp => new PermissionContextAuthorizationHandler( + sp.GetRequiredService(), + PermissionsContexts)); }) .Configure(appBuilder => appBuilder.UseAuthorization())); diff --git a/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs index e380c168d98..357c223f231 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs @@ -4,6 +4,7 @@ using OrchardCore.ContentFields.Fields; using OrchardCore.ContentManagement; using OrchardCore.Lists.Models; +using OrchardCore.Testing.Apis.Security; using OrchardCore.Tests.Apis.Context; using Xunit; using GraphQLApi = OrchardCore.Apis.GraphQL; diff --git a/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs index a986f9392d3..20558094a22 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs @@ -13,7 +13,8 @@ using OrchardCore.Apis.GraphQL; using OrchardCore.Apis.GraphQL.ValidationRules; using OrchardCore.Security.Permissions; -using OrchardCore.Tests.Apis.Context; +using OrchardCore.Testing.Apis.Security; +using OrchardCore.Testing.Stubs; using Xunit; namespace OrchardCore.Tests.Apis.GraphQL.ValidationRules @@ -131,7 +132,7 @@ private ExecutionOptions BuildExecutionOptions(string query, PermissionsContext Schema = new ValidationSchema(), UserContext = new GraphQLUserContext { - User = new ClaimsPrincipal(new StubIdentity()) + User = new ClaimsPrincipal(new IdentityStub()) }, ValidationRules = DocumentValidator.CoreRules.Concat(serviceProvider.GetServices()) }; From 116e7dfe16c02823553bb9d2b18a51cb86af80ad Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 31 Dec 2022 19:41:02 +0300 Subject: [PATCH 17/33] Move TestRecipeHarvester to OC.Testing --- .../Recipes/IRecipeFileProvider.cs | 11 +++++ .../Recipes/TestRecipeHarvester.cs | 40 +++++++++++++++++++ .../Apis/Context/RecipeFileProvider.cs | 16 ++++++++ .../Apis/Context/SiteStartup.cs | 4 +- 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/Recipes/IRecipeFileProvider.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Recipes/TestRecipeHarvester.cs create mode 100644 test/OrchardCore.Tests/Apis/Context/RecipeFileProvider.cs diff --git a/src/OrchardCore/OrchardCore.Testing/Recipes/IRecipeFileProvider.cs b/src/OrchardCore/OrchardCore.Testing/Recipes/IRecipeFileProvider.cs new file mode 100644 index 00000000000..a44ade34d1d --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Recipes/IRecipeFileProvider.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Microsoft.Extensions.FileProviders; + +namespace OrchardCore.Testing.Recipes; + +public interface IRecipeFileProvider +{ + IFileProvider FileProvider { get; } + + IEnumerable GetRecipes(); +} diff --git a/src/OrchardCore/OrchardCore.Testing/Recipes/TestRecipeHarvester.cs b/src/OrchardCore/OrchardCore.Testing/Recipes/TestRecipeHarvester.cs new file mode 100644 index 00000000000..7070b9479e6 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Recipes/TestRecipeHarvester.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using OrchardCore.Recipes.Models; +using OrchardCore.Recipes.Services; + +namespace OrchardCore.Testing.Recipes +{ + public class TestRecipeHarvester : IRecipeHarvester + { + private readonly IRecipeFileProvider _recipeFileProvider; + private readonly IRecipeReader _recipeReader; + + public TestRecipeHarvester(IRecipeFileProvider recipeFileProvider, IRecipeReader recipeReader) + { + _recipeFileProvider = recipeFileProvider; + _recipeReader = recipeReader; + } + + public async Task> HarvestRecipesAsync() + { + var recipeFiles = _recipeFileProvider.GetRecipes(); + + var recipeDescriptors = new List(); + foreach (var recipeFile in recipeFiles) + { + if (recipeFile.Exists) + { + var recipeDescriptor = await _recipeReader.GetRecipeDescriptor( + recipeFile.PhysicalPath, + recipeFile, + _recipeFileProvider.FileProvider); + + recipeDescriptors.Add(recipeDescriptor); + } + } + + return recipeDescriptors; + } + } +} diff --git a/test/OrchardCore.Tests/Apis/Context/RecipeFileProvider.cs b/test/OrchardCore.Tests/Apis/Context/RecipeFileProvider.cs new file mode 100644 index 00000000000..608026af80f --- /dev/null +++ b/test/OrchardCore.Tests/Apis/Context/RecipeFileProvider.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Microsoft.Extensions.FileProviders; +using System.Reflection; +using OrchardCore.Testing.Recipes; + +namespace OrchardCore.Tests.Apis.Context; + +public class RecipeFileProvider : IRecipeFileProvider +{ + public IFileProvider FileProvider => new EmbeddedFileProvider(GetType().GetTypeInfo().Assembly); + + public IEnumerable GetRecipes() + { + yield return FileProvider.GetFileInfo("Apis/Lucene/Recipes/luceneQueryTest.json"); + } +} diff --git a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs index 6f1816f1296..1078fc6d7ce 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs @@ -12,6 +12,7 @@ using OrchardCore.Modules.Manifest; using OrchardCore.Recipes.Services; using OrchardCore.Testing.Apis.Security; +using OrchardCore.Testing.Recipes; namespace OrchardCore.Tests.Apis.Context { @@ -35,7 +36,8 @@ public void ConfigureServices(IServiceCollection services) ) .ConfigureServices(serviceCollection => { - collection.AddScoped(); + serviceCollection.AddScoped(); + serviceCollection.AddScoped(); serviceCollection.AddScoped(sp => new PermissionContextAuthorizationHandler( sp.GetRequiredService(), From 12872ad2dba6f43e5a39007a6c5d2d178713dba0 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 31 Dec 2022 19:50:30 +0300 Subject: [PATCH 18/33] Split SiteContextExtensions into another file --- .../Extensions/SiteContextExtensions.cs | 55 +++++++++++++++++++ .../Apis/Context/SiteContext.cs | 27 --------- 2 files changed, 55 insertions(+), 27 deletions(-) create mode 100644 test/OrchardCore.Tests/Apis/Context/Extensions/SiteContextExtensions.cs diff --git a/test/OrchardCore.Tests/Apis/Context/Extensions/SiteContextExtensions.cs b/test/OrchardCore.Tests/Apis/Context/Extensions/SiteContextExtensions.cs new file mode 100644 index 00000000000..749b30251ad --- /dev/null +++ b/test/OrchardCore.Tests/Apis/Context/Extensions/SiteContextExtensions.cs @@ -0,0 +1,55 @@ +using System; +using OrchardCore.Testing.Apis.Security; + +namespace OrchardCore.Tests.Apis.Context +{ + public static class SiteContextExtensions + { + public static SiteContext WithDatabaseProvider(this SiteContext siteContext, string databaseProvider) + { + if (String.IsNullOrEmpty(databaseProvider)) + { + throw new ArgumentException($"'{nameof(databaseProvider)}' cannot be null or empty.", nameof(databaseProvider)); + } + + siteContext.DatabaseProvider = databaseProvider; + + return siteContext; + } + + public static SiteContext WithConnectionString(this SiteContext siteContext, string connectionString) + { + if (String.IsNullOrEmpty(connectionString)) + { + throw new ArgumentException($"'{nameof(connectionString)}' cannot be null or empty.", nameof(connectionString)); + } + + siteContext.ConnectionString = connectionString; + return siteContext; + } + + public static SiteContext WithPermissionsContext(this SiteContext siteContext, PermissionsContext permissionsContext) + { + if (permissionsContext is null) + { + throw new ArgumentNullException(nameof(permissionsContext)); + } + + siteContext.PermissionsContext = permissionsContext; + + return siteContext; + } + + public static SiteContext WithRecipe(this SiteContext siteContext, string recipeName) + { + if (String.IsNullOrEmpty(recipeName)) + { + throw new ArgumentException($"'{nameof(recipeName)}' cannot be null or empty.", nameof(recipeName)); + } + + siteContext.RecipeName = recipeName; + + return siteContext; + } + } +} diff --git a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs index 63eca38cbc6..7210b7aafc0 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs @@ -173,31 +173,4 @@ public void Dispose() Client?.Dispose(); } } - - public static class SiteContextExtensions - { - public static T WithDatabaseProvider(this T siteContext, string databaseProvider) where T : SiteContext - { - siteContext.DatabaseProvider = databaseProvider; - return siteContext; - } - - public static T WithConnectionString(this T siteContext, string connectionString) where T : SiteContext - { - siteContext.ConnectionString = connectionString; - return siteContext; - } - - public static T WithPermissionsContext(this T siteContext, PermissionsContext permissionsContext) where T : SiteContext - { - siteContext.PermissionsContext = permissionsContext; - return siteContext; - } - - public static T WithRecipe(this T siteContext, string recipeName) where T : SiteContext - { - siteContext.RecipeName = recipeName; - return siteContext; - } - } } From 7ce18aaa5dd53d2f19344b8ec16aa7baf7f636db Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 31 Dec 2022 19:58:39 +0300 Subject: [PATCH 19/33] Remove unnecessary TestRecipeHarvester --- .../Apis/Context/TestRecipeHarvester.cs | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 test/OrchardCore.Tests/Apis/Context/TestRecipeHarvester.cs diff --git a/test/OrchardCore.Tests/Apis/Context/TestRecipeHarvester.cs b/test/OrchardCore.Tests/Apis/Context/TestRecipeHarvester.cs deleted file mode 100644 index b3cf3de5209..00000000000 --- a/test/OrchardCore.Tests/Apis/Context/TestRecipeHarvester.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.Extensions.FileProviders; -using OrchardCore.Recipes.Models; -using OrchardCore.Recipes.Services; -using Xunit; - -namespace OrchardCore.Tests.Apis.Context -{ - public class TestRecipeHarvester : IRecipeHarvester - { - private readonly IRecipeReader _recipeReader; - - public TestRecipeHarvester(IRecipeReader recipeReader) - { - _recipeReader = recipeReader; - } - - public Task> HarvestRecipesAsync() - => HarvestRecipesAsync(new[] - { - "Apis/Lucene/Recipes/luceneQueryTest.json" - }); - - private async Task> HarvestRecipesAsync(string[] paths) - { - var recipeDescriptors = new List(); - var testAssemblyFileProvider = new EmbeddedFileProvider(GetType().GetTypeInfo().Assembly); - var fileInfos = new List(); - - foreach (var path in paths) - { - // EmbeddedFileProvider doesn't list directory contents. - var fileInfo = testAssemblyFileProvider.GetFileInfo(path); - Assert.True(fileInfo.Exists); - fileInfos.Add(fileInfo); - } - - foreach (var fileInfo in fileInfos) - { - var descriptor = await _recipeReader.GetRecipeDescriptor(fileInfo.PhysicalPath, fileInfo, testAssemblyFileProvider); - recipeDescriptors.Add(descriptor); - } - - return recipeDescriptors; - } - } -} From fee6883c47d68b8cad3ebb1c546b27fa194d65ce Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 31 Dec 2022 20:24:15 +0300 Subject: [PATCH 20/33] Move OrchardCoreTestFixture into OC.Testing --- .../OrchardCore.Cms.Web.csproj | 4 --- src/OrchardCore.Cms.Web/Program.cs | 5 +++ .../Infrastructure/OrchardCoreTestFixture.cs | 29 +++++++++++++++ .../OrchardCore.Testing.csproj | 1 + .../Apis/Context/MvcTestFixture.cs | 36 ------------------- .../Apis/Context/SiteContext.cs | 5 +-- 6 files changed, 38 insertions(+), 42 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/Infrastructure/OrchardCoreTestFixture.cs delete mode 100644 test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs diff --git a/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj b/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj index 62a73532bfc..1565d29d7c6 100644 --- a/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj +++ b/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj @@ -14,10 +14,6 @@ enable enable - - - - diff --git a/src/OrchardCore.Cms.Web/Program.cs b/src/OrchardCore.Cms.Web/Program.cs index 4b4d39392bd..e864d456dca 100644 --- a/src/OrchardCore.Cms.Web/Program.cs +++ b/src/OrchardCore.Cms.Web/Program.cs @@ -20,3 +20,8 @@ app.UseOrchardCore(); app.Run(); + +public partial class Program +{ + +} diff --git a/src/OrchardCore/OrchardCore.Testing/Infrastructure/OrchardCoreTestFixture.cs b/src/OrchardCore/OrchardCore.Testing/Infrastructure/OrchardCoreTestFixture.cs new file mode 100644 index 00000000000..4fc792bf558 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Infrastructure/OrchardCoreTestFixture.cs @@ -0,0 +1,29 @@ +using System; +using System.IO; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.Hosting; + +namespace OrchardCore.Testing.Infrastructure; + +public class OrchardCoreTestFixture : WebApplicationFactory where TStartup : class +{ + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + var shellsApplicationDataPath = Path.Combine(Directory.GetCurrentDirectory(), "App_Data"); + + if (Directory.Exists(shellsApplicationDataPath)) + { + Directory.Delete(shellsApplicationDataPath, true); + } + + builder.UseContentRoot(Directory.GetCurrentDirectory()); + } + + protected override IWebHostBuilder CreateWebHostBuilder() + => WebHostBuilderFactory.CreateFromAssemblyEntryPoint(typeof(Program).Assembly, Array.Empty()); + + protected override IHostBuilder CreateHostBuilder() + => Host.CreateDefaultBuilder().ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); +} diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index 291fe240b3a..91f7d60c4f6 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -27,6 +27,7 @@ + diff --git a/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs b/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs deleted file mode 100644 index 3148fd5a91f..00000000000 --- a/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.IO; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.Hosting; - -namespace OrchardCore.Tests.Apis.Context -{ - public class OrchardTestFixture : WebApplicationFactory - where TStartup : class - { - protected override void ConfigureWebHost(IWebHostBuilder builder) - { - var shellsApplicationDataPath = Path.Combine(Directory.GetCurrentDirectory(), "App_Data"); - - if (Directory.Exists(shellsApplicationDataPath)) - { - Directory.Delete(shellsApplicationDataPath, true); - } - - builder.UseContentRoot(Directory.GetCurrentDirectory()); - } - - protected override IWebHostBuilder CreateWebHostBuilder() - { - return WebHostBuilderFactory.CreateFromAssemblyEntryPoint( - typeof(Program).Assembly, Array.Empty()); - } - - protected override IHostBuilder CreateHostBuilder() - => Host.CreateDefaultBuilder() - .ConfigureWebHostDefaults(webBuilder => - webBuilder.UseStartup()); - } -} diff --git a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs index 7210b7aafc0..617bcdf643b 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs @@ -15,13 +15,14 @@ using OrchardCore.Search.Lucene; using OrchardCore.Testing.Apis.Security; using OrchardCore.Testing.Data; +using OrchardCore.Testing.Infrastructure; namespace OrchardCore.Tests.Apis.Context { public class SiteContext : IDisposable { private static readonly TablePrefixGenerator TablePrefixGenerator = new TablePrefixGenerator(); - public static OrchardTestFixture Site { get; } + public static OrchardCoreTestFixture Site { get; } public static IShellHost ShellHost { get; private set; } public static IHttpContextAccessor HttpContextAccessor { get; } public static HttpClient DefaultTenantClient { get; } @@ -37,7 +38,7 @@ public class SiteContext : IDisposable static SiteContext() { - Site = new OrchardTestFixture(); + Site = new OrchardCoreTestFixture(); ShellHost = Site.Services.GetRequiredService(); HttpContextAccessor = Site.Services.GetRequiredService(); DefaultTenantClient = Site.CreateDefaultClient(); From b07c23c44969f05990748feeb14259c03e97f745 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 31 Dec 2022 20:50:49 +0300 Subject: [PATCH 21/33] Move ModuleNameProvider into OC.Testing --- .../ModuleNamesProvider.cs | 24 +++++++++++++++++ .../Apis/Context/SiteStartup.cs | 26 ++----------------- 2 files changed, 26 insertions(+), 24 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/ModuleNamesProvider.cs diff --git a/src/OrchardCore/OrchardCore.Testing/ModuleNamesProvider.cs b/src/OrchardCore/OrchardCore.Testing/ModuleNamesProvider.cs new file mode 100644 index 00000000000..b9e568ab17f --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/ModuleNamesProvider.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using OrchardCore.Modules; +using OrchardCore.Modules.Manifest; + +namespace OrchardCore.Testing +{ + public class ModuleNamesProvider : IModuleNamesProvider + { + private readonly IEnumerable _moduleNames; + + public ModuleNamesProvider() + { + var assembly = Assembly.Load(new AssemblyName(typeof(Program).Assembly.GetName().Name)); + + _moduleNames = assembly + .GetCustomAttributes() + .Select(m => m.Name); + } + + public IEnumerable GetModuleNames() => _moduleNames; + } +} diff --git a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs index 1078fc6d7ce..a7e728dc8c5 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs @@ -1,7 +1,4 @@ using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; @@ -9,8 +6,8 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using OrchardCore.Modules; -using OrchardCore.Modules.Manifest; using OrchardCore.Recipes.Services; +using OrchardCore.Testing; using OrchardCore.Testing.Apis.Security; using OrchardCore.Testing.Recipes; @@ -48,25 +45,6 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); } - public void Configure(IApplicationBuilder app, IHostEnvironment env, ILoggerFactory loggerFactory) - { - app.UseOrchardCore(); - } - - private class ModuleNamesProvider : IModuleNamesProvider - { - private readonly string[] _moduleNames; - - public ModuleNamesProvider() - { - var assembly = Assembly.Load(new AssemblyName(typeof(Program).Assembly.GetName().Name)); - _moduleNames = assembly.GetCustomAttributes().Select(m => m.Name).ToArray(); - } - - public IEnumerable GetModuleNames() - { - return _moduleNames; - } - } + public void Configure(IApplicationBuilder app, IHostEnvironment env, ILoggerFactory loggerFactory) => app.UseOrchardCore(); } } From ead2bbf31a87ab61401185f5c1d804ab97aebdee Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sun, 1 Jan 2023 01:41:28 +0300 Subject: [PATCH 22/33] Refactoring --- .../Apis}/Extensions/SiteContextExtensions.cs | 19 +-- .../OrchardCore.Testing/Apis/ISiteContext.cs | 27 ++++ .../Apis/ISiteContextOfT.cs | 9 ++ .../PermissionContextAuthorizationHandler.cs | 2 +- .../Apis/SiteContextBase.cs | 146 ++++++++++++++++++ .../Apis/SiteContextOptions.cs | 24 +++ .../OrchardCore.Testing.csproj | 1 + .../BlogPostApiControllerTests.cs | 14 +- .../BlogPostContentStepIdempotentTests.cs | 9 +- .../BlogPostCreateDeploymentPlanTests.cs | 21 ++- .../BlogPostUpdateDeploymentPlanTests.cs | 13 +- .../Apis/Context/AgencyContext.cs | 2 + .../Apis/Context/BlogPostDeploymentContext.cs | 5 +- .../Apis/Context/SiteContext.cs | 135 ++-------------- .../Apis/Context/SiteStartup.cs | 25 +-- .../Apis/GraphQL/Blog/BlogPostTests.cs | 1 + .../Apis/Lucene/LuceneContext.cs | 5 +- 17 files changed, 288 insertions(+), 170 deletions(-) rename {test/OrchardCore.Tests/Apis/Context => src/OrchardCore/OrchardCore.Testing/Apis}/Extensions/SiteContextExtensions.cs (59%) create mode 100644 src/OrchardCore/OrchardCore.Testing/Apis/ISiteContext.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Apis/ISiteContextOfT.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Apis/SiteContextBase.cs create mode 100644 src/OrchardCore/OrchardCore.Testing/Apis/SiteContextOptions.cs diff --git a/test/OrchardCore.Tests/Apis/Context/Extensions/SiteContextExtensions.cs b/src/OrchardCore/OrchardCore.Testing/Apis/Extensions/SiteContextExtensions.cs similarity index 59% rename from test/OrchardCore.Tests/Apis/Context/Extensions/SiteContextExtensions.cs rename to src/OrchardCore/OrchardCore.Testing/Apis/Extensions/SiteContextExtensions.cs index 749b30251ad..205231ee0e4 100644 --- a/test/OrchardCore.Tests/Apis/Context/Extensions/SiteContextExtensions.cs +++ b/src/OrchardCore/OrchardCore.Testing/Apis/Extensions/SiteContextExtensions.cs @@ -1,53 +1,54 @@ using System; using OrchardCore.Testing.Apis.Security; -namespace OrchardCore.Tests.Apis.Context +namespace OrchardCore.Testing.Apis { public static class SiteContextExtensions { - public static SiteContext WithDatabaseProvider(this SiteContext siteContext, string databaseProvider) + public static ISiteContext WithDatabaseProvider(this ISiteContext siteContext, string databaseProvider) { if (String.IsNullOrEmpty(databaseProvider)) { throw new ArgumentException($"'{nameof(databaseProvider)}' cannot be null or empty.", nameof(databaseProvider)); } - siteContext.DatabaseProvider = databaseProvider; + siteContext.Options.DatabaseProvider = databaseProvider; return siteContext; } - public static SiteContext WithConnectionString(this SiteContext siteContext, string connectionString) + public static ISiteContext WithConnectionString(this ISiteContext siteContext, string connectionString) { if (String.IsNullOrEmpty(connectionString)) { throw new ArgumentException($"'{nameof(connectionString)}' cannot be null or empty.", nameof(connectionString)); } - siteContext.ConnectionString = connectionString; + siteContext.Options.ConnectionString = connectionString; + return siteContext; } - public static SiteContext WithPermissionsContext(this SiteContext siteContext, PermissionsContext permissionsContext) + public static ISiteContext WithPermissionsContext(this ISiteContext siteContext, PermissionsContext permissionsContext) { if (permissionsContext is null) { throw new ArgumentNullException(nameof(permissionsContext)); } - siteContext.PermissionsContext = permissionsContext; + siteContext.Options.PermissionsContext = permissionsContext; return siteContext; } - public static SiteContext WithRecipe(this SiteContext siteContext, string recipeName) + public static ISiteContext WithRecipe(this ISiteContext siteContext, string recipeName) { if (String.IsNullOrEmpty(recipeName)) { throw new ArgumentException($"'{nameof(recipeName)}' cannot be null or empty.", nameof(recipeName)); } - siteContext.RecipeName = recipeName; + siteContext.Options.RecipeName = recipeName; return siteContext; } diff --git a/src/OrchardCore/OrchardCore.Testing/Apis/ISiteContext.cs b/src/OrchardCore/OrchardCore.Testing/Apis/ISiteContext.cs new file mode 100644 index 00000000000..53e22f3b4b1 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Apis/ISiteContext.cs @@ -0,0 +1,27 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using OrchardCore.Apis.GraphQL.Client; +using OrchardCore.Environment.Shell; + +namespace OrchardCore.Testing.Apis +{ + public interface ISiteContext : IDisposable + { + static IShellHost ShellHost { get; } + + static HttpClient DefaultTenantClient { get; } + + SiteContextOptions Options { init; get; } + + HttpClient Client { get; } + + string TenantName { get; } + + OrchardGraphQLClient GraphQLClient { get; } + + Task InitializeAsync(); + + Task RunRecipeAsync(string recipeName, string recipePath); + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/Apis/ISiteContextOfT.cs b/src/OrchardCore/OrchardCore.Testing/Apis/ISiteContextOfT.cs new file mode 100644 index 00000000000..7b2f60caddc --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Apis/ISiteContextOfT.cs @@ -0,0 +1,9 @@ +using OrchardCore.Testing.Infrastructure; + +namespace OrchardCore.Testing.Apis +{ + public interface ISiteContext : ISiteContext where TSiteStartup : class + { + static OrchardCoreTestFixture Site { get; } + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionContextAuthorizationHandler.cs b/src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionContextAuthorizationHandler.cs index d9bf6400722..f75b88ef187 100644 --- a/src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionContextAuthorizationHandler.cs +++ b/src/OrchardCore/OrchardCore.Testing/Apis/Security/PermissionContextAuthorizationHandler.cs @@ -32,7 +32,7 @@ public PermissionContextAuthorizationHandler(IHttpContextAccessor httpContextAcc } } - // Used for static graphql test; passes a permissionsContext directly + // Used for static graphql test; passes a permissions Context directly public PermissionContextAuthorizationHandler(PermissionsContext permissionsContext) { _permissionsContext = permissionsContext; diff --git a/src/OrchardCore/OrchardCore.Testing/Apis/SiteContextBase.cs b/src/OrchardCore/OrchardCore.Testing/Apis/SiteContextBase.cs new file mode 100644 index 00000000000..c6749dcd8a7 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Apis/SiteContextBase.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using OrchardCore.Apis.GraphQL.Client; +using OrchardCore.Environment.Shell; +using OrchardCore.Recipes.Services; +using OrchardCore.Tenants.ViewModels; +using OrchardCore.Testing.Data; +using OrchardCore.Testing.Infrastructure; + +namespace OrchardCore.Testing.Apis +{ + public abstract class SiteContextBase : ISiteContext where TSiteStartup : class + { + static SiteContextBase() + { + Site = new OrchardCoreTestFixture(); + ShellHost = Site.Services.GetRequiredService(); + DefaultTenantClient = Site.CreateDefaultClient(); + } + + public SiteContextBase() + { + Options = new SiteContextOptions(); + } + + public static OrchardCoreTestFixture Site { get; } + + public static IShellHost ShellHost { get; private set; } + + public static HttpClient DefaultTenantClient { get; } + + public SiteContextOptions Options { init; get; } + + public HttpClient Client { get; private set; } + + public string TenantName { get; private set; } + + public OrchardGraphQLClient GraphQLClient { get; protected set; } + + public virtual async Task InitializeAsync() + { + var tenantName = Guid.NewGuid().ToString("n"); + + if (String.IsNullOrEmpty(Options.TablePrefix)) + { + Options.TablePrefix = await new TablePrefixGenerator().GeneratePrefixAsync(); + } + + var createResult = await CreateSiteAsync(tenantName); + + var content = await createResult.Content.ReadAsStringAsync(); + + await SetupSiteAsync(tenantName); + + lock (Site) + { + var url = new Uri(content.Trim('"')); + url = new Uri(url.Scheme + "://" + url.Authority + url.LocalPath + "/"); + + Client = Site.CreateDefaultClient(url); + + TenantName = tenantName; + } + + if (Options.PermissionsContext != null) + { + var permissionContextKey = Guid.NewGuid().ToString(); + + SiteContextOptions.PermissionsContexts.TryAdd(permissionContextKey, Options.PermissionsContext); + + Client.DefaultRequestHeaders.Add("PermissionsContext", permissionContextKey); + } + + GraphQLClient = new OrchardGraphQLClient(Client); + } + + public async Task RunRecipeAsync(string recipeName, string recipePath) + { + var shellScope = await ShellHost.GetScopeAsync(TenantName); + + await shellScope.UsingServiceScopeAsync(async scope => + { + var shellFeaturesManager = scope.ServiceProvider.GetRequiredService(); + var recipeHarvesters = scope.ServiceProvider.GetRequiredService>(); + var recipeExecutor = scope.ServiceProvider.GetRequiredService(); + + var recipeCollections = await Task.WhenAll(recipeHarvesters + .Select(recipe => recipe.HarvestRecipesAsync())); + + var recipe = recipeCollections + .SelectMany(r => r) + .FirstOrDefault(d => d.RecipeFileInfo.Name == recipeName && d.BasePath == recipePath); + + var executionId = Guid.NewGuid().ToString("n"); + + await recipeExecutor.ExecuteAsync(executionId, recipe, new Dictionary(), CancellationToken.None); + }); + } + + public void Dispose() => Client?.Dispose(); + + private async Task CreateSiteAsync(string tenantName) + { + var createModel = new CreateApiViewModel + { + DatabaseProvider = Options.DatabaseProvider, + TablePrefix = Options.TablePrefix, + ConnectionString = Options.ConnectionString, + RecipeName = Options.RecipeName, + Name = tenantName, + RequestUrlPrefix = tenantName + }; + + var result = await DefaultTenantClient.PostAsJsonAsync("api/tenants/create", createModel); + + result.EnsureSuccessStatusCode(); + + return result; + } + + private async Task SetupSiteAsync(string tenantName) + { + var setupModel = new SetupApiViewModel + { + SiteName = "Orchard Core Site", + DatabaseProvider = Options.DatabaseProvider, + TablePrefix = Options.TablePrefix, + ConnectionString = Options.ConnectionString, + RecipeName = Options.RecipeName, + UserName = "admin", + Password = "P@ssw0rd", + Name = tenantName, + Email = "admin@OrchardCore.net" + }; + + var result = await DefaultTenantClient.PostAsJsonAsync("api/tenants/setup", setupModel); + + result.EnsureSuccessStatusCode(); + } + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/Apis/SiteContextOptions.cs b/src/OrchardCore/OrchardCore.Testing/Apis/SiteContextOptions.cs new file mode 100644 index 00000000000..1644031b9ac --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Apis/SiteContextOptions.cs @@ -0,0 +1,24 @@ +using System.Collections.Concurrent; +using OrchardCore.Testing.Apis.Security; + +namespace OrchardCore.Testing.Apis; + +public class SiteContextOptions +{ + static SiteContextOptions() + { + PermissionsContexts = new(); + } + + public static ConcurrentDictionary PermissionsContexts { get; set; } + + public string RecipeName { get; set; } = "Blog"; + + public string DatabaseProvider { get; set; } = "Sqlite"; + + public string ConnectionString { get; set; } + + public string TablePrefix { get; set; } + + public PermissionsContext PermissionsContext { get; set; } +} diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index 91f7d60c4f6..2bf277eda44 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -29,6 +29,7 @@ + diff --git a/test/OrchardCore.Tests/Apis/ContentManagement/ContentApiController/BlogPostApiControllerTests.cs b/test/OrchardCore.Tests/Apis/ContentManagement/ContentApiController/BlogPostApiControllerTests.cs index ae3a386edcd..3499db0be39 100644 --- a/test/OrchardCore.Tests/Apis/ContentManagement/ContentApiController/BlogPostApiControllerTests.cs +++ b/test/OrchardCore.Tests/Apis/ContentManagement/ContentApiController/BlogPostApiControllerTests.cs @@ -10,6 +10,7 @@ using OrchardCore.Autoroute.Models; using OrchardCore.ContentManagement; using OrchardCore.ContentManagement.Records; +using OrchardCore.Environment.Shell; using OrchardCore.Lists.Models; using OrchardCore.Taxonomies.Fields; using OrchardCore.Tests.Apis.Context; @@ -75,12 +76,13 @@ public async Task ShouldOnlyCreateTwoContentItemRecordsForExistingContentItem() await context.Client.PostAsJsonAsync("api/content", context.BlogPost); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostApiControllerContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPosts = await session.Query(x => x.ContentType == "BlogPost").ListAsync(); - Assert.Equal(2, blogPosts.Count()); }); } @@ -253,7 +255,9 @@ public async Task ShouldFailValidationWhenAutoroutePathIsNotUnique() Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); Assert.Contains("Your permalink is already in use.", problemDetails.Detail); - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostApiControllerContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingServiceScopeAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPosts = await session.Query(x => @@ -313,7 +317,9 @@ public async Task ShouldGenerateUniqueAutoroutePath() publishedContentItem.ContentItemId }; - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostApiControllerContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingServiceScopeAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var newAutoroutePartIndex = await session diff --git a/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostContentStepIdempotentTests.cs b/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostContentStepIdempotentTests.cs index d77cac07777..f4eeb7eb884 100644 --- a/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostContentStepIdempotentTests.cs +++ b/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostContentStepIdempotentTests.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using OrchardCore.ContentManagement; using OrchardCore.ContentManagement.Records; +using OrchardCore.Environment.Shell; using OrchardCore.Tests.Apis.Context; using Xunit; using YesSql; @@ -31,7 +32,9 @@ public async Task ShouldProduceSameOutcomeForNewContentOnMultipleExecutions() await context.PostRecipeAsync(recipe); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostDeploymentContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPosts = await session.Query(x => @@ -71,7 +74,9 @@ public async Task ShouldProduceSameOutcomeForExistingContentItemVersionOnMultipl await context.PostRecipeAsync(recipe); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostDeploymentContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPosts = await session.Query(x => diff --git a/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostCreateDeploymentPlanTests.cs b/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostCreateDeploymentPlanTests.cs index 86e3acaaaa4..316bf47705d 100644 --- a/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostCreateDeploymentPlanTests.cs +++ b/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostCreateDeploymentPlanTests.cs @@ -6,6 +6,7 @@ using OrchardCore.Autoroute.Models; using OrchardCore.ContentManagement; using OrchardCore.ContentManagement.Records; +using OrchardCore.Environment.Shell; using OrchardCore.Tests.Apis.Context; using Xunit; using YesSql; @@ -32,7 +33,9 @@ public async Task ShouldCreateNewPublishedContentItemVersion() await context.PostRecipeAsync(recipe); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostDeploymentContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPosts = await session.Query(x => @@ -73,7 +76,9 @@ public async Task ShouldDiscardDraftThenCreateNewPublishedContentItemVersion() await context.PostRecipeAsync(recipe); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostDeploymentContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPosts = await session.Query(x => @@ -118,7 +123,9 @@ public async Task ShouldDiscardDraftThenCreateNewDraftContentItemVersion() await context.PostRecipeAsync(recipe); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostDeploymentContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPosts = await session.Query(x => @@ -162,7 +169,9 @@ public async Task ShouldCreateNewPublishedContentItem() await context.PostRecipeAsync(recipe); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostDeploymentContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPostsCount = await session.Query(x => @@ -207,7 +216,9 @@ public async Task ShouldIgnoreDuplicateContentItems() await context.PostRecipeAsync(firstRecipe); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostDeploymentContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPostsCount = await session.Query(x => diff --git a/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostUpdateDeploymentPlanTests.cs b/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostUpdateDeploymentPlanTests.cs index 986aa44ab8c..8e89d96f517 100644 --- a/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostUpdateDeploymentPlanTests.cs +++ b/test/OrchardCore.Tests/Apis/ContentManagement/DeploymentPlans/BlogPostUpdateDeploymentPlanTests.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using OrchardCore.ContentManagement; using OrchardCore.ContentManagement.Records; +using OrchardCore.Environment.Shell; using OrchardCore.Tests.Apis.Context; using Xunit; using YesSql; @@ -29,7 +30,9 @@ public async Task ShouldUpdateExistingContentItemVersion() await context.PostRecipeAsync(recipe); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostDeploymentContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingServiceScopeAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPosts = await session.Query(x => @@ -62,7 +65,9 @@ public async Task ShouldDiscardDraftThenUpdateExistingContentItemVersion() await context.PostRecipeAsync(recipe); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostDeploymentContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingServiceScopeAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPosts = await session.Query(x => @@ -103,7 +108,9 @@ public async Task ShouldUpdateDraftThenPublishExistingContentItemVersion() await context.PostRecipeAsync(recipe); // Test - await context.UsingTenantScopeAsync(async scope => + var shellScope = await BlogPostDeploymentContext.ShellHost.GetScopeAsync(context.TenantName); + + await shellScope.UsingAsync(async scope => { var session = scope.ServiceProvider.GetRequiredService(); var blogPosts = await session.Query(x => diff --git a/test/OrchardCore.Tests/Apis/Context/AgencyContext.cs b/test/OrchardCore.Tests/Apis/Context/AgencyContext.cs index e0bf460b3f8..726bf47eab9 100644 --- a/test/OrchardCore.Tests/Apis/Context/AgencyContext.cs +++ b/test/OrchardCore.Tests/Apis/Context/AgencyContext.cs @@ -1,3 +1,5 @@ +using OrchardCore.Testing.Apis; + namespace OrchardCore.Tests.Apis.Context { public class AgencyContext : SiteContext diff --git a/test/OrchardCore.Tests/Apis/Context/BlogPostDeploymentContext.cs b/test/OrchardCore.Tests/Apis/Context/BlogPostDeploymentContext.cs index c300e45bc21..a7227fc1879 100644 --- a/test/OrchardCore.Tests/Apis/Context/BlogPostDeploymentContext.cs +++ b/test/OrchardCore.Tests/Apis/Context/BlogPostDeploymentContext.cs @@ -9,6 +9,7 @@ using OrchardCore.ContentManagement; using OrchardCore.Deployment.Remote.Services; using OrchardCore.Deployment.Remote.ViewModels; +using OrchardCore.Environment.Shell; namespace OrchardCore.Tests.Apis.Context { @@ -43,7 +44,9 @@ public override async Task InitializeAsync() OriginalBlogPost = await content.Content.ReadAsAsync(); OriginalBlogPostVersionId = OriginalBlogPost.ContentItemVersionId; - await UsingTenantScopeAsync(async scope => + var shellScope = await ShellHost.GetScopeAsync(TenantName); + + await shellScope.UsingAsync(async scope => { var remoteClientService = scope.ServiceProvider.GetRequiredService(); diff --git a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs index 617bcdf643b..a71d6d2caff 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs @@ -1,140 +1,35 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Net.Http; -using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using OrchardCore.Apis.GraphQL.Client; -using OrchardCore.BackgroundTasks; using OrchardCore.ContentManagement; using OrchardCore.Environment.Shell; -using OrchardCore.Environment.Shell.Scope; -using OrchardCore.Recipes.Services; using OrchardCore.Search.Lucene; -using OrchardCore.Testing.Apis.Security; -using OrchardCore.Testing.Data; -using OrchardCore.Testing.Infrastructure; +using OrchardCore.Testing.Apis; namespace OrchardCore.Tests.Apis.Context { - public class SiteContext : IDisposable + public class SiteContext : SiteContextBase { - private static readonly TablePrefixGenerator TablePrefixGenerator = new TablePrefixGenerator(); - public static OrchardCoreTestFixture Site { get; } - public static IShellHost ShellHost { get; private set; } - public static IHttpContextAccessor HttpContextAccessor { get; } - public static HttpClient DefaultTenantClient { get; } - - public string RecipeName { get; set; } = "Blog"; - public string DatabaseProvider { get; set; } = "Sqlite"; - public string ConnectionString { get; set; } - public PermissionsContext PermissionsContext { get; set; } - - public HttpClient Client { get; private set; } - public string TenantName { get; private set; } - public OrchardGraphQLClient GraphQLClient { get; private set; } - - static SiteContext() + public SiteContext() { - Site = new OrchardCoreTestFixture(); - ShellHost = Site.Services.GetRequiredService(); - HttpContextAccessor = Site.Services.GetRequiredService(); - DefaultTenantClient = Site.CreateDefaultClient(); + this.WithRecipe("Blog") + .WithDatabaseProvider("Sqlite"); } - public virtual async Task InitializeAsync() + public override async Task InitializeAsync() { - var tenantName = Guid.NewGuid().ToString("n"); - var tablePrefix = await TablePrefixGenerator.GeneratePrefixAsync(); - - var createModel = new Tenants.ViewModels.CreateApiViewModel - { - DatabaseProvider = DatabaseProvider, - TablePrefix = tablePrefix, - ConnectionString = ConnectionString, - RecipeName = RecipeName, - Name = tenantName, - RequestUrlPrefix = tenantName - }; - - var createResult = await DefaultTenantClient.PostAsJsonAsync("api/tenants/create", createModel); - createResult.EnsureSuccessStatusCode(); - - var content = await createResult.Content.ReadAsStringAsync(); - - var url = new Uri(content.Trim('"')); - url = new Uri(url.Scheme + "://" + url.Authority + url.LocalPath + "/"); - - var setupModel = new Tenants.ViewModels.SetupApiViewModel - { - SiteName = "Test Site", - DatabaseProvider = DatabaseProvider, - TablePrefix = tablePrefix, - ConnectionString = ConnectionString, - RecipeName = RecipeName, - UserName = "admin", - Password = "Password01_", - Name = tenantName, - Email = "Nick@Orchard" - }; - - var setupResult = await DefaultTenantClient.PostAsJsonAsync("api/tenants/setup", setupModel); - setupResult.EnsureSuccessStatusCode(); - - lock (Site) - { - Client = Site.CreateDefaultClient(url); - TenantName = tenantName; - } - - if (PermissionsContext != null) - { - var permissionContextKey = Guid.NewGuid().ToString(); - SiteStartup.PermissionsContexts.TryAdd(permissionContextKey, PermissionsContext); - Client.DefaultRequestHeaders.Add("PermissionsContext", permissionContextKey); - } + await base.InitializeAsync(); GraphQLClient = new OrchardGraphQLClient(Client); } - public async Task UsingTenantScopeAsync(Func execute, bool activateShell = true) + public async Task ResetLuceneIndiciesAsync(string indexName) { - // Ensure that 'HttpContext' is not null before using a 'ShellScope'. var shellScope = await ShellHost.GetScopeAsync(TenantName); - HttpContextAccessor.HttpContext = shellScope.ShellContext.CreateHttpContext(); - await shellScope.UsingAsync(execute, activateShell); - } - public async Task RunRecipeAsync(string recipeName, string recipePath) - { - await UsingTenantScopeAsync(async scope => - { - var shellFeaturesManager = scope.ServiceProvider.GetRequiredService(); - var recipeHarvesters = scope.ServiceProvider.GetRequiredService>(); - var recipeExecutor = scope.ServiceProvider.GetRequiredService(); - - var recipeCollections = await Task.WhenAll( - recipeHarvesters.Select(recipe => recipe.HarvestRecipesAsync())); - - var recipes = recipeCollections.SelectMany(recipeCollection => recipeCollection); - var recipe = recipes - .FirstOrDefault(recipe => recipe.RecipeFileInfo.Name == recipeName && recipe.BasePath == recipePath); - - var executionId = Guid.NewGuid().ToString("n"); - - await recipeExecutor.ExecuteAsync( - executionId, - recipe, - new Dictionary(), - CancellationToken.None); - }); - } - - public async Task ResetLuceneIndiciesAsync(string indexName) - { - await UsingTenantScopeAsync(async scope => + await shellScope.UsingServiceScopeAsync(async scope => { var luceneIndexSettingsService = scope.ServiceProvider.GetRequiredService(); var luceneIndexingService = scope.ServiceProvider.GetRequiredService(); @@ -142,6 +37,7 @@ await UsingTenantScopeAsync(async scope => var luceneIndexSettings = await luceneIndexSettingsService.GetSettingsAsync(indexName); luceneIndexingService.ResetIndexAsync(indexName); + await luceneIndexingService.ProcessContentItemsAsync(indexName); }); } @@ -159,19 +55,12 @@ public async Task CreateContentItem(string contentType, Action(); return response.ContentItemId; } - public Task DeleteContentItem(string contentItemId) - { - return Client.DeleteAsync("api/content/" + contentItemId); - } - - public void Dispose() - { - Client?.Dispose(); - } + public async Task DeleteContentItem(string contentItemId) => await Client.DeleteAsync("api/content/" + contentItemId); } } diff --git a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs index a7e728dc8c5..9d351791549 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; @@ -8,6 +7,7 @@ using OrchardCore.Modules; using OrchardCore.Recipes.Services; using OrchardCore.Testing; +using OrchardCore.Testing.Apis; using OrchardCore.Testing.Apis.Security; using OrchardCore.Testing.Recipes; @@ -15,30 +15,19 @@ namespace OrchardCore.Tests.Apis.Context { public class SiteStartup { - public readonly static ConcurrentDictionary PermissionsContexts; - - static SiteStartup() - { - PermissionsContexts = new ConcurrentDictionary(); - } - public void ConfigureServices(IServiceCollection services) { - services.AddOrchardCms(builder => - builder.AddSetupFeatures( - "OrchardCore.Tenants" - ) - .AddTenantFeatures( - "OrchardCore.Apis.GraphQL" - ) + services.AddOrchardCms(builder => builder + .AddSetupFeatures("OrchardCore.Tenants") + .AddTenantFeatures("OrchardCore.Apis.GraphQL") .ConfigureServices(serviceCollection => { serviceCollection.AddScoped(); serviceCollection.AddScoped(); - serviceCollection.AddScoped(sp => new PermissionContextAuthorizationHandler( - sp.GetRequiredService(), - PermissionsContexts)); + serviceCollection.AddScoped(sp => + new PermissionContextAuthorizationHandler(sp.GetRequiredService(), + SiteContextOptions.PermissionsContexts)); }) .Configure(appBuilder => appBuilder.UseAuthorization())); diff --git a/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs index 357c223f231..94d5aa68bd5 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs @@ -4,6 +4,7 @@ using OrchardCore.ContentFields.Fields; using OrchardCore.ContentManagement; using OrchardCore.Lists.Models; +using OrchardCore.Testing.Apis; using OrchardCore.Testing.Apis.Security; using OrchardCore.Tests.Apis.Context; using Xunit; diff --git a/test/OrchardCore.Tests/Apis/Lucene/LuceneContext.cs b/test/OrchardCore.Tests/Apis/Lucene/LuceneContext.cs index 534713bc0c5..0f37028b255 100644 --- a/test/OrchardCore.Tests/Apis/Lucene/LuceneContext.cs +++ b/test/OrchardCore.Tests/Apis/Lucene/LuceneContext.cs @@ -1,13 +1,10 @@ +using OrchardCore.Testing.Apis; using OrchardCore.Tests.Apis.Context; namespace OrchardCore.Tests.Apis.Lucene { public class LuceneContext : SiteContext { - static LuceneContext() - { - } - public LuceneContext() { this.WithRecipe("luceneQueryTest"); From 6025dbbb653b5cd9250774c9bda4aa94ce065506 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 6 Jan 2023 16:53:38 +0300 Subject: [PATCH 23/33] Fix merge issue --- .../OrchardCore.Testing/Apis/ISiteContext.cs | 2 + .../Apis/SiteContextBase.cs | 3 + .../Security/PermissionHandlerTests.cs | 1 + .../Apis/Context/SiteContext.cs | 78 +------------------ .../RolesPermissionsHandlerTests.cs | 2 +- .../Shell/ShellContainerFactoryTests.cs | 2 +- 6 files changed, 12 insertions(+), 76 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Testing/Apis/ISiteContext.cs b/src/OrchardCore/OrchardCore.Testing/Apis/ISiteContext.cs index 53e22f3b4b1..0681b1406ca 100644 --- a/src/OrchardCore/OrchardCore.Testing/Apis/ISiteContext.cs +++ b/src/OrchardCore/OrchardCore.Testing/Apis/ISiteContext.cs @@ -10,6 +10,8 @@ public interface ISiteContext : IDisposable { static IShellHost ShellHost { get; } + static IShellSettingsManager ShellSettingsManager { get; } + static HttpClient DefaultTenantClient { get; } SiteContextOptions Options { init; get; } diff --git a/src/OrchardCore/OrchardCore.Testing/Apis/SiteContextBase.cs b/src/OrchardCore/OrchardCore.Testing/Apis/SiteContextBase.cs index c6749dcd8a7..045f4635227 100644 --- a/src/OrchardCore/OrchardCore.Testing/Apis/SiteContextBase.cs +++ b/src/OrchardCore/OrchardCore.Testing/Apis/SiteContextBase.cs @@ -20,6 +20,7 @@ static SiteContextBase() { Site = new OrchardCoreTestFixture(); ShellHost = Site.Services.GetRequiredService(); + ShellSettingsManager = Site.Services.GetRequiredService(); DefaultTenantClient = Site.CreateDefaultClient(); } @@ -32,6 +33,8 @@ public SiteContextBase() public static IShellHost ShellHost { get; private set; } + public static IShellSettingsManager ShellSettingsManager { get; private set; } + public static HttpClient DefaultTenantClient { get; } public SiteContextOptions Options { init; get; } diff --git a/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs b/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs index c19603d9a18..cfb6c9f9988 100644 --- a/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs +++ b/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using OrchardCore.Security; using OrchardCore.Security.AuthorizationHandlers; using OrchardCore.Security.Permissions; diff --git a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs index 46d2bcef9fe..b443b2f421f 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteContext.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteContext.cs @@ -1,8 +1,6 @@ using OrchardCore.Apis.GraphQL.Client; using OrchardCore.ContentManagement; using OrchardCore.Environment.Shell; -using OrchardCore.Environment.Shell.Scope; -using OrchardCore.Recipes.Services; using OrchardCore.Search.Lucene; using OrchardCore.Testing.Apis; @@ -10,83 +8,15 @@ namespace OrchardCore.Tests.Apis.Context { public class SiteContext : SiteContextBase { - private static readonly TablePrefixGenerator TablePrefixGenerator = new TablePrefixGenerator(); - public static OrchardTestFixture Site { get; } - public static IShellHost ShellHost { get; private set; } - public static IShellSettingsManager ShellSettingsManager { get; private set; } - public static IHttpContextAccessor HttpContextAccessor { get; } - public static HttpClient DefaultTenantClient { get; } - - public string RecipeName { get; set; } = "Blog"; - public string DatabaseProvider { get; set; } = "Sqlite"; - public string ConnectionString { get; set; } - public PermissionsContext PermissionsContext { get; set; } - - public HttpClient Client { get; private set; } - public string TenantName { get; private set; } - public OrchardGraphQLClient GraphQLClient { get; private set; } - - static SiteContext() + public SiteContext() { - Site = new OrchardTestFixture(); - ShellHost = Site.Services.GetRequiredService(); - ShellSettingsManager = Site.Services.GetRequiredService(); - HttpContextAccessor = Site.Services.GetRequiredService(); - DefaultTenantClient = Site.CreateDefaultClient(); + this.WithRecipe("Blog") + .WithDatabaseProvider("Sqlite"); } public override async Task InitializeAsync() { - var tenantName = Guid.NewGuid().ToString("n"); - var tablePrefix = await TablePrefixGenerator.GeneratePrefixAsync(); - - var createModel = new Tenants.ViewModels.CreateApiViewModel - { - DatabaseProvider = DatabaseProvider, - TablePrefix = tablePrefix, - ConnectionString = ConnectionString, - RecipeName = RecipeName, - Name = tenantName, - RequestUrlPrefix = tenantName, - Schema = null, - }; - - var createResult = await DefaultTenantClient.PostAsJsonAsync("api/tenants/create", createModel); - createResult.EnsureSuccessStatusCode(); - - var content = await createResult.Content.ReadAsStringAsync(); - - var url = new Uri(content.Trim('"')); - url = new Uri(url.Scheme + "://" + url.Authority + url.LocalPath + "/"); - - var setupModel = new Tenants.ViewModels.SetupApiViewModel - { - SiteName = "Test Site", - DatabaseProvider = DatabaseProvider, - TablePrefix = tablePrefix, - ConnectionString = ConnectionString, - RecipeName = RecipeName, - UserName = "admin", - Password = "Password01_", - Name = tenantName, - Email = "Nick@Orchard", - }; - - var setupResult = await DefaultTenantClient.PostAsJsonAsync("api/tenants/setup", setupModel); - setupResult.EnsureSuccessStatusCode(); - - lock (Site) - { - Client = Site.CreateDefaultClient(url); - TenantName = tenantName; - } - - if (PermissionsContext != null) - { - var permissionContextKey = Guid.NewGuid().ToString(); - SiteStartup.PermissionsContexts.TryAdd(permissionContextKey, PermissionsContext); - Client.DefaultRequestHeaders.Add("PermissionsContext", permissionContextKey); - } + await base.InitializeAsync(); GraphQLClient = new OrchardGraphQLClient(Client); } diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs index 5f21f4de2ec..7390689e303 100644 --- a/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs +++ b/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs @@ -1,7 +1,7 @@ using OrchardCore.Roles; using OrchardCore.Security; using OrchardCore.Security.Permissions; -using OrchardCore.Tests.Security; +using OrchardCore.Testing.Security; namespace OrchardCore.Tests.Modules.OrchardCore.Roles { diff --git a/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs b/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs index 64200bb961e..f65cd3a7d6c 100644 --- a/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs +++ b/test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs @@ -4,7 +4,7 @@ using OrchardCore.Environment.Shell.Builders; using OrchardCore.Environment.Shell.Builders.Models; using OrchardCore.Environment.Shell.Descriptor.Models; -using OrchardCore.Tests.Stubs; +using OrchardCore.Testing.Stubs; using StartupBase = OrchardCore.Modules.StartupBase; namespace OrchardCore.Tests.Shell From db53d7b19109cbb979900dde2508fde4b5ab14d5 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 6 Jan 2023 17:07:22 +0300 Subject: [PATCH 24/33] Move common namespaces into global usings --- .../Data/TablePrefixGeneratorTests.cs | 3 --- .../Security/PermissionHandlerTests.cs | 1 - test/OrchardCore.Testing.Tests/UseCultureAttributeTests.cs | 2 -- test/OrchardCore.Testing.Tests/Usings.cs | 5 ++++- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/test/OrchardCore.Testing.Tests/Data/TablePrefixGeneratorTests.cs b/test/OrchardCore.Testing.Tests/Data/TablePrefixGeneratorTests.cs index fe4f2e202a1..cc4a1ed0799 100644 --- a/test/OrchardCore.Testing.Tests/Data/TablePrefixGeneratorTests.cs +++ b/test/OrchardCore.Testing.Tests/Data/TablePrefixGeneratorTests.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - namespace OrchardCore.Testing.Data.Tests { public class TablePrefixGeneratorTests diff --git a/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs b/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs index cfb6c9f9988..c19603d9a18 100644 --- a/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs +++ b/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs @@ -1,4 +1,3 @@ -using System.Threading.Tasks; using OrchardCore.Security; using OrchardCore.Security.AuthorizationHandlers; using OrchardCore.Security.Permissions; diff --git a/test/OrchardCore.Testing.Tests/UseCultureAttributeTests.cs b/test/OrchardCore.Testing.Tests/UseCultureAttributeTests.cs index 1f8b85b25ce..08a3dbbaeaf 100644 --- a/test/OrchardCore.Testing.Tests/UseCultureAttributeTests.cs +++ b/test/OrchardCore.Testing.Tests/UseCultureAttributeTests.cs @@ -1,5 +1,3 @@ -using System.Globalization; - namespace OrchardCore.Testing.Tests; public class UseCultureAttributeTests diff --git a/test/OrchardCore.Testing.Tests/Usings.cs b/test/OrchardCore.Testing.Tests/Usings.cs index 8c927eb747a..8e08b5e452b 100644 --- a/test/OrchardCore.Testing.Tests/Usings.cs +++ b/test/OrchardCore.Testing.Tests/Usings.cs @@ -1 +1,4 @@ -global using Xunit; \ No newline at end of file +global using System.Collections.Generic; +global using System.Globalization; +global using System.Threading.Tasks; +global using Xunit; From 3ce359173df6c75d626e4daf4217afc4ba3c6872 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 6 Jan 2023 18:27:50 +0300 Subject: [PATCH 25/33] Add readonly modifier --- src/OrchardCore/OrchardCore.Testing/Stubs/ThemeManagerStub.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/OrchardCore/OrchardCore.Testing/Stubs/ThemeManagerStub.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/ThemeManagerStub.cs index 8165c7dea41..2df9e4ac3e8 100644 --- a/src/OrchardCore/OrchardCore.Testing/Stubs/ThemeManagerStub.cs +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/ThemeManagerStub.cs @@ -6,7 +6,8 @@ namespace OrchardCore.Testing.Stubs; public class ThemeManagerStub : IThemeManager { - private IExtensionInfo _extensionInfo; + private readonly IExtensionInfo _extensionInfo; + public ThemeManagerStub(IExtensionInfo extensionInfo) { _extensionInfo = extensionInfo; From 137b5de29459eeae31d61cc8e37329d25667b972 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 6 Jan 2023 23:33:47 +0300 Subject: [PATCH 26/33] TestRecipeHarvester -> RecipeHarvesterStub --- .../RecipeHarvesterStub.cs} | 7 ++++--- test/OrchardCore.Tests/Apis/Context/SiteStartup.cs | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) rename src/OrchardCore/OrchardCore.Testing/{Recipes/TestRecipeHarvester.cs => Stubs/RecipeHarvesterStub.cs} (85%) diff --git a/src/OrchardCore/OrchardCore.Testing/Recipes/TestRecipeHarvester.cs b/src/OrchardCore/OrchardCore.Testing/Stubs/RecipeHarvesterStub.cs similarity index 85% rename from src/OrchardCore/OrchardCore.Testing/Recipes/TestRecipeHarvester.cs rename to src/OrchardCore/OrchardCore.Testing/Stubs/RecipeHarvesterStub.cs index 7070b9479e6..3a69990ccf2 100644 --- a/src/OrchardCore/OrchardCore.Testing/Recipes/TestRecipeHarvester.cs +++ b/src/OrchardCore/OrchardCore.Testing/Stubs/RecipeHarvesterStub.cs @@ -2,15 +2,16 @@ using System.Threading.Tasks; using OrchardCore.Recipes.Models; using OrchardCore.Recipes.Services; +using OrchardCore.Testing.Recipes; -namespace OrchardCore.Testing.Recipes +namespace OrchardCore.Testing.Stubs { - public class TestRecipeHarvester : IRecipeHarvester + public class RecipeHarvesterStub : IRecipeHarvester { private readonly IRecipeFileProvider _recipeFileProvider; private readonly IRecipeReader _recipeReader; - public TestRecipeHarvester(IRecipeFileProvider recipeFileProvider, IRecipeReader recipeReader) + public RecipeHarvesterStub(IRecipeFileProvider recipeFileProvider, IRecipeReader recipeReader) { _recipeFileProvider = recipeFileProvider; _recipeReader = recipeReader; diff --git a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs index ad96668cfe5..5594a6e436a 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs @@ -4,6 +4,7 @@ using OrchardCore.Testing.Apis; using OrchardCore.Testing.Apis.Security; using OrchardCore.Testing.Recipes; +using OrchardCore.Testing.Stubs; namespace OrchardCore.Tests.Apis.Context { @@ -17,7 +18,7 @@ public void ConfigureServices(IServiceCollection services) .ConfigureServices(serviceCollection => { serviceCollection.AddScoped(); - serviceCollection.AddScoped(); + serviceCollection.AddScoped(); serviceCollection.AddScoped(sp => new PermissionContextAuthorizationHandler(sp.GetRequiredService(), From 9a0f2a5ef2f6eccbd71c9cf98506974905a5de1e Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 13 Jan 2023 23:44:56 +0300 Subject: [PATCH 27/33] Move SuccessAsync() to AuthorizationHandlerContextExtensions --- .../AuthorizationHandlerContextExtensions.cs | 14 ++++++++++++++ .../Security/PermissionHandlerHelper.cs | 9 --------- .../Security/PermissionHandlerTests.cs | 1 + 3 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.Testing/Security/Extensions/AuthorizationHandlerContextExtensions.cs diff --git a/src/OrchardCore/OrchardCore.Testing/Security/Extensions/AuthorizationHandlerContextExtensions.cs b/src/OrchardCore/OrchardCore.Testing/Security/Extensions/AuthorizationHandlerContextExtensions.cs new file mode 100644 index 00000000000..6331556a7c5 --- /dev/null +++ b/src/OrchardCore/OrchardCore.Testing/Security/Extensions/AuthorizationHandlerContextExtensions.cs @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using OrchardCore.Testing.Fakes; + +namespace Microsoft.AspNetCore.Authorization; + +public static class AuthorizationHandlerContextExtensions +{ + public static async Task SuccessAsync(this AuthorizationHandlerContext context, params string[] permissionNames) + { + var handler = new FakePermissionHandler(permissionNames); + + await handler.HandleAsync(context); + } +} diff --git a/src/OrchardCore/OrchardCore.Testing/Security/PermissionHandlerHelper.cs b/src/OrchardCore/OrchardCore.Testing/Security/PermissionHandlerHelper.cs index e7db6ee1df1..c0b4a53b41c 100644 --- a/src/OrchardCore/OrchardCore.Testing/Security/PermissionHandlerHelper.cs +++ b/src/OrchardCore/OrchardCore.Testing/Security/PermissionHandlerHelper.cs @@ -1,9 +1,7 @@ using System.Security.Claims; -using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using OrchardCore.Security.Permissions; using OrchardCore.Security; -using OrchardCore.Testing.Fakes; namespace OrchardCore.Testing.Security; @@ -29,11 +27,4 @@ public static AuthorizationHandlerContext CreateTestAuthorizationHandlerContext( return new AuthorizationHandlerContext(new[] { new PermissionRequirement(required) }, principal, null); } - - public static async Task SuccessAsync(this AuthorizationHandlerContext context, params string[] permissionNames) - { - var handler = new FakePermissionHandler(permissionNames); - - await handler.HandleAsync(context); - } } diff --git a/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs b/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs index c19603d9a18..23f9c1071c1 100644 --- a/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs +++ b/test/OrchardCore.Testing.Tests/Security/PermissionHandlerTests.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Authorization; using OrchardCore.Security; using OrchardCore.Security.AuthorizationHandlers; using OrchardCore.Security.Permissions; From b1d42863ec5e4f4c7658744cee7315ae89d81166 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 13 Jan 2023 23:57:48 +0300 Subject: [PATCH 28/33] Replace RolesMockHelper wtih OrchardCoreMock.CreateRoleManager() --- .../Mocks/OrchardCoreSecurityMocks.cs | 4 ++-- .../Modules/OrchardCore.Roles/RolesMockHelper.cs | 15 --------------- .../RolesPermissionsHandlerTests.cs | 8 +++++--- ...aultUserClaimsPrincipalProviderFactoryTests.cs | 2 +- 4 files changed, 8 insertions(+), 21 deletions(-) delete mode 100644 test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesMockHelper.cs diff --git a/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs index 917a06af6b3..de363f914fa 100644 --- a/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs +++ b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs @@ -59,7 +59,7 @@ public static Mock> CreateUserManagerMock() where TUse return userManagerMock; } - public static RoleManager CreateRoleManager() where TRole : class + public static Mock> CreateRoleManager() where TRole : class { var roleStoreMock = new Mock>().Object; var rolesValidators = new List> @@ -74,6 +74,6 @@ public static RoleManager CreateRoleManager() where TRole : class new IdentityErrorDescriber(), null); - return roleManagerMock.Object; + return roleManagerMock; } } diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesMockHelper.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesMockHelper.cs deleted file mode 100644 index 5600e77ceab..00000000000 --- a/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesMockHelper.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace OrchardCore.Tests.Modules.OrchardCore.Roles -{ - public static class RolesMockHelper - { - public static Mock> MockRoleManager() - where TRole : class - { - var store = new Mock>().Object; - var validators = new List>(); - validators.Add(new RoleValidator()); - - return new Mock>(store, validators, new UpperInvariantLookupNormalizer(), new IdentityErrorDescriber(), null); - } - } -} diff --git a/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs b/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs index 7390689e303..be1a13959d7 100644 --- a/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs +++ b/test/OrchardCore.Tests/Modules/OrchardCore.Roles/RolesPermissionsHandlerTests.cs @@ -1,6 +1,7 @@ using OrchardCore.Roles; using OrchardCore.Security; using OrchardCore.Security.Permissions; +using OrchardCore.Testing.Mocks; using OrchardCore.Testing.Security; namespace OrchardCore.Tests.Modules.OrchardCore.Roles @@ -119,15 +120,16 @@ public async Task IsCaseIsensitive(string required, bool authenticated) private static RolesPermissionsHandler CreatePermissionHandler(params Role[] roles) { - var roleManager = RolesMockHelper.MockRoleManager(); + var roleManagerMock = OrchardCoreMock.CreateRoleManager(); foreach (var role in roles) { - roleManager.Setup(m => m.FindByNameAsync(role.RoleName)).ReturnsAsync(role); + roleManagerMock.Setup(m => m.FindByNameAsync(role.RoleName)).ReturnsAsync(role); } var permissionGrantingService = new DefaultPermissionGrantingService(); - return new RolesPermissionsHandler(roleManager.Object, permissionGrantingService); + + return new RolesPermissionsHandler(roleManagerMock.Object, permissionGrantingService); } } } diff --git a/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs b/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs index 5893e792d9f..d80ea6fa91c 100644 --- a/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs +++ b/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs @@ -26,7 +26,7 @@ public async Task EnsurePrincipalHasExpectedClaims(bool emailVerified) userManager.Setup(m => m.IsEmailConfirmedAsync(user)).ReturnsAsync(emailVerified); } - var roleManager = OrchardCoreMock.CreateRoleManager(); + var roleManager = OrchardCoreMock.CreateRoleManager().Object; var options = new Mock>(); options.Setup(a => a.Value).Returns(new IdentityOptions()); From b89d4d12682bb85c92512d4c91612a52ad1f7a6e Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Fri, 13 Jan 2023 23:59:51 +0300 Subject: [PATCH 29/33] CreateUserManagerMock -> CreateUserManager --- .../Mocks/OrchardCoreSecurityMocks.cs | 4 ++-- ...DefaultUserClaimsPrincipalProviderFactoryTests.cs | 2 +- .../OrchardCore.Users/RegistrationControllerTests.cs | 2 +- .../OrchardCore.Users/UserValidatorTests.cs | 12 ++++++------ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs index de363f914fa..21178e1e28a 100644 --- a/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs +++ b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs @@ -13,7 +13,7 @@ public static partial class OrchardCoreMock public static SignInManager CreateSignInManager(UserManager userManager = null) where TUser : class, IUser { var context = new Mock(); - var manager = userManager ?? CreateUserManagerMock().Object; + var manager = userManager ?? CreateUserManager().Object; var signInManager = new Mock>( manager, @@ -34,7 +34,7 @@ public static SignInManager CreateSignInManager(UserManager return signInManager.Object; } - public static Mock> CreateUserManagerMock() where TUser : class + public static Mock> CreateUserManager() where TUser : class { var userStore = new Mock>(); var identityOptions = new IdentityOptions(); diff --git a/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs b/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs index d80ea6fa91c..ef29b22070c 100644 --- a/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs +++ b/test/OrchardCore.Tests/OrchardCore.Users/OrchardCore.Users.Core/DefaultUserClaimsPrincipalProviderFactoryTests.cs @@ -15,7 +15,7 @@ public class DefaultUserClaimsPrincipalProviderFactoryTests public async Task EnsurePrincipalHasExpectedClaims(bool emailVerified) { //Arrange - var userManager = OrchardCoreMock.CreateUserManagerMock(); + var userManager = OrchardCoreMock.CreateUserManager(); var user = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo", Email = "foo@foo.com" }; userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.UserId); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); diff --git a/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs b/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs index 82f0f793461..e114d5018d4 100644 --- a/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs +++ b/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs @@ -108,7 +108,7 @@ private static RegistrationController SetupRegistrationController() private static RegistrationController SetupRegistrationController(RegistrationSettings registrationSettings) { var users = new List(); - var mockUserManager = OrchardCoreMock.CreateUserManagerMock(); + var mockUserManager = OrchardCoreMock.CreateUserManager(); mockUserManager.Setup(um => um.FindByEmailAsync(It.IsAny())) .Returns(e => { diff --git a/test/OrchardCore.Tests/OrchardCore.Users/UserValidatorTests.cs b/test/OrchardCore.Tests/OrchardCore.Users/UserValidatorTests.cs index cbe96a7e3a9..809b4092f90 100644 --- a/test/OrchardCore.Tests/OrchardCore.Users/UserValidatorTests.cs +++ b/test/OrchardCore.Tests/OrchardCore.Users/UserValidatorTests.cs @@ -10,7 +10,7 @@ public class UserValidatorTests public async Task CanValidateUser() { // Arrange - var userManager = OrchardCoreMock.CreateUserManagerMock(); + var userManager = OrchardCoreMock.CreateUserManager(); var user = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo", Email = "foo@foo.com" }; userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.UserId); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); @@ -29,7 +29,7 @@ public async Task ShouldRequireEmail() { // Arrange var describer = new IdentityErrorDescriber(); - var userManager = OrchardCoreMock.CreateUserManagerMock(); + var userManager = OrchardCoreMock.CreateUserManager(); var user = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo" }; userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.UserId); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); @@ -49,7 +49,7 @@ public async Task ShouldRequireValidEmail() { // Arrange var describer = new IdentityErrorDescriber(); - var userManager = OrchardCoreMock.CreateUserManagerMock(); + var userManager = OrchardCoreMock.CreateUserManager(); var user = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo", Email = "foo" }; userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.UserId); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); @@ -69,7 +69,7 @@ public async Task ShouldRequireUniqueEmail() { // Arrange var describer = new IdentityErrorDescriber(); - var userManager = OrchardCoreMock.CreateUserManagerMock(); + var userManager = OrchardCoreMock.CreateUserManager(); var existingUser = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo", Email = "foo@foo.com" }; userManager.Setup(m => m.GetUserIdAsync(existingUser)).ReturnsAsync(existingUser.UserId); userManager.Setup(m => m.GetUserNameAsync(existingUser)).ReturnsAsync(existingUser.UserName); @@ -96,7 +96,7 @@ public async Task ShouldRequireUserNameIsNotAnEmailAddress() { // Arrange var describer = new IdentityErrorDescriber(); - var userManager = OrchardCoreMock.CreateUserManagerMock(); + var userManager = OrchardCoreMock.CreateUserManager(); var user = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "foo@foo.com", Email = "foo" }; userManager.Setup(m => m.GetUserIdAsync(user)).ReturnsAsync(user.UserId); userManager.Setup(m => m.GetUserNameAsync(user)).ReturnsAsync(user.UserName); @@ -116,7 +116,7 @@ public async Task ShouldRequireUniqueUserName() { // Arrange var describer = new IdentityErrorDescriber(); - var userManager = OrchardCoreMock.CreateUserManagerMock(); + var userManager = OrchardCoreMock.CreateUserManager(); var existingUser = new User { UserId = Guid.NewGuid().ToString("n"), UserName = "Foo", Email = "bar@bar.com" }; userManager.Setup(m => m.GetUserIdAsync(existingUser)).ReturnsAsync(existingUser.UserId); userManager.Setup(m => m.GetUserNameAsync(existingUser)).ReturnsAsync(existingUser.UserName); From fcf7c12a1e364fad552faa72950ae03e085423aa Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 14 Jan 2023 00:05:27 +0300 Subject: [PATCH 30/33] OrchardCoreMock.CreateSignInManager() should returns mocked object --- .../OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs | 4 ++-- .../OrchardCore.Users/RegistrationControllerTests.cs | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs index 21178e1e28a..03084233ec2 100644 --- a/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs +++ b/src/OrchardCore/OrchardCore.Testing/Mocks/OrchardCoreSecurityMocks.cs @@ -10,7 +10,7 @@ namespace OrchardCore.Testing.Mocks; public static partial class OrchardCoreMock { - public static SignInManager CreateSignInManager(UserManager userManager = null) where TUser : class, IUser + public static Mock> CreateSignInManager(UserManager userManager = null) where TUser : class, IUser { var context = new Mock(); var manager = userManager ?? CreateUserManager().Object; @@ -31,7 +31,7 @@ public static SignInManager CreateSignInManager(UserManager .Setup(x => x.SignInAsync(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(Task.CompletedTask); - return signInManager.Object; + return signInManager; } public static Mock> CreateUserManager() where TUser : class diff --git a/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs b/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs index e114d5018d4..a6fd6a34e58 100644 --- a/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs +++ b/test/OrchardCore.Tests/OrchardCore.Users/RegistrationControllerTests.cs @@ -132,6 +132,8 @@ private static RegistrationController SetupRegistrationController(RegistrationSe .Callback>((u, p, e) => users.Add(u)) .ReturnsAsync, IUserService, IUser>((u, p, e) => u); + var signInManagerMock = OrchardCoreMock.CreateSignInManager(mockUserManager.Object); + var urlHelperMock = new Mock(); urlHelperMock.Setup(urlHelper => urlHelper.Action(It.IsAny())); @@ -173,7 +175,7 @@ private static RegistrationController SetupRegistrationController(RegistrationSe .Returns(userService.Object); mockServiceProvider .Setup(x => x.GetService(typeof(SignInManager))) - .Returns(OrchardCoreMock.CreateSignInManager(mockUserManager.Object)); + .Returns(signInManagerMock.Object); mockServiceProvider .Setup(x => x.GetService(typeof(ITempDataDictionaryFactory))) .Returns(Mock.Of()); From 262b7ea138b46bfdda2d064e1a46c231db8469a5 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 25 Feb 2023 17:01:34 +0300 Subject: [PATCH 31/33] Address feedback --- .../Infrastructure/OrchardCoreTestFixture.cs | 2 +- .../OrchardCore.Testing/ModuleNamesProvider.cs | 10 +++++++--- .../OrchardCore.Testing/OrchardCore.Testing.csproj | 2 +- test/OrchardCore.Tests/Apis/Context/SiteStartup.cs | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/OrchardCore/OrchardCore.Testing/Infrastructure/OrchardCoreTestFixture.cs b/src/OrchardCore/OrchardCore.Testing/Infrastructure/OrchardCoreTestFixture.cs index 4fc792bf558..1c7a0aac5fc 100644 --- a/src/OrchardCore/OrchardCore.Testing/Infrastructure/OrchardCoreTestFixture.cs +++ b/src/OrchardCore/OrchardCore.Testing/Infrastructure/OrchardCoreTestFixture.cs @@ -22,7 +22,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) } protected override IWebHostBuilder CreateWebHostBuilder() - => WebHostBuilderFactory.CreateFromAssemblyEntryPoint(typeof(Program).Assembly, Array.Empty()); + => WebHostBuilderFactory.CreateFromAssemblyEntryPoint(typeof(TStartup).Assembly, Array.Empty()); protected override IHostBuilder CreateHostBuilder() => Host.CreateDefaultBuilder().ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); diff --git a/src/OrchardCore/OrchardCore.Testing/ModuleNamesProvider.cs b/src/OrchardCore/OrchardCore.Testing/ModuleNamesProvider.cs index b9e568ab17f..0f3a8b7380c 100644 --- a/src/OrchardCore/OrchardCore.Testing/ModuleNamesProvider.cs +++ b/src/OrchardCore/OrchardCore.Testing/ModuleNamesProvider.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -10,11 +11,14 @@ public class ModuleNamesProvider : IModuleNamesProvider { private readonly IEnumerable _moduleNames; - public ModuleNamesProvider() + public ModuleNamesProvider(Assembly assembly) { - var assembly = Assembly.Load(new AssemblyName(typeof(Program).Assembly.GetName().Name)); + if (assembly == null) + { + throw new ArgumentNullException(nameof(assembly)); + } - _moduleNames = assembly + _moduleNames = Assembly.Load(new AssemblyName(assembly.GetName().Name)) .GetCustomAttributes() .Select(m => m.Name); } diff --git a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj index 2bf277eda44..308a2ff487d 100644 --- a/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj +++ b/src/OrchardCore/OrchardCore.Testing/OrchardCore.Testing.csproj @@ -27,8 +27,8 @@ - + diff --git a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs index 5594a6e436a..040cc915120 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs @@ -26,7 +26,7 @@ public void ConfigureServices(IServiceCollection services) }) .Configure(appBuilder => appBuilder.UseAuthorization())); - services.AddSingleton(); + services.AddSingleton(new ModuleNamesProvider(typeof(Program).Assembly)); } public void Configure(IApplicationBuilder app, IHostEnvironment env, ILoggerFactory loggerFactory) => app.UseOrchardCore(); From 9b145aedeb9007d2e5da980bb19a0983f750d42f Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 25 Feb 2023 17:07:28 +0300 Subject: [PATCH 32/33] Revert changes in OC.Cms.Web --- src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj | 5 +++++ src/OrchardCore.Cms.Web/Program.cs | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj b/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj index 1565d29d7c6..821099c13dd 100644 --- a/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj +++ b/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj @@ -14,6 +14,11 @@ enable enable + + + + + diff --git a/src/OrchardCore.Cms.Web/Program.cs b/src/OrchardCore.Cms.Web/Program.cs index e864d456dca..4b4d39392bd 100644 --- a/src/OrchardCore.Cms.Web/Program.cs +++ b/src/OrchardCore.Cms.Web/Program.cs @@ -20,8 +20,3 @@ app.UseOrchardCore(); app.Run(); - -public partial class Program -{ - -} From c604fec225a8f45c2621e25e5c89fe5382bed063 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Sat, 25 Feb 2023 17:39:56 +0300 Subject: [PATCH 33/33] Add docs --- src/docs/topics/testing/README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/docs/topics/testing/README.md diff --git a/src/docs/topics/testing/README.md b/src/docs/topics/testing/README.md new file mode 100644 index 00000000000..b1676fdb934 --- /dev/null +++ b/src/docs/topics/testing/README.md @@ -0,0 +1,31 @@ +# Testing with Orchard Core + +When developing an OrchardCore solutions, most of the times you want to unit test the most mandatory parts of your application/module. +That's why we provide a testing infrastructure APIs, that will allow you to get started easily. + +The best way to see how it works, is by looking at `OrchardCore.Tests` project in the source code. + +## Unit Tests + +For unit testing, `OrchardCore.Testing` provides a lot of mocks ans stubs that accelerate the process of testing your application/module. Moreover it contains helpers and utility classes that might help during writing unit tests. + +### UseCultureAttribute + +With the help of `UseCultureAttribute` you scope your method under test (MUT) to run on a specific culture, which is quite useful in many cases. + +```csharp +[Fact] +[UseCulture("ar-YE")] +public void UnitTestName() +{ + // Omitted for brivety +} +``` + +## Integration Tests + +For integration testing, `OrchardCore.Testing` provides some classes that accelerate the process of testing your application/module. + +### SiteContextBase<TSiteStartup> + +You create a `SiteContext` object and configure it by using the `SiteContextOptions` for building a site that using a certain database and recipe.