Merge remote-tracking branch 'origin/v9/9.1' into v9/dev
# Conflicts: # build/templates/UmbracoPackage/.template.config/template.json # build/templates/UmbracoProject/.template.config/template.json # src/Directory.Build.props
This commit is contained in:
5
tests/.editorconfig
Normal file
5
tests/.editorconfig
Normal file
@@ -0,0 +1,5 @@
|
||||
root = false
|
||||
|
||||
[*.cs]
|
||||
csharp_style_var_when_type_is_apparent = true:none
|
||||
csharp_style_var_elsewhere = true:none
|
||||
@@ -766,6 +766,77 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Packaging
|
||||
Assert.That(testContentType.ContentTypeCompositionExists("Seo"), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ImportDocumentType_NewTypeWithOmittedHistoryCleanupPolicy_InsertsDefaultPolicy()
|
||||
{
|
||||
// Arrange
|
||||
var withoutCleanupPolicy = XElement.Parse(ImportResources.SingleDocType);
|
||||
|
||||
// Act
|
||||
var contentTypes = PackageDataInstallation
|
||||
.ImportDocumentType(withoutCleanupPolicy, 0)
|
||||
.OfType<IContentTypeWithHistoryCleanup>();
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.NotNull(contentTypes.Single().HistoryCleanup);
|
||||
Assert.IsFalse(contentTypes.Single().HistoryCleanup.PreventCleanup);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ImportDocumentType_WithHistoryCleanupPolicyElement_ImportsWithCorrectValues()
|
||||
{
|
||||
// Arrange
|
||||
var docTypeElement = XElement.Parse(ImportResources.SingleDocType_WithCleanupPolicy);
|
||||
|
||||
// Act
|
||||
var contentTypes = PackageDataInstallation
|
||||
.ImportDocumentType(docTypeElement, 0)
|
||||
.OfType<IContentTypeWithHistoryCleanup>();
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.NotNull(contentTypes.Single().HistoryCleanup);
|
||||
Assert.IsTrue(contentTypes.Single().HistoryCleanup.PreventCleanup);
|
||||
Assert.AreEqual(1, contentTypes.Single().HistoryCleanup.KeepAllVersionsNewerThanDays);
|
||||
Assert.AreEqual(2, contentTypes.Single().HistoryCleanup.KeepLatestVersionPerDayForDays);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ImportDocumentType_ExistingTypeWithOmittedHistoryCleanupPolicy_DoesNotOverwriteDatabaseContent()
|
||||
{
|
||||
// Arrange
|
||||
var withoutCleanupPolicy = XElement.Parse(ImportResources.SingleDocType);
|
||||
var withCleanupPolicy = XElement.Parse(ImportResources.SingleDocType_WithCleanupPolicy);
|
||||
|
||||
// Act
|
||||
var contentTypes = PackageDataInstallation
|
||||
.ImportDocumentType(withCleanupPolicy, 0)
|
||||
.OfType<IContentTypeWithHistoryCleanup>();
|
||||
|
||||
var contentTypesUpdated = PackageDataInstallation
|
||||
.ImportDocumentType(withoutCleanupPolicy, 0)
|
||||
.OfType<IContentTypeWithHistoryCleanup>();
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.NotNull(contentTypes.Single().HistoryCleanup);
|
||||
Assert.IsTrue(contentTypes.Single().HistoryCleanup.PreventCleanup);
|
||||
Assert.AreEqual(1, contentTypes.Single().HistoryCleanup.KeepAllVersionsNewerThanDays);
|
||||
Assert.AreEqual(2, contentTypes.Single().HistoryCleanup.KeepLatestVersionPerDayForDays);
|
||||
|
||||
Assert.NotNull(contentTypesUpdated.Single().HistoryCleanup);
|
||||
Assert.IsTrue(contentTypesUpdated.Single().HistoryCleanup.PreventCleanup);
|
||||
Assert.AreEqual(1, contentTypes.Single().HistoryCleanup.KeepAllVersionsNewerThanDays);
|
||||
Assert.AreEqual(2, contentTypes.Single().HistoryCleanup.KeepLatestVersionPerDayForDays);
|
||||
});
|
||||
}
|
||||
|
||||
private void AddLanguages()
|
||||
{
|
||||
var globalSettings = new GlobalSettings();
|
||||
|
||||
@@ -25,6 +25,7 @@ using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Media;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
|
||||
@@ -225,6 +226,58 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
|
||||
Assert.AreEqual(media.Properties[Constants.Conventions.Media.Bytes].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Bytes).Single().Value);
|
||||
Assert.AreEqual(media.Properties[Constants.Conventions.Media.Extension].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Extension).Single().Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Serialize_ForContentTypeWithHistoryCleanupPolicy_OutputsSerializedHistoryCleanupPolicy()
|
||||
{
|
||||
// Arrange
|
||||
var template = TemplateBuilder.CreateTextPageTemplate();
|
||||
FileService.SaveTemplate(template); // else, FK violation on contentType!
|
||||
|
||||
var contentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: template.Id);
|
||||
|
||||
contentType.HistoryCleanup = new HistoryCleanup
|
||||
{
|
||||
PreventCleanup = true,
|
||||
KeepAllVersionsNewerThanDays = 1,
|
||||
KeepLatestVersionPerDayForDays = 2
|
||||
};
|
||||
|
||||
ContentTypeService.Save(contentType);
|
||||
|
||||
// Act
|
||||
var element = Serializer.Serialize(contentType);
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(element.Element("HistoryCleanupPolicy")!.Attribute("preventCleanup")!.Value, Is.EqualTo("true"));
|
||||
Assert.That(element.Element("HistoryCleanupPolicy")!.Attribute("keepAllVersionsNewerThanDays")!.Value, Is.EqualTo("1"));
|
||||
Assert.That(element.Element("HistoryCleanupPolicy")!.Attribute("keepLatestVersionPerDayForDays")!.Value, Is.EqualTo("2"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Serialize_ForContentTypeWithNullHistoryCleanupPolicy_DoesNotOutputSerializedDefaultPolicy()
|
||||
{
|
||||
// Arrange
|
||||
var template = TemplateBuilder.CreateTextPageTemplate();
|
||||
FileService.SaveTemplate(template); // else, FK violation on contentType!
|
||||
|
||||
var contentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: template.Id);
|
||||
|
||||
contentType.HistoryCleanup = null;
|
||||
|
||||
ContentTypeService.Save(contentType);
|
||||
|
||||
var element = Serializer.Serialize(contentType);
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(element.Element("HistoryCleanupPolicy"), Is.Null);
|
||||
});
|
||||
}
|
||||
|
||||
private void CreateDictionaryData()
|
||||
{
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importin
|
||||
/// </info>
|
||||
/// <Documents>
|
||||
/// <DocumentSet importMode="root">
|
||||
/// <NewType id="1148" parentID="-1" level="1" creatorID="0" sortOrder="9" createDate="2013-07-23T12:06:07" updateDate="2013-07-23T15:56:37" nodeName="DoIt" urlName="doit" path="-1,1148" isDoc="" nodeType="1134" creatorName="admin" writerName="admin" writerID="0" template="1133" nodeTy [rest of string was truncated]";.
|
||||
/// <NewType key="9c9b55d0-2fbf-4f12-afea-023bd7b2519d" id="1148" parentID="-1" level="1" creatorID="0" sortOrder="9" createDate="2013-07-23T12:06:07" updateDate="2013-07-23T15:56:37" nodeName="DoIt" urlName="doit" path="-1,1148" isDoc="" nodeType="1134" creatorName="admin" writerName= [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string CheckboxList_Content_Package {
|
||||
get {
|
||||
@@ -91,7 +91,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importin
|
||||
/// </info>
|
||||
/// <Documents>
|
||||
/// <DocumentSet importMode="root">
|
||||
/// <umbHomePage id="1068" parentID="-1" level="1" creatorID="0" sortOrder="0" createDate="2014-11-26T12:52:35" updateDate="2014-11-26T12:52:36" nodeName="Home" urlName="home" path="-1,1068" isDoc="" nodeType="1056" creatorName="Morten Christensen" writerName="Morten Christensen" [rest of string was truncated]";.
|
||||
/// <umbHomePage key="9c9b55d0-2fbf-4f12-afea-023bd7b2519d" id="1068" parentID="-1" level="1" creatorID="0" sortOrder="0" createDate="2014-11-26T12:52:35" updateDate="2014-11-26T12:52:36" nodeName="Home" urlName="home" path="-1,1068" isDoc="" nodeType="1056" creatorName="Morten Ch [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string CompositionsTestPackage {
|
||||
get {
|
||||
@@ -124,15 +124,14 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importin
|
||||
/// <files />
|
||||
/// <info>
|
||||
/// <package>
|
||||
/// <name>Dictionary-Package</name>
|
||||
/// <name>Dictionary-Package</name>
|
||||
/// </package>
|
||||
/// </info>
|
||||
/// <DictionaryItems>
|
||||
/// <DictionaryItem Key="Parent">
|
||||
/// <DictionaryItem Key="28f2e02a-8c66-4fcd-85e3-8524d551c0d3" Name="Parent">
|
||||
/// <Value LanguageId="2" LanguageCultureAlias="nb-NO"><![CDATA[ForelderVerdi]]></Value>
|
||||
/// <Value LanguageId="3" LanguageCultureAlias="en-GB"><![CDATA[ParentValue]]></Value>
|
||||
/// <DictionaryItem Key="Child">
|
||||
/// <Value LanguageId="2" LanguageCultureAlias="nb-NO"><![CDATA[BarnV [rest of string was truncated]";.
|
||||
/// <DictionaryItem Key="e7dba0a9-d517-4ba4-8e18-2764d392c611" Name=" [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string Dictionary_Package {
|
||||
get {
|
||||
@@ -239,6 +238,33 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importin
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
|
||||
///<DocumentType>
|
||||
/// <Info>
|
||||
/// <Name>test</Name>
|
||||
/// <Key>150ead17-d359-42a2-ac33-6504cc52ced1</Key>
|
||||
/// <Alias>test</Alias>
|
||||
/// <Icon>folder.gif</Icon>
|
||||
/// <Thumbnail>folder.png</Thumbnail>
|
||||
/// <Description>
|
||||
/// </Description>
|
||||
/// <AllowAtRoot>False</AllowAtRoot>
|
||||
/// <AllowedTemplates>
|
||||
/// <Template>test</Template>
|
||||
/// </AllowedTemplates>
|
||||
/// <DefaultTemplate>test</DefaultTemplate>
|
||||
/// </Info>
|
||||
/// <Structure>
|
||||
/// <DocumentType>test</DocumentType>
|
||||
/// </Str [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string SingleDocType_WithCleanupPolicy {
|
||||
get {
|
||||
return ResourceManager.GetString("SingleDocType_WithCleanupPolicy", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
///<umbPackage>
|
||||
@@ -249,8 +275,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importin
|
||||
/// </info>
|
||||
/// <Documents>
|
||||
/// <DocumentSet importMode="root">
|
||||
/// <Homepage id="1072" parentID="-1" level="1" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:39" updateDate="2013-02-17T09:10:47" nodeName="Home" urlName="home" path="-1,1072" isDoc="" nodeType="1062" creatorName="admin" writerName="admin" writerID="0" template="1049">
|
||||
/// <slide [rest of string was truncated]";.
|
||||
/// <Homepage key="9c9b55d0-2fbf-4f12-afea-023bd7b2519d" id="1072" parentID="-1" level="1" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:39" updateDate="2013-02-17T09:10:47" nodeName="Home" urlName="home" path="-1,1072" isDoc="" nodeType="1062" creatorName="admin" writerName="admin" wr [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string StandardMvc_Package {
|
||||
get {
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
@@ -26,36 +26,36 @@
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
@@ -157,4 +157,7 @@
|
||||
<data name="MediaTypesAndMedia_Package.xml" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>MediaTypesAndMedia-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
<data name="SingleDocType_WithCleanupPolicy" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>SingleDocType-WithCleanupPolicy.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<DocumentType>
|
||||
<Info>
|
||||
<Name>test</Name>
|
||||
<Key>150ead17-d359-42a2-ac33-6504cc52ced1</Key>
|
||||
<Alias>test</Alias>
|
||||
<Icon>folder.gif</Icon>
|
||||
<Thumbnail>folder.png</Thumbnail>
|
||||
<Description>
|
||||
</Description>
|
||||
<AllowAtRoot>False</AllowAtRoot>
|
||||
<AllowedTemplates>
|
||||
<Template>test</Template>
|
||||
</AllowedTemplates>
|
||||
<DefaultTemplate>test</DefaultTemplate>
|
||||
</Info>
|
||||
<Structure>
|
||||
<DocumentType>test</DocumentType>
|
||||
</Structure>
|
||||
<GenericProperties>
|
||||
<GenericProperty>
|
||||
<Name>test</Name>
|
||||
<Alias>test</Alias>
|
||||
<Type>b4471851-82b6-4c75-afa4-39fa9c6a75e9</Type>
|
||||
<Definition>fbaf13a8-4036-41f2-93a3-974f678c312a</Definition>
|
||||
<Tab>
|
||||
</Tab>
|
||||
<Mandatory>False</Mandatory>
|
||||
<Validation>
|
||||
</Validation>
|
||||
<Description><![CDATA[]]></Description>
|
||||
</GenericProperty>
|
||||
</GenericProperties>
|
||||
<Tabs />
|
||||
<HistoryCleanupPolicy preventCleanup="true" keepAllVersionsNewerThanDays="1" keepLatestVersionPerDayForDays="2" />
|
||||
</DocumentType>
|
||||
@@ -0,0 +1,483 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Tests.Integration.TestServerTest;
|
||||
using Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
using Umbraco.Cms.Web.Common.Formatters;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
[TestFixture]
|
||||
public class EntityControllerTests : UmbracoTestServerTestBase
|
||||
{
|
||||
[Test]
|
||||
public async Task GetUrlsByIds_MediaWithIntegerIds_ReturnsValidMap()
|
||||
{
|
||||
IMediaTypeService mediaTypeService = Services.GetRequiredService<IMediaTypeService>();
|
||||
IMediaService mediaService = Services.GetRequiredService<IMediaService>();
|
||||
|
||||
var mediaItems = new List<Media>();
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
IMediaType mediaType = mediaTypeService.Get("image");
|
||||
mediaTypeService.Save(mediaType);
|
||||
|
||||
mediaItems.Add(MediaBuilder.CreateMediaImage(mediaType, -1));
|
||||
mediaItems.Add(MediaBuilder.CreateMediaImage(mediaType, -1));
|
||||
|
||||
foreach (Media media in mediaItems)
|
||||
{
|
||||
mediaService.Save(media);
|
||||
}
|
||||
}
|
||||
|
||||
var queryParameters = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = Constants.UdiEntityType.Media
|
||||
};
|
||||
|
||||
var url = LinkGenerator.GetUmbracoControllerUrl("GetUrlsByIds", typeof(EntityController), queryParameters);
|
||||
|
||||
var payload = new
|
||||
{
|
||||
ids = new[]
|
||||
{
|
||||
mediaItems[0].Id,
|
||||
mediaItems[1].Id,
|
||||
}
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await HttpClientJsonExtensions.PostAsJsonAsync(Client, url, payload);
|
||||
|
||||
// skip pointless un-parseable cruft.
|
||||
(await response.Content.ReadAsStreamAsync()).Seek(AngularJsonMediaTypeFormatter.XsrfPrefix.Length, SeekOrigin.Begin);
|
||||
|
||||
IDictionary<int, string> results = await response.Content.ReadFromJsonAsync<IDictionary<int, string>>();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.IsTrue(results![payload.ids[0]].StartsWith("/media"));
|
||||
Assert.IsTrue(results![payload.ids[1]].StartsWith("/media"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetUrlsByIds_Media_ReturnsEmptyStringsInMapForUnknownItems()
|
||||
{
|
||||
var queryParameters = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = Constants.UdiEntityType.Media
|
||||
};
|
||||
|
||||
var url = LinkGenerator.GetUmbracoControllerUrl("GetUrlsByIds", typeof(EntityController), queryParameters);
|
||||
|
||||
var payload = new
|
||||
{
|
||||
ids = new[] { 1, 2 }
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await HttpClientJsonExtensions.PostAsJsonAsync(Client, url, payload);
|
||||
|
||||
// skip pointless un-parseable cruft.
|
||||
(await response.Content.ReadAsStreamAsync()).Seek(AngularJsonMediaTypeFormatter.XsrfPrefix.Length, SeekOrigin.Begin);
|
||||
|
||||
IDictionary<int, string> results = await response.Content.ReadFromJsonAsync<IDictionary<int, string>>();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.That(results!.Keys.Count, Is.EqualTo(2));
|
||||
Assert.AreEqual(results![payload.ids[0]], string.Empty);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetUrlsByIds_MediaWithGuidIds_ReturnsValidMap()
|
||||
{
|
||||
IMediaTypeService mediaTypeService = Services.GetRequiredService<IMediaTypeService>();
|
||||
IMediaService mediaService = Services.GetRequiredService<IMediaService>();
|
||||
|
||||
var mediaItems = new List<Media>();
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
IMediaType mediaType = mediaTypeService.Get("image");
|
||||
mediaTypeService.Save(mediaType);
|
||||
|
||||
mediaItems.Add(MediaBuilder.CreateMediaImage(mediaType, -1));
|
||||
mediaItems.Add(MediaBuilder.CreateMediaImage(mediaType, -1));
|
||||
|
||||
foreach (Media media in mediaItems)
|
||||
{
|
||||
mediaService.Save(media);
|
||||
}
|
||||
}
|
||||
|
||||
var queryParameters = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = Constants.UdiEntityType.Media
|
||||
};
|
||||
|
||||
var url = LinkGenerator.GetUmbracoControllerUrl("GetUrlsByIds", typeof(EntityController), queryParameters);
|
||||
|
||||
var payload = new
|
||||
{
|
||||
ids = new[]
|
||||
{
|
||||
mediaItems[0].Key.ToString(),
|
||||
mediaItems[1].Key.ToString(),
|
||||
}
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await HttpClientJsonExtensions.PostAsJsonAsync(Client, url, payload);
|
||||
|
||||
// skip pointless un-parseable cruft.
|
||||
(await response.Content.ReadAsStreamAsync()).Seek(AngularJsonMediaTypeFormatter.XsrfPrefix.Length, SeekOrigin.Begin);
|
||||
|
||||
IDictionary<string, string> results = await response.Content.ReadFromJsonAsync<IDictionary<string, string>>();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.IsTrue(results![payload.ids[0]].StartsWith("/media"));
|
||||
Assert.IsTrue(results![payload.ids[1]].StartsWith("/media"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetUrlsByIds_MediaWithUdiIds_ReturnsValidMap()
|
||||
{
|
||||
IMediaTypeService mediaTypeService = Services.GetRequiredService<IMediaTypeService>();
|
||||
IMediaService mediaService = Services.GetRequiredService<IMediaService>();
|
||||
|
||||
var mediaItems = new List<Media>();
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
IMediaType mediaType = mediaTypeService.Get("image");
|
||||
mediaTypeService.Save(mediaType);
|
||||
|
||||
mediaItems.Add(MediaBuilder.CreateMediaImage(mediaType, -1));
|
||||
mediaItems.Add(MediaBuilder.CreateMediaImage(mediaType, -1));
|
||||
|
||||
foreach (Media media in mediaItems)
|
||||
{
|
||||
mediaService.Save(media);
|
||||
}
|
||||
}
|
||||
|
||||
var queryParameters = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = Constants.UdiEntityType.Media
|
||||
};
|
||||
|
||||
var url = LinkGenerator.GetUmbracoControllerUrl("GetUrlsByIds", typeof(EntityController), queryParameters);
|
||||
|
||||
var payload = new
|
||||
{
|
||||
ids = new[]
|
||||
{
|
||||
mediaItems[0].GetUdi().ToString(),
|
||||
mediaItems[1].GetUdi().ToString(),
|
||||
}
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await HttpClientJsonExtensions.PostAsJsonAsync(Client, url, payload);
|
||||
|
||||
// skip pointless un-parseable cruft.
|
||||
(await response.Content.ReadAsStreamAsync()).Seek(AngularJsonMediaTypeFormatter.XsrfPrefix.Length, SeekOrigin.Begin);
|
||||
|
||||
IDictionary<string, string> results = await response.Content.ReadFromJsonAsync<IDictionary<string, string>>();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.IsTrue(results![payload.ids[0]].StartsWith("/media"));
|
||||
Assert.IsTrue(results![payload.ids[1]].StartsWith("/media"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetUrlsByIds_Documents_ReturnsHashesInMapForUnknownItems()
|
||||
{
|
||||
var queryParameters = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = Constants.UdiEntityType.Document
|
||||
};
|
||||
|
||||
var url = LinkGenerator.GetUmbracoControllerUrl("GetUrlsByIds", typeof(EntityController), queryParameters);
|
||||
|
||||
var payload = new
|
||||
{
|
||||
ids = new[] { 1, 2 }
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await HttpClientJsonExtensions.PostAsJsonAsync(Client, url, payload);
|
||||
|
||||
// skip pointless un-parseable cruft.
|
||||
(await response.Content.ReadAsStreamAsync()).Seek(AngularJsonMediaTypeFormatter.XsrfPrefix.Length, SeekOrigin.Begin);
|
||||
|
||||
IDictionary<int, string> results = await response.Content.ReadFromJsonAsync<IDictionary<int, string>>();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.That(results!.Keys.Count, Is.EqualTo(2));
|
||||
Assert.AreEqual(results![payload.ids[0]], "#");
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetUrlsByIds_DocumentWithIntIds_ReturnsValidMap()
|
||||
{
|
||||
IContentTypeService contentTypeService = Services.GetRequiredService<IContentTypeService>();
|
||||
IContentService contentService = Services.GetRequiredService<IContentService>();
|
||||
|
||||
var contentItems = new List<IContent>();
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
IContentType contentType = ContentTypeBuilder.CreateBasicContentType();
|
||||
contentTypeService.Save(contentType);
|
||||
|
||||
ContentBuilder builder = new ContentBuilder()
|
||||
.WithContentType(contentType);
|
||||
|
||||
Content root = builder.WithName("foo").Build();
|
||||
contentService.SaveAndPublish(root);
|
||||
|
||||
contentItems.Add(builder.WithParent(root).WithName("bar").Build());
|
||||
contentItems.Add(builder.WithParent(root).WithName("baz").Build());
|
||||
|
||||
foreach (IContent content in contentItems)
|
||||
{
|
||||
contentService.SaveAndPublish(content);
|
||||
}
|
||||
}
|
||||
|
||||
var queryParameters = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = Constants.UdiEntityType.Document
|
||||
};
|
||||
|
||||
var url = LinkGenerator.GetUmbracoControllerUrl("GetUrlsByIds", typeof(EntityController), queryParameters);
|
||||
|
||||
var payload = new
|
||||
{
|
||||
ids = new[]
|
||||
{
|
||||
contentItems[0].Id,
|
||||
contentItems[1].Id,
|
||||
}
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await HttpClientJsonExtensions.PostAsJsonAsync(Client, url, payload);
|
||||
|
||||
// skip pointless un-parseable cruft.
|
||||
(await response.Content.ReadAsStreamAsync()).Seek(AngularJsonMediaTypeFormatter.XsrfPrefix.Length, SeekOrigin.Begin);
|
||||
|
||||
IDictionary<int, string> results = await response.Content.ReadFromJsonAsync<IDictionary<int, string>>();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.IsTrue(results![payload.ids[0]].StartsWith("/bar"));
|
||||
Assert.IsTrue(results![payload.ids[1]].StartsWith("/baz"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetUrlsByIds_DocumentWithGuidIds_ReturnsValidMap()
|
||||
{
|
||||
IContentTypeService contentTypeService = Services.GetRequiredService<IContentTypeService>();
|
||||
IContentService contentService = Services.GetRequiredService<IContentService>();
|
||||
|
||||
var contentItems = new List<IContent>();
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
IContentType contentType = ContentTypeBuilder.CreateBasicContentType();
|
||||
contentTypeService.Save(contentType);
|
||||
|
||||
ContentBuilder builder = new ContentBuilder()
|
||||
.WithContentType(contentType);
|
||||
|
||||
Content root = builder.WithName("foo").Build();
|
||||
contentService.SaveAndPublish(root);
|
||||
|
||||
contentItems.Add(builder.WithParent(root).WithName("bar").Build());
|
||||
contentItems.Add(builder.WithParent(root).WithName("baz").Build());
|
||||
|
||||
foreach (IContent content in contentItems)
|
||||
{
|
||||
contentService.SaveAndPublish(content);
|
||||
}
|
||||
}
|
||||
|
||||
var queryParameters = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = Constants.UdiEntityType.Document
|
||||
};
|
||||
|
||||
var url = LinkGenerator.GetUmbracoControllerUrl("GetUrlsByIds", typeof(EntityController), queryParameters);
|
||||
|
||||
var payload = new
|
||||
{
|
||||
ids = new[]
|
||||
{
|
||||
contentItems[0].Key.ToString(),
|
||||
contentItems[1].Key.ToString(),
|
||||
}
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await HttpClientJsonExtensions.PostAsJsonAsync(Client, url, payload);
|
||||
|
||||
// skip pointless un-parseable cruft.
|
||||
(await response.Content.ReadAsStreamAsync()).Seek(AngularJsonMediaTypeFormatter.XsrfPrefix.Length, SeekOrigin.Begin);
|
||||
|
||||
IDictionary<string, string> results = await response.Content.ReadFromJsonAsync<IDictionary<string, string>>();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.IsTrue(results![payload.ids[0]].StartsWith("/bar"));
|
||||
Assert.IsTrue(results![payload.ids[1]].StartsWith("/baz"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetUrlsByIds_DocumentWithUdiIds_ReturnsValidMap()
|
||||
{
|
||||
IContentTypeService contentTypeService = Services.GetRequiredService<IContentTypeService>();
|
||||
IContentService contentService = Services.GetRequiredService<IContentService>();
|
||||
|
||||
var contentItems = new List<IContent>();
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
IContentType contentType = ContentTypeBuilder.CreateBasicContentType();
|
||||
contentTypeService.Save(contentType);
|
||||
|
||||
ContentBuilder builder = new ContentBuilder()
|
||||
.WithContentType(contentType);
|
||||
|
||||
Content root = builder.WithName("foo").Build();
|
||||
contentService.SaveAndPublish(root);
|
||||
|
||||
contentItems.Add(builder.WithParent(root).WithName("bar").Build());
|
||||
contentItems.Add(builder.WithParent(root).WithName("baz").Build());
|
||||
|
||||
foreach (IContent content in contentItems)
|
||||
{
|
||||
contentService.SaveAndPublish(content);
|
||||
}
|
||||
}
|
||||
|
||||
var queryParameters = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = Constants.UdiEntityType.Document
|
||||
};
|
||||
|
||||
var url = LinkGenerator.GetUmbracoControllerUrl("GetUrlsByIds", typeof(EntityController), queryParameters);
|
||||
|
||||
var payload = new
|
||||
{
|
||||
ids = new[]
|
||||
{
|
||||
contentItems[0].GetUdi().ToString(),
|
||||
contentItems[1].GetUdi().ToString(),
|
||||
}
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await HttpClientJsonExtensions.PostAsJsonAsync(Client, url, payload);
|
||||
|
||||
// skip pointless un-parseable cruft.
|
||||
(await response.Content.ReadAsStreamAsync()).Seek(AngularJsonMediaTypeFormatter.XsrfPrefix.Length, SeekOrigin.Begin);
|
||||
|
||||
IDictionary<string, string> results = await response.Content.ReadFromJsonAsync<IDictionary<string, string>>();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.IsTrue(results![payload.ids[0]].StartsWith("/bar"));
|
||||
Assert.IsTrue(results![payload.ids[1]].StartsWith("/baz"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetByIds_MultipleCalls_WorksAsExpected()
|
||||
{
|
||||
IContentTypeService contentTypeService = Services.GetRequiredService<IContentTypeService>();
|
||||
IContentService contentService = Services.GetRequiredService<IContentService>();
|
||||
|
||||
var contentItems = new List<IContent>();
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
IContentType contentType = ContentTypeBuilder.CreateBasicContentType();
|
||||
contentTypeService.Save(contentType);
|
||||
|
||||
ContentBuilder builder = new ContentBuilder()
|
||||
.WithContentType(contentType);
|
||||
|
||||
Content root = builder.WithName("foo").Build();
|
||||
contentService.SaveAndPublish(root);
|
||||
|
||||
contentItems.Add(builder.WithParent(root).WithName("bar").Build());
|
||||
contentItems.Add(builder.WithParent(root).WithName("baz").Build());
|
||||
|
||||
foreach (IContent content in contentItems)
|
||||
{
|
||||
contentService.SaveAndPublish(content);
|
||||
}
|
||||
}
|
||||
|
||||
var queryParameters = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = Constants.UdiEntityType.Document
|
||||
};
|
||||
|
||||
var url = LinkGenerator.GetUmbracoControllerUrl("GetByIds", typeof(EntityController), queryParameters);
|
||||
|
||||
var udiPayload = new
|
||||
{
|
||||
ids = new[]
|
||||
{
|
||||
contentItems[0].GetUdi().ToString(),
|
||||
contentItems[1].GetUdi().ToString(),
|
||||
}
|
||||
};
|
||||
|
||||
var intPayload = new
|
||||
{
|
||||
ids = new[]
|
||||
{
|
||||
contentItems[0].Id,
|
||||
contentItems[1].Id,
|
||||
}
|
||||
};
|
||||
|
||||
HttpResponseMessage udiResponse = await HttpClientJsonExtensions.PostAsJsonAsync(Client, url, udiPayload);
|
||||
HttpResponseMessage intResponse = await HttpClientJsonExtensions.PostAsJsonAsync(Client, url, intPayload);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(HttpStatusCode.OK, udiResponse.StatusCode, "First request error");
|
||||
Assert.AreEqual(HttpStatusCode.OK, intResponse.StatusCode, "Second request error");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Infrastructure.Security;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
@@ -10,65 +14,35 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Security
|
||||
[TestFixture]
|
||||
public class MemberPasswordHasherTests
|
||||
{
|
||||
private MemberPasswordHasher CreateSut() => new MemberPasswordHasher(new LegacyPasswordSecurity(), new JsonNetSerializer());
|
||||
|
||||
[Test]
|
||||
public void VerifyHashedPassword_GivenAnAspNetIdentity2PasswordHash_ThenExpectSuccessRehashNeeded()
|
||||
[TestCase("Password123!", "AQAAAAEAACcQAAAAEGF/tTVoL6ef3bQPZFYfbgKFu1CDQIAMgyY1N4EDt9jqdG/hsOX93X1U6LNvlIQ3mw==", null, ExpectedResult = PasswordVerificationResult.Success, Description = "AspNetCoreIdentityPasswordHash: Correct password")]
|
||||
[TestCase("wrongPassword", "AQAAAAEAACcQAAAAEGF/tTVoL6ef3bQPZFYfbgKFu1CDQIAMgyY1N4EDt9jqdG/hsOX93X1U6LNvlIQ3mw==", null, ExpectedResult = PasswordVerificationResult.Failed, Description = "AspNetCoreIdentityPasswordHash: Wrong password")]
|
||||
[TestCase("Password123!", "yDiU2YyuYZU4jz6F0fpErQ==BxNRHkXBVyJs9gwWF6ktWdfDwYf5bwm+rvV7tOcNNx8=", null, ExpectedResult = PasswordVerificationResult.SuccessRehashNeeded, Description = "GivenALegacyPasswordHash: Correct password")]
|
||||
[TestCase("wrongPassword", "yDiU2YyuYZU4jz6F0fpErQ==BxNRHkXBVyJs9gwWF6ktWdfDwYf5bwm+rvV7tOcNNx8=", null, ExpectedResult = PasswordVerificationResult.Failed, Description = "GivenALegacyPasswordHash: Wrong password")]
|
||||
[TestCase("Password123!", "AJszAsQqxOYbASKfL3JVUu6cjU18ouizXDfX4j7wLlir8SWj2yQaTepE9e5bIohIsQ==", null, ExpectedResult = PasswordVerificationResult.SuccessRehashNeeded, Description = "GivenALegacyPasswordHash: Correct password")]
|
||||
[TestCase("wrongPassword", "AJszAsQqxOYbASKfL3JVUu6cjU18ouizXDfX4j7wLlir8SWj2yQaTepE9e5bIohIsQ==", null, ExpectedResult = PasswordVerificationResult.Failed, Description = "GivenALegacyPasswordHash: Wrong password")]
|
||||
[TestCase("1234567890", "1234567890", null, ExpectedResult = PasswordVerificationResult.Failed, Description = "ClearText: Correct password, but not supported")]
|
||||
[TestCase("wrongPassword", "1234567890", null, ExpectedResult = PasswordVerificationResult.Failed, Description = "ClearText: Wrong password")]
|
||||
[TestCase("1234567890", "XyFRG4/xJ5JGQJYqqIFK70BjHdM=", null, ExpectedResult = PasswordVerificationResult.SuccessRehashNeeded, Description = "Hashed: Correct password")]
|
||||
[TestCase("wrongPassword", "XyFRG4/xJ5JGQJYqqIFK70BjHdM=", null, ExpectedResult = PasswordVerificationResult.Failed, Description = "Hashed: Wrong password")]
|
||||
[TestCase("1234567890", "K2JPOhoqNoysfnnD67QsWDSliHrjoSTRTvv9yiaKf30=", "1D43BFA074DF6DCEF6E44A7F5B5F56CDDD60BE198FBBB0222C96A5BD696F3CAA", ExpectedResult = PasswordVerificationResult.SuccessRehashNeeded, Description = "Encrypted: Correct password and correct decryptionKey")]
|
||||
[TestCase("wrongPassword", "K2JPOhoqNoysfnnD67QsWDSliHrjoSTRTvv9yiaKf30=", "1D43BFA074DF6DCEF6E44A7F5B5F56CDDD60BE198FBBB0222C96A5BD696F3CAA", ExpectedResult = PasswordVerificationResult.Failed, Description = "Encrypted: Wrong password but correct decryptionKey")]
|
||||
[TestCase("1234567890", "qiuwRr4K7brpTcIzLFfR3iGG9zj4/z4ewHCVZmYUDKM=", "B491B602E0CE1D52450A8089FD2013B340743A7EFCC12B039BD11977A083ACA1", ExpectedResult = PasswordVerificationResult.Failed, Description = "Encrypted: Correct password but wrong decryptionKey")]
|
||||
[TestCase("1234567890", "qiuwRr4K7brpTcIzLFfR3iGG9zj4/z4ewHCVZmYUDKM=", "InvalidDecryptionKey", ExpectedResult = PasswordVerificationResult.Failed, Description = "Encrypted: Invalid decryptionKey")]
|
||||
public PasswordVerificationResult VerifyHashedPassword(string password, string encryptedPassword, string decryptionKey)
|
||||
{
|
||||
const string password = "Password123!";
|
||||
const string hash = "AJszAsQqxOYbASKfL3JVUu6cjU18ouizXDfX4j7wLlir8SWj2yQaTepE9e5bIohIsQ==";
|
||||
var member = new MemberIdentityUser() { PasswordConfig = null };
|
||||
|
||||
var sut = CreateSut();
|
||||
var result = sut.VerifyHashedPassword(new MemberIdentityUser(), hash, password);
|
||||
var sut = new MemberPasswordHasher(
|
||||
new LegacyPasswordSecurity(),
|
||||
new JsonNetSerializer(),
|
||||
Options.Create<LegacyPasswordMigrationSettings>(new LegacyPasswordMigrationSettings()
|
||||
{
|
||||
MachineKeyDecryptionKey = decryptionKey
|
||||
}),
|
||||
NullLoggerFactory.Instance.CreateLogger<MemberPasswordHasher>());
|
||||
|
||||
Assert.AreEqual(result, PasswordVerificationResult.SuccessRehashNeeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyHashedPassword_GivenAnAspNetCoreIdentityPasswordHash_ThenExpectSuccess()
|
||||
{
|
||||
const string password = "Password123!";
|
||||
const string hash = "AQAAAAEAACcQAAAAEGF/tTVoL6ef3bQPZFYfbgKFu1CDQIAMgyY1N4EDt9jqdG/hsOX93X1U6LNvlIQ3mw==";
|
||||
|
||||
var sut = CreateSut();
|
||||
var result = sut.VerifyHashedPassword(new MemberIdentityUser(), hash, password);
|
||||
|
||||
Assert.AreEqual(result, PasswordVerificationResult.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyHashedPassword_GivenALegacyPasswordHash_ThenExpectSuccessRehashNeeded()
|
||||
{
|
||||
const string password = "Password123!";
|
||||
const string hash = "yDiU2YyuYZU4jz6F0fpErQ==BxNRHkXBVyJs9gwWF6ktWdfDwYf5bwm+rvV7tOcNNx8=";
|
||||
|
||||
var sut = CreateSut();
|
||||
var result = sut.VerifyHashedPassword(new MemberIdentityUser(), hash, password);
|
||||
|
||||
Assert.AreEqual(result, PasswordVerificationResult.SuccessRehashNeeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyHashedPassword_GivenAnUnknownBase64Hash_ThenExpectInvalidOperationException()
|
||||
{
|
||||
var hashBytes = new byte[] {3, 2, 1};
|
||||
var hash = Convert.ToBase64String(hashBytes);
|
||||
|
||||
var sut = CreateSut();
|
||||
Assert.Throws<InvalidOperationException>(() => sut.VerifyHashedPassword(new MemberIdentityUser(), hash, "password"));
|
||||
}
|
||||
|
||||
[TestCase("AJszAsQqxOYbASKfL3JVUu6cjU18ouizXDfX4j7wLlir8SWj2yQaTepE9e5bIohIsQ==")]
|
||||
[TestCase("AQAAAAEAACcQAAAAEGF/tTVoL6ef3bQPZFYfbgKFu1CDQIAMgyY1N4EDt9jqdG/hsOX93X1U6LNvlIQ3mw==")]
|
||||
[TestCase("yDiU2YyuYZU4jz6F0fpErQ==BxNRHkXBVyJs9gwWF6ktWdfDwYf5bwm+rvV7tOcNNx8=")]
|
||||
public void VerifyHashedPassword_GivenAnInvalidPassword_ThenExpectFailure(string hash)
|
||||
{
|
||||
const string invalidPassword = "nope";
|
||||
|
||||
var sut = CreateSut();
|
||||
var result = sut.VerifyHashedPassword(new MemberIdentityUser(), hash, invalidPassword);
|
||||
|
||||
Assert.AreEqual(result, PasswordVerificationResult.Failed);
|
||||
return sut.VerifyHashedPassword(member, encryptedPassword, password);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
using AutoFixture;
|
||||
using AutoFixture.AutoMoq;
|
||||
using AutoFixture.Kernel;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Smidge;
|
||||
using Smidge.Cache;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Semver;
|
||||
using Umbraco.Cms.Web.Common.RuntimeMinification;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Common.RuntimeMinification
|
||||
{
|
||||
/// <remarks>
|
||||
/// UmbracoCustomizations kindly configures an IUmbracoVersion so we need to go verbose without AutoMoqData
|
||||
/// </remarks>
|
||||
[TestFixture]
|
||||
public class UmbracoSmidgeConfigCacheBusterTests
|
||||
{
|
||||
[Test]
|
||||
public void GetValue_DefaultReleaseSetupWithNoConfiguredVersion_HasSensibleDefaults()
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
fixture.Customize(new AutoMoqCustomization());
|
||||
|
||||
var umbracoVersion = fixture.Freeze<Mock<IUmbracoVersion>>();
|
||||
var entryAssemblyMetadata = fixture.Freeze<Mock<IEntryAssemblyMetadata>>();
|
||||
var sut = fixture.Create<UmbracoSmidgeConfigCacheBuster>();
|
||||
|
||||
umbracoVersion.Setup(x => x.SemanticVersion).Returns(new SemVersion(9, 4, 5, "beta", "41658f99"));
|
||||
entryAssemblyMetadata.Setup(x => x.Name).Returns("Bills.Brilliant.Bakery");
|
||||
entryAssemblyMetadata.Setup(x => x.InformationalVersion).Returns("42.1.2-alpha+41658f99");
|
||||
|
||||
var result = sut.GetValue();
|
||||
|
||||
var expected = $"Bills.Brilliant.Bakery_9.4.5-beta+41658f99_42.1.2-alpha+41658f99".GenerateHash();
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_DefaultReleaseSetupWithConfiguredVersion_HasSensibleDefaults()
|
||||
{
|
||||
var config = Options.Create(new RuntimeMinificationSettings { Version = "1" });
|
||||
var fixture = new Fixture();
|
||||
fixture.Customize(new AutoMoqCustomization());
|
||||
fixture.Inject(config);
|
||||
|
||||
var umbracoVersion = fixture.Freeze<Mock<IUmbracoVersion>>();
|
||||
var entryAssemblyMetadata = fixture.Freeze<Mock<IEntryAssemblyMetadata>>();
|
||||
var sut = fixture.Create<UmbracoSmidgeConfigCacheBuster>();
|
||||
|
||||
umbracoVersion.Setup(x => x.SemanticVersion).Returns(new SemVersion(9, 4, 5, "beta", "41658f99"));
|
||||
entryAssemblyMetadata.Setup(x => x.Name).Returns("Bills.Brilliant.Bakery");
|
||||
entryAssemblyMetadata.Setup(x => x.InformationalVersion).Returns("42.1.2-alpha+41658f99");
|
||||
|
||||
var result = sut.GetValue();
|
||||
|
||||
var expected = $"1_9.4.5-beta+41658f99_42.1.2-alpha+41658f99".GenerateHash();
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_DefaultReleaseSetupWithNoConfiguredVersion_ChangesWhenUmbracoVersionChanges()
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
fixture.Customize(new AutoMoqCustomization());
|
||||
|
||||
var umbracoVersion = fixture.Freeze<Mock<IUmbracoVersion>>();
|
||||
var entryAssemblyMetadata = fixture.Freeze<Mock<IEntryAssemblyMetadata>>();
|
||||
var sut = fixture.Create<UmbracoSmidgeConfigCacheBuster>();
|
||||
|
||||
umbracoVersion.Setup(x => x.SemanticVersion).Returns(new SemVersion(9, 4, 5, "beta", "41658f99"));
|
||||
entryAssemblyMetadata.Setup(x => x.Name).Returns("Bills.Brilliant.Bakery");
|
||||
entryAssemblyMetadata.Setup(x => x.InformationalVersion).Returns("42.1.2-alpha+41658f99");
|
||||
|
||||
var before = sut.GetValue();
|
||||
|
||||
umbracoVersion.Setup(x => x.SemanticVersion).Returns(new SemVersion(9, 5, 0, "beta", "41658f99"));
|
||||
sut = fixture.Create<UmbracoSmidgeConfigCacheBuster>();
|
||||
|
||||
var after = sut.GetValue();
|
||||
|
||||
Assert.AreNotEqual(before, after);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_DefaultReleaseSetupWithNoConfiguredVersion_ChangesWhenDownstreamVersionChanges()
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
fixture.Customize(new AutoMoqCustomization());
|
||||
|
||||
var umbracoVersion = fixture.Freeze<Mock<IUmbracoVersion>>();
|
||||
var entryAssemblyMetadata = fixture.Freeze<Mock<IEntryAssemblyMetadata>>();
|
||||
var sut = fixture.Create<UmbracoSmidgeConfigCacheBuster>();
|
||||
|
||||
umbracoVersion.Setup(x => x.SemanticVersion).Returns(new SemVersion(9, 4, 5, "beta", "41658f99"));
|
||||
entryAssemblyMetadata.Setup(x => x.Name).Returns("Bills.Brilliant.Bakery");
|
||||
entryAssemblyMetadata.Setup(x => x.InformationalVersion).Returns("42.1.2-alpha+41658f99");
|
||||
|
||||
var before = sut.GetValue();
|
||||
|
||||
entryAssemblyMetadata.Setup(x => x.InformationalVersion).Returns("42.2.0-rc");
|
||||
sut = fixture.Create<UmbracoSmidgeConfigCacheBuster>();
|
||||
|
||||
var after = sut.GetValue();
|
||||
|
||||
Assert.AreNotEqual(before, after);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user