Merge branch 'v9/contrib' into temp-11381

This commit is contained in:
Mole
2021-12-21 09:42:39 +01:00
598 changed files with 24731 additions and 47642 deletions

5
tests/.editorconfig Normal file
View File

@@ -0,0 +1,5 @@
root = false
[*.cs]
csharp_style_var_when_type_is_apparent = true:none
csharp_style_var_elsewhere = true:none

View File

@@ -343,17 +343,11 @@ context('Content', () => {
// Rollback
cy.get('.umb-box-header :button').click();
cy.get('.umb-box-content > div > .input-block-level')
.find('option[label*=' + new Date().getDate() + ']')
.then(elements => {
const option = elements[elements.length - 1].getAttribute('value');
cy.get('.umb-box-content > div > .input-block-level')
.select(option);
});
cy.get('.-selectable.cursor-pointer:first').click();
cy.get('.umb-editor-footer-content__right-side > [button-style="success"] > .umb-button > .btn-success').click();
cy.reload();
refreshContentTree();
// Assert
cy.get('.history').find('.umb-badge').contains('Save').should('be.visible');
@@ -759,7 +753,8 @@ context('Content', () => {
// Click macro
cy.get(':nth-child(4) > .umb-card-grid-item > :nth-child(1)').click();
// Select the macro
cy.get('.umb-card-grid-item').contains(macroName).click();
cy.get(`.umb-card-grid-item[title='${macroName}']`).click('bottom');
// Save and publish
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').click();

View File

@@ -0,0 +1,366 @@
/// <reference types="Cypress" />
import {
DocumentTypeBuilder,
ContentBuilder
} from 'umbraco-cypress-testhelpers';
context('Routing', () => {
let swedishLanguageId = 0;
const swedishCulture = "sv";
const danishCulture = "da"
const nodeName = "Root";
const childNodeName = "Child";
const grandChildNodeName = "Grandchild";
const rootDocTypeName = "Test document type";
function refreshContentTree() {
// Refresh to update the tree
cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick();
cy.umbracoContextMenuAction("action-refreshNode").click();
// We have to wait in case the execution is slow, otherwise we'll try and click the item before it appears in the UI
cy.get('.umb-tree-item__inner').should('exist', {timeout: 10000});
}
function saveNewLanguages() {
// Save Danish
const url = "/umbraco/backoffice/umbracoapi/language/SaveLanguage";
const danishRequestBody = {
culture: danishCulture
}
cy.umbracoApiRequest(url, "POST", danishRequestBody);
// Save Swedish
const swedishRequestBody = {
culture: swedishCulture
}
cy.umbracoApiRequest(url, "POST", swedishRequestBody).then((responseBody) => {
swedishLanguageId = responseBody["id"];
});
}
function configureDomain(id, name, lang) {
//Save domain for child node
const url = "/umbraco/backoffice/umbracoapi/content/PostSaveLanguageAndDomains"
const body = {
nodeId : id,
domains : [
{
name : name,
lang : lang
}],
language : 0
}
cy.umbracoApiRequest(url, 'POST', body);
}
beforeEach(() => {
cy.umbracoLogin(Cypress.env('username'), Cypress.env('password'));
// Ensure cleaned before tests run
cy.deleteAllContent();
cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName);
cy.umbracoEnsureLanguageNotExists(danishCulture);
cy.umbracoEnsureLanguageNotExists(swedishCulture);
});
afterEach(() => {
// Cleanup after tests
cy.deleteAllContent();
cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName);
cy.umbracoEnsureLanguageNotExists(danishCulture);
cy.umbracoEnsureLanguageNotExists(swedishCulture);
})
it('Root node published in language A, Child node published in language A', () => {
const rootDocType = new DocumentTypeBuilder()
.withName(rootDocTypeName)
.withAllowAsRoot(true)
.withAllowCultureVariation(true)
.build();
saveNewLanguages();
cy.saveDocumentType(rootDocType).then((generatedRootDocType) => {
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(generatedRootDocType["alias"])
.withAction("publishNew")
.addVariant()
.withCulture('en-US')
.withName(nodeName)
.withSave(true)
.withPublish(true)
.done()
.build();
cy.saveContent(rootContentNode).then((generatedRootContent) => {
const childContentNode = new ContentBuilder()
.withContentTypeAlias(generatedRootDocType["alias"])
.withAction("saveNew")
.withParent(generatedRootContent["id"])
.addVariant()
.withCulture('en-US')
.withName(childNodeName)
.withSave(true)
.done()
.build();
cy.saveContent(childContentNode);
});
});
// Refresh to update the tree
refreshContentTree();
cy.umbracoTreeItem("content", [nodeName, childNodeName]).click();
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').click();
// Pop-up with what cultures you want to publish shows, click it
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').last().click();
// Assert
cy.get('.alert-success').should('exist');
});
it('Root node published in language A, Child node published in language B', () => {
const rootDocType = new DocumentTypeBuilder()
.withName(rootDocTypeName)
.withAllowAsRoot(true)
.withAllowCultureVariation(true)
.build();
saveNewLanguages();
cy.saveDocumentType(rootDocType).then((generatedRootDocType) => {
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(generatedRootDocType["alias"])
.withAction("publishNew")
.addVariant()
.withCulture('en-US')
.withName(nodeName)
.withSave(true)
.withPublish(true)
.done()
.build();
cy.saveContent(rootContentNode).then((generatedRootContent) => {
const childContentNode = new ContentBuilder()
.withContentTypeAlias(generatedRootDocType["alias"])
.withAction("saveNew")
.withParent(generatedRootContent["id"])
.addVariant()
.withCulture('en-US')
.withName(childNodeName)
.withSave(true)
.done()
.addVariant()
.withCulture(swedishCulture)
.withName("Bärn")
.withSave(true)
.done()
.build();
cy.saveContent(childContentNode);
});
});
// Refresh to update the tree
refreshContentTree();
cy.umbracoTreeItem("content", [nodeName, childNodeName]).click();
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').click();
// Pop-up with what cultures you want to publish shows, click it
cy.get('.umb-list').should('be.visible');
cy.get('.checkbox').last().click();
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').last().click();
// Assert
cy.get('.alert-success').should('have.length', 2);
cy.get('.alert-warning').should('exist');
});
it('Root node published in language A, Child node published in language A + B, Grandchild published in A + B', () => {
const rootDocType = new DocumentTypeBuilder()
.withName(rootDocTypeName)
.withAllowAsRoot(true)
.withAllowCultureVariation(true)
.build();
saveNewLanguages();
cy.saveDocumentType(rootDocType).then((generatedRootDocType) => {
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(generatedRootDocType["alias"])
.withAction("publishNew")
.addVariant()
.withCulture('en-US')
.withName(nodeName)
.withSave(true)
.withPublish(true)
.done()
.build();
cy.saveContent(rootContentNode).then((generatedRootContent) => {
configureDomain(generatedRootContent["id"], "/en", 1);
const childContentNode = new ContentBuilder()
.withContentTypeAlias(generatedRootDocType["alias"])
.withAction("saveNew")
.withParent(generatedRootContent["id"])
.addVariant()
.withCulture('en-US')
.withName(childNodeName)
.withSave(true)
.done()
.addVariant()
.withCulture(swedishCulture)
.withName("Barn")
.withSave(true)
.done()
.build();
cy.saveContent(childContentNode).then((generatedChildContent) => {
configureDomain(generatedChildContent["id"], "/sv", swedishLanguageId);
const grandChildContentNode = new ContentBuilder()
.withContentTypeAlias(generatedRootDocType["alias"])
.withAction("saveNew")
.withParent(generatedChildContent["id"])
.addVariant()
.withCulture('en-US')
.withName(grandChildNodeName)
.withSave(true)
.done()
.addVariant()
.withCulture(swedishCulture)
.withName("Barnbarn")
.withSave(true)
.done()
.build();
cy.saveContent(grandChildContentNode);
});
});
});
// Refresh to update the tree
refreshContentTree();
// Publish Child
cy.umbracoTreeItem("content", [nodeName, childNodeName]).click();
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').click();
//Pop-up with what cultures you want to publish shows, click it
cy.get('.umb-list').should('be.visible');
cy.get('.checkbox').last().click();
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').last().click();
// Publish Grandchild
cy.umbracoTreeItem("content", [nodeName, childNodeName, grandChildNodeName]).click();
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').click();
// Pop-up with what cultures you want to publish shows, click it
cy.get('.umb-list').should('be.visible');
cy.get('.checkbox').last().click();
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').last().click();
// Assert
cy.get('.alert-success').should('have.length', 2);
cy.get('.alert-warning').should('not.exist');
});
it('Root node published in language A, Child node published in language A + B, Grandchild published in A + B + C', () => {
const rootDocType = new DocumentTypeBuilder()
.withName(rootDocTypeName)
.withAllowAsRoot(true)
.withAllowCultureVariation(true)
.build();
saveNewLanguages();
cy.saveDocumentType(rootDocType).then((generatedRootDocType) => {
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(generatedRootDocType["alias"])
.withAction("publishNew")
.addVariant()
.withCulture('en-US')
.withName(nodeName)
.withSave(true)
.withPublish(true)
.done()
.build();
cy.saveContent(rootContentNode).then((generatedRootContent) => {
configureDomain(generatedRootContent["id"], "/en", 1);
const childContentNode = new ContentBuilder()
.withContentTypeAlias(generatedRootDocType["alias"])
.withAction("saveNew")
.withParent(generatedRootContent["id"])
.addVariant()
.withCulture('en-US')
.withName(childNodeName)
.withSave(true)
.done()
.addVariant()
.withCulture(swedishCulture)
.withName("Barn")
.withSave(true)
.done()
.build();
cy.saveContent(childContentNode).then((generatedChildContent) => {
configureDomain(generatedChildContent["id"], "/sv", swedishLanguageId);
const grandChildContentNode = new ContentBuilder()
.withContentTypeAlias(generatedRootDocType["alias"])
.withAction("saveNew")
.withParent(generatedChildContent["id"])
.addVariant()
.withCulture('en-US')
.withName(grandChildNodeName)
.withSave(true)
.done()
.addVariant()
.withCulture(swedishCulture)
.withName("Barnbarn")
.withSave(true)
.done()
.addVariant()
.withCulture(danishCulture)
.withName("Barnebarn")
.withSave(true)
.done()
.build();
cy.saveContent(grandChildContentNode);
});
});
});
// Refresh to update the tree
refreshContentTree();
// Publish Child
cy.umbracoTreeItem("content", [nodeName, childNodeName]).click();
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').click();
// Pop-up with what cultures you want to publish shows, click it
cy.get('.umb-list').should('be.visible');
cy.get('.checkbox').last().click();
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').last().click();
// Publish Grandchild
cy.umbracoTreeItem("content", [nodeName, childNodeName, grandChildNodeName]).click();
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').click();
// Pop-up with what cultures you want to publish shows, click it
cy.get('.umb-list').should('be.visible');
cy.get('.checkbox').click({multiple : true});
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').last().click();
// Assert
cy.get('.alert-success').should('exist');
cy.get('.alert-warning').should('exist');
});
});

View File

@@ -8,8 +8,8 @@ import {
context('DataTypes', () => {
beforeEach(() => {
cy.umbracoLogin(Cypress.env('username'), Cypress.env('password'), false);
});
cy.umbracoLogin(Cypress.env('username'), Cypress.env('password'));
});
it('Tests Approved Colors', () => {
cy.deleteAllContent();
@@ -26,6 +26,12 @@ context('DataTypes', () => {
//umbracoMakeDocTypeWithDataTypeAndContent(name, alias, pickerDataType);
cy.umbracoCreateDocTypeWithContent(name, alias, pickerDataType);
//Editing template with some content
cy.editTemplate(name, '@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ApprovedColourTest>' +
'\n@{' +
'\n Layout = null;' +
'\n}' +
'\n<p style="color:@Model.UmbracoTest">Lorem ipsum dolor sit amet</p>');
// Act
// Enter content
@@ -36,22 +42,19 @@ context('DataTypes', () => {
//Save
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').click();
cy.umbracoSuccessNotification().should('be.visible');
//Editing template with some content
cy.editTemplate(name, '@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ApprovedColourTest>' +
'\n@{' +
'\n Layout = null;' +
'\n}' +
'\n<p style="color:@Model.UmbracoTest">Lorem ipsum dolor sit amet</p>');
//Assert
const expected = `<p style="color:000000" > Lorem ipsum dolor sit amet </p>`;
cy.umbracoVerifyRenderedViewContent('/', expected, true).should('be.true');
cy.get('.umb-button__overlay').should('not.be.visible');
//Pick another colour to verify both work
cy.get('.btn-FF0000').click();
//Save
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').click();
cy.umbracoSuccessNotification().should('be.visible');
cy.umbracoButtonByLabelKey('buttons_saveAndPublish').should('be.visible');
cy.get('.umb-button__overlay').should('not.be.visible');
//Assert
const expected2 = '<p style="color:FF0000">Lorem ipsum dolor sit amet</p>';
cy.umbracoVerifyRenderedViewContent('/', expected2, true).should('be.true');
@@ -100,6 +103,7 @@ context('DataTypes', () => {
cy.get('.property-error').should('be.visible');
// Clean
cy.umbracoEnsureTemplateNameNotExists(name);
cy.umbracoEnsureDataTypeNameNotExists(name);
cy.umbracoEnsureDocumentTypeNameNotExists(name);
})

View File

@@ -24,7 +24,7 @@ context('System Information', () => {
cy.contains('Current Culture').parent().should('contain', 'en-US');
cy.contains('Current UI Culture').parent().should('contain', 'en-US');
});
it('Checks language displays correctly after switching', () => {
//Navigate to edit user and change language
@@ -32,10 +32,8 @@ context('System Information', () => {
cy.get('[alias="editUser"]').click();
cy.get('[name="culture"]').select('string:da-DK', { force: true});
cy.umbracoButtonByLabelKey('buttons_save').click({force: true});
//Refresh site to display new language
cy.reload();
cy.get('.umb-tour-step', { timeout: 60000 }).should('be.visible'); // We now due to the api calls this will be shown, but slow computers can take a while
cy.get('.umb-tour-step__close').click();
cy.umbracoSuccessNotification().should('be.visible');
openSystemInformation();
//Assert
cy.contains('Current Culture').parent().should('contain', 'da-DK');

View File

@@ -0,0 +1,61 @@
/// <reference types="Cypress" />
context('Languages', () => {
beforeEach(() => {
cy.umbracoLogin(Cypress.env('username'), Cypress.env('password'), false);
});
it('Creates language', () => {
// Setup
const language = 'Danish';
const culture = 'da';
cy.umbracoEnsureLanguageCultureNotExists(culture);
cy.umbracoSection('settings');
// Enter language tree and create new language
cy.umbracoTreeItem('settings', ['Languages']).click();
cy.umbracoButtonByLabelKey('languages_addLanguage').click();
cy.get('select[name="newLang"]').select(language);
// Save and assert success
cy.umbracoButtonByLabelKey('buttons_save').click();
cy.umbracoSuccessNotification().should('be.visible');
// Cleanup
cy.umbracoEnsureLanguageCultureNotExists(culture);
});
it('Deletes language', () => {
// Setup
const language1 = 'da';
const language2 = 'en-GB';
cy.umbracoEnsureLanguageCultureNotExists(language1);
cy.umbracoEnsureLanguageCultureNotExists(language2);
cy.umbracoCreateLanguage(language1, true, '1');
cy.umbracoCreateLanguage(language2, true, '1');
//Enter settings section and wait for everything to load
cy.umbracoSection('settings');
cy.get('.umb-box-content').should('be.visible');
cy.get('li .umb-tree-root:contains("Settings")').should("be.visible");
// Enter language tree and select the language we just created
cy.umbracoTreeItem('settings', ['Languages']).click();
// Assert there are 3 languages
cy.get('tbody > tr').should('have.length', 3);
// Delete UK Language
cy.get('umb-button[label-key="general_delete"]').last().click();
cy.umbracoButtonByLabelKey('contentTypeEditor_yesDelete').click();
// Assert there is only 2 languages
cy.get('tbody > tr').should('have.length', 2);
// Cleanup
cy.umbracoEnsureLanguageCultureNotExists(language1);
cy.umbracoEnsureLanguageCultureNotExists(language2);
});
});

View File

@@ -16,7 +16,7 @@ context('Media Types', () => {
cy.umbracoTreeItem("settings", ["Media Types"]).rightclick();
cy.umbracoContextMenuAction("action-create").click();
cy.get('.menu-label').first().click(); // TODO: Fucked we cant use something like cy.umbracoContextMenuAction("action-mediaType").click();
cy.get('.menu-label localize[key="content_mediatype"]').click();
//Type name

View File

@@ -29,7 +29,7 @@ context('Partial View Macro Files', () => {
openPartialViewMacroCreatePanel();
cy.get('.menu-label').first().click(); // TODO: Fucked we cant use something like cy.umbracoContextMenuAction("action-label").click();
cy.get('.menu-label localize[key="create_newPartialViewMacro"]').click();
//Type name
cy.umbracoEditorHeaderName(name);

View File

@@ -26,7 +26,7 @@ context('Partial Views', () => {
openPartialViewsCreatePanel();
cy.umbracoContextMenuAction("action-create").click();
cy.get('.menu-label').first().click(); // TODO: Fucked we cant use something like cy.umbracoContextMenuAction("action-mediaType").click();
cy.get('.menu-label localize[key="create_newEmptyPartialView"]').click();
//Type name
cy.umbracoEditorHeaderName(name);
@@ -73,7 +73,7 @@ context('Partial Views', () => {
openPartialViewsCreatePanel();
cy.umbracoContextMenuAction("action-create").click();
cy.get('.menu-label').first().click();
cy.get('.menu-label localize[key="create_newEmptyPartialView"]').click();
// The test would fail intermittently, most likely because the editor didn't have time to load
// This should ensure that the editor is loaded and the test should no longer fail unexpectedly.

View File

@@ -23,7 +23,10 @@ context('Scripts', () => {
cy.umbracoTreeItem("settings", ["Scripts"]).rightclick();
cy.umbracoContextMenuAction("action-create").click();
cy.get('.menu-label').first().click(); // TODO: Fucked we cant use something like cy.umbracoContextMenuAction("action-mediaType").click();
cy.get('.menu-label localize[key="create_newJavascriptFile"]').click();
//We have to wait here till everything is loaded, or worker will throw error
cy.intercept('/umbraco/lib/ace-builds/src-min-noconflict/worker-javascript.js').as('aceWorker');
cy.wait('@aceWorker');
//Type name
cy.umbracoEditorHeaderName(name);
@@ -33,6 +36,8 @@ context('Scripts', () => {
//Assert
cy.umbracoSuccessNotification().should('be.visible');
cy.umbracoScriptExists(fileName).should('be.true');

View File

@@ -1,15 +1,21 @@
/// <reference types="Cypress" />
context('Stylesheets', () => {
const name = "TestStylesheet";
const fileName = name + ".css";
beforeEach(() => {
cy.umbracoLogin(Cypress.env('username'), Cypress.env('password'));
cy.umbracoEnsureStylesheetNameNotExists(fileName);
});
afterEach(() => {
// Clean up, this ensures that even if tests break we clean up
cy.umbracoEnsureStylesheetNameNotExists(fileName);
});
it('Create new style sheet file', () => {
const name = "TestStylesheet";
const fileName = name + ".css";
cy.umbracoEnsureStylesheetNameNotExists(fileName);
cy.umbracoSection('settings');
cy.get('li .umb-tree-root:contains("Settings")').should("be.visible");
@@ -17,19 +23,52 @@ context('Stylesheets', () => {
cy.umbracoTreeItem("settings", ["Stylesheets"]).rightclick();
cy.umbracoContextMenuAction("action-create").click();
cy.get('.menu-label').first().click(); // TODO: Fucked we cant use something like cy.umbracoContextMenuAction("action-mediaType").click();
cy.get('.menu-label').first().click(); // TODO: Would be better to use something like cy.umbracoContextMenuAction("action-mediaType").click();
// We have to wait here till everything is loaded, or worker will throw error
cy.intercept('/umbraco/lib/ace-builds/src-min-noconflict/worker-css.js').as('aceWorker');
cy.wait('@aceWorker');
//Type name
// Type name
cy.umbracoEditorHeaderName(name);
//Save
// Save
cy.get('.btn-success').click();
//Assert
// Assert
cy.umbracoSuccessNotification().should('be.visible');
//Clean up
cy.umbracoEnsureStylesheetNameNotExists(fileName);
});
it('Deletes a stylesheet', () => {
var stylesheetData = {
"virtualPath": "/css/",
"path": null,
"name": name,
"content": "",
"fileType": "stylesheets",
"snippet": null,
"id": "0",
"notifications": []
}
let url = '/umbraco/backoffice/umbracoapi/codefile/PostSave'
cy.umbracoApiRequest(url, 'POST', stylesheetData);
// Navigate to Settings section
cy.umbracoSection('settings');
cy.get('li .umb-tree-root:contains("Settings")').should("be.visible");
// Open stylesheet tree
cy.get('[data-element="tree-item-stylesheets"] > .umb-tree-item__inner > .umb-tree-item__arrow').click();
// Delete stylesheet
cy.get('.umb-tree-item__inner > .umb-tree-item__label').contains(name).rightclick();
cy.get('.umb-action-link').click();
cy.get('[ng-if="showConfirm"]').click();
// Assert
cy.get('.umb-tree-item__inner > .umb-tree-item__label').contains(name).should('not.exist');
});
});

View File

@@ -68,7 +68,9 @@ context('Templates', () => {
// Open partial view
cy.umbracoTreeItem("settings", ["Templates", name]).click();
// Edit
cy.get('.ace_text-input').type(edit, {force:true} );
cy.get('.ace_content').type(edit);
cy.get('.ace_content').contains(edit).should('be.visible');
cy.get('.btn-success').should('be.visible')
// Navigate away
cy.umbracoSection('content');
@@ -101,7 +103,9 @@ context('Templates', () => {
// Open partial view
cy.umbracoTreeItem("settings", ["Templates", name]).click();
// Edit
cy.get('.ace_text-input').type(edit, {force:true} );
cy.get('.ace_content').type(edit);
cy.get('.ace_content').contains(edit).should('be.visible');
cy.get('.btn-success').should('be.visible')
// Navigate away
cy.umbracoSection('content');
@@ -136,7 +140,7 @@ context('Templates', () => {
// Insert macro
cy.umbracoButtonByLabelKey('general_insert').click();
cy.get('.umb-insert-code-box__title').contains('Macro').click();
cy.get('.umb-card-grid-item').contains(name).click();
cy.get(`.umb-card-grid-item[title='${name}']`).click('bottom');
// Assert
cy.get('.ace_content').contains('@await Umbraco.RenderMacroAsync("' + name + '")').should('exist');

View File

@@ -1,29 +1,30 @@
/// <reference types="Cypress" />
import {
DocumentTypeBuilder,
import {
DocumentTypeBuilder,
AliasHelper
} from 'umbraco-cypress-testhelpers';
const tabsDocTypeName = 'Tabs Test Document';
const tabsDocTypeAlias = AliasHelper.toAlias(tabsDocTypeName);
context('Tabs', () => {
beforeEach(() => {
cy.umbracoLogin(Cypress.env('username'), Cypress.env('password'), false);
});
afterEach(() => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName)
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
cy.umbracoEnsureTemplateNameNotExists(tabsDocTypeName);
});
function OpenDocTypeFolder(){
cy.umbracoSection('settings');
// We have to wait in case the execution is slow, otherwise we'll try and click the item before it appears in the UI
cy.get('li .umb-tree-root:contains("Settings")').should("be.visible");
cy.get('.umb-tree-item__inner > .umb-tree-item__arrow').eq(0).click();
cy.get('.umb-tree-item__inner > .umb-tree-item__label').contains(tabsDocTypeName).click();
cy.umbracoTreeItem('settings', ["Document Types", tabsDocTypeName]).click();
}
function CreateDocWithTabAndNavigate(){
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -44,8 +45,8 @@ import {
cy.saveDocumentType(tabsDocType);
OpenDocTypeFolder();
}
it('Create tab', () => {
it('Create tab', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
cy.deleteAllContent();
const tabsDocType = new DocumentTypeBuilder()
@@ -72,13 +73,13 @@ import {
cy.get('[aria-hidden="false"] > .umb-box-content > .umb-group-builder__group-add-property').click();
cy.get('.editor-label').type('property name');
cy.get('[data-element="editor-add"]').click();
//Search for textstring
cy.get('#datatype-search').type('Textstring');
// Choose first item
cy.get('[title="Textstring"]').closest("li").click();
// Save property
cy.get('.btn-success').last().click();
cy.umbracoButtonByLabelKey('buttons_save').click();
@@ -87,21 +88,19 @@ import {
cy.get('[title="tab1"]').should('be.visible');
cy.get('[title="tab2"]').should('be.visible');
});
it('Delete tabs', () => {
it('Delete tabs', () => {
CreateDocWithTabAndNavigate();
//Check if tab is there, else if it wasnt created, this test would always pass
cy.get('[title="aTab 1"]').should('be.visible');
//Delete a tab
cy.get('.btn-reset > .icon-trash').click();
cy.get('.btn-reset > [icon="icon-trash"]').first().click();
cy.get('.umb-button > .btn').last().click();
cy.umbracoButtonByLabelKey('buttons_save').click();
//Assert
cy.get('[title="aTab 1"]').should('not.exist');
//Clean
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
});
it('Delete property in tab', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -132,7 +131,7 @@ import {
cy.get('[title=urlPicker]').should('be.visible');
cy.get('[title=picker]').should('not.exist');
});
it('Delete group in tab', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -159,7 +158,7 @@ import {
cy.saveDocumentType(tabsDocType);
OpenDocTypeFolder();
//Delete group
cy.get('.umb-group-builder__group-remove > .icon-trash').eq(1).click();
cy.get('.umb-group-builder__group-remove > [icon="icon-trash"]').eq(1).click();
cy.umbracoButtonByLabelKey('actions_delete').click();
cy.umbracoButtonByLabelKey('buttons_save').click()
//Assert
@@ -167,7 +166,7 @@ import {
cy.get('[title=picker]').should('be.visible');
cy.get('[title=urlPicker]').should('not.exist');
});
it('Reorders tab', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -219,7 +218,7 @@ import {
cy.get('.umb-group-builder__group-title-input').eq(1).invoke('attr', 'title').should('eq', 'aTab 3')
cy.get('.umb-group-builder__group-title-input').eq(2).invoke('attr', 'title').should('eq', 'aTab 1')
});
it('Reorders groups in a tab', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -249,7 +248,7 @@ import {
OpenDocTypeFolder();
cy.get('[alias="reorder"]').click();
cy.get('.umb-property-editor-tiny').eq(2).type('1');
cy.get('[alias="reorder"]').click();
cy.umbracoButtonByLabelKey('buttons_save').click();
//Assert
@@ -257,7 +256,7 @@ import {
cy.get('.umb-group-builder__group-title-input').eq(2)
.invoke('attr', 'title').should('eq', 'aTab 1/aTab group 2');
});
it('Reorders properties in a tab', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -286,12 +285,12 @@ import {
cy.get('[alias="reorder"]').click();
cy.get('.umb-group-builder__group-sort-value').first().type('2');
cy.get('[alias="reorder"]').click();
cy.umbracoButtonByLabelKey('buttons_save').click();
cy.umbracoButtonByLabelKey('buttons_save').click();
//Assert
cy.umbracoSuccessNotification().should('be.visible');
cy.get('.umb-locked-field__input').last().invoke('attr', 'title').should('eq', 'urlPicker');
});
it('Tab name cannot be empty', () => {
CreateDocWithTabAndNavigate();
cy.get('.umb-group-builder__group-title-input').first().clear();
@@ -299,7 +298,7 @@ import {
//Assert
cy.umbracoErrorNotification().should('be.visible');
});
it('Two tabs cannot have the same name', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -326,7 +325,7 @@ import {
//Assert
cy.umbracoErrorNotification().should('be.visible');
});
it('Group name cannot be empty', () => {
CreateDocWithTabAndNavigate();
cy.get('.clearfix > .-placeholder').click();
@@ -334,7 +333,7 @@ import {
//Assert
cy.umbracoErrorNotification().should('be.visible');
});
it('Group name cannot have the same name', () => {
CreateDocWithTabAndNavigate();
cy.get('.clearfix > .-placeholder').click();
@@ -343,7 +342,7 @@ import {
//Assert
cy.umbracoErrorNotification().should('be.visible');
});
it('Drag a group into another tab', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -394,7 +393,7 @@ import {
cy.umbracoSuccessNotification().should('be.visible');
cy.get('[title="aTab 1/aTab group 2"]').should('be.visible');
});
it('Drag and drop reorders a tab', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -446,7 +445,7 @@ import {
cy.umbracoSuccessNotification().should('be.visible');
cy.get('[title="aTab 2"]').should('be.visible');
});
it('Drags and drops a property in a tab', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -502,7 +501,7 @@ import {
cy.umbracoSuccessNotification().should('be.visible');
cy.get('[title="urlPickerTabTwo"]').should('be.visible');
});
it('Drags and drops a group and converts to tab', () => {
cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName);
const tabsDocType = new DocumentTypeBuilder()
@@ -549,4 +548,4 @@ import {
cy.umbracoSuccessNotification().should('be.visible');
cy.get('[title="tabGroup"]').should('be.visible');
});
});
});

View File

@@ -1,13 +1,40 @@
/// <reference types="Cypress" />
context('Users', () => {
const name = "Alice Bobson";
const email = "alice-bobson@acceptancetest.umbraco";
const startContentIds = [];
const startMediaIds = [];
const userGroups = ["admin"];
const userData =
{
"id": -1,
"parentId": -1,
"name": name,
"username": email,
"culture": "en-US",
"email": email,
"startContentIds": startContentIds,
"startMediaIds": startMediaIds,
"userGroups": userGroups,
"message": ""
};
beforeEach(() => {
cy.umbracoLogin(Cypress.env('username'), Cypress.env('password'));
});
afterEach(() => {
//Clean up
cy.umbracoEnsureUserEmailNotExists(email);
});
function createUser(){
let url = '/umbraco/backoffice/umbracoapi/users/PostCreateUser';
cy.umbracoApiRequest(url, 'POST', userData);
}
it('Create user', () => {
const name = "Alice Bobson";
const email = "alice-bobson@acceptancetest.umbraco";
cy.umbracoEnsureUserEmailNotExists(email);
cy.umbracoSection('users');
@@ -24,55 +51,16 @@ context('Users', () => {
cy.get('.umb-button > .btn > .umb-button__content').click();
cy.umbracoButtonByLabelKey("user_goToProfile").should('be.visible');
//Clean up
cy.umbracoEnsureUserEmailNotExists(email);
});
it('Update user', () => {
// Set userdata
const name = "Alice Bobson";
const email = "alice-bobson@acceptancetest.umbraco";
const startContentIds = [];
const startMediaIds = [];
const userGroups = ["admin"];
var userData =
{
"id": -1,
"parentId": -1,
"name": name,
"username": email,
"culture": "en-US",
"email": email,
"startContentIds": startContentIds,
"startMediaIds": startMediaIds,
"userGroups": userGroups,
"message": ""
};
// Ensure user doesn't exist
cy.umbracoEnsureUserEmailNotExists(email);
// Create user through API
cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => {
cy.request({
method: 'POST',
url: '/umbraco/backoffice/umbracoapi/users/PostCreateUser',
followRedirect: true,
headers: {
Accept: 'application/json',
'X-UMB-XSRF-TOKEN': token.value,
},
body: userData,
log: false,
}).then((response) => {
return;
});
});
//Create user through API
createUser();
// Go to the user and edit their name
cy.umbracoSection('users');
@@ -82,50 +70,15 @@ context('Users', () => {
// assert save succeeds
cy.umbracoSuccessNotification().should('be.visible');
cy.umbracoEnsureUserEmailNotExists(email);
})
it('Delete user', () => {
// Set userdata
const name = "Alice Bobson";
const email = "alice-bobson@acceptancetest.umbraco";
const startContentIds = [];
const startMediaIds = [];
const userGroups = ["admin"];
var userData =
{
"id": -1,
"parentId": -1,
"name": name,
"username": email,
"culture": "en-US",
"email": email,
"startContentIds": startContentIds,
"startMediaIds": startMediaIds,
"userGroups": userGroups,
"message": ""
};
it('Delete user', () => {
// Ensure user doesn't exist
cy.umbracoEnsureUserEmailNotExists(email);
// Create user through API
cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => {
cy.request({
method: 'POST',
url: '/umbraco/backoffice/umbracoapi/users/PostCreateUser',
followRedirect: true,
headers: {
Accept: 'application/json',
'X-UMB-XSRF-TOKEN': token.value,
},
body: userData,
log: false,
}).then((response) => {
return;
});
});
//Create user through API
createUser();
// Go to the user and delete them
cy.umbracoSection('users');
@@ -135,6 +88,5 @@ context('Users', () => {
// assert deletion succeeds
cy.umbracoSuccessNotification().should('be.visible');
cy.umbracoEnsureUserEmailNotExists(email);
})
});
});

View File

@@ -26,5 +26,72 @@
import {Command} from 'umbraco-cypress-testhelpers';
import {Chainable} from './chainable';
import { JsonHelper } from 'umbraco-cypress-testhelpers';
new Chainable();
new Command().registerCypressCommands();
Cypress.Commands.add('umbracoCreateLanguage', (culture, isMandatory = false, fallbackLanguageId = 1) => {
var langData =
{
"culture": culture,
"isMandatory": isMandatory,
"fallbackLanguageId": fallbackLanguageId
};
// Create language through API
cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => {
cy.request({
method: 'POST',
url: '/umbraco/backoffice/umbracoapi/language/SaveLanguage',
followRedirect: true,
headers: {
Accept: 'application/json',
'X-UMB-XSRF-TOKEN': token.value,
},
body: langData,
log: false,
}).then((response) => {
return;
});
});
});
Cypress.Commands.add('umbracoEnsureLanguageCultureNotExists', (culture) => {
cy.getCookie('UMB-XSRF-TOKEN', { log: false }).then((token) => {
cy.request({
method: 'GET',
url: '/umbraco/backoffice/umbracoapi/language/GetAllLanguages',
followRedirect: true,
headers: {
Accept: 'application/json',
'X-UMB-XSRF-TOKEN': token.value,
},
log: false,
}).then((response) => {
const searchBody = JsonHelper.getBody(response);
if (searchBody.length > 0) {
let languageId = null;
for (const sb of searchBody) {
if (sb.culture === culture) {
languageId = sb.id;
}
}
if (languageId !== null) {
cy.request({
method: 'POST',
url: '/umbraco/backoffice/umbracoapi/language/DeleteLanguage?id=' + languageId,
followRedirect: false,
headers: {
ContentType: 'application/json',
'X-UMB-XSRF-TOKEN': token.value,
},
}).then((resp) => {
return;
});
}
}
});
});
});

View File

@@ -3,3 +3,28 @@
// type definitions for custom commands like "createDefaultTodos"
// <reference types="support" />
export {};
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
interface Chainable<Subject> {
/**
* Checks to see if the language with specified culture does not exist
* If it does it will automatically delete it
* @param {string} culture Culture of language to delete
* @example cy.umbracoEnsureLanguageCultureNotExists('da-DK');
*/
umbracoEnsureLanguageCultureNotExists: (culture: string) => Chainable<void>;
/**
* Creates a language from a culture
* @param {string} culture Culture of the language - fx "da_DK"
* @param {boolean} isMandatory Set whether the language is mandatory or not. Defaults to false
* @param {string} fallbackLanguageId of the language to fallback to. Defaults to 1 which is en_US
* @example cy.umbracoCreateLanguage('da', true, '1');
*/
umbracoCreateLanguage: (culture: string, isMandatory: boolean, fallbackLanguageId: string) => Chainable<void>;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -9,11 +9,11 @@
},
"devDependencies": {
"cross-env": "^7.0.2",
"cypress": "^6.8.0",
"cypress": "8.4.1",
"del": "^6.0.0",
"ncp": "^2.0.0",
"prompt": "^1.2.0",
"umbraco-cypress-testhelpers": "^1.0.0-beta-58"
"umbraco-cypress-testhelpers": "^1.0.0-beta-62"
},
"dependencies": {
"typescript": "^3.9.2"

View File

@@ -72,7 +72,7 @@ namespace Umbraco.Cms.Tests.Common.Builders
public ContentBuilder WithContentType(IContentType contentType)
{
_contentTypeBuilder = null;
_contentType = contentType;
_contentType = contentType;
return this;
}
@@ -172,6 +172,11 @@ namespace Umbraco.Cms.Tests.Common.Builders
content.SortOrder = sortOrder;
content.Trashed = trashed;
if (contentType.DefaultTemplate?.Id > 0)
{
content.TemplateId = contentType.DefaultTemplate.Id;
}
foreach (KeyValuePair<string, string> cultureName in _cultureNames)
{
content.SetCultureName(cultureName.Value, cultureName.Key);

View File

@@ -0,0 +1,221 @@
using System;
using System.Collections.Generic;
using Umbraco.Extensions;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.Common.Builders.Interfaces;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Core.PropertyEditors;
using Moq;
using Umbraco.Cms.Infrastructure.Serialization;
using System.Linq;
namespace Umbraco.Cms.Tests.Common.Builders
{
public class ContentDataBuilder : BuilderBase<ContentData>, IWithNameBuilder
{
private string _name;
private DateTime? _now;
private string _segment;
private int? _versionId;
private int? _writerId;
private int? _templateId;
private bool? _published;
private Dictionary<string, PropertyData[]> _properties;
private Dictionary<string, CultureVariation> _cultureInfos;
string IWithNameBuilder.Name
{
get => _name;
set => _name = value;
}
public ContentDataBuilder WithVersionDate(DateTime now)
{
_now = now;
return this;
}
public ContentDataBuilder WithUrlSegment(string segment)
{
_segment = segment;
return this;
}
public ContentDataBuilder WithVersionId(int versionId)
{
_versionId = versionId;
return this;
}
public ContentDataBuilder WithWriterId(int writerId)
{
_writerId = writerId;
return this;
}
public ContentDataBuilder WithTemplateId(int templateId)
{
_templateId = templateId;
return this;
}
public ContentDataBuilder WithPublished(bool published)
{
_published = published;
return this;
}
public ContentDataBuilder WithProperties(Dictionary<string, PropertyData[]> properties)
{
_properties = properties;
return this;
}
public ContentDataBuilder WithCultureInfos(Dictionary<string, CultureVariation> cultureInfos)
{
_cultureInfos = cultureInfos;
return this;
}
/// <summary>
/// Build and dynamically update an existing content type
/// </summary>
/// <typeparam name="TContentType"></typeparam>
/// <param name="shortStringHelper"></param>
/// <param name="propertyDataTypes"></param>
/// <param name="contentType"></param>
/// <param name="contentTypeAlias">
/// Will configure the content type with this alias/name if supplied when it's not already set on the content type.
/// </param>
/// <param name="autoCreateCultureNames"></param>
/// <returns></returns>
public ContentData Build<TContentType>(
IShortStringHelper shortStringHelper,
Dictionary<string, IDataType> propertyDataTypes,
TContentType contentType,
string contentTypeAlias = null,
bool autoCreateCultureNames = false) where TContentType : class, IContentTypeComposition
{
if (_name.IsNullOrWhiteSpace())
{
throw new InvalidOperationException("Cannot build without a name");
}
_segment ??= _name.ToLower().ReplaceNonAlphanumericChars('-');
// create or copy the current culture infos for the content
Dictionary<string, CultureVariation> contentCultureInfos = _cultureInfos == null
? new Dictionary<string, CultureVariation>()
: new Dictionary<string, CultureVariation>(_cultureInfos);
contentType.Alias ??= contentTypeAlias;
contentType.Name ??= contentTypeAlias;
contentType.Key = contentType.Key == default ? Guid.NewGuid() : contentType.Key;
contentType.Id = contentType.Id == default ? Math.Abs(contentTypeAlias.GetHashCode()) : contentType.Id;
if (_properties == null)
{
_properties = new Dictionary<string, PropertyData[]>();
}
foreach (KeyValuePair<string, PropertyData[]> prop in _properties)
{
//var dataType = new DataType(new VoidEditor("Label", Mock.Of<IDataValueEditorFactory>()), new ConfigurationEditorJsonSerializer())
//{
// Id = 4
//};
if (!propertyDataTypes.TryGetValue(prop.Key, out IDataType dataType))
{
dataType = propertyDataTypes.First().Value;
}
var propertyType = new PropertyType(shortStringHelper, dataType, prop.Key);
// check each property for culture and set variations accordingly,
// this will also ensure that we have the correct culture name on the content
// set for each culture too.
foreach (PropertyData cultureValue in prop.Value.Where(x => !x.Culture.IsNullOrWhiteSpace()))
{
// set the property type to vary based on the values
propertyType.Variations |= ContentVariation.Culture;
// if there isn't already a culture, then add one with the default name
if (autoCreateCultureNames && !contentCultureInfos.TryGetValue(cultureValue.Culture, out CultureVariation cultureVariation))
{
cultureVariation = new CultureVariation
{
Date = DateTime.Now,
IsDraft = true,
Name = _name,
UrlSegment = _segment
};
contentCultureInfos[cultureValue.Culture] = cultureVariation;
}
}
// set variations for segments if there is any
if (prop.Value.Any(x => !x.Segment.IsNullOrWhiteSpace()))
{
propertyType.Variations |= ContentVariation.Segment;
contentType.Variations |= ContentVariation.Segment;
}
if (!contentType.PropertyTypeExists(propertyType.Alias))
{
contentType.AddPropertyType(propertyType);
}
}
if (contentCultureInfos.Count > 0)
{
contentType.Variations |= ContentVariation.Culture;
WithCultureInfos(contentCultureInfos);
}
var result = Build();
return result;
}
public override ContentData Build()
{
var now = _now ?? DateTime.Now;
var versionId = _versionId ?? 1;
var writerId = _writerId ?? -1;
var templateId = _templateId ?? 0;
var published = _published ?? true;
var properties = _properties ?? new Dictionary<string, PropertyData[]>();
var cultureInfos = _cultureInfos ?? new Dictionary<string, CultureVariation>();
var segment = _segment ?? _name.ToLower().ReplaceNonAlphanumericChars('-');
var contentData = new ContentData(
_name,
segment,
versionId,
now,
writerId,
templateId,
published,
properties,
cultureInfos);
return contentData;
}
public static ContentData CreateBasic(string name, DateTime? versionDate = null)
=> new ContentDataBuilder()
.WithName(name)
.WithVersionDate(versionDate ?? DateTime.Now)
.Build();
public static ContentData CreateVariant(string name, Dictionary<string, CultureVariation> cultureInfos, DateTime? versionDate = null, bool published = true)
=> new ContentDataBuilder()
.WithName(name)
.WithVersionDate(versionDate ?? DateTime.Now)
.WithCultureInfos(cultureInfos)
.WithPublished(published)
.Build();
}
}

View File

@@ -0,0 +1,96 @@
using System;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
namespace Umbraco.Cms.Tests.Common.Builders
{
public class ContentNodeKitBuilder : BuilderBase<ContentNodeKit>
{
private int _contentTypeId;
private ContentNode _contentNode;
private ContentData _draftData;
private ContentData _publishedData;
public ContentNodeKitBuilder WithContentNode(ContentNode contentNode)
{
_contentNode = contentNode;
return this;
}
public ContentNodeKitBuilder WithContentNode(int id, Guid uid, int level, string path, int sortOrder, int parentContentId, DateTime createDate, int creatorId)
{
_contentNode = new ContentNode(id, uid, level, path, sortOrder, parentContentId, createDate, creatorId);
return this;
}
public ContentNodeKitBuilder WithContentTypeId(int contentTypeId)
{
_contentTypeId = contentTypeId;
return this;
}
public ContentNodeKitBuilder WithDraftData(ContentData draftData)
{
_draftData = draftData;
return this;
}
public ContentNodeKitBuilder WithPublishedData(ContentData publishedData)
{
_publishedData = publishedData;
return this;
}
public override ContentNodeKit Build()
{
var data = new ContentNodeKit(_contentNode, _contentTypeId, _draftData, _publishedData);
return data;
}
/// <summary>
/// Creates a ContentNodeKit
/// </summary>
/// <param name="contentTypeId"></param>
/// <param name="id"></param>
/// <param name="path"></param>
/// <param name="sortOrder"></param>
/// <param name="level">
/// Optional. Will get calculated based on the path value if not specified.
/// </param>
/// <param name="parentContentId">
/// Optional. Will get calculated based on the path value if not specified.
/// </param>
/// <param name="creatorId"></param>
/// <param name="uid"></param>
/// <param name="createDate"></param>
/// <param name="draftData"></param>
/// <param name="publishedData"></param>
/// <returns></returns>
public static ContentNodeKit CreateWithContent(
int contentTypeId,
int id,
string path,
int? sortOrder = null,
int? level = null,
int? parentContentId = null,
int creatorId = -1,
Guid? uid = null,
DateTime? createDate = null,
ContentData draftData = null,
ContentData publishedData = null)
{
var pathParts = path.Split(',');
if (pathParts.Length >= 2)
{
parentContentId ??= int.Parse(pathParts[^2]);
}
return new ContentNodeKitBuilder()
.WithContentTypeId(contentTypeId)
.WithContentNode(id, uid ?? Guid.NewGuid(), level ?? pathParts.Length - 1, path, sortOrder ?? 0, parentContentId.Value, createDate ?? DateTime.Now, creatorId)
.WithDraftData(draftData)
.WithPublishedData(publishedData)
.Build();
}
}
}

View File

@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.Common.Builders.Interfaces;
using Constants = Umbraco.Cms.Core.Constants;
@@ -113,6 +114,7 @@ namespace Umbraco.Cms.Tests.Common.Builders
contentType.CreatorId = GetCreatorId();
contentType.Trashed = GetTrashed();
contentType.IsContainer = GetIsContainer();
contentType.HistoryCleanup = new HistoryCleanup();
contentType.Variations = contentVariation;

View File

@@ -0,0 +1,7 @@
namespace Umbraco.Cms.Tests.Common.Builders.Interfaces
{
public interface IWithAllowAsRootBuilder
{
bool? AllowAsRoot { get; set; }
}
}

View File

@@ -0,0 +1,36 @@
using System.Collections.Generic;
using Umbraco.Extensions;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
using System.Linq;
namespace Umbraco.Cms.Tests.Common.Builders
{
public class PropertyDataBuilder : BuilderBase<Dictionary<string, PropertyData[]>>
{
private readonly Dictionary<string, List<PropertyData>> _properties = new();
public PropertyDataBuilder WithPropertyData(string alias, PropertyData propertyData)
{
if (!_properties.TryGetValue(alias, out List<PropertyData> propertyDataCollection))
{
propertyDataCollection = new List<PropertyData>();
_properties[alias] = propertyDataCollection;
}
propertyDataCollection.Add(propertyData);
return this;
}
public PropertyDataBuilder WithPropertyData(string alias, object value, string culture = null, string segment = null)
=> WithPropertyData(alias, new PropertyData
{
Culture = culture ?? string.Empty,
Segment = segment ?? string.Empty,
Value = value
});
public override Dictionary<string, PropertyData[]> Build()
=> _properties.ToDictionary(x => x.Key, x => x.Value.ToArray());
}
}

View File

@@ -0,0 +1,152 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
namespace Umbraco.Cms.Tests.Common.Published
{
public static class PublishedContentXml
{
// The content XML that was used for the old PublishContentCacheTests
public static string PublishContentCacheTestsXml()
=> @"<?xml version=""1.0"" encoding=""utf-8""?><!DOCTYPE root[
<!ELEMENT Home ANY>
<!ATTLIST Home id ID #REQUIRED>
]>
<root id=""-1"">
<Home id=""1046"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""2"" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" nodeName=""Home"" urlName=""home"" writerName=""admin"" creatorName=""admin"" path=""-1,1046"" isDoc=""""><content><![CDATA[]]></content>
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""1"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc=""""><content><![CDATA[]]></content>
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""1"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc=""""><content><![CDATA[]]></content>
</Home>
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""2"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc=""""><content><![CDATA[]]></content>
</Home>
</Home>
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""2"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub 2"" urlName=""sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1175"" isDoc=""""><content><![CDATA[]]></content>
</Home>
<Home id=""1177"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""2"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub'Apostrophe"" urlName=""sub'apostrophe"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1177"" isDoc=""""><content><![CDATA[]]></content>
</Home>
</Home>
<Home id=""1172"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test"" writerName=""admin"" creatorName=""admin"" path=""-1,1172"" isDoc="""" />
</root>";
// The content XML that was used in the old BaseWebTest class
public static string BaseWebTestXml(int templateId)
=> @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE root[
<!ELEMENT Home ANY>
<!ATTLIST Home id ID #REQUIRED>
<!ELEMENT CustomDocument ANY>
<!ATTLIST CustomDocument id ID #REQUIRED>
]>
<root id=""-1"">
<Home id=""1046"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" nodeName=""Home"" urlName=""home"" writerName=""admin"" creatorName=""admin"" path=""-1,1046"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoUrlAlias><![CDATA[this/is/my/alias, anotheralias]]></umbracoUrlAlias>
<umbracoNaviHide>1</umbracoNaviHide>
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""">
<content><![CDATA[<div>This is some content</div>]]></content>
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoUrlAlias><![CDATA[only/one/alias]]></umbracoUrlAlias>
<creatorName><![CDATA[Custom data with same property name as the member name]]></creatorName>
</Home>
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc="""">
<content><![CDATA[]]></content>
</Home>
<CustomDocument id=""1177"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1177"" isDoc="""" />
<CustomDocument id=""1178"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 2"" urlName=""custom-sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178"" isDoc="""" />
<CustomDocument id=""1179"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 3 with accént character"" urlName=""custom-sub-3-with-accént-character"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1179"" isDoc="""" />
<CustomDocument id=""1180"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 4 with æøå"" urlName=""custom-sub-4-with-æøå"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1180"" isDoc="""" />
</Home>
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub 2"" urlName=""sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1175"" isDoc=""""><content><![CDATA[]]></content>
</Home>
</Home>
<CustomDocument id=""1172"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1172"" isDoc="""" />
</root>";
// The content XML that was used in the old TestWithDatabase class
public static string TestWithDatabaseXml(int templateId)
=> @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE root[
<!ELEMENT Home ANY>
<!ATTLIST Home id ID #REQUIRED>
<!ELEMENT CustomDocument ANY>
<!ATTLIST CustomDocument id ID #REQUIRED>
]>
<root id=""-1"">
<Home id=""1046"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" nodeName=""Home"" urlName=""home"" writerName=""admin"" creatorName=""admin"" path=""-1,1046"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoUrlAlias><![CDATA[this/is/my/alias, anotheralias]]></umbracoUrlAlias>
<umbracoNaviHide>1</umbracoNaviHide>
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""">
<content><![CDATA[<div>This is some content</div>]]></content>
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoUrlAlias><![CDATA[only/one/alias]]></umbracoUrlAlias>
<creatorName><![CDATA[Custom data with same property name as the member name]]></creatorName>
</Home>
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc="""">
<content><![CDATA[]]></content>
</Home>
<CustomDocument id=""1177"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1177"" isDoc="""" />
<CustomDocument id=""1178"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 2"" urlName=""custom-sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178"" isDoc="""" />
</Home>
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub 2"" urlName=""sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1175"" isDoc=""""><content><![CDATA[]]></content>
</Home>
</Home>
<CustomDocument id=""1172"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1172"" isDoc="""" />
</root>";
// The content XML that was used in the old PublishedContentTest class
public static string PublishedContentTestXml(int templateId, Guid node1173Guid)
=> @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE root[
<!ELEMENT Home ANY>
<!ATTLIST Home id ID #REQUIRED>
<!ELEMENT CustomDocument ANY>
<!ATTLIST CustomDocument id ID #REQUIRED>
]>
<root id=""-1"">
<Home id=""1046"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" nodeName=""Home"" urlName=""home"" writerName=""admin"" creatorName=""admin"" path=""-1,1046"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoUrlAlias><![CDATA[this/is/my/alias, anotheralias]]></umbracoUrlAlias>
<umbracoNaviHide>1</umbracoNaviHide>
<testRecursive><![CDATA[This is the recursive val]]></testRecursive>
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""" key=""" + node1173Guid + @""">
<content><![CDATA[<div>This is some content</div>]]></content>
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
<testRecursive><![CDATA[]]></testRecursive>
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoUrlAlias><![CDATA[only/one/alias]]></umbracoUrlAlias>
<creatorName><![CDATA[Custom data with same property name as the member name]]></creatorName>
<testRecursive><![CDATA[]]></testRecursive>
</Home>
<CustomDocument id=""117"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2018-07-18T10:06:37"" updateDate=""2018-07-18T10:06:37"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,117"" isDoc="""">
<umbracoNaviHide>0</umbracoNaviHide>
</CustomDocument>
<CustomDocument id=""1177"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1177"" isDoc="""">
<umbracoNaviHide>0</umbracoNaviHide>
</CustomDocument>
<CustomDocument id=""1178"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 2"" urlName=""custom-sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178"" isDoc="""">
<umbracoNaviHide>0</umbracoNaviHide>
<CustomDocument id=""1179"" parentID=""1178"" level=""4"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub sub 1"" urlName=""custom-sub-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178,1179"" isDoc="""" />
</CustomDocument>
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""5"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc="""" key=""CDB83BBC-A83B-4BA6-93B8-AADEF67D3C09"">
<content><![CDATA[]]></content>
<umbracoNaviHide>1</umbracoNaviHide>
</Home>
</Home>
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub 2"" urlName=""sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1175"" isDoc=""""><content><![CDATA[]]></content>
</Home>
<CustomDocument id=""4444"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,4444"" isDoc="""">
<selectedNodes><![CDATA[1172,1176,1173]]></selectedNodes>
</CustomDocument>
</Home>
<CustomDocument id=""1172"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1172"" isDoc="""" />
</root>";
}
}

View File

@@ -0,0 +1,146 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Linq;
using Umbraco.Extensions;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Builders;
using System;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Core.PropertyEditors;
using Moq;
using Umbraco.Cms.Infrastructure.Serialization;
namespace Umbraco.Cms.Tests.Common.Published
{
/// <summary>
/// Converts legacy Umbraco XML structures to NuCache <see cref="ContentNodeKit"/> collections
/// to populate a test implementation of <see cref="INuCacheContentService"/>
/// </summary>
/// <remarks>
/// This does not support variant data because the XML structure doesn't support variant data.
/// </remarks>
public static class PublishedContentXmlAdapter
{
/// <summary>
/// Generate a collection of <see cref="ContentNodeKit"/> based on legacy umbraco XML
/// </summary>
/// <param name="xml">The legacy umbraco XML</param>
/// <param name="shortStringHelper"></param>
/// <param name="contentTypes">Dynamically generates a list of <see cref="ContentType"/>s based on the XML data</param>
/// <param name="dataTypes">Dynamically generates a list of <see cref="DataType"/> for tests</param>
/// <returns></returns>
public static IEnumerable<ContentNodeKit> GetContentNodeKits(
string xml,
IShortStringHelper shortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes)
{
// use the label data type for all data for these tests except in the case
// where a property is named 'content', in which case use the RTE.
var serializer = new ConfigurationEditorJsonSerializer();
var labelDataType = new DataType(new VoidEditor("Label", Mock.Of<IDataValueEditorFactory>()), serializer) { Id = 3 };
var rteDataType = new DataType(new VoidEditor("RTE", Mock.Of<IDataValueEditorFactory>()), serializer) { Id = 4 };
dataTypes = new[] { labelDataType, rteDataType };
var kitsAndXml = new List<(ContentNodeKit kit, XElement node)>();
var xDoc = XDocument.Parse(xml);
IEnumerable<XElement> nodes = xDoc.XPathSelectElements("//*[@isDoc]");
foreach (XElement node in nodes)
{
var id = node.AttributeValue<int>("id");
Guid key = node.AttributeValue<Guid?>("key") ?? id.ToGuid();
var propertyElements = node.Elements().Where(x => x.Attribute("id") == null);
var properties = new Dictionary<string, PropertyData[]>();
foreach(XElement propertyElement in propertyElements)
{
properties[propertyElement.Name.LocalName] = new[]
{
// TODO: builder?
new PropertyData
{
Culture = string.Empty,
Segment = string.Empty,
Value = propertyElement.Value
}
};
}
var contentData = new ContentDataBuilder()
.WithName(node.AttributeValue<string>("nodeName"))
.WithProperties(properties)
.WithPublished(true)
.WithTemplateId(node.AttributeValue<int>("template"))
.WithUrlSegment(node.AttributeValue<string>("urlName"))
.WithVersionDate(node.AttributeValue<DateTime>("updateDate"))
.WithWriterId(node.AttributeValue<int>("writerID"))
.Build();
ContentNodeKit kit = ContentNodeKitBuilder.CreateWithContent(
node.AttributeValue<int>("nodeType"),
id,
node.AttributeValue<string>("path"),
node.AttributeValue<int>("sortOrder"),
node.AttributeValue<int>("level"),
node.AttributeValue<int>("parentID"),
node.AttributeValue<int>("creatorID"),
key,
node.AttributeValue<DateTime>("createDate"),
contentData,
contentData);
kitsAndXml.Add((kit, node));
}
// put together the unique content types
var contentTypesIdToType = new Dictionary<int, ContentType>();
foreach((ContentNodeKit kit, XElement node) in kitsAndXml)
{
if (!contentTypesIdToType.TryGetValue(kit.ContentTypeId, out ContentType contentType))
{
contentType = new ContentType(shortStringHelper, -1)
{
Id = kit.ContentTypeId,
Alias = node.Name.LocalName
};
SetContentTypeProperties(shortStringHelper, labelDataType, rteDataType, kit, contentType);
contentTypesIdToType[kit.ContentTypeId] = contentType;
}
else
{
// we've already created it but might need to add properties
SetContentTypeProperties(shortStringHelper, labelDataType, rteDataType, kit, contentType);
}
}
contentTypes = contentTypesIdToType.Values.ToArray();
return kitsAndXml.Select(x => x.kit);
}
private static void SetContentTypeProperties(IShortStringHelper shortStringHelper, DataType labelDataType, DataType rteDataType, ContentNodeKit kit, ContentType contentType)
{
foreach (KeyValuePair<string, PropertyData[]> property in kit.DraftData.Properties)
{
var propertyType = new PropertyType(shortStringHelper, labelDataType, property.Key);
if (!contentType.PropertyTypeExists(propertyType.Alias))
{
if (propertyType.Alias == "content")
{
propertyType.DataTypeId = rteDataType.Id;
}
contentType.AddPropertyType(propertyType);
}
}
}
}
}

View File

@@ -8,6 +8,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.Common.Published
{
public class PublishedSnapshotTestObjects
{
[PublishedModel("element1")]

View File

@@ -1,68 +0,0 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Serialization;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent
{
public class AutoPublishedContentType : PublishedContentType
{
private static readonly IPublishedPropertyType Default;
static AutoPublishedContentType()
{
var configurationEditorJsonSerializer = new ConfigurationEditorJsonSerializer();
var jsonSerializer = new JsonNetSerializer();
var dataTypeServiceMock = new Mock<IDataTypeService>();
var dataType = new DataType(
new VoidEditor(
Mock.Of<IDataValueEditorFactory>()),
configurationEditorJsonSerializer)
{
Id = 666
};
dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield);
var factory = new PublishedContentTypeFactory(Mock.Of<IPublishedModelFactory>(), new PropertyValueConverterCollection(() => Enumerable.Empty<IPropertyValueConverter>()), dataTypeServiceMock.Object);
Default = factory.CreatePropertyType("*", 666);
}
public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable<PublishedPropertyType> propertyTypes)
: base(key, id, alias, PublishedItemType.Content, Enumerable.Empty<string>(), propertyTypes, ContentVariation.Nothing)
{
}
public AutoPublishedContentType(Guid key, int id, string alias, Func<IPublishedContentType, IEnumerable<IPublishedPropertyType>> propertyTypes)
: base(key, id, alias, PublishedItemType.Content, Enumerable.Empty<string>(), propertyTypes, ContentVariation.Nothing)
{
}
public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes)
: base(key, id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, ContentVariation.Nothing)
{
}
public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable<string> compositionAliases, Func<IPublishedContentType, IEnumerable<IPublishedPropertyType>> propertyTypes)
: base(key, id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, ContentVariation.Nothing)
{
}
public override IPublishedPropertyType GetPropertyType(string alias)
{
IPublishedPropertyType propertyType = base.GetPropertyType(alias);
return propertyType ?? Default;
}
}
}

View File

@@ -1,20 +0,0 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Moq;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent
{
[PublishedModel("ContentType2")]
public class ContentType2 : PublishedContentModel
{
public ContentType2(IPublishedContent content, IPublishedValueFallback fallback)
: base(content, fallback)
{
}
public int Prop1 => this.Value<int>(Mock.Of<IPublishedValueFallback>(), "prop1");
}
}

View File

@@ -1,16 +0,0 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Umbraco.Cms.Core.Models.PublishedContent;
namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent
{
[PublishedModel("ContentType2Sub")]
public class ContentType2Sub : ContentType2
{
public ContentType2Sub(IPublishedContent content, IPublishedValueFallback fallback)
: base(content, fallback)
{
}
}
}

View File

@@ -1,84 +0,0 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using Umbraco.Cms.Core.PublishedCache.Internal;
namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent
{
public class InternalPublishedPropertyWithLanguageVariants : InternalPublishedProperty
{
private readonly IDictionary<string, object> _solidSourceValues = new Dictionary<string, object>();
private readonly IDictionary<string, object> _solidValues = new Dictionary<string, object>();
private readonly IDictionary<string, object> _solidXPathValues = new Dictionary<string, object>();
public override object GetSourceValue(string culture = null, string segment = null)
{
if (string.IsNullOrEmpty(culture))
{
return base.GetSourceValue(culture, segment);
}
return _solidSourceValues.ContainsKey(culture) ? _solidSourceValues[culture] : null;
}
public override object GetValue(string culture = null, string segment = null)
{
if (string.IsNullOrEmpty(culture))
{
return base.GetValue(culture, segment);
}
return _solidValues.ContainsKey(culture) ? _solidValues[culture] : null;
}
public override object GetXPathValue(string culture = null, string segment = null)
{
if (string.IsNullOrEmpty(culture))
{
return base.GetXPathValue(culture, segment);
}
return _solidXPathValues.ContainsKey(culture) ? _solidXPathValues[culture] : null;
}
public override bool HasValue(string culture = null, string segment = null)
{
if (string.IsNullOrEmpty(culture))
{
return base.HasValue(culture, segment);
}
return _solidSourceValues.ContainsKey(culture);
}
public void SetSourceValue(string culture, object value, bool defaultValue = false)
{
_solidSourceValues.Add(culture, value);
if (defaultValue)
{
SolidSourceValue = value;
SolidHasValue = true;
}
}
public void SetValue(string culture, object value, bool defaultValue = false)
{
_solidValues.Add(culture, value);
if (defaultValue)
{
SolidValue = value;
SolidHasValue = true;
}
}
public void SetXPathValue(string culture, object value, bool defaultValue = false)
{
_solidXPathValues.Add(culture, value);
if (defaultValue)
{
SolidXPathValue = value;
}
}
}
}

View File

@@ -1,19 +0,0 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Moq;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent
{
public class PublishedContentStrong1 : PublishedContentModel
{
public PublishedContentStrong1(IPublishedContent content, IPublishedValueFallback fallback)
: base(content, fallback)
{
}
public int StrongValue => this.Value<int>(Mock.Of<IPublishedValueFallback>(), "strongValue");
}
}

View File

@@ -1,19 +0,0 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Moq;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent
{
public class PublishedContentStrong1Sub : PublishedContentStrong1
{
public PublishedContentStrong1Sub(IPublishedContent content, IPublishedValueFallback fallback)
: base(content, fallback)
{
}
public int AnotherValue => this.Value<int>(Mock.Of<IPublishedValueFallback>(), "anotherValue");
}
}

View File

@@ -1,19 +0,0 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Moq;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent
{
public class PublishedContentStrong2 : PublishedContentModel
{
public PublishedContentStrong2(IPublishedContent content, IPublishedValueFallback fallback)
: base(content, fallback)
{
}
public int StrongValue => this.Value<int>(Mock.Of<IPublishedValueFallback>(), "strongValue");
}
}

View File

@@ -0,0 +1,12 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Umbraco.Cms.Core.Routing;
namespace Umbraco.Cms.Tests.Common
{
public class TestLastChanceFinder : IContentLastChanceFinder
{
public bool TryFindContent(IPublishedRequestBuilder frequest) => false;
}
}

View File

@@ -7,10 +7,14 @@ namespace Umbraco.Cms.Tests.Common
{
public class TestPublishedSnapshotAccessor : IPublishedSnapshotAccessor
{
private IPublishedSnapshot _snapshot = null;
public bool TryGetPublishedSnapshot(out IPublishedSnapshot publishedSnapshot)
{
publishedSnapshot = null;
return false;
publishedSnapshot = _snapshot;
return _snapshot != null;
}
public void SetCurrent(IPublishedSnapshot snapshot) => _snapshot = snapshot;
}
}

View File

@@ -6,12 +6,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using NUnit.Framework.Internal;
using Umbraco.Cms.Core.Exceptions;
namespace Umbraco.Cms.Tests.Common.Testing
{
public abstract class TestOptionAttributeBase : Attribute
{
[Obsolete("This is not used anymore - Test classes are found using nunit helpers")]
public static readonly List<Assembly> ScanAssemblies = new List<Assembly>();
public static TOptions GetTestOptions<TOptions>(MethodInfo method)
@@ -29,26 +31,8 @@ namespace Umbraco.Cms.Tests.Common.Testing
where TOptions : TestOptionAttributeBase, new()
{
TestContext.TestAdapter test = TestContext.CurrentContext.Test;
var typeName = test.ClassName;
var methodName = test.MethodName;
// This will only get types from whatever is already loaded in the app domain.
var type = Type.GetType(typeName, false);
if (type == null)
{
// automatically add the executing and calling assemblies to the list to scan for this type
var scanAssemblies = ScanAssemblies.Union(new[] { Assembly.GetExecutingAssembly(), Assembly.GetCallingAssembly() }).ToList();
type = scanAssemblies
.Select(assembly => assembly.GetType(typeName, false))
.FirstOrDefault(x => x != null);
if (type == null)
{
throw new PanicException($"Could not resolve the running test fixture from type name {typeName}.\n" +
$"To use base classes from Umbraco.Tests, add your test assembly to TestOptionAttributeBase.ScanAssemblies");
}
}
var type = TestExecutionContext.CurrentContext.TestObject.GetType();
MethodInfo methodInfo = type.GetMethod(methodName); // what about overloads?
TOptions options = GetTestOptions<TOptions>(methodInfo);
return options;

View File

@@ -6,10 +6,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Examine.Lucene" Version="2.0.0" />
<PackageReference Include="Examine.Lucene" Version="2.0.1" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.10" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.11" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0">

View File

@@ -4,6 +4,7 @@
using System;
using System.Linq.Expressions;
using System.Net.Http;
using System.Reflection;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@@ -24,7 +25,6 @@ using Umbraco.Cms.Tests.Integration.DependencyInjection;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Cms.Web.BackOffice.Controllers;
using Umbraco.Cms.Web.Common.Controllers;
using Umbraco.Cms.Web.UI;
using Umbraco.Cms.Web.Website.Controllers;
using Umbraco.Extensions;
@@ -52,17 +52,22 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
*
* See https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests
*/
var factory = new UmbracoWebApplicationFactory<Startup>(CreateHostBuilder, BeforeHostStart);
var factory = new UmbracoWebApplicationFactory<UmbracoTestServerTestBase>(CreateHostBuilder, BeforeHostStart);
// additional host configuration for web server integration tests
Factory = factory.WithWebHostBuilder(builder =>
{
// Otherwise inferred as $(SolutionDir)/Umbraco.Tests.Integration (note lack of src/tests)
builder.UseContentRoot(Assembly.GetExecutingAssembly().GetRootDirectorySafe());
// Executes after the standard ConfigureServices method
builder.ConfigureTestServices(services =>
// Add a test auth scheme with a test auth handler to authn and assign the user
services.AddAuthentication(TestAuthHandler.TestAuthenticationScheme)
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(TestAuthHandler.TestAuthenticationScheme, options => { })));
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(TestAuthHandler.TestAuthenticationScheme, options => { }));
});
Client = Factory.CreateClient(new WebApplicationFactoryClientOptions
{
@@ -141,7 +146,7 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
protected LinkGenerator LinkGenerator { get; private set; }
protected WebApplicationFactory<Startup> Factory { get; private set; }
protected WebApplicationFactory<UmbracoTestServerTestBase> Factory { get; private set; }
public override void ConfigureServices(IServiceCollection services)
{

View File

@@ -6,6 +6,7 @@ using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Infrastructure.Persistence;
@@ -118,13 +119,13 @@ namespace Umbraco.Cms.Tests.Integration.Testing
string filename = Path.Combine(s_filesPath, DatabaseName).ToUpper();
foreach (string database in s_localDbInstance.GetDatabases())
Parallel.ForEach(s_localDbInstance.GetDatabases(), instance =>
{
if (database.StartsWith(filename))
if (instance.StartsWith(filename))
{
s_localDbInstance.DropDatabase(database);
s_localDbInstance.DropDatabase(instance);
}
}
});
_localDb.StopInstance(InstanceName);

View File

@@ -6,6 +6,7 @@ using System.Collections.Concurrent;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Infrastructure.Persistence;
@@ -118,10 +119,7 @@ namespace Umbraco.Cms.Tests.Integration.Testing
{
}
foreach (TestDbMeta testDatabase in _testDatabases)
{
Drop(testDatabase);
}
Parallel.ForEach(_testDatabases, Drop);
}
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Tests.Integration.TestServerTest;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core
{
[TestFixture]
public class PublishedContentQueryAccessorTests : UmbracoTestServerTestBase
{
[Test]
public async Task PublishedContentQueryAccessor_WithRequestScope_WillProvideQuery()
{
HttpResponseMessage result = await Client.GetAsync("/demo-published-content-query-accessor");
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
}
}
public class PublishedContentQueryAccessorTestController : Controller
{
private readonly IPublishedContentQueryAccessor _accessor;
public PublishedContentQueryAccessorTestController(IPublishedContentQueryAccessor accessor)
{
_accessor = accessor;
}
[HttpGet("demo-published-content-query-accessor")]
public IActionResult Test()
{
var success = _accessor.TryGetValue(out IPublishedContentQuery query);
if (!success || query == null)
{
throw new ApplicationException("It doesn't work");
}
return Ok();
}
}
}

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Bogus;
using Examine;
using Lucene.Net.Util;
using Newtonsoft.Json;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
@@ -47,6 +49,43 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Examine.Lucene.UmbracoExamine
}
}
[Test]
public void GivenIndexingDocument_WhenRichTextPropertyData_CanStoreImmenseFields()
{
using (GetSynchronousContentIndex(false, out UmbracoContentIndex index, out _, out ContentValueSetBuilder contentValueSetBuilder, null))
{
index.CreateIndex();
ContentType contentType = ContentTypeBuilder.CreateBasicContentType();
contentType.AddPropertyType(new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Ntext)
{
Alias = "rte",
Name = "RichText",
PropertyEditorAlias = Cms.Core.Constants.PropertyEditors.Aliases.TinyMce
});
Content content = ContentBuilder.CreateBasicContent(contentType);
content.Id = 555;
content.Path = "-1,555";
var luceneStringFieldMaxLength = ByteBlockPool.BYTE_BLOCK_SIZE - 2;
var faker = new Faker();
var immenseText = faker.Random.String(length: luceneStringFieldMaxLength + 10);
content.Properties["rte"].SetValue(immenseText);
IEnumerable<ValueSet> valueSet = contentValueSetBuilder.GetValueSets(content);
index.IndexItems(valueSet);
ISearchResults results = index.Searcher.CreateQuery().Id(555).Execute();
ISearchResult result = results.First();
var key = $"{UmbracoExamineFieldNames.RawFieldPrefix}rte";
Assert.IsTrue(result.Values.ContainsKey(key));
Assert.Greater(result.Values[key].Length, luceneStringFieldMaxLength);
}
}
[Test]
public void GivenIndexingDocument_WhenGridPropertyData_ThenDataIndexedInSegregatedFields()
{

View File

@@ -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();

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.IO;
@@ -73,7 +74,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
{
var templateRepo = new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper);
var templateRepo = new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper, Mock.Of<IViewHelper>());
ContentTypeRepository repository = ContentTypeRepository;
Template[] templates = new[]
{
@@ -273,7 +274,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
Assert.AreNotEqual(propertyType.Key, Guid.Empty);
}
TestHelper.AssertPropertyValuesAreEqual(fetched, contentType, ignoreProperties: new[] { "DefaultTemplate", "AllowedTemplates", "UpdateDate" });
TestHelper.AssertPropertyValuesAreEqual(fetched, contentType, ignoreProperties: new[] { "DefaultTemplate", "AllowedTemplates", "UpdateDate", "HistoryCleanup" });
}
}
@@ -378,6 +379,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
//// Alias = display.Alias,
Path = display.Path,
//// AdditionalData = display.AdditionalData,
HistoryCleanup = display.HistoryCleanup,
// ContentTypeBasic
Alias = display.Alias,

View File

@@ -114,7 +114,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
appCaches ??= AppCaches;
templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper);
templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper, Mock.Of<IViewHelper>());
var tagRepository = new TagRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<TagRepository>());
var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches, ShortStringHelper);
var languageRepository = new LanguageRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<LanguageRepository>(), globalSettings);

View File

@@ -0,0 +1,204 @@
using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories
{
/// <remarks>
/// v9 -> Tests.Integration
/// </remarks>
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public class DocumentVersionRepositoryTest : UmbracoIntegrationTest
{
public IFileService FileService => GetRequiredService<IFileService>();
public IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
public IContentService ContentService => GetRequiredService<IContentService>();
[Test]
public void GetDocumentVersionsEligibleForCleanup_Always_ExcludesActiveVersions()
{
Template template = TemplateBuilder.CreateTextPageTemplate();
FileService.SaveTemplate(template);
var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id);
ContentTypeService.Save(contentType);
var content = ContentBuilder.CreateSimpleContent(contentType);
ContentService.SaveAndPublish(content);
// At this point content has 2 versions, a draft version and a published version.
ContentService.SaveAndPublish(content);
// At this point content has 3 versions, a historic version, a draft version and a published version.
using (ScopeProvider.CreateScope())
{
var sut = new DocumentVersionRepository(ScopeAccessor);
var results = sut.GetDocumentVersionsEligibleForCleanup();
Assert.Multiple(() =>
{
Assert.AreEqual(1, results.Count);
Assert.AreEqual(1, results.First().VersionId);
});
}
}
[Test]
public void GetDocumentVersionsEligibleForCleanup_Always_ExcludesPinnedVersions()
{
Template template = TemplateBuilder.CreateTextPageTemplate();
FileService.SaveTemplate(template);
var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id);
ContentTypeService.Save(contentType);
ContentTypeService.Save(contentType);
var content = ContentBuilder.CreateSimpleContent(contentType);
ContentService.SaveAndPublish(content);
// At this point content has 2 versions, a draft version and a published version.
ContentService.SaveAndPublish(content);
ContentService.SaveAndPublish(content);
ContentService.SaveAndPublish(content);
// At this point content has 5 versions, 3 historic versions, a draft version and a published version.
var allVersions = ContentService.GetVersions(content.Id);
Debug.Assert(allVersions.Count() == 5); // Sanity check
using (var scope = ScopeProvider.CreateScope())
{
scope.Database.Update<ContentVersionDto>("set preventCleanup = 1 where id in (1,3)");
var sut = new DocumentVersionRepository(ScopeAccessor);
var results = sut.GetDocumentVersionsEligibleForCleanup();
Assert.Multiple(() =>
{
Assert.AreEqual(1, results.Count);
// We pinned 1 & 3
// 4 is current
// 5 is published
// So all that is left is 2
Assert.AreEqual(2, results.First().VersionId);
});
}
}
[Test]
public void DeleteVersions_Always_DeletesSpecifiedVersions()
{
Template template = TemplateBuilder.CreateTextPageTemplate();
FileService.SaveTemplate(template);
var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id);
ContentTypeService.Save(contentType);
var content = ContentBuilder.CreateSimpleContent(contentType);
ContentService.SaveAndPublish(content);
ContentService.SaveAndPublish(content);
ContentService.SaveAndPublish(content);
ContentService.SaveAndPublish(content);
using (var scope = ScopeProvider.CreateScope())
{
var query = scope.SqlContext.Sql();
query.Select<ContentVersionDto>()
.From<ContentVersionDto>();
var sut = new DocumentVersionRepository(ScopeAccessor);
sut.DeleteVersions(new []{1,2,3});
var after = scope.Database.Fetch<ContentVersionDto>(query);
Assert.Multiple(() =>
{
Assert.AreEqual(2, after.Count);
Assert.True(after.All(x => x.Id > 3));
});
}
}
[Test]
public void GetPagedItemsByContentId_WithInvariantCultureContent_ReturnsPaginatedResults()
{
Template template = TemplateBuilder.CreateTextPageTemplate();
FileService.SaveTemplate(template);
var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id);
ContentTypeService.Save(contentType);
var content = ContentBuilder.CreateSimpleContent(contentType);
ContentService.SaveAndPublish(content); // Draft + Published
ContentService.SaveAndPublish(content); // New Draft
using (ScopeProvider.CreateScope())
{
var sut = new DocumentVersionRepository((IScopeAccessor)ScopeProvider);
var page1 = sut.GetPagedItemsByContentId(content.Id, 0, 2, out var page1Total);
var page2 = sut.GetPagedItemsByContentId(content.Id, 1, 2, out var page2Total);
Assert.Multiple(() =>
{
Assert.AreEqual(2, page1.Count());
Assert.AreEqual(3, page1Total);
Assert.AreEqual(1, page2.Count());
Assert.AreEqual(3, page2Total);
});
}
}
[Test]
public void GetPagedItemsByContentId_WithVariantCultureContent_ReturnsPaginatedResults()
{
Template template = TemplateBuilder.CreateTextPageTemplate();
FileService.SaveTemplate(template);
var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id);
contentType.Variations = ContentVariation.Culture;
foreach (var propertyType in contentType.PropertyTypes)
{
propertyType.Variations = ContentVariation.Culture;
}
FileService.SaveTemplate(contentType.DefaultTemplate);
ContentTypeService.Save(contentType);
var content = ContentBuilder.CreateSimpleContent(contentType, "foo", culture:"en-US");
content.SetCultureName("foo", "en-US");
ContentService.SaveAndPublish(content, "en-US"); // Draft + Published
ContentService.SaveAndPublish(content, "en-US"); // New Draft
using (ScopeProvider.CreateScope())
{
var sut = new DocumentVersionRepository((IScopeAccessor)ScopeProvider);
var page1 = sut.GetPagedItemsByContentId(content.Id, 0, 2, out var page1Total, 1);
var page2 = sut.GetPagedItemsByContentId(content.Id, 1, 2, out var page2Total, 1);
Assert.Multiple(() =>
{
Assert.AreEqual(2, page1.Count());
Assert.AreEqual(3, page1Total);
Assert.AreEqual(1, page2.Count());
Assert.AreEqual(3, page2Total);
});
}
}
}
}

View File

@@ -38,10 +38,11 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
private IHostingEnvironment HostingEnvironment => GetRequiredService<IHostingEnvironment>();
private FileSystems FileSystems => GetRequiredService<FileSystems>();
private IViewHelper ViewHelper => GetRequiredService<IViewHelper>();
private ITemplateRepository CreateRepository(IScopeProvider provider) =>
new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper);
new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper, ViewHelper);
[Test]
public void Can_Instantiate_Repository()
{
@@ -90,16 +91,14 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
// Act
var template = new Template(ShortStringHelper, "test", "test")
{
Content = ViewHelper.GetDefaultFileContent()
Content = "mock-content"
};
repository.Save(template);
// Assert
Assert.That(repository.Get("test"), Is.Not.Null);
Assert.That(FileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True);
Assert.AreEqual(
@"@usingUmbraco.Cms.Web.Common.PublishedModels;@inheritsUmbraco.Cms.Web.Common.Views.UmbracoViewPage@{Layout=null;}".StripWhitespace(),
template.Content.StripWhitespace());
Assert.AreEqual("mock-content", template.Content.StripWhitespace());
}
}
@@ -144,13 +143,13 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
// Act
var template = new Template(ShortStringHelper, "test", "test")
{
Content = ViewHelper.GetDefaultFileContent()
Content = "mock-content"
};
repository.Save(template);
var template2 = new Template(ShortStringHelper, "test", "test")
{
Content = ViewHelper.GetDefaultFileContent()
Content = "mock-content"
};
repository.Save(template2);
@@ -172,13 +171,13 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
// Act
var template = new Template(ShortStringHelper, "test", "test")
{
Content = ViewHelper.GetDefaultFileContent()
Content = "mock-content"
};
repository.Save(template);
var template2 = new Template(ShortStringHelper, "test1", "test1")
{
Content = ViewHelper.GetDefaultFileContent()
Content = "mock-content"
};
repository.Save(template2);
@@ -205,7 +204,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
// Act
var template = new Template(ShortStringHelper, "test", "test")
{
Content = ViewHelper.GetDefaultFileContent()
Content = "mock-content"
};
repository.Save(template);
@@ -216,7 +215,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
// Assert
Assert.That(FileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True);
Assert.That(updated.Content, Is.EqualTo(ViewHelper.GetDefaultFileContent() + "<html></html>"));
Assert.That(updated.Content, Is.EqualTo("mock-content" + "<html></html>"));
}
}
@@ -232,7 +231,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos
var template = new Template(ShortStringHelper, "test", "test")
{
Content = ViewHelper.GetDefaultFileContent()
Content = "mock-content"
};
repository.Save(template);

View File

@@ -0,0 +1,119 @@
using System;
using Microsoft.AspNetCore.Http;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.DependencyInjection;
using Umbraco.Cms.Tests.Common;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping;
using Umbraco.Extensions;
namespace Umbraco.Tests.Scoping
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public class ScopedNuCacheTests : UmbracoIntegrationTest
{
private IContentService ContentService => GetRequiredService<IContentService>();
private Mock<IHttpContextAccessor> MockHttpContextAccessor { get; set; } = CreateMockHttpContextAccessor();
private IUmbracoContextFactory UmbracoContextFactory => GetRequiredService<IUmbracoContextFactory>();
private IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
private IVariationContextAccessor VariationContextAccessor => GetRequiredService<IVariationContextAccessor>();
protected override void CustomTestSetup(IUmbracoBuilder builder)
{
NotificationHandler.PublishedContent = notification => { };
builder.Services.AddUnique<IServerMessenger, ScopedRepositoryTests.LocalServerMessenger>();
builder.AddCoreNotifications();
builder.AddNotificationHandler<ContentPublishedNotification, NotificationHandler>();
builder.Services.AddUnique<IUmbracoContextAccessor, TestUmbracoContextAccessor>();
builder.Services.AddUnique<IHttpContextAccessor>(MockHttpContextAccessor.Object);
builder.AddNuCache();
}
public class NotificationHandler : INotificationHandler<ContentPublishedNotification>
{
public void Handle(ContentPublishedNotification notification) => PublishedContent?.Invoke(notification);
public static Action<ContentPublishedNotification> PublishedContent { get; set; }
}
private static Mock<IHttpContextAccessor> CreateMockHttpContextAccessor()
{
var mockHttpContextAccessor = new Mock<IHttpContextAccessor>();
var httpContext = new DefaultHttpContext();
httpContext.Request.Scheme = "http";
httpContext.Request.Host = new HostString("localhost");
mockHttpContextAccessor.SetupGet(x => x.HttpContext).Returns(httpContext);
return mockHttpContextAccessor;
}
[TestCase(true)]
[TestCase(false)]
public void TestScope(bool complete)
{
var umbracoContext = UmbracoContextFactory.EnsureUmbracoContext().UmbracoContext;
// create document type, document
var contentType = new ContentType(ShortStringHelper, -1) { Alias = "CustomDocument", Name = "Custom Document" };
ContentTypeService.Save(contentType);
var item = new Content("name", -1, contentType);
using (var scope = ScopeProvider.CreateScope())
{
ContentService.SaveAndPublish(item);
scope.Complete();
}
// event handler
var evented = 0;
NotificationHandler.PublishedContent = notification =>
{
evented++;
var e = umbracoContext.Content.GetById(item.Id);
// during events, due to LiveSnapshot, we see the changes
Assert.IsNotNull(e);
Assert.AreEqual("changed", e.Name(VariationContextAccessor));
};
// been created
var x = umbracoContext.Content.GetById(item.Id);
Assert.IsNotNull(x);
Assert.AreEqual("name", x.Name(VariationContextAccessor));
using (var scope = ScopeProvider.CreateScope())
{
item.Name = "changed";
ContentService.SaveAndPublish(item);
if (complete)
{
scope.Complete();
}
}
// only 1 event occuring because we are publishing twice for the same event for
// the same object and the scope deduplicates the events (uses the latest)
Assert.AreEqual(complete ? 1 : 0, evented);
// after the scope,
// if completed, we see the changes
// else changes have been rolled back
x = umbracoContext.Content.GetById(item.Id);
Assert.IsNotNull(x);
Assert.AreEqual(complete ? "changed" : "name", x.Name(VariationContextAccessor));
}
}
}

View File

@@ -3,27 +3,26 @@
using System;
using System.Linq;
using System.Threading;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using NPoco;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping;
using Umbraco.Extensions;
using Language = Umbraco.Cms.Core.Models.Language;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
{
@@ -52,9 +51,14 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
protected override void CustomTestSetup(IUmbracoBuilder builder)
{
InMemoryConfiguration[Constants.Configuration.ConfigNuCache + ":" + nameof(NuCacheSettings.NuCacheSerializerType)] = NuCacheSerializerType.JSON.ToString();
builder.AddNuCache();
builder.Services.AddUnique<IServerMessenger, ScopedRepositoryTests.LocalServerMessenger>();
builder.Services.PostConfigure<NuCacheSettings>(options =>
{
options.NuCacheSerializerType = NuCacheSerializerType.JSON;
});
}
private void AssertJsonStartsWith(int id, string expected)
@@ -1333,7 +1337,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
{
Alias = alias,
Name = alias,
Variations = variance
Variations = variance,
};
private PropertyTypeCollection CreatePropertyCollection(params (string alias, ContentVariation variance)[] props)

View File

@@ -0,0 +1,119 @@
using System;
using System.Diagnostics;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
internal class ContentVersionCleanupServiceTest : UmbracoIntegrationTest
{
public IFileService FileService => GetRequiredService<IFileService>();
public IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
public IContentService ContentService => GetRequiredService<IContentService>();
public IContentVersionService ContentVersionService => GetRequiredService<IContentVersionService>();
/// <remarks>
/// This is covered by the unit tests, but nice to know it deletes on infra.
/// And proves implementation is compatible with SQL CE.
/// </remarks>
[Test]
public void PerformContentVersionCleanup_WithNoKeepPeriods_DeletesEverythingExceptActive()
{
// For reference, Our currently has
// 5000 Documents
// With 200K Versions
// With 11M Property data
Template template = TemplateBuilder.CreateTextPageTemplate();
FileService.SaveTemplate(template);
ContentType contentTypeA = ContentTypeBuilder.CreateSimpleContentType("contentTypeA", "contentTypeA", defaultTemplateId: template.Id);
// Kill all historic
contentTypeA.HistoryCleanup.PreventCleanup = false;
contentTypeA.HistoryCleanup.KeepAllVersionsNewerThanDays = 0;
contentTypeA.HistoryCleanup.KeepLatestVersionPerDayForDays = 0;
ContentTypeService.Save(contentTypeA);
Content content = ContentBuilder.CreateSimpleContent(contentTypeA);
ContentService.SaveAndPublish(content);
for (var i = 0; i < 10; i++)
{
ContentService.SaveAndPublish(content);
}
Report before = GetReport();
Debug.Assert(before.ContentVersions == 12); // 10 historic + current draft + current published
Debug.Assert(before.PropertyData == 12 * 3); // CreateSimpleContentType = 3 props
ContentVersionService.PerformContentVersionCleanup(DateTime.Now.AddHours(1));
Report after = GetReport();
Assert.Multiple(() =>
{
Assert.AreEqual(2, after.ContentVersions); // current draft, current published
Assert.AreEqual(2, after.DocumentVersions);
Assert.AreEqual(6, after.PropertyData); // CreateSimpleContentType = 3 props
});
}
private Report GetReport()
{
using (IScope scope = ScopeProvider.CreateScope(autoComplete: true))
{
// SQL CE is fun!
var contentVersions = scope.Database.Single<int>(@"select count(1) from umbracoContentVersion");
var documentVersions = scope.Database.Single<int>(@"select count(1) from umbracoDocumentVersion");
var propertyData = scope.Database.Single<int>(@"select count(1) from umbracoPropertyData");
return new Report
{
ContentVersions = contentVersions,
DocumentVersions = documentVersions,
PropertyData = propertyData
};
}
}
private void InsertCleanupPolicy(IContentType contentType, int daysToKeepAll, int daysToRollupAll, bool preventCleanup = false)
{
using (IScope scope = ScopeProvider.CreateScope(autoComplete: true))
{
var entity = new ContentVersionCleanupPolicyDto
{
ContentTypeId = contentType.Id,
KeepAllVersionsNewerThanDays = daysToKeepAll,
KeepLatestVersionPerDayForDays = daysToRollupAll,
PreventCleanup = preventCleanup,
Updated = DateTime.Today
};
scope.Database.Insert(entity);
}
}
private class Report
{
public int ContentVersions { get; set; }
public int DocumentVersions { get; set; }
public int PropertyData { get; set; }
}
}
}

View File

@@ -6,7 +6,13 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using NUnit.Framework;
using Umbraco.Extensions;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Tests.Common.Builders;
@@ -14,6 +20,13 @@ using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importing;
using Microsoft.Extensions.Logging;
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
{
@@ -22,6 +35,14 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
public class EntityXmlSerializerTests : UmbracoIntegrationTest
{
private IEntityXmlSerializer Serializer => GetRequiredService<IEntityXmlSerializer>();
private IContentService ContentService => GetRequiredService<IContentService>();
private IMediaService MediaService => GetRequiredService<IMediaService>();
private IUserService UserService => GetRequiredService<IUserService>();
private IMediaTypeService MediaTypeService => GetRequiredService<IMediaTypeService>();
private IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
private IDataValueEditorFactory DataValueEditorFactory => GetRequiredService<IDataValueEditorFactory>();
private ILocalizedTextService TextService => GetRequiredService<ILocalizedTextService>();
private IFileService FileService => GetRequiredService<IFileService>();
[Test]
public void Can_Export_Macro()
@@ -89,6 +110,175 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
Assert.That(xml.ToString(), Is.EqualTo(languageItemsElement.ToString()));
}
[Test]
public void Can_Generate_Xml_Representation_Of_Content()
{
// Arrange
var template = TemplateBuilder.CreateTextPageTemplate();
FileService.SaveTemplate(template); // else, FK violation on contentType!
var contentType = ContentTypeBuilder.CreateTextPageContentType(
defaultTemplateId: template.Id);
ContentTypeService.Save(contentType);
var content = ContentBuilder.CreateTextpageContent(contentType, "Root Home", -1);
ContentService.Save(content, Constants.Security.SuperUserId);
var nodeName = content.ContentType.Alias.ToSafeAlias(ShortStringHelper);
var urlName = content.GetUrlSegment(ShortStringHelper, new[] { new DefaultUrlSegmentProvider(ShortStringHelper) });
// Act
XElement element = content.ToXml(Serializer);
// Assert
Assert.That(element, Is.Not.Null);
Assert.That(element.Name.LocalName, Is.EqualTo(nodeName));
Assert.AreEqual(content.Id.ToString(), (string)element.Attribute("id"));
Assert.AreEqual(content.ParentId.ToString(), (string)element.Attribute("parentID"));
Assert.AreEqual(content.Level.ToString(), (string)element.Attribute("level"));
Assert.AreEqual(content.CreatorId.ToString(), (string)element.Attribute("creatorID"));
Assert.AreEqual(content.SortOrder.ToString(), (string)element.Attribute("sortOrder"));
Assert.AreEqual(content.CreateDate.ToString("s"), (string)element.Attribute("createDate"));
Assert.AreEqual(content.UpdateDate.ToString("s"), (string)element.Attribute("updateDate"));
Assert.AreEqual(content.Name, (string)element.Attribute("nodeName"));
Assert.AreEqual(urlName, (string)element.Attribute("urlName"));
Assert.AreEqual(content.Path, (string)element.Attribute("path"));
Assert.AreEqual("", (string)element.Attribute("isDoc"));
Assert.AreEqual(content.ContentType.Id.ToString(), (string)element.Attribute("nodeType"));
Assert.AreEqual(content.GetCreatorProfile(UserService).Name, (string)element.Attribute("creatorName"));
Assert.AreEqual(content.GetWriterProfile(UserService).Name, (string)element.Attribute("writerName"));
Assert.AreEqual(content.WriterId.ToString(), (string)element.Attribute("writerID"));
Assert.AreEqual(content.TemplateId.ToString(), (string)element.Attribute("template"));
Assert.AreEqual(content.Properties["title"].GetValue().ToString(), element.Elements("title").Single().Value);
Assert.AreEqual(content.Properties["bodyText"].GetValue().ToString(), element.Elements("bodyText").Single().Value);
Assert.AreEqual(content.Properties["keywords"].GetValue().ToString(), element.Elements("keywords").Single().Value);
Assert.AreEqual(content.Properties["description"].GetValue().ToString(), element.Elements("description").Single().Value);
}
[Test]
public void Can_Generate_Xml_Representation_Of_Media()
{
// Arrange
var mediaType = MediaTypeBuilder.CreateImageMediaType("image2");
MediaTypeService.Save(mediaType);
// reference, so static ctor runs, so event handlers register
// and then, this will reset the width, height... because the file does not exist, of course ;-(
var loggerFactory = NullLoggerFactory.Instance;
var scheme = Mock.Of<IMediaPathScheme>();
var contentSettings = new ContentSettings();
var mediaFileManager = new MediaFileManager(
Mock.Of<IFileSystem>(),
scheme,
loggerFactory.CreateLogger<MediaFileManager>(),
ShortStringHelper,
Services,
Options.Create(new ContentSettings()));
var ignored = new FileUploadPropertyEditor(
DataValueEditorFactory,
mediaFileManager,
Options.Create(contentSettings),
TextService,
Services.GetRequiredService<UploadAutoFillProperties>(),
ContentService,
IOHelper);
var media = MediaBuilder.CreateMediaImage(mediaType, -1);
media.WriterId = -1; // else it's zero and that's not a user and it breaks the tests
MediaService.Save(media, Constants.Security.SuperUserId);
// so we have to force-reset these values because the property editor has cleared them
media.SetValue(Constants.Conventions.Media.Width, "200");
media.SetValue(Constants.Conventions.Media.Height, "200");
media.SetValue(Constants.Conventions.Media.Bytes, "100");
media.SetValue(Constants.Conventions.Media.Extension, "png");
var nodeName = media.ContentType.Alias.ToSafeAlias(ShortStringHelper);
var urlName = media.GetUrlSegment(ShortStringHelper, new[] { new DefaultUrlSegmentProvider(ShortStringHelper) });
// Act
XElement element = media.ToXml(Serializer);
// Assert
Assert.That(element, Is.Not.Null);
Assert.That(element.Name.LocalName, Is.EqualTo(nodeName));
Assert.AreEqual(media.Id.ToString(), (string)element.Attribute("id"));
Assert.AreEqual(media.ParentId.ToString(), (string)element.Attribute("parentID"));
Assert.AreEqual(media.Level.ToString(), (string)element.Attribute("level"));
Assert.AreEqual(media.SortOrder.ToString(), (string)element.Attribute("sortOrder"));
Assert.AreEqual(media.CreateDate.ToString("s"), (string)element.Attribute("createDate"));
Assert.AreEqual(media.UpdateDate.ToString("s"), (string)element.Attribute("updateDate"));
Assert.AreEqual(media.Name, (string)element.Attribute("nodeName"));
Assert.AreEqual(urlName, (string)element.Attribute("urlName"));
Assert.AreEqual(media.Path, (string)element.Attribute("path"));
Assert.AreEqual("", (string)element.Attribute("isDoc"));
Assert.AreEqual(media.ContentType.Id.ToString(), (string)element.Attribute("nodeType"));
Assert.AreEqual(media.GetCreatorProfile(UserService).Name, (string)element.Attribute("writerName"));
Assert.AreEqual(media.CreatorId.ToString(), (string)element.Attribute("writerID"));
Assert.IsNull(element.Attribute("template"));
Assert.AreEqual(media.Properties[Constants.Conventions.Media.File].GetValue().ToString(), element.Elements(Constants.Conventions.Media.File).Single().Value);
Assert.AreEqual(media.Properties[Constants.Conventions.Media.Width].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Width).Single().Value);
Assert.AreEqual(media.Properties[Constants.Conventions.Media.Height].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Height).Single().Value);
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()
{
ILocalizationService localizationService = GetRequiredService<ILocalizationService>();
@@ -104,7 +294,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
.Build();
localizationService.Save(languageEnGb);
var parentItem = new DictionaryItem("Parent") {Key = Guid.Parse("28f2e02a-8c66-4fcd-85e3-8524d551c0d3")};
var parentItem = new DictionaryItem("Parent") { Key = Guid.Parse("28f2e02a-8c66-4fcd-85e3-8524d551c0d3") };
var parentTranslations = new List<IDictionaryTranslation>
{
new DictionaryTranslation(languageNbNo, "ForelderVerdi"),
@@ -113,7 +303,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
parentItem.Translations = parentTranslations;
localizationService.Save(parentItem);
var childItem = new DictionaryItem(parentItem.Key, "Child"){Key = Guid.Parse("e7dba0a9-d517-4ba4-8e18-2764d392c611")};
var childItem = new DictionaryItem(parentItem.Key, "Child") { Key = Guid.Parse("e7dba0a9-d517-4ba4-8e18-2764d392c611") };
var childTranslations = new List<IDictionaryTranslation>
{
new DictionaryTranslation(languageNbNo, "BarnVerdi"),

View File

@@ -72,7 +72,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importin
/// &lt;/info&gt;
/// &lt;Documents&gt;
/// &lt;DocumentSet importMode=&quot;root&quot;&gt;
/// &lt;NewType id=&quot;1148&quot; parentID=&quot;-1&quot; level=&quot;1&quot; creatorID=&quot;0&quot; sortOrder=&quot;9&quot; createDate=&quot;2013-07-23T12:06:07&quot; updateDate=&quot;2013-07-23T15:56:37&quot; nodeName=&quot;DoIt&quot; urlName=&quot;doit&quot; path=&quot;-1,1148&quot; isDoc=&quot;&quot; nodeType=&quot;1134&quot; creatorName=&quot;admin&quot; writerName=&quot;admin&quot; writerID=&quot;0&quot; template=&quot;1133&quot; nodeTy [rest of string was truncated]&quot;;.
/// &lt;NewType key=&quot;9c9b55d0-2fbf-4f12-afea-023bd7b2519d&quot; id=&quot;1148&quot; parentID=&quot;-1&quot; level=&quot;1&quot; creatorID=&quot;0&quot; sortOrder=&quot;9&quot; createDate=&quot;2013-07-23T12:06:07&quot; updateDate=&quot;2013-07-23T15:56:37&quot; nodeName=&quot;DoIt&quot; urlName=&quot;doit&quot; path=&quot;-1,1148&quot; isDoc=&quot;&quot; nodeType=&quot;1134&quot; creatorName=&quot;admin&quot; writerName= [rest of string was truncated]&quot;;.
/// </summary>
internal static string CheckboxList_Content_Package {
get {
@@ -91,7 +91,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importin
/// &lt;/info&gt;
/// &lt;Documents&gt;
/// &lt;DocumentSet importMode=&quot;root&quot;&gt;
/// &lt;umbHomePage id=&quot;1068&quot; parentID=&quot;-1&quot; level=&quot;1&quot; creatorID=&quot;0&quot; sortOrder=&quot;0&quot; createDate=&quot;2014-11-26T12:52:35&quot; updateDate=&quot;2014-11-26T12:52:36&quot; nodeName=&quot;Home&quot; urlName=&quot;home&quot; path=&quot;-1,1068&quot; isDoc=&quot;&quot; nodeType=&quot;1056&quot; creatorName=&quot;Morten Christensen&quot; writerName=&quot;Morten Christensen&quot; [rest of string was truncated]&quot;;.
/// &lt;umbHomePage key=&quot;9c9b55d0-2fbf-4f12-afea-023bd7b2519d&quot; id=&quot;1068&quot; parentID=&quot;-1&quot; level=&quot;1&quot; creatorID=&quot;0&quot; sortOrder=&quot;0&quot; createDate=&quot;2014-11-26T12:52:35&quot; updateDate=&quot;2014-11-26T12:52:36&quot; nodeName=&quot;Home&quot; urlName=&quot;home&quot; path=&quot;-1,1068&quot; isDoc=&quot;&quot; nodeType=&quot;1056&quot; creatorName=&quot;Morten Ch [rest of string was truncated]&quot;;.
/// </summary>
internal static string CompositionsTestPackage {
get {
@@ -124,15 +124,14 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importin
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;Dictionary-Package&lt;/name&gt;
/// &lt;name&gt;Dictionary-Package&lt;/name&gt;
/// &lt;/package&gt;
/// &lt;/info&gt;
/// &lt;DictionaryItems&gt;
/// &lt;DictionaryItem Key=&quot;Parent&quot;&gt;
/// &lt;DictionaryItem Key=&quot;28f2e02a-8c66-4fcd-85e3-8524d551c0d3&quot; Name=&quot;Parent&quot;&gt;
/// &lt;Value LanguageId=&quot;2&quot; LanguageCultureAlias=&quot;nb-NO&quot;&gt;&lt;![CDATA[ForelderVerdi]]&gt;&lt;/Value&gt;
/// &lt;Value LanguageId=&quot;3&quot; LanguageCultureAlias=&quot;en-GB&quot;&gt;&lt;![CDATA[ParentValue]]&gt;&lt;/Value&gt;
/// &lt;DictionaryItem Key=&quot;Child&quot;&gt;
/// &lt;Value LanguageId=&quot;2&quot; LanguageCultureAlias=&quot;nb-NO&quot;&gt;&lt;![CDATA[BarnV [rest of string was truncated]&quot;;.
/// &lt;DictionaryItem Key=&quot;e7dba0a9-d517-4ba4-8e18-2764d392c611&quot; Name=&quot; [rest of string was truncated]&quot;;.
/// </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 &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
///&lt;DocumentType&gt;
/// &lt;Info&gt;
/// &lt;Name&gt;test&lt;/Name&gt;
/// &lt;Key&gt;150ead17-d359-42a2-ac33-6504cc52ced1&lt;/Key&gt;
/// &lt;Alias&gt;test&lt;/Alias&gt;
/// &lt;Icon&gt;folder.gif&lt;/Icon&gt;
/// &lt;Thumbnail&gt;folder.png&lt;/Thumbnail&gt;
/// &lt;Description&gt;
/// &lt;/Description&gt;
/// &lt;AllowAtRoot&gt;False&lt;/AllowAtRoot&gt;
/// &lt;AllowedTemplates&gt;
/// &lt;Template&gt;test&lt;/Template&gt;
/// &lt;/AllowedTemplates&gt;
/// &lt;DefaultTemplate&gt;test&lt;/DefaultTemplate&gt;
/// &lt;/Info&gt;
/// &lt;Structure&gt;
/// &lt;DocumentType&gt;test&lt;/DocumentType&gt;
/// &lt;/Str [rest of string was truncated]&quot;;.
/// </summary>
internal static string SingleDocType_WithCleanupPolicy {
get {
return ResourceManager.GetString("SingleDocType_WithCleanupPolicy", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
@@ -249,8 +275,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importin
/// &lt;/info&gt;
/// &lt;Documents&gt;
/// &lt;DocumentSet importMode=&quot;root&quot;&gt;
/// &lt;Homepage id=&quot;1072&quot; parentID=&quot;-1&quot; level=&quot;1&quot; creatorID=&quot;0&quot; sortOrder=&quot;0&quot; createDate=&quot;2013-02-17T09:04:39&quot; updateDate=&quot;2013-02-17T09:10:47&quot; nodeName=&quot;Home&quot; urlName=&quot;home&quot; path=&quot;-1,1072&quot; isDoc=&quot;&quot; nodeType=&quot;1062&quot; creatorName=&quot;admin&quot; writerName=&quot;admin&quot; writerID=&quot;0&quot; template=&quot;1049&quot;&gt;
/// &lt;slide [rest of string was truncated]&quot;;.
/// &lt;Homepage key=&quot;9c9b55d0-2fbf-4f12-afea-023bd7b2519d&quot; id=&quot;1072&quot; parentID=&quot;-1&quot; level=&quot;1&quot; creatorID=&quot;0&quot; sortOrder=&quot;0&quot; createDate=&quot;2013-02-17T09:04:39&quot; updateDate=&quot;2013-02-17T09:10:47&quot; nodeName=&quot;Home&quot; urlName=&quot;home&quot; path=&quot;-1,1072&quot; isDoc=&quot;&quot; nodeType=&quot;1062&quot; creatorName=&quot;admin&quot; writerName=&quot;admin&quot; wr [rest of string was truncated]&quot;;.
/// </summary>
internal static string StandardMvc_Package {
get {

View File

@@ -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>

View File

@@ -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>

View File

@@ -0,0 +1,87 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)]
public class NuCacheRebuildTests : UmbracoIntegrationTest
{
private IFileService FileService => GetRequiredService<IFileService>();
private IContentService ContentService => GetRequiredService<IContentService>();
private IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
private IPublishedSnapshotService PublishedSnapshotService => GetRequiredService<IPublishedSnapshotService>();
[Test]
public void UnpublishedNameChanges()
{
var urlSegmentProvider = new DefaultUrlSegmentProvider(ShortStringHelper);
Template template = TemplateBuilder.CreateTextPageTemplate();
FileService.SaveTemplate(template);
ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: template.Id);
ContentTypeService.Save(contentType);
Content content = ContentBuilder.CreateTextpageContent(contentType, "hello", Constants.System.Root);
ContentService.SaveAndPublish(content);
IContent cachedContent = ContentService.GetById(content.Id);
var segment = urlSegmentProvider.GetUrlSegment(cachedContent);
// Does a new node work?
Assert.AreEqual("hello", segment);
content.Name = "goodbye";
cachedContent = ContentService.GetById(content.Id);
segment = urlSegmentProvider.GetUrlSegment(cachedContent);
// We didn't save anything, so all should still be the same
Assert.AreEqual("hello", segment);
ContentService.Save(content);
cachedContent = ContentService.GetById(content.Id);
segment = urlSegmentProvider.GetUrlSegment(cachedContent);
// At this point we have saved the new name, but not published. The url should still be the previous name
Assert.AreEqual("hello", segment);
PublishedSnapshotService.Rebuild();
cachedContent = ContentService.GetById(content.Id);
segment = urlSegmentProvider.GetUrlSegment(cachedContent);
// After a rebuild, the unpublished name should still not be the url.
// This was previously incorrect, per #11074
Assert.AreEqual("hello", segment);
ContentService.SaveAndPublish(content);
cachedContent = ContentService.GetById(content.Id);
segment = urlSegmentProvider.GetUrlSegment(cachedContent);
// The page has now been published, so we should see the new url segment
Assert.AreEqual("goodbye", segment);
PublishedSnapshotService.Rebuild();
cachedContent = ContentService.GetById(content.Id);
segment = urlSegmentProvider.GetUrlSegment(cachedContent);
// Just double checking that things remain after a rebuild
Assert.AreEqual("goodbye", segment);
}
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
@@ -10,7 +10,6 @@
</PropertyGroup>
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
<PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="68.2.0.6" />
<RuntimeHostConfigurationOption Include="System.Globalization.AppLocalIcu" Value="68.2" />
</ItemGroup>
@@ -52,6 +51,8 @@
<DesignTime>True</DesignTime>
<DependentUpon>ImportResources.resx</DependentUpon>
</Compile>
<None Remove="Umbraco.Web.BackOffice\UrlAndDomains\package.xml" />
<EmbeddedResource Include="Umbraco.Web.BackOffice\UrlAndDomains\package.xml" />
</ItemGroup>
<ItemGroup>
@@ -79,10 +80,12 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Examine.Lucene" Version="2.0.0" />
<PackageReference Include="Bogus" Version="33.1.1" />
<PackageReference Include="Examine.Lucene" Version="2.0.1" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.10" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.11" />
<PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="68.2.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0">
@@ -99,7 +102,6 @@
<ProjectReference Include="..\..\src\Umbraco.PublishedCache.NuCache\Umbraco.PublishedCache.NuCache.csproj" />
<ProjectReference Include="..\Umbraco.Tests.Common\Umbraco.Tests.Common.csproj" />
<ProjectReference Include="..\..\src\Umbraco.Web.BackOffice\Umbraco.Web.BackOffice.csproj" />
<ProjectReference Include="..\..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj" />
<ProjectReference Include="..\..\src\Umbraco.Web.Website\Umbraco.Web.Website.csproj" />
</ItemGroup>

View File

@@ -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");
});
}
}
}

View File

@@ -0,0 +1,153 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Packaging;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Tests.Common;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Web.BackOffice.UrlAndDomains
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Mapper = true, WithApplication = true,
Logger = UmbracoTestOptions.Logger.Console)]
public class DomainAndUrlsTests : UmbracoIntegrationTest
{
[SetUp]
public void Setup()
{
XDocument xml = PackageMigrationResource.GetEmbeddedPackageDataManifest(GetType());
IPackagingService packagingService = GetRequiredService<IPackagingService>();
InstallationSummary = packagingService.InstallCompiledPackageData(xml);
Root = InstallationSummary.ContentInstalled.First();
ContentService.SaveAndPublish(Root);
var cultures = new List<string>();
cultures.Add(GetRequiredService<ILocalizationService>().GetDefaultLanguageIsoCode());
foreach (ILanguage language in InstallationSummary.LanguagesInstalled)
{
cultures.Add(language.IsoCode);
}
Cultures = cultures.ToArray();
IHttpContextAccessor httpContextAccessor = GetRequiredService<IHttpContextAccessor>();
httpContextAccessor.HttpContext = new DefaultHttpContext
{
Request =
{
Scheme = "https",
Host = new HostString("localhost"),
Path = "/",
QueryString = new QueryString(string.Empty)
}
};
//Like the request middleware we specify the VariationContext to the default language.
_variationContextAccessor.VariationContext = new VariationContext(Cultures[0]);
GetRequiredService<IUmbracoContextFactory>().EnsureUmbracoContext();
}
private IContentService ContentService => GetRequiredService<IContentService>();
public InstallationSummary InstallationSummary { get; set; }
protected override void CustomTestSetup(IUmbracoBuilder builder)
{
builder.Services.AddUnique<IVariationContextAccessor>(_variationContextAccessor);
builder.AddNuCache();
}
private readonly TestVariationContextAccessor _variationContextAccessor = new TestVariationContextAccessor();
public IContent Root { get; set; }
public string[] Cultures { get; set; }
[Test]
public void Having_three_cultures_and_set_domain_on_all_of_them()
{
foreach (var culture in Cultures)
{
SetDomainOnContent(Root, culture, GetDomainUrlFromCultureCode(culture));
}
IEnumerable<UrlInfo> rootUrls = GetContentUrlsAsync(Root);
Assert.Multiple(() =>
{
Assert.AreEqual(6, rootUrls.Count());
foreach (var culture in Cultures)
{
var domain = GetDomainUrlFromCultureCode(culture);
Assert.IsTrue(rootUrls.Any(x => x.Text == domain));
Assert.IsTrue(rootUrls.Any(x => x.Text == "https://localhost" + domain));
}
});
}
[Test]
public void Having_three_cultures_but_set_domain_on_a_non_default_language()
{
var culture = Cultures[1];
var domain = GetDomainUrlFromCultureCode(culture);
SetDomainOnContent(Root, culture, domain);
IEnumerable<UrlInfo> rootUrls = GetContentUrlsAsync(Root);
Assert.Multiple(() =>
{
Assert.AreEqual(4, rootUrls.Count());
//We expect two for the domain that is setup
Assert.IsTrue(rootUrls.Any(x => x.IsUrl && x.Text == domain && x.Culture == culture));
Assert.IsTrue(rootUrls.Any(x => x.IsUrl && x.Text == "https://localhost" + domain && x.Culture == culture));
//We expect the default language to be routable on the default path "/"
Assert.IsTrue(rootUrls.Any(x=>x.IsUrl && x.Text == "/" && x.Culture == Cultures[0]));
//We dont expect non-default languages without a domain to be routable
Assert.IsTrue(rootUrls.Any(x=>x.IsUrl == false && x.Culture == Cultures[2]));
});
}
private static string GetDomainUrlFromCultureCode(string culture) =>
"/" + culture.Replace("-", string.Empty).ToLower() + "/";
private void SetDomainOnContent(IContent content, string cultureIsoCode, string domain)
{
IDomainService domainService = GetRequiredService<IDomainService>();
var langId = GetRequiredService<ILocalizationService>().GetLanguageIdByIsoCode(cultureIsoCode);
domainService.Save(
new UmbracoDomain(domain) { RootContentId = content.Id, LanguageId = langId });
}
private IEnumerable<UrlInfo> GetContentUrlsAsync(IContent root) =>
root.GetContentUrlsAsync(
GetRequiredService<IPublishedRouter>(),
GetRequiredService<IUmbracoContextAccessor>().GetRequiredUmbracoContext(),
GetRequiredService<ILocalizationService>(),
GetRequiredService<ILocalizedTextService>(),
ContentService,
GetRequiredService<IVariationContextAccessor>(),
GetRequiredService<ILogger<IContent>>(),
GetRequiredService<UriUtility>(),
GetRequiredService<IPublishedUrlProvider>()
).GetAwaiter().GetResult();
}
}

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<umbPackage>
<info>
<package>
<name>Test</name>
</package>
</info>
<Documents>
<DocumentSet importMode="root">
<textPageLang id="5818" key="092b28ba-f1ce-4469-9573-ed716cfe32bc" parentID="-1" level="1" creatorID="-1" sortOrder="0" createDate="2021-10-13T15:39:32" updateDate="2021-10-13T15:39:32" nodeName="svSE" urlName="svse" path="-1,5818" isDoc="" nodeName-sv-se="svSE" nodeName-da="daDK" nodeName-en-us="enUS" nodeType="4130" nodeTypeAlias="textPageLang" creatorName="Bjarke Berg" writerName="Bjarke Berg" writerID="1" template="4129" isPublished="true" />
</DocumentSet>
</Documents>
<DocumentTypes>
<DocumentType>
<Info>
<Name>TextPageLang</Name>
<Alias>textPageLang</Alias>
<Key>d4a44303-bf68-4f34-9f87-6668ff9e9cdc</Key>
<Icon>icon-document</Icon>
<Thumbnail>folder.png</Thumbnail>
<Description />
<AllowAtRoot>True</AllowAtRoot>
<IsListView>False</IsListView>
<IsElement>False</IsElement>
<Variations>Culture</Variations>
<Compositions />
<AllowedTemplates>
<Template>TextPageLang</Template>
</AllowedTemplates>
<DefaultTemplate>TextPageLang</DefaultTemplate>
</Info>
<Structure>
<DocumentType>textPage</DocumentType>
<DocumentType>textPageLang</DocumentType>
</Structure>
<GenericProperties>
<GenericProperty>
<Name>Grid</Name>
<Alias>grid</Alias>
<Key>74dcad47-03e6-4190-a7d5-480bd1d96783</Key>
<Type>Umbraco.Grid</Type>
<Definition>9ccf22c3-34c5-4e58-b365-a2d806c00540</Definition>
<Tab Alias="content">Content</Tab>
<SortOrder>0</SortOrder>
<Mandatory>False</Mandatory>
<LabelOnTop>False</LabelOnTop>
<Variations>Culture</Variations>
</GenericProperty>
</GenericProperties>
<Tabs>
<Tab>
<Id>2074</Id>
<Key>1cd3a297-a821-49e9-98d8-5c21ddd2aeaf</Key>
<Type>Group</Type>
<Caption>Content</Caption>
<Alias>content</Alias>
<SortOrder>0</SortOrder>
</Tab>
</Tabs>
</DocumentType>
</DocumentTypes>
<MediaTypes />
<Templates />
<Stylesheets />
<Scripts />
<PartialViews />
<Macros />
<MacroPartialViews />
<DictionaryItems />
<Languages>
<Language Id="1003" CultureAlias="da" FriendlyName="dansk" />
<Language Id="3" CultureAlias="sv-SE" FriendlyName="svensk (Sverige)" />
<Language Id="1" CultureAlias="en-US" FriendlyName="English (United States)" />
</Languages>
<DataTypes />
<MediaItems />
</umbPackage>

View File

@@ -2,26 +2,7 @@
// See LICENSE for more details.
using System;
using System.Linq;
using AutoFixture;
using AutoFixture.AutoMoq;
using AutoFixture.Kernel;
using AutoFixture.NUnit3;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Moq;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.BackOffice.Controllers;
using Umbraco.Cms.Web.BackOffice.Install;
using Umbraco.Cms.Web.BackOffice.Routing;
using Umbraco.Cms.Web.Common.Security;
namespace Umbraco.Cms.Tests.UnitTests.AutoFixture
{
@@ -34,64 +15,8 @@ namespace Umbraco.Cms.Tests.UnitTests.AutoFixture
/// [Frozen] can be used to ensure the same variable is injected and available as parameter for the test
/// </summary>
public AutoMoqDataAttribute()
: base(() => AutoMockCustomizations.Default)
: base(UmbracoAutoMoqFixtureFactory.CreateDefaultFixture)
{
}
internal static class AutoMockCustomizations
{
public static IFixture Default => new Fixture().Customize(new UmbracoCustomization());
private class UmbracoCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<BackOfficeIdentityUser>(
u => u.FromFactory<string, string, string>(
(a, b, c) => BackOfficeIdentityUser.CreateNew(new GlobalSettings(), a, b, c)));
fixture
.Customize(new ConstructorCustomization(typeof(UsersController), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(InstallController), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(PreviewController), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(MemberController), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(BackOfficeController), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(BackOfficeUserManager), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(MemberManager), new GreedyConstructorQuery()));
fixture.Customize(new AutoMoqCustomization());
// When requesting an IUserStore ensure we actually uses a IUserLockoutStore
fixture.Customize<IUserStore<BackOfficeIdentityUser>>(cc => cc.FromFactory(() => Mock.Of<IUserLockoutStore<BackOfficeIdentityUser>>()));
fixture.Customize<ConfigConnectionString>(
u => u.FromFactory<string, string, string>(
(a, b, c) => new ConfigConnectionString(a, b, c)));
fixture.Customize<IUmbracoVersion>(
u => u.FromFactory(
() => new UmbracoVersion()));
fixture.Customize<BackOfficeAreaRoutes>(u => u.FromFactory(
() => new BackOfficeAreaRoutes(
Options.Create(new GlobalSettings()),
Mock.Of<IHostingEnvironment>(x => x.ToAbsolute(It.IsAny<string>()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty),
Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run),
new UmbracoApiControllerTypeCollection(() => Enumerable.Empty<Type>()))));
fixture.Customize<PreviewRoutes>(u => u.FromFactory(
() => new PreviewRoutes(
Options.Create(new GlobalSettings()),
Mock.Of<IHostingEnvironment>(x => x.ToAbsolute(It.IsAny<string>()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty),
Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run))));
var connectionStrings = new ConnectionStrings();
fixture.Customize<ConnectionStrings>(x => x.FromFactory(() => connectionStrings));
var httpContextAccessor = new HttpContextAccessor { HttpContext = new DefaultHttpContext() };
fixture.Customize<HttpContext>(x => x.FromFactory(() => httpContextAccessor.HttpContext));
fixture.Customize<IHttpContextAccessor>(x => x.FromFactory(() => httpContextAccessor));
}
}
}
}
}

View File

@@ -0,0 +1,10 @@
using AutoFixture;
namespace Umbraco.Cms.Tests.UnitTests.AutoFixture.Customizations
{
internal class OmitRecursionCustomization : ICustomization
{
public void Customize(IFixture fixture) =>
fixture.Behaviors.Add(new OmitOnRecursionBehavior());
}
}

View File

@@ -0,0 +1,78 @@
using System;
using System.Linq;
using AutoFixture;
using AutoFixture.Kernel;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Moq;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.BackOffice.Controllers;
using Umbraco.Cms.Web.BackOffice.Install;
using Umbraco.Cms.Web.BackOffice.Routing;
using Umbraco.Cms.Web.Common.Security;
namespace Umbraco.Cms.Tests.UnitTests.AutoFixture.Customizations
{
internal class UmbracoCustomizations : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<BackOfficeIdentityUser>(
u => u.FromFactory<string, string, string>(
(a, b, c) => BackOfficeIdentityUser.CreateNew(new GlobalSettings(), a, b, c)));
fixture
.Customize(new ConstructorCustomization(typeof(UsersController), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(InstallController), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(PreviewController), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(MemberController), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(BackOfficeController), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(BackOfficeUserManager), new GreedyConstructorQuery()))
.Customize(new ConstructorCustomization(typeof(MemberManager), new GreedyConstructorQuery()));
// When requesting an IUserStore ensure we actually uses a IUserLockoutStore
fixture.Customize<IUserStore<BackOfficeIdentityUser>>(cc => cc.FromFactory(Mock.Of<IUserLockoutStore<BackOfficeIdentityUser>>));
fixture.Customize<ConfigConnectionString>(
u => u.FromFactory<string, string, string>(
(a, b, c) => new ConfigConnectionString(a, b, c)));
fixture.Customize<IUmbracoVersion>(
u => u.FromFactory(
() => new UmbracoVersion()));
fixture.Customize<HostingSettings>(x =>
x.With(settings => settings.ApplicationVirtualPath, string.Empty));
fixture.Customize<BackOfficeAreaRoutes>(u => u.FromFactory(
() => new BackOfficeAreaRoutes(
Options.Create(new GlobalSettings()),
Mock.Of<IHostingEnvironment>(x => x.ToAbsolute(It.IsAny<string>()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty),
Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run),
new UmbracoApiControllerTypeCollection(Enumerable.Empty<Type>))));
fixture.Customize<PreviewRoutes>(u => u.FromFactory(
() => new PreviewRoutes(
Options.Create(new GlobalSettings()),
Mock.Of<IHostingEnvironment>(x => x.ToAbsolute(It.IsAny<string>()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty),
Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run))));
var configConnectionString = new ConfigConnectionString(
"ss",
"Data Source=(localdb)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\Umbraco.mdf;Integrated Security=True");
fixture.Customize<ConfigConnectionString>(x => x.FromFactory(() => configConnectionString));
var httpContextAccessor = new HttpContextAccessor { HttpContext = new DefaultHttpContext() };
fixture.Customize<HttpContext>(x => x.FromFactory(() => httpContextAccessor.HttpContext));
fixture.Customize<IHttpContextAccessor>(x => x.FromFactory(() => httpContextAccessor));
fixture.Customize<WebRoutingSettings>(x => x.With(settings => settings.UmbracoApplicationUrl, "http://localhost:5000"));
}
}
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) Umbraco.
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
@@ -15,7 +15,7 @@ namespace Umbraco.Cms.Tests.UnitTests.AutoFixture
/// [Frozen] can be used to ensure the same variable is injected and available as parameter for the test
/// </summary>
public InlineAutoMoqDataAttribute(params object[] arguments)
: base(() => AutoMoqDataAttribute.AutoMockCustomizations.Default, arguments)
: base(UmbracoAutoMoqFixtureFactory.CreateDefaultFixture, arguments)
{
}
}

View File

@@ -0,0 +1,15 @@
using AutoFixture;
using AutoFixture.AutoMoq;
using Umbraco.Cms.Tests.UnitTests.AutoFixture.Customizations;
namespace Umbraco.Cms.Tests.UnitTests.AutoFixture
{
internal static class UmbracoAutoMoqFixtureFactory
{
internal static IFixture CreateDefaultFixture() =>
new Fixture()
.Customize(new AutoMoqCustomization { ConfigureMembers = true })
.Customize(new OmitRecursionCustomization())
.Customize(new UmbracoCustomizations());
}
}

View File

@@ -0,0 +1,278 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
using Umbraco.Cms.Infrastructure.Serialization;
using Umbraco.Cms.Tests.Common;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.TestHelpers
{
[TestFixture]
public class PublishedSnapshotServiceTestBase
{
[SetUp]
public virtual void Setup()
{
VariationContextAccessor = new TestVariationContextAccessor();
PublishedSnapshotAccessor = new TestPublishedSnapshotAccessor();
}
[TearDown]
public void Teardown() => SnapshotService?.Dispose();
protected IShortStringHelper ShortStringHelper { get; } = TestHelper.ShortStringHelper;
protected virtual IPublishedModelFactory PublishedModelFactory { get; } = new NoopPublishedModelFactory();
protected IContentTypeService ContentTypeService { get; private set; }
protected IMediaTypeService MediaTypeService { get; private set; }
protected IDataTypeService DataTypeService { get; private set; }
protected IDomainService DomainService { get; private set; }
protected IPublishedValueFallback PublishedValueFallback { get; private set; }
protected IPublishedSnapshotService SnapshotService { get; private set; }
protected IVariationContextAccessor VariationContextAccessor { get; private set; }
protected TestPublishedSnapshotAccessor PublishedSnapshotAccessor { get; private set; }
protected TestNuCacheContentService NuCacheContentService { get; private set; }
protected PublishedContentTypeFactory PublishedContentTypeFactory { get; private set; }
protected GlobalSettings GlobalSettings { get; } = new();
protected virtual PropertyValueConverterCollection PropertyValueConverterCollection =>
new(() => new[] { new TestSimpleTinyMceValueConverter() });
protected IPublishedContent GetContent(int id)
{
IPublishedSnapshot snapshot = GetPublishedSnapshot();
IPublishedContent doc = snapshot.Content.GetById(id);
Assert.IsNotNull(doc);
return doc;
}
protected IPublishedContent GetMedia(int id)
{
IPublishedSnapshot snapshot = GetPublishedSnapshot();
IPublishedContent doc = snapshot.Media.GetById(id);
Assert.IsNotNull(doc);
return doc;
}
protected UrlProvider GetUrlProvider(
IUmbracoContextAccessor umbracoContextAccessor,
RequestHandlerSettings requestHandlerSettings,
WebRoutingSettings webRoutingSettings,
out UriUtility uriUtility)
{
uriUtility = new UriUtility(Mock.Of<IHostingEnvironment>());
var urlProvider = new DefaultUrlProvider(
Options.Create(requestHandlerSettings),
Mock.Of<ILogger<DefaultUrlProvider>>(),
new SiteDomainMapper(),
umbracoContextAccessor,
uriUtility,
Mock.Of<ILocalizationService>(x=>x.GetDefaultLanguageIsoCode() == GlobalSettings.DefaultUILanguage)
);
var publishedUrlProvider = new UrlProvider(
umbracoContextAccessor,
Options.Create(webRoutingSettings),
new UrlProviderCollection(() => new[] { urlProvider }),
new MediaUrlProviderCollection(() => Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IVariationContextAccessor>());
return publishedUrlProvider;
}
protected static PublishedRouter CreatePublishedRouter(
IUmbracoContextAccessor umbracoContextAccessor,
IEnumerable<IContentFinder> contentFinders = null,
IPublishedUrlProvider publishedUrlProvider = null) => new(Options.Create(new WebRoutingSettings()),
new ContentFinderCollection(() => contentFinders ?? Enumerable.Empty<IContentFinder>()),
new TestLastChanceFinder(), new TestVariationContextAccessor(), Mock.Of<IProfilingLogger>(),
Mock.Of<ILogger<PublishedRouter>>(), publishedUrlProvider ?? Mock.Of<IPublishedUrlProvider>(),
Mock.Of<IRequestAccessor>(), Mock.Of<IPublishedValueFallback>(), Mock.Of<IFileService>(),
Mock.Of<IContentTypeService>(), umbracoContextAccessor, Mock.Of<IEventAggregator>());
protected IUmbracoContextAccessor GetUmbracoContextAccessor(string urlAsString)
{
IPublishedSnapshot snapshot = GetPublishedSnapshot();
var uri = new Uri(urlAsString.Contains(Uri.SchemeDelimiter)
? urlAsString
: $"http://example.com{urlAsString}");
IUmbracoContext umbracoContext = Mock.Of<IUmbracoContext>(
x => x.CleanedUmbracoUrl == uri
&& x.Content == snapshot.Content
&& x.PublishedSnapshot == snapshot);
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
return umbracoContextAccessor;
}
/// <summary>
/// Used as a property editor for any test property that has an editor alias called "Umbraco.Void.RTE"
/// </summary>
private class TestSimpleTinyMceValueConverter : SimpleTinyMceValueConverter
{
public override bool IsConverter(IPublishedPropertyType propertyType)
=> propertyType.EditorAlias == "Umbraco.Void.RTE";
}
protected static DataType[] GetDefaultDataTypes()
{
var serializer = new ConfigurationEditorJsonSerializer();
// create data types, property types and content types
var dataType =
new DataType(new VoidEditor("Editor", Mock.Of<IDataValueEditorFactory>()), serializer) { Id = 3 };
return new[] { dataType };
}
protected virtual ServiceContext CreateServiceContext(IContentType[] contentTypes, IMediaType[] mediaTypes,
IDataType[] dataTypes)
{
var contentTypeService = new Mock<IContentTypeService>();
contentTypeService.Setup(x => x.GetAll()).Returns(contentTypes);
contentTypeService.Setup(x => x.GetAll(It.IsAny<int[]>())).Returns(contentTypes);
contentTypeService.Setup(x => x.Get(It.IsAny<string>()))
.Returns((string alias) => contentTypes.FirstOrDefault(x => x.Alias.InvariantEquals(alias)));
var mediaTypeService = new Mock<IMediaTypeService>();
mediaTypeService.Setup(x => x.GetAll()).Returns(mediaTypes);
mediaTypeService.Setup(x => x.GetAll(It.IsAny<int[]>())).Returns(mediaTypes);
mediaTypeService.Setup(x => x.Get(It.IsAny<string>()))
.Returns((string alias) => mediaTypes.FirstOrDefault(x => x.Alias.InvariantEquals(alias)));
var contentTypeServiceBaseFactory = new Mock<IContentTypeBaseServiceProvider>();
contentTypeServiceBaseFactory.Setup(x => x.For(It.IsAny<IContentBase>()))
.Returns(contentTypeService.Object);
var dataTypeServiceMock = new Mock<IDataTypeService>();
dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataTypes);
return ServiceContext.CreatePartial(
dataTypeService: dataTypeServiceMock.Object,
memberTypeService: Mock.Of<IMemberTypeService>(),
memberService: Mock.Of<IMemberService>(),
contentTypeService: contentTypeService.Object,
mediaTypeService: mediaTypeService.Object,
localizationService: Mock.Of<ILocalizationService>(),
domainService: Mock.Of<IDomainService>(),
fileService: Mock.Of<IFileService>()
);
}
/// <summary>
/// Creates a published snapshot and set the accessor to resolve the created one
/// </summary>
/// <returns></returns>
protected IPublishedSnapshot GetPublishedSnapshot()
{
IPublishedSnapshot snapshot = SnapshotService.CreatePublishedSnapshot(null);
PublishedSnapshotAccessor.SetCurrent(snapshot);
return snapshot;
}
/// <summary>
/// Initializes the <see cref="IPublishedSnapshotService'" /> with a source of data
/// </summary>
/// <param name="contentNodeKits"></param>
/// <param name="contentTypes"></param>
protected void InitializedCache(
IEnumerable<ContentNodeKit> contentNodeKits,
IContentType[] contentTypes,
IDataType[] dataTypes = null,
IEnumerable<ContentNodeKit> mediaNodeKits = null,
IMediaType[] mediaTypes = null)
{
// create a data source for NuCache
NuCacheContentService = new TestNuCacheContentService(contentNodeKits, mediaNodeKits);
IRuntimeState runtime = Mock.Of<IRuntimeState>();
Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run);
// create a service context
ServiceContext serviceContext = CreateServiceContext(
contentTypes ?? Array.Empty<IContentType>(),
mediaTypes ?? Array.Empty<IMediaType>(),
dataTypes ?? GetDefaultDataTypes());
DataTypeService = serviceContext.DataTypeService;
ContentTypeService = serviceContext.ContentTypeService;
MediaTypeService = serviceContext.MediaTypeService;
DomainService = serviceContext.DomainService;
// create a scope provider
IScopeProvider scopeProvider = Mock.Of<IScopeProvider>();
Mock.Get(scopeProvider)
.Setup(x => x.CreateScope(
It.IsAny<IsolationLevel>(),
It.IsAny<RepositoryCacheMode>(),
It.IsAny<IEventDispatcher>(),
It.IsAny<IScopedNotificationPublisher>(),
It.IsAny<bool?>(),
It.IsAny<bool>(),
It.IsAny<bool>()))
.Returns(Mock.Of<IScope>);
// create a published content type factory
PublishedContentTypeFactory = new PublishedContentTypeFactory(
PublishedModelFactory,
PropertyValueConverterCollection,
DataTypeService);
ITypeFinder typeFinder = TestHelper.GetTypeFinder();
var nuCacheSettings = new NuCacheSettings();
// at last, create the complete NuCache snapshot service!
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
SnapshotService = new PublishedSnapshotService(
options,
Mock.Of<ISyncBootStateAccessor>(x => x.GetSyncBootState() == SyncBootState.WarmBoot),
new SimpleMainDom(),
serviceContext,
PublishedContentTypeFactory,
PublishedSnapshotAccessor,
VariationContextAccessor,
Mock.Of<IProfilingLogger>(),
NullLoggerFactory.Instance,
scopeProvider,
NuCacheContentService,
new TestDefaultCultureAccessor(),
Options.Create(GlobalSettings),
PublishedModelFactory,
TestHelper.GetHostingEnvironment(),
Options.Create(nuCacheSettings),
//ContentNestedDataSerializerFactory,
new ContentDataSerializer(new DictionaryOfPropertyDataSerializer()));
// invariant is the current default
VariationContextAccessor.VariationContext = new VariationContext();
PublishedValueFallback = new PublishedValueFallback(serviceContext, VariationContextAccessor);
}
}
}

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Infrastructure.PublishedCache.Persistence;
namespace Umbraco.Cms.Tests.UnitTests.TestHelpers
{
public class TestNuCacheContentService : INuCacheContentService
{
private IPublishedModelFactory PublishedModelFactory { get; } = new NoopPublishedModelFactory();
public TestNuCacheContentService(params ContentNodeKit[] kits)
: this((IEnumerable<ContentNodeKit>)kits)
{ }
public TestNuCacheContentService(IEnumerable<ContentNodeKit> contentKits, IEnumerable<ContentNodeKit> mediaKits = null)
{
ContentKits = contentKits?.ToDictionary(x => x.Node.Id, x => x) ?? new Dictionary<int, ContentNodeKit>();
MediaKits = mediaKits?.ToDictionary(x => x.Node.Id, x => x) ?? new Dictionary<int, ContentNodeKit>();
}
public Dictionary<int, ContentNodeKit> ContentKits { get; }
public Dictionary<int, ContentNodeKit> MediaKits { get; }
// note: it is important to clone the returned kits, as the inner
// ContentNode is directly reused and modified by the snapshot service
public ContentNodeKit GetContentSource(int id)
=> ContentKits.TryGetValue(id, out ContentNodeKit kit) ? kit.Clone(PublishedModelFactory) : default;
public IEnumerable<ContentNodeKit> GetAllContentSources()
=> ContentKits.Values
.OrderBy(x => x.Node.Level)
.ThenBy(x => x.Node.ParentContentId)
.ThenBy(x => x.Node.SortOrder)
.Select(x => x.Clone(PublishedModelFactory));
public IEnumerable<ContentNodeKit> GetBranchContentSources(int id)
=> ContentKits.Values
.Where(x => x.Node.Path.EndsWith("," + id) || x.Node.Path.Contains("," + id + ","))
.OrderBy(x => x.Node.Level)
.ThenBy(x => x.Node.ParentContentId)
.ThenBy(x => x.Node.SortOrder)
.Select(x => x.Clone(PublishedModelFactory));
public IEnumerable<ContentNodeKit> GetTypeContentSources(IEnumerable<int> ids)
=> ContentKits.Values
.Where(x => ids.Contains(x.ContentTypeId))
.OrderBy(x => x.Node.Level)
.ThenBy(x => x.Node.ParentContentId)
.ThenBy(x => x.Node.SortOrder)
.Select(x => x.Clone(PublishedModelFactory));
public ContentNodeKit GetMediaSource(int id)
=> MediaKits.TryGetValue(id, out ContentNodeKit kit) ? kit.Clone(PublishedModelFactory) : default;
public IEnumerable<ContentNodeKit> GetAllMediaSources()
=> MediaKits.Values
.OrderBy(x => x.Node.Level)
.ThenBy(x => x.Node.ParentContentId)
.ThenBy(x => x.Node.SortOrder)
.Select(x => x.Clone(PublishedModelFactory));
public IEnumerable<ContentNodeKit> GetBranchMediaSources(int id)
=> MediaKits.Values
.Where(x => x.Node.Path.EndsWith("," + id) || x.Node.Path.Contains("," + id + ","))
.OrderBy(x => x.Node.Level)
.ThenBy(x => x.Node.ParentContentId)
.ThenBy(x => x.Node.SortOrder)
.Select(x => x.Clone(PublishedModelFactory));
public IEnumerable<ContentNodeKit> GetTypeMediaSources(IEnumerable<int> ids)
=> MediaKits.Values
.Where(x => ids.Contains(x.ContentTypeId))
.OrderBy(x => x.Node.Level)
.ThenBy(x => x.Node.ParentContentId)
.ThenBy(x => x.Node.SortOrder)
.Select(x => x.Clone(PublishedModelFactory));
public void DeleteContentItem(IContentBase item) => throw new NotImplementedException();
public void DeleteContentItems(IEnumerable<IContentBase> items) => throw new NotImplementedException();
public void RefreshContent(IContent content) => throw new NotImplementedException();
public void RebuildDatabaseCacheIfSerializerChanged() => throw new NotImplementedException();
public void RefreshMedia(IMedia media) => throw new NotImplementedException();
public void RefreshMember(IMember member) => throw new NotImplementedException();
public void Rebuild(IReadOnlyCollection<int> contentTypeIds = null, IReadOnlyCollection<int> mediaTypeIds = null, IReadOnlyCollection<int> memberTypeIds = null) => throw new NotImplementedException();
public bool VerifyContentDbCache() => throw new NotImplementedException();
public bool VerifyMediaDbCache() => throw new NotImplementedException();
public bool VerifyMemberDbCache() => throw new NotImplementedException();
}
}

View File

@@ -1,7 +1,7 @@
using NUnit.Framework;
using NUnit.Framework;
using Umbraco.Core.Collections;
namespace Umbraco.Tests.Collections
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Collections
{
[TestFixture]
public class StackQueueTests
@@ -10,13 +10,13 @@ namespace Umbraco.Tests.Collections
public void Queue()
{
var sq = new StackQueue<int>();
for (int i = 0; i < 3; i++)
for (var i = 0; i < 3; i++)
{
sq.Enqueue(i);
}
var expected = 0;
while(sq.Count > 0)
while (sq.Count > 0)
{
var next = sq.Dequeue();
Assert.AreEqual(expected, next);
@@ -28,7 +28,7 @@ namespace Umbraco.Tests.Collections
public void Stack()
{
var sq = new StackQueue<int>();
for (int i = 0; i < 3; i++)
for (var i = 0; i < 3; i++)
{
sq.Push(i);
}
@@ -46,7 +46,7 @@ namespace Umbraco.Tests.Collections
public void Stack_And_Queue()
{
var sq = new StackQueue<int>();
for (int i = 0; i < 5; i++)
for (var i = 0; i < 5; i++)
{
if (i % 2 == 0)
{

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using NUnit.Framework;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Configurations
{
[TestFixture]
public class LanguageXmlTests
{
[Test]
[Platform("Win")] //TODO figure out why Path.GetFullPath("/mnt/c/...") is not considered an absolute path on linux + mac
public void Can_Load_Language_Xml_Files()
{
var languageDirectoryPath = GetLanguageDirectory();
var readFilesCount = 0;
var xmlDocument = new XmlDocument();
var directoryInfo = new DirectoryInfo(languageDirectoryPath);
foreach (var languageFile in directoryInfo.GetFiles("*.xml", SearchOption.TopDirectoryOnly))
{
// Load will throw an exception if the XML isn't valid.
xmlDocument.Load(languageFile.FullName);
readFilesCount++;
}
// Ensure that at least one file was read.
Assert.AreNotEqual(0, readFilesCount);
}
private static string GetLanguageDirectory()
{
var testDirectoryPathParts = Path.GetDirectoryName(TestContext.CurrentContext.TestDirectory)
.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);
var solutionDirectoryPathParts = testDirectoryPathParts
.Take(Array.IndexOf(testDirectoryPathParts, "tests"));
var languageFolderPathParts = new List<string>(solutionDirectoryPathParts);
var additionalPathParts = new[] { "Umbraco.Web.UI", "umbraco", "config", "lang" };
languageFolderPathParts.AddRange(additionalPathParts);
// Hack for build-server - when this path is generated in that envrionment it's missing the "src" folder.
// Not sure why, but if it's missing we'll add it in the right place.
if (!languageFolderPathParts.Contains("src"))
{
languageFolderPathParts.Insert(languageFolderPathParts.Count - additionalPathParts.Length, "src");
}
return string.Join(Path.DirectorySeparatorChar.ToString(), languageFolderPathParts);
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
// TODO: We should be able to decouple this from the base db tests since we're just mocking the services now
[TestFixture]
public class ContentFinderByAliasTests : UrlRoutingTestBase
{
[TestCase("/this/is/my/alias", 1001)]
[TestCase("/anotheralias", 1001)]
[TestCase("/page2/alias", 10011)]
[TestCase("/2ndpagealias", 10011)]
[TestCase("/only/one/alias", 100111)]
[TestCase("/ONLY/one/Alias", 100111)]
[TestCase("/alias43", 100121)]
public async Task Lookup_By_Url_Alias(string urlAsString, int nodeMatch)
{
var umbracoContextAccessor = GetUmbracoContextAccessor(urlAsString);
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var lookup =
new ContentFinderByUrlAlias(Mock.Of<ILogger<ContentFinderByUrlAlias>>(), Mock.Of<IPublishedValueFallback>(), VariationContextAccessor, umbracoContextAccessor);
var result = lookup.TryFindContent(frequest);
Assert.IsTrue(result);
Assert.AreEqual(frequest.PublishedContent.Id, nodeMatch);
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -8,40 +9,18 @@ using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Tests.Routing
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class ContentFinderByAliasWithDomainsTests : ContentFinderByAliasTests
public class ContentFinderByAliasWithDomainsTests : UrlRoutingTestBase
{
private PublishedContentType _publishedContentType;
protected override void Initialize()
{
base.Initialize();
var properties = new[]
{
new PublishedPropertyType(
propertyTypeAlias:"umbracoUrlAlias",
dataTypeId: Constants.DataTypes.Textbox,
isUserProperty:false,
variations: ContentVariation.Nothing,
propertyValueConverters:new PropertyValueConverterCollection(Enumerable.Empty<IPropertyValueConverter>()),
contentType:Mock.Of<IPublishedContentType>(),
publishedModelFactory:Mock.Of<IPublishedModelFactory>(),
factory:Mock.Of<IPublishedContentTypeFactory>()
)
};
_publishedContentType = new PublishedContentType(Guid.NewGuid(), 0, "Doc", PublishedItemType.Content, Enumerable.Empty<string>(), properties, ContentVariation.Nothing);
}
protected override PublishedContentType GetPublishedContentTypeByAlias(string alias)
{
if (alias == "Doc") return _publishedContentType;
return null;
}
[TestCase("http://domain1.com/this/is/my/alias", "de-DE", -1001)] // alias to domain's page fails - no alias on domain's home
[TestCase("http://domain1.com/page2/alias", "de-DE", 10011)] // alias to sub-page works
@@ -56,10 +35,11 @@ namespace Umbraco.Tests.Routing
public async Task Lookup_By_Url_Alias_And_Domain(string inputUrl, string expectedCulture, int expectedNode)
{
//SetDomains1();
var umbracoContextAccessor = GetUmbracoContextAccessor(inputUrl);
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var umbracoContext = GetUmbracoContext(inputUrl);
var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext));
var request = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var request = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
// must lookup domain
publishedRouter.FindDomain(request);
@@ -68,7 +48,7 @@ namespace Umbraco.Tests.Routing
Assert.AreEqual(expectedCulture, request.Culture);
}
var finder = new ContentFinderByUrlAlias(LoggerFactory.CreateLogger<ContentFinderByUrlAlias>(), Mock.Of<IPublishedValueFallback>(), VariationContextAccessor, GetUmbracoContextAccessor(umbracoContext));
var finder = new ContentFinderByUrlAlias(Mock.Of<ILogger<ContentFinderByUrlAlias>>(), Mock.Of<IPublishedValueFallback>(), VariationContextAccessor, umbracoContextAccessor);
var result = finder.TryFindContent(request);
if (expectedNode > 0)

View File

@@ -0,0 +1,57 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class ContentFinderByIdTests : PublishedSnapshotServiceTestBase
{
[SetUp]
public override void Setup()
{
base.Setup();
string xml = PublishedContentXml.BaseWebTestXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
}
[TestCase("/1046", 1046)]
public async Task Lookup_By_Id(string urlAsString, int nodeMatch)
{
var umbracoContextAccessor = GetUmbracoContextAccessor(urlAsString);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var webRoutingSettings = new WebRoutingSettings();
var lookup = new ContentFinderByIdPath(Options.Create(webRoutingSettings), Mock.Of<ILogger<ContentFinderByIdPath>>(), Mock.Of<IRequestAccessor>(), umbracoContextAccessor);
var result = lookup.TryFindContent(frequest);
Assert.IsTrue(result);
Assert.AreEqual(frequest.PublishedContent.Id, nodeMatch);
}
}
}

View File

@@ -0,0 +1,63 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class ContentFinderByPageIdQueryTests : PublishedSnapshotServiceTestBase
{
[SetUp]
public override void Setup()
{
base.Setup();
string xml = PublishedContentXml.BaseWebTestXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
}
[TestCase("/?umbPageId=1046", 1046)]
[TestCase("/?UMBPAGEID=1046", 1046)]
[TestCase("/default.aspx?umbPageId=1046", 1046)] // TODO: Should this match??
[TestCase("/some/other/page?umbPageId=1046", 1046)] // TODO: Should this match??
[TestCase("/some/other/page.aspx?umbPageId=1046", 1046)] // TODO: Should this match??
public async Task Lookup_By_Page_Id(string urlAsString, int nodeMatch)
{
var umbracoContextAccessor = GetUmbracoContextAccessor(urlAsString);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var queryStrings = HttpUtility.ParseQueryString(umbracoContext.CleanedUmbracoUrl.Query);
var mockRequestAccessor = new Mock<IRequestAccessor>();
mockRequestAccessor.Setup(x => x.GetRequestValue("umbPageID"))
.Returns(queryStrings["umbPageID"]);
var lookup = new ContentFinderByPageIdQuery(mockRequestAccessor.Object, umbracoContextAccessor);
var result = lookup.TryFindContent(frequest);
Assert.IsTrue(result);
Assert.AreEqual(frequest.PublishedContent.Id, nodeMatch);
}
}
}

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class ContentFinderByUrlAndTemplateTests : PublishedSnapshotServiceTestBase
{
private IFileService _fileService;
[SetUp]
public override void Setup()
{
base.Setup();
string xml = PublishedContentXml.BaseWebTestXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
}
protected override ServiceContext CreateServiceContext(IContentType[] contentTypes, IMediaType[] mediaTypes, IDataType[] dataTypes)
{
var serviceContext = base.CreateServiceContext(contentTypes, mediaTypes, dataTypes);
var fileService = Mock.Get(serviceContext.FileService);
fileService.Setup(x => x.GetTemplate(It.IsAny<string>()))
.Returns((string alias) => new Template(ShortStringHelper, alias, alias));
_fileService = fileService.Object;
return serviceContext;
}
[TestCase("/blah")]
[TestCase("/home/Sub1/blah")]
[TestCase("/Home/Sub1/Blah")] //different cases
public async Task Match_Document_By_Url_With_Template(string urlAsString)
{
GlobalSettings.HideTopLevelNodeFromPath = false;
var umbracoContextAccessor = GetUmbracoContextAccessor(urlAsString);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var webRoutingSettings = new WebRoutingSettings();
var lookup = new ContentFinderByUrlAndTemplate(
Mock.Of<ILogger<ContentFinderByUrlAndTemplate>>(),
_fileService,
ContentTypeService,
umbracoContextAccessor,
Microsoft.Extensions.Options.Options.Create(webRoutingSettings));
var result = lookup.TryFindContent(frequest);
IPublishedRequest request = frequest.Build();
Assert.IsTrue(result);
Assert.IsNotNull(frequest.PublishedContent);
var templateAlias = request.GetTemplateAlias();
Assert.IsNotNull(templateAlias);
Assert.AreEqual("blah".ToUpperInvariant(), templateAlias.ToUpperInvariant());
}
}
}

View File

@@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class ContentFinderByUrlTests : PublishedSnapshotServiceTestBase
{
private async Task<(ContentFinderByUrl finder, IPublishedRequestBuilder frequest)> GetContentFinder(string urlString)
{
string xml = PublishedContentXml.BaseWebTestXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
var umbracoContextAccessor = GetUmbracoContextAccessor(urlString);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var lookup = new ContentFinderByUrl(Mock.Of<ILogger<ContentFinderByUrl>>(), umbracoContextAccessor);
return (lookup, frequest);
}
[TestCase("/", 1046)]
[TestCase("/Sub1", 1173)]
[TestCase("/sub1", 1173)]
[TestCase("/home/sub1", -1)] // should fail
// these two are special. getNiceUrl(1046) returns "/" but getNiceUrl(1172) cannot also return "/" so
// we've made it return "/test-page" => we have to support that URL back in the lookup...
[TestCase("/home", 1046)]
[TestCase("/test-page", 1172)]
public async Task Match_Document_By_Url_Hide_Top_Level(string urlString, int expectedId)
{
GlobalSettings.HideTopLevelNodeFromPath = true;
var lookup = await GetContentFinder(urlString);
Assert.IsTrue(GlobalSettings.HideTopLevelNodeFromPath);
// FIXME: debugging - going further down, the routes cache is NOT empty?!
if (urlString == "/home/sub1")
System.Diagnostics.Debugger.Break();
var result = lookup.finder.TryFindContent(lookup.frequest);
if (expectedId > 0)
{
Assert.IsTrue(result);
Assert.AreEqual(expectedId, lookup.frequest.PublishedContent.Id);
}
else
{
Assert.IsFalse(result);
}
}
[TestCase("/", 1046)]
[TestCase("/home", 1046)]
[TestCase("/home/Sub1", 1173)]
[TestCase("/Home/Sub1", 1173)] //different cases
public async Task Match_Document_By_Url(string urlString, int expectedId)
{
GlobalSettings.HideTopLevelNodeFromPath = false;
var lookup = await GetContentFinder(urlString);
Assert.IsFalse(GlobalSettings.HideTopLevelNodeFromPath);
var result = lookup.finder.TryFindContent(lookup.frequest);
Assert.IsTrue(result);
Assert.AreEqual(expectedId, lookup.frequest.PublishedContent.Id);
}
/// <summary>
/// This test handles requests with special characters in the URL.
/// </summary>
/// <param name="urlString"></param>
/// <param name="expectedId"></param>
[TestCase("/", 1046)]
[TestCase("/home/sub1/custom-sub-3-with-accént-character", 1179)]
[TestCase("/home/sub1/custom-sub-4-with-æøå", 1180)]
public async Task Match_Document_By_Url_With_Special_Characters(string urlString, int expectedId)
{
GlobalSettings.HideTopLevelNodeFromPath = false;
var lookup = await GetContentFinder(urlString);
var result = lookup.finder.TryFindContent(lookup.frequest);
Assert.IsTrue(result);
Assert.AreEqual(expectedId, lookup.frequest.PublishedContent.Id);
}
/// <summary>
/// This test handles requests with a hostname associated.
/// The logic for handling this goes through the DomainHelper and is a bit different
/// from what happens in a normal request - so it has a separate test with a mocked
/// hostname added.
/// </summary>
/// <param name="urlString"></param>
/// <param name="expectedId"></param>
[TestCase("/", 1046)]
[TestCase("/home/sub1/custom-sub-3-with-accént-character", 1179)]
[TestCase("/home/sub1/custom-sub-4-with-æøå", 1180)]
public async Task Match_Document_By_Url_With_Special_Characters_Using_Hostname(string urlString, int expectedId)
{
GlobalSettings.HideTopLevelNodeFromPath = false;
var lookup = await GetContentFinder(urlString);
lookup.frequest.SetDomain(new DomainAndUri(new Domain(1, "mysite", -1, "en-US", false), new Uri("http://mysite/")));
var result = lookup.finder.TryFindContent(lookup.frequest);
Assert.IsTrue(result);
Assert.AreEqual(expectedId, lookup.frequest.PublishedContent.Id);
}
/// <summary>
/// This test handles requests with a hostname with special characters associated.
/// The logic for handling this goes through the DomainHelper and is a bit different
/// from what happens in a normal request - so it has a separate test with a mocked
/// hostname added.
/// </summary>
/// <param name="urlString"></param>
/// <param name="expectedId"></param>
[TestCase("/æøå/", 1046)]
[TestCase("/æøå/home/sub1", 1173)]
[TestCase("/æøå/home/sub1/custom-sub-3-with-accént-character", 1179)]
[TestCase("/æøå/home/sub1/custom-sub-4-with-æøå", 1180)]
public async Task Match_Document_By_Url_With_Special_Characters_In_Hostname(string urlString, int expectedId)
{
GlobalSettings.HideTopLevelNodeFromPath = false;
var lookup = await GetContentFinder(urlString);
lookup.frequest.SetDomain(new DomainAndUri(new Domain(1, "mysite/æøå", -1, "en-US", false), new Uri("http://mysite/æøå")));
var result = lookup.finder.TryFindContent(lookup.frequest);
Assert.IsTrue(result);
Assert.AreEqual(expectedId, lookup.frequest.PublishedContent.Id);
}
}
}

View File

@@ -1,42 +1,47 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Routing;
using Umbraco.Extensions;
namespace Umbraco.Tests.Routing
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class ContentFinderByUrlWithDomainsTests : UrlRoutingTestBase
{
void SetDomains3()
private void SetDomains3()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"}
});
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"}
});
}
void SetDomains4()
private void SetDomains4()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
new UmbracoDomain("domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
});
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
new UmbracoDomain("domain1.com/en") {Id = 2, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("domain1.com/fr") {Id = 3, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain3.com/") {Id = 4, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/en") {Id = 5, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/fr") {Id = 6, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
});
}
protected override string GetXmlContent(int templateId)
{
return @"<?xml version=""1.0"" encoding=""utf-8""?>
=> @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE root[
<!ELEMENT Doc ANY>
<!ATTLIST Doc id ID #REQUIRED>
@@ -115,7 +120,6 @@ namespace Umbraco.Tests.Routing
</Doc>
</Doc>
</root>";
}
[TestCase("http://domain1.com/", 1001)]
[TestCase("http://domain1.com/1001-1", 10011)]
@@ -125,16 +129,17 @@ namespace Umbraco.Tests.Routing
{
SetDomains3();
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = true };
GlobalSettings.HideTopLevelNodeFromPath = true;
var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettings);
var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext), Factory);
var umbracoContextAccessor = GetUmbracoContextAccessor(url);
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
// must lookup domain else lookup by URL fails
publishedRouter.FindDomain(frequest);
var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var lookup = new ContentFinderByUrl(Mock.Of<ILogger<ContentFinderByUrl>>(), umbracoContextAccessor);
var result = lookup.TryFindContent(frequest);
Assert.IsTrue(result);
Assert.AreEqual(expectedId, frequest.PublishedContent.Id);
@@ -164,19 +169,20 @@ namespace Umbraco.Tests.Routing
SetDomains4();
// defaults depend on test environment
expectedCulture = expectedCulture ?? System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
expectedCulture ??= System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = true };
GlobalSettings.HideTopLevelNodeFromPath = true;
var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettings);
var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext), Factory);
var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var umbracoContextAccessor = GetUmbracoContextAccessor(url);
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
// must lookup domain else lookup by URL fails
publishedRouter.FindDomain(frequest);
Assert.AreEqual(expectedCulture, frequest.Culture);
var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var lookup = new ContentFinderByUrl(Mock.Of<ILogger<ContentFinderByUrl>>(), umbracoContextAccessor);
var result = lookup.TryFindContent(frequest);
Assert.IsTrue(result);
Assert.AreEqual(expectedId, frequest.PublishedContent.Id);

View File

@@ -1,124 +1,151 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Routing;
using Umbraco.Extensions;
namespace Umbraco.Tests.Routing
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
internal class DomainsAndCulturesTests : UrlRoutingTestBase
public class DomainsAndCulturesTests : UrlRoutingTestBase
{
protected override void Compose()
{
base.Compose();
Builder.Services.AddTransient<ISiteDomainMapper, SiteDomainMapper>();
}
private void SetDomains1()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("domain1.com/")
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
Id = 1,
LanguageId = LangDeId,
RootContentId = 1001,
LanguageIsoCode = "de-DE"
},
new UmbracoDomain("domain1.com/en")
{
Id = 1,
LanguageId = LangEngId,
RootContentId = 10011,
LanguageIsoCode = "en-US"
},
new UmbracoDomain("domain1.com/fr")
{
Id = 1,
LanguageId = LangFrId,
RootContentId = 10012,
LanguageIsoCode = "fr-FR"
}
});
new UmbracoDomain("domain1.com/")
{
Id = 1,
LanguageId = LangDeId,
RootContentId = 1001,
LanguageIsoCode = "de-DE"
},
new UmbracoDomain("domain1.com/en")
{
Id = 2,
LanguageId = LangEngId,
RootContentId = 10011,
LanguageIsoCode = "en-US"
},
new UmbracoDomain("domain1.com/fr")
{
Id = 3,
LanguageId = LangFrId,
RootContentId = 10012,
LanguageIsoCode = "fr-FR"
}
});
}
private void SetDomains2()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("domain1.com/")
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
Id = 1,
LanguageId = LangDeId,
RootContentId = 1001,
LanguageIsoCode = "de-DE"
},
new UmbracoDomain("domain1.com/en")
new UmbracoDomain("domain1.com/")
{
Id = 1,
LanguageId = LangDeId,
RootContentId = 1001,
LanguageIsoCode = "de-DE"
},
new UmbracoDomain("domain1.com/en")
{
Id = 2,
LanguageId = LangEngId,
RootContentId = 10011,
LanguageIsoCode = "en-US"
},
new UmbracoDomain("domain1.com/fr")
{
Id = 3,
LanguageId = LangFrId,
RootContentId = 10012,
LanguageIsoCode = "fr-FR"
},
new UmbracoDomain("*1001")
{
Id = 4,
LanguageId = LangDeId,
RootContentId = 1001,
LanguageIsoCode = "de-DE"
},
new UmbracoDomain("*10011")
{
Id = 5,
LanguageId = LangCzId,
RootContentId = 10011,
LanguageIsoCode = "cs-CZ"
},
new UmbracoDomain("*100112")
{
Id = 6,
LanguageId = LangNlId,
RootContentId = 100112,
LanguageIsoCode = "nl-NL"
},
new UmbracoDomain("*1001122")
{
Id = 7,
LanguageId = LangDkId,
RootContentId = 1001122,
LanguageIsoCode = "da-DK"
},
new UmbracoDomain("*10012")
{
Id = 8,
LanguageId = LangNlId,
RootContentId = 10012,
LanguageIsoCode = "nl-NL"
},
new UmbracoDomain("*10031")
{
Id = 9,
LanguageId = LangNlId,
RootContentId =10031,
LanguageIsoCode = "nl-NL"
}
});
}
// domains such as "/en" are natively supported, and when instanciating
// DomainAndUri for them, the host will come from the current request
//
private void SetDomains3()
{
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
Id = 1,
LanguageId = LangEngId,
RootContentId = 10011,
LanguageIsoCode = "en-US"
},
new UmbracoDomain("domain1.com/fr")
{
Id = 1,
LanguageId = LangFrId,
RootContentId = 10012,
LanguageIsoCode = "fr-FR"
},
new UmbracoDomain("*1001")
{
Id = 1,
LanguageId = LangDeId,
RootContentId = 1001,
LanguageIsoCode = "de-DE"
},
new UmbracoDomain("*10011")
{
Id = 1,
LanguageId = LangCzId,
RootContentId = 10011,
LanguageIsoCode = "cs-CZ"
},
new UmbracoDomain("*100112")
{
Id = 1,
LanguageId = LangNlId,
RootContentId = 100112,
LanguageIsoCode = "nl-NL"
},
new UmbracoDomain("*1001122")
{
Id = 1,
LanguageId = LangDkId,
RootContentId = 1001122,
LanguageIsoCode = "da-DK"
},
new UmbracoDomain("*10012")
{
Id = 1,
LanguageId = LangNlId,
RootContentId = 10012,
LanguageIsoCode = "nl-NL"
},
new UmbracoDomain("*10031")
{
Id = 1,
LanguageId = LangNlId,
RootContentId =10031,
LanguageIsoCode = "nl-NL"
}
});
new UmbracoDomain("/en")
{
Id = 1,
LanguageId = LangEngId,
RootContentId = 10011,
LanguageIsoCode = "en-US"
},
new UmbracoDomain("/fr")
{
Id = 2,
LanguageId = LangFrId,
RootContentId = 10012,
LanguageIsoCode = "fr-FR"
}
});
}
protected override string GetXmlContent(int templateId)
{
return @"<?xml version=""1.0"" encoding=""utf-8""?>
=> @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE root[
<!ELEMENT Doc ANY>
<!ATTLIST Doc id ID #REQUIRED>
@@ -250,7 +277,6 @@ namespace Umbraco.Tests.Routing
</Doc>
</Doc>
</root>";
}
#region Cases
[TestCase("http://domain1.com/", "de-DE", 1001)]
@@ -265,18 +291,19 @@ namespace Umbraco.Tests.Routing
{
SetDomains1();
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
GlobalSettings.HideTopLevelNodeFromPath = false;
var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings);
var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext), Factory);
var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var umbracoContextAccessor = GetUmbracoContextAccessor(inputUrl);
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
// lookup domain
publishedRouter.FindDomain(frequest);
Assert.AreEqual(expectedCulture, frequest.Culture);
var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var finder = new ContentFinderByUrl(Mock.Of<ILogger<ContentFinderByUrl>>(), umbracoContextAccessor);
var result = finder.TryFindContent(frequest);
Assert.IsTrue(result);
@@ -311,19 +338,20 @@ namespace Umbraco.Tests.Routing
SetDomains2();
// defaults depend on test environment
expectedCulture = expectedCulture ?? System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
expectedCulture ??= System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
GlobalSettings.HideTopLevelNodeFromPath = false;
var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings);
var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext), Factory);
var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var umbracoContextAccessor = GetUmbracoContextAccessor(inputUrl);
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
// lookup domain
publishedRouter.FindDomain(frequest);
// find document
var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var finder = new ContentFinderByUrl(Mock.Of<ILogger<ContentFinderByUrl>>(), umbracoContextAccessor);
var result = finder.TryFindContent(frequest);
// apply wildcard domain
@@ -333,29 +361,7 @@ namespace Umbraco.Tests.Routing
Assert.AreEqual(expectedCulture, frequest.Culture);
Assert.AreEqual(frequest.PublishedContent.Id, expectedNode);
}
// domains such as "/en" are natively supported, and when instanciating
// DomainAndUri for them, the host will come from the current request
//
private void SetDomains3()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("/en")
{
Id = 1,
LanguageId = LangEngId,
RootContentId = 10011,
LanguageIsoCode = "en-US"
},
new UmbracoDomain("/fr")
{
Id = 1,
LanguageId = LangFrId,
RootContentId = 10012,
LanguageIsoCode = "fr-FR"
}
});
}
#region Cases
[TestCase("http://domain1.com/en", "en-US", 10011)]
@@ -367,10 +373,13 @@ namespace Umbraco.Tests.Routing
{
SetDomains3();
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings);
var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext), Factory);
var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
GlobalSettings.HideTopLevelNodeFromPath = false;
var umbracoContextAccessor = GetUmbracoContextAccessor(inputUrl);
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
// lookup domain
publishedRouter.FindDomain(frequest);
@@ -378,7 +387,7 @@ namespace Umbraco.Tests.Routing
Assert.AreEqual(expectedCulture, frequest.Culture);
var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var finder = new ContentFinderByUrl(Mock.Of<ILogger<ContentFinderByUrl>>(), umbracoContextAccessor);
var result = finder.TryFindContent(frequest);
Assert.IsTrue(result);

View File

@@ -0,0 +1,216 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class GetContentUrlsTests : PublishedSnapshotServiceTestBase
{
private WebRoutingSettings _webRoutingSettings;
private RequestHandlerSettings _requestHandlerSettings;
[SetUp]
public override void Setup()
{
base.Setup();
_webRoutingSettings = new WebRoutingSettings();
_requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
GlobalSettings.HideTopLevelNodeFromPath = false;
string xml = PublishedContentXml.BaseWebTestXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
}
private ILocalizedTextService GetTextService()
{
var textService = new Mock<ILocalizedTextService>();
textService.Setup(x => x.Localize(
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<CultureInfo>(),
It.IsAny<IDictionary<string, string>>()
))
.Returns((string key, string alias, CultureInfo culture, IDictionary<string, string> args)
=> $"{key}/{alias}");
return textService.Object;
}
private ILocalizationService GetLangService(params string[] isoCodes)
{
var allLangs = isoCodes
.Select(CultureInfo.GetCultureInfo)
.Select(culture => new Language(GlobalSettings, culture.Name)
{
CultureName = culture.DisplayName,
IsDefault = true,
IsMandatory = true
}).ToArray();
var langServiceMock = new Mock<ILocalizationService>();
langServiceMock.Setup(x => x.GetAllLanguages()).Returns(allLangs);
langServiceMock.Setup(x => x.GetDefaultLanguageIsoCode()).Returns(allLangs.First(x=>x.IsDefault).IsoCode);
return langServiceMock.Object;
}
[Test]
public async Task Content_Not_Published()
{
var contentType = ContentTypeBuilder.CreateBasicContentType();
var content = ContentBuilder.CreateBasicContent(contentType);
content.Id = 1046; // FIXME: we are using this ID only because it's built into the test XML published cache
content.Path = "-1,1046";
var umbracoContextAccessor = GetUmbracoContextAccessor("http://localhost:8000");
var publishedRouter = CreatePublishedRouter(
umbracoContextAccessor,
new[] { new ContentFinderByUrl(Mock.Of<ILogger<ContentFinderByUrl>>(), umbracoContextAccessor) });
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, _requestHandlerSettings, _webRoutingSettings, out UriUtility uriUtility);
var urls = (await content.GetContentUrlsAsync(
publishedRouter,
umbracoContext,
GetLangService("en-US", "fr-FR"),
GetTextService(),
Mock.Of<IContentService>(),
VariationContextAccessor,
Mock.Of<ILogger<IContent>>(),
uriUtility,
urlProvider)).ToList();
Assert.AreEqual(1, urls.Count);
Assert.AreEqual("content/itemNotPublished", urls[0].Text);
Assert.IsFalse(urls[0].IsUrl);
}
[Test]
public async Task Invariant_Root_Content_Published_No_Domains()
{
var contentType = ContentTypeBuilder.CreateBasicContentType();
var content = ContentBuilder.CreateBasicContent(contentType);
content.Id = 1046; // FIXME: we are using this ID only because it's built into the test XML published cache
content.Path = "-1,1046";
content.Published = true;
var umbracoContextAccessor = GetUmbracoContextAccessor("http://localhost:8000");
var publishedRouter = CreatePublishedRouter(
umbracoContextAccessor,
new[] { new ContentFinderByUrl(Mock.Of<ILogger<ContentFinderByUrl>>(), umbracoContextAccessor) });
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, _requestHandlerSettings, _webRoutingSettings, out UriUtility uriUtility);
var urls = (await content.GetContentUrlsAsync(
publishedRouter,
umbracoContext,
GetLangService("en-US", "fr-FR"),
GetTextService(),
Mock.Of<IContentService>(),
VariationContextAccessor,
Mock.Of<ILogger<IContent>>(),
uriUtility,
urlProvider)).ToList();
Assert.AreEqual(2, urls.Count);
var enUrl = urls.First(x => x.Culture == "en-US");
Assert.AreEqual("/home/", enUrl.Text);
Assert.AreEqual("en-US", enUrl.Culture);
Assert.IsTrue(enUrl.IsUrl);
var frUrl = urls.First(x => x.Culture == "fr-FR");
Assert.IsFalse(frUrl.IsUrl);
}
[Test]
public async Task Invariant_Child_Content_Published_No_Domains()
{
var contentType = ContentTypeBuilder.CreateBasicContentType();
var parent = ContentBuilder.CreateBasicContent(contentType);
parent.Id = 1046; // FIXME: we are using this ID only because it's built into the test XML published cache
parent.Name = "home";
parent.Path = "-1,1046";
parent.Published = true;
var child = ContentBuilder.CreateBasicContent(contentType);
child.Name = "sub1";
child.Id = 1173; // FIXME: we are using this ID only because it's built into the test XML published cache
child.Path = "-1,1046,1173";
child.Published = true;
var umbracoContextAccessor = GetUmbracoContextAccessor("http://localhost:8000");
var publishedRouter = CreatePublishedRouter(
umbracoContextAccessor,
new[] { new ContentFinderByUrl(Mock.Of<ILogger<ContentFinderByUrl>>(), umbracoContextAccessor) });
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var localizationService = GetLangService("en-US", "fr-FR");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, _requestHandlerSettings, _webRoutingSettings, out UriUtility uriUtility);
var urls = (await child.GetContentUrlsAsync(
publishedRouter,
umbracoContext,
localizationService,
GetTextService(),
Mock.Of<IContentService>(),
VariationContextAccessor,
Mock.Of<ILogger<IContent>>(),
uriUtility,
urlProvider)).ToList();
Assert.AreEqual(2, urls.Count);
var enUrl = urls.First(x => x.Culture == "en-US");
Assert.AreEqual("/home/sub1/", enUrl.Text);
Assert.AreEqual("en-US", enUrl.Culture);
Assert.IsTrue(enUrl.IsUrl);
var frUrl = urls.First(x => x.Culture == "fr-FR");
Assert.IsFalse(frUrl.IsUrl);
}
// TODO: We need a lot of tests here, the above was just to get started with being able to unit test this method
// * variant URLs without domains assigned, what happens?
// * variant URLs with domains assigned, but also having more languages installed than there are domains/cultures assigned
// * variant URLs with an ancestor culture unpublished
// * invariant URLs with ancestors as variants
// * ... probably a lot more
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Tests.Common;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class PublishedRouterTests
{
private PublishedRouter CreatePublishedRouter(IUmbracoContextAccessor umbracoContextAccessor)
=> new PublishedRouter(
Microsoft.Extensions.Options.Options.Create(new WebRoutingSettings()),
new ContentFinderCollection(() => Enumerable.Empty<IContentFinder>()),
new TestLastChanceFinder(),
new TestVariationContextAccessor(),
Mock.Of<IProfilingLogger>(),
Mock.Of<ILogger<PublishedRouter>>(),
Mock.Of<IPublishedUrlProvider>(),
Mock.Of<IRequestAccessor>(),
Mock.Of<IPublishedValueFallback>(),
Mock.Of<IFileService>(),
Mock.Of<IContentTypeService>(),
umbracoContextAccessor,
Mock.Of<IEventAggregator>());
private IUmbracoContextAccessor GetUmbracoContextAccessor()
{
var uri = new Uri("http://example.com");
var umbracoContext = Mock.Of<IUmbracoContext>(x => x.CleanedUmbracoUrl == uri);
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
return umbracoContextAccessor;
}
[Test]
public async Task ConfigureRequest_Returns_False_Without_HasPublishedContent()
{
var umbracoContextAccessor = GetUmbracoContextAccessor();
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var request = await publishedRouter.CreateRequestAsync(umbracoContextAccessor.GetRequiredUmbracoContext().CleanedUmbracoUrl);
var result = publishedRouter.BuildRequest(request);
Assert.IsFalse(result.Success());
}
[Test]
public async Task ConfigureRequest_Returns_False_When_IsRedirect()
{
var umbracoContextAccessor = GetUmbracoContextAccessor();
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var request = await publishedRouter.CreateRequestAsync(umbracoContextAccessor.GetRequiredUmbracoContext().CleanedUmbracoUrl);
var content = GetPublishedContentMock();
request.SetPublishedContent(content.Object);
request.SetCulture("en-AU");
request.SetRedirect("/hello");
var result = publishedRouter.BuildRequest(request);
Assert.IsFalse(result.Success());
}
private Mock<IPublishedContent> GetPublishedContentMock()
{
var pc = new Mock<IPublishedContent>();
pc.Setup(content => content.Id).Returns(1);
pc.Setup(content => content.Name).Returns("test");
pc.Setup(content => content.CreateDate).Returns(DateTime.Now);
pc.Setup(content => content.UpdateDate).Returns(DateTime.Now);
pc.Setup(content => content.Path).Returns("-1,1");
pc.Setup(content => content.Parent).Returns(() => null);
pc.Setup(content => content.Properties).Returns(new Collection<IPublishedProperty>());
pc.Setup(content => content.ContentType).Returns(new PublishedContentType(Guid.NewGuid(), 22, "anything", PublishedItemType.Content, Enumerable.Empty<string>(), Enumerable.Empty<PublishedPropertyType>(), ContentVariation.Nothing));
return pc;
}
}
}

View File

@@ -0,0 +1,57 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class UrlProviderWithHideTopLevelNodeFromPathTests : PublishedSnapshotServiceTestBase
{
[SetUp]
public override void Setup()
{
base.Setup();
string xml = PublishedContentXml.BaseWebTestXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
GlobalSettings.HideTopLevelNodeFromPath = true;
}
[TestCase(1046, "/")]
[TestCase(1173, "/sub1/")]
[TestCase(1174, "/sub1/sub2/")]
[TestCase(1176, "/sub1/sub-3/")]
[TestCase(1177, "/sub1/custom-sub-1/")]
[TestCase(1178, "/sub1/custom-sub-2/")]
[TestCase(1175, "/sub-2/")]
[TestCase(1172, "/test-page/")] // not hidden because not first root
public void Get_Url_Hiding_Top_Level(int nodeId, string niceUrlMatch)
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
var umbracoContextAccessor = GetUmbracoContextAccessor("/test");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
var result = urlProvider.GetUrl(nodeId);
Assert.AreEqual(niceUrlMatch, result);
}
}
}

View File

@@ -0,0 +1,336 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
using Umbraco.Cms.Tests.Common;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class UrlProviderWithoutHideTopLevelNodeFromPathTests : PublishedSnapshotServiceTestBase
{
private const string CacheKeyPrefix = "NuCache.ContentCache.RouteByContent";
[SetUp]
public override void Setup()
{
base.Setup();
GlobalSettings.HideTopLevelNodeFromPath = false;
}
private void PopulateCache(string culture = "fr-FR")
{
var dataTypes = GetDefaultDataTypes();
var propertyDataTypes = new Dictionary<string, IDataType>
{
// we only have one data type for this test which will be resolved with string empty.
[string.Empty] = dataTypes[0]
};
var contentType1 = new ContentType(ShortStringHelper, -1);
ContentData rootData = new ContentDataBuilder()
.WithName("Page" + Guid.NewGuid())
.WithCultureInfos(new Dictionary<string, CultureVariation>
{
[culture] = new CultureVariation
{
Name = "root",
IsDraft = true,
Date = DateTime.Now,
UrlSegment = "root"
},
})
.Build(ShortStringHelper, propertyDataTypes, contentType1, "alias");
ContentNodeKit root = ContentNodeKitBuilder.CreateWithContent(
contentType1.Id,
9876, $"-1,9876",
draftData: rootData,
publishedData: rootData);
ContentData parentData = new ContentDataBuilder()
.WithName("Page" + Guid.NewGuid())
.WithCultureInfos(new Dictionary<string, CultureVariation>
{
[culture] = new CultureVariation
{
Name = "home",
IsDraft = true,
Date = DateTime.Now,
UrlSegment = "home"
},
})
.Build();
ContentNodeKit parent = ContentNodeKitBuilder.CreateWithContent(
contentType1.Id,
5432, $"-1,9876,5432",
parentContentId: 9876,
draftData: parentData,
publishedData: parentData);
ContentData contentData = new ContentDataBuilder()
.WithName("Page" + Guid.NewGuid())
.WithCultureInfos(new Dictionary<string, CultureVariation>
{
[culture] = new CultureVariation
{
Name = "name-fr2",
IsDraft = true,
Date = DateTime.Now,
UrlSegment = "test-fr"
},
})
.Build();
ContentNodeKit content = ContentNodeKitBuilder.CreateWithContent(
contentType1.Id,
1234, $"-1,9876,5432,1234",
parentContentId: 5432,
draftData: contentData,
publishedData: contentData);
InitializedCache(new[] { root, parent, content }, new[] { contentType1 }, dataTypes: dataTypes);
}
private void SetDomains1()
{
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("http://example.us/") {Id = 1, RootContentId = 9876, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://example.fr/") {Id = 2, RootContentId = 9876, LanguageIsoCode = "fr-FR"}
});
}
/// <summary>
/// This checks that when we retrieve a NiceUrl for multiple items that there are no issues with cache overlap
/// and that they are all cached correctly.
/// </summary>
[Test]
public void Ensure_Cache_Is_Correct()
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = false };
string xml = PublishedContentXml.BaseWebTestXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
var umbracoContextAccessor = GetUmbracoContextAccessor("/test");
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
var samples = new Dictionary<int, string> {
{ 1046, "/home" },
{ 1173, "/home/sub1" },
{ 1174, "/home/sub1/sub2" },
{ 1176, "/home/sub1/sub-3" },
{ 1177, "/home/sub1/custom-sub-1" },
{ 1178, "/home/sub1/custom-sub-2" },
{ 1175, "/home/sub-2" },
{ 1172, "/test-page" }
};
foreach (var sample in samples)
{
var result = urlProvider.GetUrl(sample.Key);
Assert.AreEqual(sample.Value, result);
}
var randomSample = new KeyValuePair<int, string>(1177, "/home/sub1/custom-sub-1");
for (int i = 0; i < 5; i++)
{
var result = urlProvider.GetUrl(randomSample.Key);
Assert.AreEqual(randomSample.Value, result);
}
var cache = (FastDictionaryAppCache)umbracoContext.PublishedSnapshot.ElementsCache;
var cachedRoutes = cache.Keys.Where(x => x.StartsWith(CacheKeyPrefix)).ToList();
Assert.AreEqual(8, cachedRoutes.Count);
foreach (var sample in samples)
{
var cacheKey = $"{CacheKeyPrefix}[P:{sample.Key}]";
var found = (string)cache.Get(cacheKey);
Assert.IsNotNull(found);
Assert.AreEqual(sample.Value, found);
}
}
[TestCase(1046, "/home/")]
[TestCase(1173, "/home/sub1/")]
[TestCase(1174, "/home/sub1/sub2/")]
[TestCase(1176, "/home/sub1/sub-3/")]
[TestCase(1177, "/home/sub1/custom-sub-1/")]
[TestCase(1178, "/home/sub1/custom-sub-2/")]
[TestCase(1175, "/home/sub-2/")]
[TestCase(1172, "/test-page/")]
public void Get_Url_Not_Hiding_Top_Level(int nodeId, string niceUrlMatch)
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
string xml = PublishedContentXml.BaseWebTestXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
var umbracoContextAccessor = GetUmbracoContextAccessor("/test");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
var result = urlProvider.GetUrl(nodeId);
Assert.AreEqual(niceUrlMatch, result);
}
[Test]
[TestCase("fr-FR", ExpectedResult = "#")] // Non default cultures cannot return urls
[TestCase("en-US", ExpectedResult = "/root/home/test-fr/")] // Default culture can return urls
public string Get_Url_For_Culture_Variant_Without_Domains_Non_Current_Url(string culture)
{
const string currentUri = "http://example.us/test";
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
PopulateCache(culture);
var umbracoContextAccessor = GetUmbracoContextAccessor(currentUri);
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
//even though we are asking for a specific culture URL, there are no domains assigned so all that can be returned is a normal relative URL.
var url = urlProvider.GetUrl(1234, culture: culture);
return url;
}
/// <summary>
/// This tests DefaultUrlProvider.GetUrl with a specific culture when the current URL is the culture specific domain
/// </summary>
[Test]
public void Get_Url_For_Culture_Variant_With_Current_Url()
{
const string currentUri = "http://example.fr/test";
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
PopulateCache();
SetDomains1();
var umbracoContextAccessor = GetUmbracoContextAccessor(currentUri);
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
var url = urlProvider.GetUrl(1234, culture: "fr-FR");
Assert.AreEqual("/home/test-fr/", url);
}
/// <summary>
/// This tests DefaultUrlProvider.GetUrl with a specific culture when the current URL is not the culture specific domain
/// </summary>
[Test]
public void Get_Url_For_Culture_Variant_Non_Current_Url()
{
const string currentUri = "http://example.us/test";
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
PopulateCache();
SetDomains1();
var umbracoContextAccessor = GetUmbracoContextAccessor(currentUri);
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
var url = urlProvider.GetUrl(1234, culture: "fr-FR");
//the current uri is not the culture specific domain we want, so the result is an absolute path to the culture specific domain
Assert.AreEqual("http://example.fr/home/test-fr/", url);
}
[Test]
public void Get_Url_Relative_Or_Absolute()
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
string xml = PublishedContentXml.BaseWebTestXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
var umbracoContextAccessor = GetUmbracoContextAccessor("http://example.com/test");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
Assert.AreEqual("/home/sub1/custom-sub-1/", urlProvider.GetUrl(1177));
urlProvider.Mode = UrlMode.Absolute;
Assert.AreEqual("http://example.com/home/sub1/custom-sub-1/", urlProvider.GetUrl(1177));
}
[Test]
public void Get_Url_Unpublished()
{
var requestHandlerSettings = new RequestHandlerSettings();
string xml = PublishedContentXml.BaseWebTestXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
var umbracoContextAccessor = GetUmbracoContextAccessor("http://example.com/test");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
//mock the Umbraco settings that we need
Assert.AreEqual("#", urlProvider.GetUrl(999999));
urlProvider.Mode = UrlMode.Absolute;
Assert.AreEqual("#", urlProvider.GetUrl(999999));
}
}
}

View File

@@ -1,68 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Routing;
using Constants = Umbraco.Cms.Core.Constants;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
namespace Umbraco.Tests.Routing
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
// TODO: We should be able to decouple this from the base db tests since we're just mocking the services now
[TestFixture]
public class ContentFinderByAliasTests : UrlRoutingTestBase
public abstract class UrlRoutingTestBase : PublishedSnapshotServiceTestBase
{
private PublishedContentType _publishedContentType;
protected override void Initialize()
[SetUp]
public override void Setup()
{
base.Initialize();
base.Setup();
string xml = GetXmlContent(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
var properties = new[]
{
new PublishedPropertyType("umbracoUrlAlias", Constants.DataTypes.Textbox, false, ContentVariation.Nothing,
new PropertyValueConverterCollection(Enumerable.Empty<IPropertyValueConverter>()),
Mock.Of<IPublishedModelFactory>(),
Mock.Of<IPublishedContentTypeFactory>()),
};
_publishedContentType = new PublishedContentType(Guid.NewGuid(), 0, "Doc", PublishedItemType.Content, Enumerable.Empty<string>(), properties, ContentVariation.Nothing);
}
protected override PublishedContentType GetPublishedContentTypeByAlias(string alias)
// Sets up the mock domain service
protected override ServiceContext CreateServiceContext(IContentType[] contentTypes, IMediaType[] mediaTypes, IDataType[] dataTypes)
{
if (alias == "Doc") return _publishedContentType;
return null;
var serviceContext = base.CreateServiceContext(contentTypes, mediaTypes, dataTypes);
//setup mock domain service
var domainService = Mock.Get(serviceContext.DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("domain1.com/"){Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"},
new UmbracoDomain("domain1.com/en"){Id = 2, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("domain1.com/fr"){Id = 3, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}
});
return serviceContext;
}
[TestCase("/this/is/my/alias", 1001)]
[TestCase("/anotheralias", 1001)]
[TestCase("/page2/alias", 10011)]
[TestCase("/2ndpagealias", 10011)]
[TestCase("/only/one/alias", 100111)]
[TestCase("/ONLY/one/Alias", 100111)]
[TestCase("/alias43", 100121)]
public async Task Lookup_By_Url_Alias(string urlAsString, int nodeMatch)
{
var umbracoContext = GetUmbracoContext(urlAsString);
var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext));
var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var lookup =
new ContentFinderByUrlAlias(LoggerFactory.CreateLogger<ContentFinderByUrlAlias>(), Mock.Of<IPublishedValueFallback>(), VariationContextAccessor, GetUmbracoContextAccessor(umbracoContext));
var result = lookup.TryFindContent(frequest);
Assert.IsTrue(result);
Assert.AreEqual(frequest.PublishedContent.Id, nodeMatch);
}
protected override string GetXmlContent(int templateId)
{
return @"<?xml version=""1.0"" encoding=""utf-8""?>
protected virtual string GetXmlContent(int templateId)
=> @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE root[
<!ELEMENT Doc ANY>
<!ATTLIST Doc id ID #REQUIRED>
@@ -147,7 +134,12 @@ namespace Umbraco.Tests.Routing
</Doc>
</Doc>
</root>";
}
public const int LangDeId = 333;
public const int LangEngId = 334;
public const int LangFrId = 335;
public const int LangCzId = 336;
public const int LangNlId = 337;
public const int LangDkId = 338;
}
}

View File

@@ -1,10 +1,11 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
@@ -13,77 +14,83 @@ using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Tests.Common;
using Umbraco.Extensions;
using Umbraco.Tests.LegacyXmlPublishedCache;
namespace Umbraco.Tests.Routing
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class UrlsProviderWithDomainsTests : UrlRoutingTestBase
{
private IUmbracoContextAccessor UmbracoContextAccessor { get; } = new TestUmbracoContextAccessor();
protected override void Compose()
{
base.Compose();
private const string CacheKeyPrefix = "NuCache.ContentCache.RouteByContent";
Builder.Services.AddUnique(Mock.Of<IDomainService>());
Builder.Services.AddTransient<ISiteDomainMapper, SiteDomainMapper>();
private void SetDomains1()
{
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("domain1.com") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"}
});
}
void SetDomains1()
private void SetDomains2()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("domain1.com") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"}
});
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("http://domain1.com/foo") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"}
});
}
void SetDomains2()
private void SetDomains3()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("http://domain1.com/foo") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"}
});
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangFrId, RootContentId = 10011, LanguageIsoCode = "fr-FR"}
});
}
void SetDomains3()
private void SetDomains4()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangFrId, RootContentId = 10011, LanguageIsoCode = "fr-FR"}
});
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1.com/en") {Id = 2, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1.com/fr") {Id = 3, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain3.com/") {Id = 4, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/en") {Id = 5, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/fr") {Id = 6, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
});
}
void SetDomains4()
private void SetDomains5()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
});
}
var domainService = Mock.Get(DomainService);
void SetDomains5()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1a.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1b.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain1a.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain1b.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
});
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1a.com/en") {Id = 2, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1b.com/en") {Id = 3, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain1.com/fr") {Id = 4, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain1a.com/fr") {Id = 5, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain1b.com/fr") {Id = 6, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
new UmbracoDomain("http://domain3.com/en") {Id = 7, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain3.com/fr") {Id = 8, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
});
}
protected override string GetXmlContent(int templateId)
{
return @"<?xml version=""1.0"" encoding=""utf-8""?>
=> @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE root[
<!ELEMENT Doc ANY>
<!ATTLIST Doc id ID #REQUIRED>
@@ -162,7 +169,6 @@ namespace Umbraco.Tests.Routing
</Doc>
</Doc>
</root>";
}
// with one simple domain "domain1.com"
// basic tests
@@ -179,21 +185,18 @@ namespace Umbraco.Tests.Routing
[TestCase(10011, "https://domain1.com", false, "/1001-1/")]
public void Get_Url_SimpleDomain(int nodeId, string currentUrl, bool absolute, string expected)
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings);
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings),
LoggerFactory.CreateLogger<DefaultUrlProvider>(),
new SiteDomainMapper(), umbracoContextAccessor, UriUtility);
var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider);
SetDomains1();
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
GlobalSettings.HideTopLevelNodeFromPath = false;
var umbracoContextAccessor = GetUmbracoContextAccessor("/test");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
var currentUri = new Uri(currentUrl);
var mode = absolute ? UrlMode.Absolute : UrlMode.Auto;
var result = publishedUrlProvider.GetUrl(nodeId, mode, current: currentUri);
var result = urlProvider.GetUrl(nodeId, mode, current: currentUri);
Assert.AreEqual(expected, result);
}
@@ -212,21 +215,18 @@ namespace Umbraco.Tests.Routing
[TestCase(10011, "https://domain1.com", false, "http://domain1.com/foo/1001-1/")]
public void Get_Url_SimpleWithSchemeAndPath(int nodeId, string currentUrl, bool absolute, string expected)
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings);
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings),
LoggerFactory.CreateLogger<DefaultUrlProvider>(),
new SiteDomainMapper(), umbracoContextAccessor, UriUtility);
var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider);
SetDomains2();
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
GlobalSettings.HideTopLevelNodeFromPath = false;
var umbracoContextAccessor = GetUmbracoContextAccessor("/test");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
var currentUri = new Uri(currentUrl);
var mode = absolute ? UrlMode.Absolute : UrlMode.Auto;
var result = publishedUrlProvider.GetUrl(nodeId, mode, current : currentUri);
var result = urlProvider.GetUrl(nodeId, mode, current: currentUri);
Assert.AreEqual(expected, result);
}
@@ -237,21 +237,18 @@ namespace Umbraco.Tests.Routing
[TestCase(1002, "http://domain1.com", false, "/1002/")]
public void Get_Url_DeepDomain(int nodeId, string currentUrl, bool absolute, string expected)
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings);
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings),
LoggerFactory.CreateLogger<DefaultUrlProvider>(),
new SiteDomainMapper(), umbracoContextAccessor, UriUtility);
var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider);
SetDomains3();
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
GlobalSettings.HideTopLevelNodeFromPath = false;
var umbracoContextAccessor = GetUmbracoContextAccessor("/test");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
var currentUri = new Uri(currentUrl);
var mode = absolute ? UrlMode.Absolute : UrlMode.Auto;
var result = publishedUrlProvider.GetUrl(nodeId, mode, current : currentUri);
var result = urlProvider.GetUrl(nodeId, mode, current: currentUri);
Assert.AreEqual(expected, result);
}
@@ -268,152 +265,130 @@ namespace Umbraco.Tests.Routing
[TestCase(100321, "http://domain3.com", false, "/fr/1003-2-1/")]
public void Get_Url_NestedDomains(int nodeId, string currentUrl, bool absolute, string expected)
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings);
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
var urlProvider = new DefaultUrlProvider(
Microsoft.Extensions.Options.Options.Create(requestHandlerSettings),
LoggerFactory.CreateLogger<DefaultUrlProvider>(),
new SiteDomainMapper(), umbracoContextAccessor, UriUtility);
var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider);
SetDomains4();
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
GlobalSettings.HideTopLevelNodeFromPath = false;
var umbracoContextAccessor = GetUmbracoContextAccessor("/test");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
var currentUri = new Uri(currentUrl);
var mode = absolute ? UrlMode.Absolute : UrlMode.Auto;
var result = publishedUrlProvider.GetUrl(nodeId, mode, current : currentUri);
var result = urlProvider.GetUrl(nodeId, mode, current: currentUri);
Assert.AreEqual(expected, result);
}
[Test]
public void Get_Url_DomainsAndCache()
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings);
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
var urlProvider = new DefaultUrlProvider(
Microsoft.Extensions.Options.Options.Create(requestHandlerSettings),
LoggerFactory.CreateLogger<DefaultUrlProvider>(),
new SiteDomainMapper(), umbracoContextAccessor, UriUtility);
var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider);
SetDomains4();
string ignore;
ignore = publishedUrlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = publishedUrlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = publishedUrlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = publishedUrlProvider.GetUrl(10012, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = publishedUrlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = publishedUrlProvider.GetUrl(10013, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = publishedUrlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = publishedUrlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain2.com"));
ignore = publishedUrlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain2.com"));
ignore = publishedUrlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain2.com"));
ignore = publishedUrlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain2.com"));
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
GlobalSettings.HideTopLevelNodeFromPath = false;
var cache = umbracoContext.Content as PublishedContentCache;
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported.");
var cachedRoutes = cache.RoutesCache.GetCachedRoutes();
var umbracoContextAccessor = GetUmbracoContextAccessor("/test");
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
string ignore;
ignore = urlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = urlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = urlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = urlProvider.GetUrl(10012, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = urlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = urlProvider.GetUrl(10013, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = urlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain1.com"));
ignore = urlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain2.com"));
ignore = urlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain2.com"));
ignore = urlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain2.com"));
ignore = urlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain2.com"));
var cache = (FastDictionaryAppCache)umbracoContext.PublishedSnapshot.ElementsCache;
var cachedRoutes = cache.Keys.Where(x => x.StartsWith(CacheKeyPrefix)).ToList();
Assert.AreEqual(7, cachedRoutes.Count);
var cachedIds = cache.RoutesCache.GetCachedIds();
Assert.AreEqual(0, cachedIds.Count);
//var cachedIds = cache.RoutesCache.GetCachedIds();
//Assert.AreEqual(0, cachedIds.Count);
CheckRoute(cachedRoutes, cachedIds, 1001, "1001/");
CheckRoute(cachedRoutes, cachedIds, 10011, "10011/");
CheckRoute(cachedRoutes, cachedIds, 100111, "10011/1001-1-1");
CheckRoute(cachedRoutes, cachedIds, 10012, "10012/");
CheckRoute(cachedRoutes, cachedIds, 100121, "10012/1001-2-1");
CheckRoute(cachedRoutes, cachedIds, 10013, "1001/1001-3");
CheckRoute(cachedRoutes, cachedIds, 1002, "/1002");
CheckRoute(cache, 1001, "1001/");
CheckRoute(cache, 10011, "10011/");
CheckRoute(cache, 100111, "10011/1001-1-1");
CheckRoute(cache, 10012, "10012/");
CheckRoute(cache, 100121, "10012/1001-2-1");
CheckRoute(cache, 10013, "1001/1001-3");
CheckRoute(cache, 1002, "/1002");
// use the cache
Assert.AreEqual("/", publishedUrlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/en/", publishedUrlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/en/1001-1-1/", publishedUrlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/fr/", publishedUrlProvider.GetUrl(10012, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/fr/1001-2-1/", publishedUrlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/1001-3/", publishedUrlProvider.GetUrl(10013, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/1002/", publishedUrlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/", urlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/en/", urlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/en/1001-1-1/", urlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/fr/", urlProvider.GetUrl(10012, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/fr/1001-2-1/", urlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/1001-3/", urlProvider.GetUrl(10013, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("/1002/", urlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain1.com")));
Assert.AreEqual("http://domain1.com/fr/1001-2-1/", publishedUrlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain2.com")));
Assert.AreEqual("http://domain1.com/fr/1001-2-1/", urlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain2.com")));
}
private static void CheckRoute(IDictionary<int, string> routes, IDictionary<string, int> ids, int id, string route)
private static void CheckRoute(FastDictionaryAppCache routes, int id, string route)
{
Assert.IsTrue(routes.ContainsKey(id));
Assert.AreEqual(route, routes[id]);
Assert.IsFalse(ids.ContainsKey(route));
var cacheKey = $"{CacheKeyPrefix}[P:{id}]";
var found = (string)routes.Get(cacheKey);
Assert.IsNotNull(found);
Assert.AreEqual(route, found);
}
[Test]
public void Get_Url_Relative_Or_Absolute()
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
var umbracoContext = GetUmbracoContext("http://domain1.com/test", 1111, globalSettings: globalSettings);
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
var urlProvider = new DefaultUrlProvider(
Microsoft.Extensions.Options.Options.Create(requestHandlerSettings),
LoggerFactory.CreateLogger<DefaultUrlProvider>(),
new SiteDomainMapper(), umbracoContextAccessor, UriUtility);
var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider);
SetDomains4();
Assert.AreEqual("/en/1001-1-1/", publishedUrlProvider.GetUrl(100111));
Assert.AreEqual("http://domain3.com/en/1003-1-1/", publishedUrlProvider.GetUrl(100311));
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
GlobalSettings.HideTopLevelNodeFromPath = false;
publishedUrlProvider.Mode = UrlMode.Absolute;
var umbracoContextAccessor = GetUmbracoContextAccessor("http://domain1.com/test");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
Assert.AreEqual("http://domain1.com/en/1001-1-1/", publishedUrlProvider.GetUrl(100111));
Assert.AreEqual("http://domain3.com/en/1003-1-1/", publishedUrlProvider.GetUrl(100311));
Assert.AreEqual("/en/1001-1-1/", urlProvider.GetUrl(100111));
Assert.AreEqual("http://domain3.com/en/1003-1-1/", urlProvider.GetUrl(100311));
urlProvider.Mode = UrlMode.Absolute;
Assert.AreEqual("http://domain1.com/en/1001-1-1/", urlProvider.GetUrl(100111));
Assert.AreEqual("http://domain3.com/en/1003-1-1/", urlProvider.GetUrl(100311));
}
[Test]
public void Get_Url_Alternate()
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
var umbracoContext = GetUmbracoContext("http://domain1.com/en/test", 1111, globalSettings: globalSettings);
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
var urlProvider = new DefaultUrlProvider(
Microsoft.Extensions.Options.Options.Create(requestHandlerSettings),
LoggerFactory.CreateLogger<DefaultUrlProvider>(),
new SiteDomainMapper(), umbracoContextAccessor, UriUtility);
var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider);
SetDomains5();
var url = publishedUrlProvider.GetUrl(100111, UrlMode.Absolute);
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
GlobalSettings.HideTopLevelNodeFromPath = false;
var umbracoContextAccessor = GetUmbracoContextAccessor("http://domain1.com/en/test");
UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility);
var url = urlProvider.GetUrl(100111, UrlMode.Absolute);
Assert.AreEqual("http://domain1.com/en/1001-1-1/", url);
var result = publishedUrlProvider.GetOtherUrls(100111).ToArray();
var result = urlProvider.GetOtherUrls(100111).ToArray();
foreach (var x in result) Console.WriteLine(x);
foreach (var x in result)
Console.WriteLine(x);
Assert.AreEqual(2, result.Length);
Assert.AreEqual(result[0].Text, "http://domain1b.com/en/1001-1-1/");
Assert.AreEqual(result[1].Text, "http://domain1a.com/en/1001-1-1/");
}
private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider)
{
var webRoutingSettings = new WebRoutingSettings();
return new UrlProvider(
new TestUmbracoContextAccessor(umbracoContext),
Microsoft.Extensions.Options.Options.Create(webRoutingSettings),
new UrlProviderCollection(new []{urlProvider}),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IVariationContextAccessor>()
);
}
}
}

View File

@@ -5,17 +5,19 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Tests.Common;
using Umbraco.Extensions;
using Umbraco.Tests.LegacyXmlPublishedCache;
namespace Umbraco.Tests.Routing
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing
{
[TestFixture]
public class UrlsWithNestedDomains : UrlRoutingTestBase
@@ -25,61 +27,60 @@ namespace Umbraco.Tests.Routing
// using the closest domain to the node - here we test that if we request
// a non-canonical route, it is not cached / the cache is not polluted
protected override void Compose()
{
base.Compose();
Builder.Services.AddUnique(Mock.Of<IDomainService>());
Builder.Services.AddTransient<ISiteDomainMapper, SiteDomainMapper>();
}
[Test]
public async Task DoNotPolluteCache()
{
var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true };
var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false };
GlobalSettings.HideTopLevelNodeFromPath = false;
SetDomains1();
const string url = "http://domain1.com/1001-1/1001-1-1";
// get the nice URL for 100111
var umbracoContext = GetUmbracoContext(url, 9999, globalSettings: globalSettings);
var umbracoContextAccessor = GetUmbracoContextAccessor(umbracoContext);
var umbracoContextAccessor = GetUmbracoContextAccessor(url);
var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext();
var urlProvider = new DefaultUrlProvider(
Microsoft.Extensions.Options.Options.Create(requestHandlerSettings),
LoggerFactory.CreateLogger<DefaultUrlProvider>(),
new SiteDomainMapper(), umbracoContextAccessor, UriUtility);
Mock.Of<ILogger<DefaultUrlProvider>>(),
new SiteDomainMapper(),
umbracoContextAccessor,
new UriUtility(Mock.Of<IHostingEnvironment>()),
Mock.Of<ILocalizationService>());
var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider);
Assert.AreEqual("http://domain2.com/1001-1-1/", publishedUrlProvider.GetUrl(100111, UrlMode.Absolute));
string absUrl = publishedUrlProvider.GetUrl(100111, UrlMode.Absolute);
Assert.AreEqual("http://domain2.com/1001-1-1/", absUrl);
const string cacheKeyPrefix = "NuCache.ContentCache.RouteByContent";
// check that the proper route has been cached
var cache = umbracoContext.Content as PublishedContentCache;
if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported.");
var cachedRoutes = cache.RoutesCache.GetCachedRoutes();
Assert.AreEqual("10011/1001-1-1", cachedRoutes[100111]);
var cache = (FastDictionaryAppCache)umbracoContext.PublishedSnapshot.ElementsCache;
var cachedRoutes = cache.Keys.Where(x => x.StartsWith(cacheKeyPrefix)).ToList();
var cacheKey = $"{cacheKeyPrefix}[P:100111]";
Assert.AreEqual("10011/1001-1-1", cache.Get(cacheKey));
// route a rogue URL
var publishedRouter = CreatePublishedRouter(umbracoContextAccessor);
var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
publishedRouter.FindDomain(frequest);
Assert.IsTrue(frequest.HasDomain());
// check that it's been routed
var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var lookup = new ContentFinderByUrl(Mock.Of<ILogger<ContentFinderByUrl>>(), umbracoContextAccessor);
var result = lookup.TryFindContent(frequest);
Assert.IsTrue(result);
Assert.AreEqual(100111, frequest.PublishedContent.Id);
// has the cache been polluted?
cachedRoutes = cache.RoutesCache.GetCachedRoutes();
Assert.AreEqual("10011/1001-1-1", cachedRoutes[100111]); // no
//Assert.AreEqual("1001/1001-1/1001-1-1", cachedRoutes[100111]); // yes
cachedRoutes = cache.Keys.Where(x => x.StartsWith(cacheKeyPrefix)).ToList();
Assert.AreEqual("10011/1001-1-1", cache.Get(cacheKey)); // no
// what's the nice URL now?
Assert.AreEqual("http://domain2.com/1001-1-1/", publishedUrlProvider.GetUrl(100111)); // good
//Assert.AreEqual("http://domain1.com/1001-1/1001-1-1", routingContext.NiceUrlProvider.GetNiceUrl(100111, true)); // bad
}
private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, object urlProvider)
@@ -87,14 +88,16 @@ namespace Umbraco.Tests.Routing
throw new NotImplementedException();
}
void SetDomains1()
private void SetDomains1()
{
SetupDomainServiceMock(new[]
{
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain2.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}
});
var domainService = Mock.Get(DomainService);
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
.Returns((bool incWildcards) => new[]
{
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
new UmbracoDomain("http://domain2.com/") {Id = 2, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}
});
}
private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider)
@@ -103,15 +106,14 @@ namespace Umbraco.Tests.Routing
return new UrlProvider(
new TestUmbracoContextAccessor(umbracoContext),
Microsoft.Extensions.Options.Options.Create(webRoutingSettings),
new UrlProviderCollection(new []{urlProvider}),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
new UrlProviderCollection(() => new[] { urlProvider }),
new MediaUrlProviderCollection(() => Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IVariationContextAccessor>()
);
}
protected override string GetXmlContent(int templateId)
{
return @"<?xml version=""1.0"" encoding=""utf-8""?>
=> @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE root[
<!ELEMENT Doc ANY>
<!ATTLIST Doc id ID #REQUIRED>
@@ -190,6 +192,5 @@ namespace Umbraco.Tests.Routing
</Doc>
</Doc>
</root>";
}
}
}

View File

@@ -0,0 +1,147 @@
using System;
using System.Threading.Tasks;
using AutoFixture.NUnit3;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Runtime;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Infrastructure.HostedServices;
using Umbraco.Cms.Tests.UnitTests.AutoFixture;
namespace Umbraco.Tests.Scheduling
{
[TestFixture]
class ContentVersionCleanupTest
{
[Test, AutoMoqData]
public async Task ContentVersionCleanup_WhenNotEnabled_DoesNotCleanupWillRepeat(
[Frozen] Mock<IOptionsMonitor<ContentSettings>> settings,
[Frozen] Mock<IMainDom> mainDom,
[Frozen] Mock<IServerRoleAccessor> serverRoleAccessor,
[Frozen] Mock<IRuntimeState> runtimeState,
[Frozen] Mock<IContentVersionService> cleanupService,
ContentVersionCleanup sut)
{
settings.Setup(x => x.CurrentValue).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new ContentVersionCleanupPolicySettings()
{
EnableCleanup = false
}
});
runtimeState.Setup(x => x.Level).Returns(RuntimeLevel.Run);
mainDom.Setup(x => x.IsMainDom).Returns(true);
serverRoleAccessor.Setup(x => x.CurrentServerRole).Returns(ServerRole.SchedulingPublisher);
await sut.PerformExecuteAsync(null);
cleanupService.Verify(x => x.PerformContentVersionCleanup(It.IsAny<DateTime>()), Times.Never);
}
[Test, AutoMoqData]
public async Task ContentVersionCleanup_RuntimeLevelNotRun_DoesNotCleanupWillRepeat(
[Frozen] Mock<IOptionsMonitor<ContentSettings>> settings,
[Frozen] Mock<IMainDom> mainDom,
[Frozen] Mock<IServerRoleAccessor> serverRoleAccessor,
[Frozen] Mock<IRuntimeState> runtimeState,
[Frozen] Mock<IContentVersionService> cleanupService,
ContentVersionCleanup sut)
{
settings.Setup(x => x.CurrentValue).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new ContentVersionCleanupPolicySettings()
{
EnableCleanup = true
}
});
runtimeState.Setup(x => x.Level).Returns(RuntimeLevel.Unknown);
mainDom.Setup(x => x.IsMainDom).Returns(true);
serverRoleAccessor.Setup(x => x.CurrentServerRole).Returns(ServerRole.SchedulingPublisher);
await sut.PerformExecuteAsync(null);
cleanupService.Verify(x => x.PerformContentVersionCleanup(It.IsAny<DateTime>()), Times.Never);
}
[Test, AutoMoqData]
public async Task ContentVersionCleanup_ServerRoleUnknown_DoesNotCleanupWillRepeat(
[Frozen] Mock<IOptionsMonitor<ContentSettings>> settings,
[Frozen] Mock<IMainDom> mainDom,
[Frozen] Mock<IServerRoleAccessor> serverRoleAccessor,
[Frozen] Mock<IRuntimeState> runtimeState,
[Frozen] Mock<IContentVersionService> cleanupService,
ContentVersionCleanup sut)
{
settings.Setup(x => x.CurrentValue).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new ContentVersionCleanupPolicySettings()
{
EnableCleanup = true
}
});
runtimeState.Setup(x => x.Level).Returns(RuntimeLevel.Run);
mainDom.Setup(x => x.IsMainDom).Returns(true);
serverRoleAccessor.Setup(x => x.CurrentServerRole).Returns(ServerRole.Unknown);
await sut.PerformExecuteAsync(null);
cleanupService.Verify(x => x.PerformContentVersionCleanup(It.IsAny<DateTime>()), Times.Never);
}
[Test, AutoMoqData]
public async Task ContentVersionCleanup_NotMainDom_DoesNotCleanupWillNotRepeat(
[Frozen] Mock<IOptionsMonitor<ContentSettings>> settings,
[Frozen] Mock<IMainDom> mainDom,
[Frozen] Mock<IServerRoleAccessor> serverRoleAccessor,
[Frozen] Mock<IRuntimeState> runtimeState,
[Frozen] Mock<IContentVersionService> cleanupService,
ContentVersionCleanup sut)
{
settings.Setup(x => x.CurrentValue).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new ContentVersionCleanupPolicySettings()
{
EnableCleanup = true
}
});
runtimeState.Setup(x => x.Level).Returns(RuntimeLevel.Run);
mainDom.Setup(x => x.IsMainDom).Returns(false);
serverRoleAccessor.Setup(x => x.CurrentServerRole).Returns(ServerRole.SchedulingPublisher);
await sut.PerformExecuteAsync(null);
cleanupService.Verify(x => x.PerformContentVersionCleanup(It.IsAny<DateTime>()), Times.Never);
}
[Test, AutoMoqData]
public async Task ContentVersionCleanup_Enabled_DelegatesToCleanupService(
[Frozen] Mock<IOptionsMonitor<ContentSettings>> settings,
[Frozen] Mock<IMainDom> mainDom,
[Frozen] Mock<IServerRoleAccessor> serverRoleAccessor,
[Frozen] Mock<IRuntimeState> runtimeState,
[Frozen] Mock<IContentVersionService> cleanupService,
ContentVersionCleanup sut)
{
settings.Setup(x => x.CurrentValue).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new ContentVersionCleanupPolicySettings()
{
EnableCleanup = true
}
});
runtimeState.Setup(x => x.Level).Returns(RuntimeLevel.Run);
mainDom.Setup(x => x.IsMainDom).Returns(true);
serverRoleAccessor.Setup(x => x.CurrentServerRole).Returns(ServerRole.SchedulingPublisher);
await sut.PerformExecuteAsync(null);
cleanupService.Verify(x => x.PerformContentVersionCleanup(It.IsAny<DateTime>()), Times.Once);
}
}
}

View File

@@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using AutoFixture.NUnit3;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.Implement;
using Umbraco.Cms.Tests.UnitTests.AutoFixture;
namespace Umbraco.Tests.Services
{
[TestFixture]
internal class ContentVersionCleanupServiceTest
{
[Test]
[AutoMoqData]
public void PerformContentVersionCleanup_Always_RespectsDeleteRevisionsCancellation(
[Frozen] Mock<IScopedNotificationPublisher> eventAggregator,
[Frozen] Mock<IContentVersionCleanupPolicy> policy,
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
List<ContentVersionMeta> someHistoricVersions,
DateTime aDateTime,
ContentVersionService sut)
{
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(someHistoricVersions);
eventAggregator.Setup(x => x.PublishCancelable(It.IsAny<ContentDeletingVersionsNotification>()))
.Returns(true);
policy.Setup(x => x.Apply(aDateTime, someHistoricVersions))
.Returns(someHistoricVersions);
// # Act
IReadOnlyCollection<ContentVersionMeta> report = sut.PerformContentVersionCleanup(aDateTime);
Assert.Multiple(() =>
{
eventAggregator.Verify(x => x.PublishCancelable(It.IsAny<ContentDeletingVersionsNotification>()), Times.Exactly(someHistoricVersions.Count));
Assert.AreEqual(0, report.Count);
});
}
[Test]
[AutoMoqData]
public void PerformContentVersionCleanup_Always_FiresDeletedVersionsForEachDeletedVersion(
[Frozen] Mock<IScopedNotificationPublisher> eventAggregator,
[Frozen] Mock<IContentVersionCleanupPolicy> policy,
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
List<ContentVersionMeta> someHistoricVersions,
DateTime aDateTime,
ContentVersionService sut)
{
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(someHistoricVersions);
eventAggregator
.Setup(x => x.PublishCancelable(It.IsAny<ICancelableNotification>()))
.Returns(false);
policy.Setup(x => x.Apply(aDateTime, someHistoricVersions))
.Returns(someHistoricVersions);
// # Act
sut.PerformContentVersionCleanup(aDateTime);
eventAggregator.Verify(x => x.Publish(It.IsAny<ContentDeletedVersionsNotification>()), Times.Exactly(someHistoricVersions.Count));
}
[Test, AutoMoqData]
public void PerformContentVersionCleanup_Always_ReturnsReportOfDeletedItems(
[Frozen] Mock<IScopedNotificationPublisher> eventAggregator,
[Frozen] Mock<IContentVersionCleanupPolicy> policy,
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
List<ContentVersionMeta> someHistoricVersions,
DateTime aDateTime,
ContentVersionService sut)
{
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(someHistoricVersions);
eventAggregator
.Setup(x => x.PublishCancelable(It.IsAny<ICancelableNotification>()))
.Returns(false);
// # Act
var report = sut.PerformContentVersionCleanup(aDateTime);
Assert.Multiple(() =>
{
Assert.Greater(report.Count, 0);
Assert.AreEqual(someHistoricVersions.Count, report.Count);
});
}
[Test, AutoMoqData]
public void PerformContentVersionCleanup_Always_AdheresToCleanupPolicy(
[Frozen] Mock<IScopedNotificationPublisher> eventAggregator,
[Frozen] Mock<IContentVersionCleanupPolicy> policy,
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
List<ContentVersionMeta> someHistoricVersions,
DateTime aDateTime,
ContentVersionService sut)
{
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(someHistoricVersions);
eventAggregator
.Setup(x => x.PublishCancelable(It.IsAny<ICancelableNotification>()))
.Returns(false);
policy.Setup(x => x.Apply(It.IsAny<DateTime>(), It.IsAny<IEnumerable<ContentVersionMeta>>()))
.Returns<DateTime, IEnumerable<ContentVersionMeta>>((_, items) => items.Take(1));
// # Act
var report = sut.PerformContentVersionCleanup(aDateTime);
Debug.Assert(someHistoricVersions.Count > 1);
Assert.Multiple(() =>
{
policy.Verify(x => x.Apply(aDateTime, someHistoricVersions), Times.Once);
Assert.AreEqual(someHistoricVersions.First(), report.Single());
});
}
/// <remarks>
/// For v9 this just needs a rewrite, no static events, no service location etc
/// </remarks>
[Test, AutoMoqData]
public void PerformContentVersionCleanup_HasVersionsToDelete_CallsDeleteOnRepositoryWithFilteredSet(
[Frozen] Mock<IScopedNotificationPublisher> eventAggregator,
[Frozen] Mock<IContentVersionCleanupPolicy> policy,
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
List<ContentVersionMeta> someHistoricVersions,
DateTime aDateTime,
ContentVersionService sut)
{
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(someHistoricVersions);
eventAggregator
.Setup(x => x.PublishCancelable(It.IsAny<ICancelableNotification>()))
.Returns(false);
var filteredSet = someHistoricVersions.Take(1);
policy.Setup(x => x.Apply(It.IsAny<DateTime>(), It.IsAny<IEnumerable<ContentVersionMeta>>()))
.Returns<DateTime, IEnumerable<ContentVersionMeta>>((_, items) => filteredSet);
// # Act
var report = sut.PerformContentVersionCleanup(aDateTime);
Debug.Assert(someHistoricVersions.Any());
var expectedId = filteredSet.First().VersionId;
documentVersionRepository.Verify(x => x.DeleteVersions(It.Is<IEnumerable<int>>(y => y.Single() == expectedId)), Times.Once);
}
}
}

View File

@@ -0,0 +1,279 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AutoFixture.NUnit3;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Infrastructure.Services.Implement;
using Umbraco.Cms.Tests.UnitTests.AutoFixture;
using ContentVersionCleanupPolicySettings = Umbraco.Cms.Core.Models.ContentVersionCleanupPolicySettings;
namespace Umbraco.Tests.Services
{
[TestFixture]
public class DefaultContentVersionCleanupPolicyTest
{
[Test, AutoMoqData]
public void Apply_AllOlderThanKeepSettings_AllVersionsReturned(
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
[Frozen] Mock<IOptions<ContentSettings>> contentSettings,
DefaultContentVersionCleanupPolicy sut)
{
var versionId = 0;
var historicItems = new List<ContentVersionMeta>
{
new ContentVersionMeta(versionId: ++versionId, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
new ContentVersionMeta(versionId: ++versionId, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
};
contentSettings.Setup(x => x.Value).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new Cms.Core.Configuration.Models.ContentVersionCleanupPolicySettings()
{
EnableCleanup = true,
KeepAllVersionsNewerThanDays = 0,
KeepLatestVersionPerDayForDays = 0
}
});
documentVersionRepository.Setup(x => x.GetCleanupPolicies())
.Returns(Array.Empty<ContentVersionCleanupPolicySettings>());
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(historicItems);
var results = sut.Apply(DateTime.Today, historicItems).ToList();
Assert.AreEqual(2, results.Count);
}
[Test, AutoMoqData]
public void Apply_OverlappingKeepSettings_KeepAllVersionsNewerThanDaysTakesPriority(
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
[Frozen] Mock<IOptions<ContentSettings>> contentSettings,
DefaultContentVersionCleanupPolicy sut)
{
var versionId = 0;
var historicItems = new List<ContentVersionMeta>
{
new ContentVersionMeta(versionId: ++versionId, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
new ContentVersionMeta(versionId: ++versionId, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
};
contentSettings.Setup(x => x.Value).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new Cms.Core.Configuration.Models.ContentVersionCleanupPolicySettings()
{
EnableCleanup = true,
KeepAllVersionsNewerThanDays = 2,
KeepLatestVersionPerDayForDays = 2
}
});
documentVersionRepository.Setup(x => x.GetCleanupPolicies())
.Returns(Array.Empty<ContentVersionCleanupPolicySettings>());
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(historicItems);
var results = sut.Apply(DateTime.Today, historicItems).ToList();
Assert.AreEqual(0, results.Count);
}
[Test, AutoMoqData]
public void Apply_WithinInKeepLatestPerDay_ReturnsSinglePerContentPerDay(
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
[Frozen] Mock<IOptions<ContentSettings>> contentSettings,
DefaultContentVersionCleanupPolicy sut)
{
var historicItems = new List<ContentVersionMeta>
{
new ContentVersionMeta(versionId: 1, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-3), false, false, false, null),
new ContentVersionMeta(versionId: 2, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-2), false, false, false, null),
new ContentVersionMeta(versionId: 3, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
new ContentVersionMeta(versionId: 4, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddDays(-1).AddHours(-3), false, false, false, null),
new ContentVersionMeta(versionId: 5, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddDays(-1).AddHours(-2), false, false, false, null),
new ContentVersionMeta(versionId: 6, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddDays(-1).AddHours(-1), false, false, false, null),
// another content
new ContentVersionMeta(versionId: 7, contentId: 2, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-3), false, false, false, null),
new ContentVersionMeta(versionId: 8, contentId: 2, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-2), false, false, false, null),
new ContentVersionMeta(versionId: 9, contentId: 2, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
};
contentSettings.Setup(x => x.Value).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new Cms.Core.Configuration.Models.ContentVersionCleanupPolicySettings()
{
EnableCleanup = true,
KeepAllVersionsNewerThanDays = 0,
KeepLatestVersionPerDayForDays = 3
}
});
documentVersionRepository.Setup(x => x.GetCleanupPolicies())
.Returns(Array.Empty<ContentVersionCleanupPolicySettings>());
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(historicItems);
var results = sut.Apply(DateTime.Today, historicItems).ToList();
// Keep latest per day for 3 days per content type
// 2 content types, one of which has 2 days of entries, the other only a single day
Assert.Multiple(() =>
{
Assert.AreEqual(6, results.Count);
Assert.AreEqual(4, results.Count(x => x.ContentTypeId == 1));
Assert.AreEqual(2, results.Count(x => x.ContentTypeId == 2));
Assert.False(results.Any(x => x.VersionId == 9)); // Most recent for content type 2
Assert.False(results.Any(x => x.VersionId == 3)); // Most recent for content type 1 today
Assert.False(results.Any(x => x.VersionId == 6)); // Most recent for content type 1 yesterday
});
}
[Test, AutoMoqData]
public void Apply_HasOverridePolicy_RespectsPreventCleanup(
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
[Frozen] Mock<IOptions<ContentSettings>> contentSettings,
DefaultContentVersionCleanupPolicy sut)
{
var historicItems = new List<ContentVersionMeta>
{
new ContentVersionMeta(versionId: 1, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-3), false, false, false, null),
new ContentVersionMeta(versionId: 2, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-2), false, false, false, null),
new ContentVersionMeta(versionId: 3, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
// another content & type
new ContentVersionMeta(versionId: 4, contentId: 2, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-3), false, false, false, null),
new ContentVersionMeta(versionId: 5, contentId: 2, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-2), false, false, false, null),
new ContentVersionMeta(versionId: 6, contentId: 2, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
};
contentSettings.Setup(x => x.Value).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new Cms.Core.Configuration.Models.ContentVersionCleanupPolicySettings()
{
EnableCleanup = true,
KeepAllVersionsNewerThanDays = 0,
KeepLatestVersionPerDayForDays = 0
}
});
documentVersionRepository.Setup(x => x.GetCleanupPolicies())
.Returns(new ContentVersionCleanupPolicySettings[]
{
new ContentVersionCleanupPolicySettings{ ContentTypeId = 2, PreventCleanup = true }
});
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(historicItems);
var results = sut.Apply(DateTime.Today, historicItems).ToList();
Assert.True(results.All(x => x.ContentTypeId == 1));
}
[Test, AutoMoqData]
public void Apply_HasOverridePolicy_RespectsKeepAll(
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
[Frozen] Mock<IOptions<ContentSettings>> contentSettings,
DefaultContentVersionCleanupPolicy sut)
{
var historicItems = new List<ContentVersionMeta>
{
new ContentVersionMeta(versionId: 1, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-3), false, false, false, null),
new ContentVersionMeta(versionId: 2, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-2), false, false, false, null),
new ContentVersionMeta(versionId: 3, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
// another content & type
new ContentVersionMeta(versionId: 4, contentId: 2, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-3), false, false, false, null),
new ContentVersionMeta(versionId: 5, contentId: 2, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-2), false, false, false, null),
new ContentVersionMeta(versionId: 6, contentId: 2, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
};
contentSettings.Setup(x => x.Value).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new Cms.Core.Configuration.Models.ContentVersionCleanupPolicySettings()
{
EnableCleanup = true,
KeepAllVersionsNewerThanDays = 0,
KeepLatestVersionPerDayForDays = 0
}
});
documentVersionRepository.Setup(x => x.GetCleanupPolicies())
.Returns(new ContentVersionCleanupPolicySettings[]
{
new ContentVersionCleanupPolicySettings{ ContentTypeId = 2, PreventCleanup = false, KeepAllVersionsNewerThanDays = 3 }
});
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(historicItems);
var results = sut.Apply(DateTime.Today, historicItems).ToList();
Assert.True(results.All(x => x.ContentTypeId == 1));
}
[Test, AutoMoqData]
public void Apply_HasOverridePolicy_RespectsKeepLatest(
[Frozen] Mock<IDocumentVersionRepository> documentVersionRepository,
[Frozen] Mock<IOptions<ContentSettings>> contentSettings,
DefaultContentVersionCleanupPolicy sut)
{
var historicItems = new List<ContentVersionMeta>
{
new ContentVersionMeta(versionId: 1, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-3), false, false, false, null),
new ContentVersionMeta(versionId: 2, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-2), false, false, false, null),
new ContentVersionMeta(versionId: 3, contentId: 1, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
// another content
new ContentVersionMeta(versionId: 4, contentId: 2, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-3), false, false, false, null),
new ContentVersionMeta(versionId: 5, contentId: 2, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-2), false, false, false, null),
new ContentVersionMeta(versionId: 6, contentId: 2, contentTypeId: 1, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
// another content & type
new ContentVersionMeta(versionId: 7, contentId: 3, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-3), false, false, false, null),
new ContentVersionMeta(versionId: 8, contentId: 3, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-2), false, false, false, null),
new ContentVersionMeta(versionId: 9, contentId: 3, contentTypeId: 2, -1, versionDate: DateTime.Today.AddHours(-1), false, false, false, null),
};
contentSettings.Setup(x => x.Value).Returns(new ContentSettings()
{
ContentVersionCleanupPolicy = new Cms.Core.Configuration.Models.ContentVersionCleanupPolicySettings()
{
EnableCleanup = true,
KeepAllVersionsNewerThanDays = 0,
KeepLatestVersionPerDayForDays = 0
}
});
documentVersionRepository.Setup(x => x.GetCleanupPolicies())
.Returns(new ContentVersionCleanupPolicySettings[]
{
new ContentVersionCleanupPolicySettings{ ContentTypeId = 2, PreventCleanup = false, KeepLatestVersionPerDayForDays = 3 }
});
documentVersionRepository.Setup(x => x.GetDocumentVersionsEligibleForCleanup())
.Returns(historicItems);
var results = sut.Apply(DateTime.Today, historicItems).ToList();
// By default no historic versions are kept
// Override policy for content type 2 keeps latest per day for 3 days, no versions retained for content type with id 1
// There were 3 entries for content type 2 all on the same day
// version id 9 is most recent for content type 2, and should be filtered, all the rest should be present.
Assert.Multiple(() =>
{
Assert.AreEqual(8, results.Count);
Assert.AreEqual(2, results.Count(x => x.ContentTypeId == 2));
Assert.False(results.Any(x => x.VersionId == 9));
});
}
}
}

View File

@@ -7,12 +7,14 @@ using Umbraco.Cms.Core.IO;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Templates
{
[TestFixture]
public class ViewHelperTests
public class DefaultViewContentProviderTests
{
private IDefaultViewContentProvider DefaultViewContentProvider => new DefaultViewContentProvider();
[Test]
public void NoOptions()
{
var view = ViewHelper.GetDefaultFileContent();
var view = DefaultViewContentProvider.GetDefaultFileContent();
Assert.AreEqual(
FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@@ -24,7 +26,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Templates
[Test]
public void Layout()
{
var view = ViewHelper.GetDefaultFileContent(layoutPageAlias: "Dharznoik");
var view = DefaultViewContentProvider.GetDefaultFileContent(layoutPageAlias: "Dharznoik");
Assert.AreEqual(
FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@@ -36,7 +38,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Templates
[Test]
public void ClassName()
{
var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName");
var view = DefaultViewContentProvider.GetDefaultFileContent(modelClassName: "ClassName");
Assert.AreEqual(
FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ClassName>
@@ -48,7 +50,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Templates
[Test]
public void Namespace()
{
var view = ViewHelper.GetDefaultFileContent(modelNamespace: "Models");
var view = DefaultViewContentProvider.GetDefaultFileContent(modelNamespace: "Models");
Assert.AreEqual(
FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@@ -60,7 +62,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Templates
[Test]
public void ClassNameAndNamespace()
{
var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models");
var view = DefaultViewContentProvider.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models");
Assert.AreEqual(
FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.ClassName>
@@ -73,7 +75,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Templates
[Test]
public void ClassNameAndNamespaceAndAlias()
{
var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels");
var view = DefaultViewContentProvider.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels");
Assert.AreEqual(
FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<MyModels.ClassName>
@@ -86,7 +88,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Templates
[Test]
public void Combined()
{
var view = ViewHelper.GetDefaultFileContent(layoutPageAlias: "Dharznoik", modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels");
var view = DefaultViewContentProvider.GetDefaultFileContent(layoutPageAlias: "Dharznoik", modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels");
Assert.AreEqual(
FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<MyModels.ClassName>

View File

@@ -66,7 +66,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Logging
ILogger<SerilogJsonLogViewer> logger = Mock.Of<ILogger<SerilogJsonLogViewer>>();
var logViewerConfig = new LogViewerConfig(LogViewerQueryRepository, Mock.Of<IScopeProvider>());
_logViewer = new SerilogJsonLogViewer(logger, logViewerConfig, loggingConfiguration, Log.Logger);
var logLevelLoader = Mock.Of<ILogLevelLoader>();
_logViewer = new SerilogJsonLogViewer(logger, logViewerConfig, loggingConfiguration, logLevelLoader, Log.Logger);
}
[OneTimeTearDown]

View File

@@ -1,12 +1,12 @@
using Moq;
using Moq;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.PublishedCache.NuCache.DataSource;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
namespace Umbraco.Tests.PublishedContent
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache
{
[TestFixture]
public class ContentSerializationTests
@@ -77,9 +77,12 @@ namespace Umbraco.Tests.PublishedContent
{
public override int Compare(CultureVariation x, CultureVariation y)
{
if (x == null && y == null) return 0;
if (x == null && y != null) return -1;
if (x != null && y == null) return 1;
if (x == null && y == null)
return 0;
if (x == null && y != null)
return -1;
if (x != null && y == null)
return 1;
return x.Date.CompareTo(y.Date) | x.IsDraft.CompareTo(y.IsDraft) | x.Name.CompareTo(y.Name) | x.UrlSegment.CompareTo(y.UrlSegment);
}
@@ -89,9 +92,12 @@ namespace Umbraco.Tests.PublishedContent
{
public override int Compare(PropertyData x, PropertyData y)
{
if (x == null && y == null) return 0;
if (x == null && y != null) return -1;
if (x != null && y == null) return 1;
if (x == null && y == null)
return 0;
if (x == null && y != null)
return -1;
if (x != null && y == null)
return 1;
var xVal = x.Value?.ToString() ?? string.Empty;
var yVal = y.Value?.ToString() ?? string.Empty;

View File

@@ -0,0 +1,85 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache
{
[TestFixture]
public class PublishContentCacheTests : PublishedSnapshotServiceTestBase
{
private IPublishedContentCache _cache;
[SetUp]
public override void Setup()
{
base.Setup();
string xml = PublishedContentXml.PublishContentCacheTestsXml();
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
// configure the Home content type to be composed of another for tests.
var compositionType = new ContentType(TestHelper.ShortStringHelper, -1)
{
Alias = "MyCompositionAlias"
};
contentTypes.First(x => x.Alias == "Home").AddContentType(compositionType);
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
_cache = GetPublishedSnapshot().Content;
}
[Test]
public void Has_Content()
{
Assert.IsTrue(_cache.HasContent());
}
[Test]
public void Get_Root_Docs()
{
var result = _cache.GetAtRoot();
Assert.AreEqual(2, result.Count());
Assert.AreEqual(1046, result.ElementAt(0).Id);
Assert.AreEqual(1172, result.ElementAt(1).Id);
}
[TestCase("/", 1046)]
[TestCase("/home", 1046)]
[TestCase("/Home", 1046)] //test different cases
[TestCase("/home/sub1", 1173)]
[TestCase("/Home/sub1", 1173)]
[TestCase("/home/Sub1", 1173)] //test different cases
[TestCase("/home/Sub'Apostrophe", 1177)]
public void Get_Node_By_Route(string route, int nodeId)
{
var result = _cache.GetByRoute(route, false);
Assert.IsNotNull(result);
Assert.AreEqual(nodeId, result.Id);
}
[TestCase("/", 1046)]
[TestCase("/sub1", 1173)]
[TestCase("/Sub1", 1173)]
public void Get_Node_By_Route_Hiding_Top_Level_Nodes(string route, int nodeId)
{
var result = _cache.GetByRoute(route, true);
Assert.IsNotNull(result);
Assert.AreEqual(nodeId, result.Id);
}
}
}

View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache
{
/// <summary>
/// Unit tests for IPublishedContent and extensions
/// </summary>
[TestFixture]
public class PublishedContentDataTableTests : PublishedSnapshotServiceTestBase
{
private readonly DataType[] _dataTypes = GetDefaultDataTypes();
private static ContentType CreateContentType(string name, IDataType dataType, IReadOnlyDictionary<string, string> propertyAliasesAndNames)
{
var contentType = new ContentType(TestHelper.ShortStringHelper, -1)
{
Alias = name,
Name = name,
Key = Guid.NewGuid(),
Id = name.GetHashCode()
};
foreach(var prop in propertyAliasesAndNames)
{
contentType.AddPropertyType(new PropertyType(TestHelper.ShortStringHelper, dataType, prop.Key)
{
Name = prop.Value
});
}
return contentType;
}
private IEnumerable<ContentNodeKit> CreateCache(
bool createChildren,
IDataType dataType,
out ContentType[] contentTypes)
{
var result = new List<ContentNodeKit>();
var valueCounter = 1;
var parentId = 3;
var properties = new Dictionary<string, string>
{
["property1"] = "Property 1",
["property2"] = "Property 2",
};
ContentType parentContentType = CreateContentType("Parent", dataType, new Dictionary<string, string>(properties)
{
["property3"] = "Property 3"
});
ContentType childContentType = CreateContentType("Child", dataType, new Dictionary<string, string>(properties)
{
["property4"] = "Property 4"
});
ContentType child2ContentType = CreateContentType("Child2", dataType, new Dictionary<string, string>(properties)
{
["property4"] = "Property 4"
});
contentTypes = new[] { parentContentType, childContentType, child2ContentType };
ContentData parentData = new ContentDataBuilder()
.WithName("Page" + Guid.NewGuid())
.WithProperties(new PropertyDataBuilder()
.WithPropertyData("property1", "value" + valueCounter)
.WithPropertyData("property2", "value" + (valueCounter + 1))
.WithPropertyData("property3", "value" + (valueCounter + 2))
.Build())
.Build();
ContentNodeKit parent = ContentNodeKitBuilder.CreateWithContent(
parentContentType.Id,
parentId, $"-1,{parentId}",
draftData: parentData,
publishedData: parentData);
result.Add(parent);
if (createChildren)
{
for (int i = 0; i < 3; i++)
{
valueCounter += 3;
var childId = parentId + i + 1;
ContentData childData = new ContentDataBuilder()
.WithName("Page" + Guid.NewGuid())
.WithProperties(new PropertyDataBuilder()
.WithPropertyData("property1", "value" + valueCounter)
.WithPropertyData("property2", "value" + (valueCounter + 1))
.WithPropertyData("property4", "value" + (valueCounter + 2))
.Build())
.Build();
ContentNodeKit child = ContentNodeKitBuilder.CreateWithContent(
i > 0 ? childContentType.Id : child2ContentType.Id,
childId, $"-1,{parentId},{childId}", i,
draftData: childData,
publishedData: childData);
result.Add(child);
}
}
return result;
}
[Test]
public void To_DataTable()
{
var cache = CreateCache(true, _dataTypes[0], out ContentType[] contentTypes);
InitializedCache(cache, contentTypes, dataTypes: _dataTypes);
var snapshot = GetPublishedSnapshot();
var root = snapshot.Content.GetAtRoot().First();
var dt = root.ChildrenAsTable(
VariationContextAccessor,
ContentTypeService,
MediaTypeService,
Mock.Of<IMemberTypeService>(),
Mock.Of<IPublishedUrlProvider>());
Assert.AreEqual(11, dt.Columns.Count);
Assert.AreEqual(3, dt.Rows.Count);
Assert.AreEqual("value4", dt.Rows[0]["Property 1"]);
Assert.AreEqual("value5", dt.Rows[0]["Property 2"]);
Assert.AreEqual("value6", dt.Rows[0]["Property 4"]);
Assert.AreEqual("value7", dt.Rows[1]["Property 1"]);
Assert.AreEqual("value8", dt.Rows[1]["Property 2"]);
Assert.AreEqual("value9", dt.Rows[1]["Property 4"]);
Assert.AreEqual("value10", dt.Rows[2]["Property 1"]);
Assert.AreEqual("value11", dt.Rows[2]["Property 2"]);
Assert.AreEqual("value12", dt.Rows[2]["Property 4"]);
}
[Test]
public void To_DataTable_With_Filter()
{
var cache = CreateCache(true, _dataTypes[0], out ContentType[] contentTypes);
InitializedCache(cache, contentTypes, dataTypes: _dataTypes);
var snapshot = GetPublishedSnapshot();
var root = snapshot.Content.GetAtRoot().First();
var dt = root.ChildrenAsTable(
VariationContextAccessor,
ContentTypeService,
MediaTypeService,
Mock.Of<IMemberTypeService>(),
Mock.Of<IPublishedUrlProvider>(),
"Child");
Assert.AreEqual(11, dt.Columns.Count);
Assert.AreEqual(2, dt.Rows.Count);
Assert.AreEqual("value7", dt.Rows[0]["Property 1"]);
Assert.AreEqual("value8", dt.Rows[0]["Property 2"]);
Assert.AreEqual("value9", dt.Rows[0]["Property 4"]);
Assert.AreEqual("value10", dt.Rows[1]["Property 1"]);
Assert.AreEqual("value11", dt.Rows[1]["Property 2"]);
Assert.AreEqual("value12", dt.Rows[1]["Property 4"]);
}
[Test]
public void To_DataTable_No_Rows()
{
var cache = CreateCache(false, _dataTypes[0], out ContentType[] contentTypes);
InitializedCache(cache, contentTypes, dataTypes: _dataTypes);
var snapshot = GetPublishedSnapshot();
var root = snapshot.Content.GetAtRoot().First();
var dt = root.ChildrenAsTable(
VariationContextAccessor,
ContentTypeService,
MediaTypeService,
Mock.Of<IMemberTypeService>(),
Mock.Of<IPublishedUrlProvider>());
//will return an empty data table
Assert.AreEqual(0, dt.Columns.Count);
Assert.AreEqual(0, dt.Rows.Count);
}
}
}

View File

@@ -0,0 +1,77 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache
{
[TestFixture]
public class PublishedContentExtensionTests : PublishedSnapshotServiceTestBase
{
private const string XmlContent = @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE root[
<!ELEMENT inherited ANY>
<!ATTLIST inherited id ID #REQUIRED>
]>
<root id=""-1"">
<inherited id=""1100"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1"" sortOrder=""1"" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" nodeName=""Home"" urlName=""home"" writerName=""admin"" creatorName=""admin"" path=""-1,1046"" isDoc=""""/>
</root>";
[SetUp]
public override void Setup()
{
base.Setup();
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
XmlContent,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
// configure inheritance for content types
var baseType = new ContentType(TestHelper.ShortStringHelper, -1) { Alias = "Base" };
contentTypes[0].AddContentType(baseType);
InitializedCache(kits, contentTypes, dataTypes);
}
[Test]
public void IsDocumentType_NonRecursive_ActualType_ReturnsTrue()
{
var publishedContent = GetContent(1100);
Assert.That(publishedContent.IsDocumentType("Inherited", false));
}
[Test]
public void IsDocumentType_NonRecursive_BaseType_ReturnsFalse()
{
var publishedContent = GetContent(1100);
Assert.That(publishedContent.IsDocumentType("Base", false), Is.False);
}
[Test]
public void IsDocumentType_Recursive_ActualType_ReturnsTrue()
{
var publishedContent = GetContent(1100);
Assert.That(publishedContent.IsDocumentType("Inherited", true));
}
[Test]
public void IsDocumentType_Recursive_BaseType_ReturnsTrue()
{
var publishedContent = GetContent(1100);
Assert.That(publishedContent.IsDocumentType("Base", true));
}
[Test]
public void IsDocumentType_Recursive_InvalidBaseType_ReturnsFalse()
{
var publishedContent = GetContent(1100);
Assert.That(publishedContent.IsDocumentType("invalidbase", true), Is.False);
}
}
}

View File

@@ -0,0 +1,346 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache
{
[TestFixture]
public class PublishedContentLanguageVariantTests : PublishedSnapshotServiceTestBase
{
[SetUp]
public override void Setup()
{
base.Setup();
var dataTypes = GetDefaultDataTypes();
var cache = CreateCache(dataTypes, out ContentType[] contentTypes);
InitializedCache(cache, contentTypes, dataTypes: dataTypes);
}
protected override PropertyValueConverterCollection PropertyValueConverterCollection
{
get
{
PropertyValueConverterCollection collection = base.PropertyValueConverterCollection;
return new PropertyValueConverterCollection(() => collection.Append(new TestNoValueValueConverter()));
}
}
private class TestNoValueValueConverter : SimpleTinyMceValueConverter
{
public override bool IsConverter(IPublishedPropertyType propertyType)
=> propertyType.Alias == "noprop";
// for this test, we return false for IsValue for this property
public override bool? IsValue(object value, PropertyValueLevel level) => false;
}
/// <summary>
/// Override to mock localization service
/// </summary>
/// <param name="contentTypes"></param>
/// <param name="dataTypes"></param>
/// <returns></returns>
protected override ServiceContext CreateServiceContext(IContentType[] contentTypes, IMediaType[] mediaTypes, IDataType[] dataTypes)
{
var serviceContext = base.CreateServiceContext(contentTypes, mediaTypes, dataTypes);
var localizationService = Mock.Get(serviceContext.LocalizationService);
var languages = new List<Language>
{
new Language(GlobalSettings, "en-US") { Id = 1, CultureName = "English", IsDefault = true },
new Language(GlobalSettings, "fr") { Id = 2, CultureName = "French" },
new Language(GlobalSettings, "es") { Id = 3, CultureName = "Spanish", FallbackLanguageId = 1 },
new Language(GlobalSettings, "it") { Id = 4, CultureName = "Italian", FallbackLanguageId = 3 },
new Language(GlobalSettings, "de") { Id = 5, CultureName = "German" },
new Language(GlobalSettings, "da") { Id = 6, CultureName = "Danish", FallbackLanguageId = 8 },
new Language(GlobalSettings, "sv") { Id = 7, CultureName = "Swedish", FallbackLanguageId = 6 },
new Language(GlobalSettings, "no") { Id = 8, CultureName = "Norweigan", FallbackLanguageId = 7 },
new Language(GlobalSettings, "nl") { Id = 9, CultureName = "Dutch", FallbackLanguageId = 1 }
};
localizationService.Setup(x => x.GetAllLanguages()).Returns(languages);
localizationService.Setup(x => x.GetLanguageById(It.IsAny<int>()))
.Returns((int id) => languages.SingleOrDefault(y => y.Id == id));
localizationService.Setup(x => x.GetLanguageByIsoCode(It.IsAny<string>()))
.Returns((string c) => languages.SingleOrDefault(y => y.IsoCode == c));
return serviceContext;
}
/// <summary>
/// Creates a content cache
/// </summary>
/// <param name="dataTypes"></param>
/// <param name="contentTypes"></param>
/// <returns></returns>
/// <remarks>
/// Builds a content hierarchy of 3 nodes, each has a different set of cultural properties.
/// The first 2 share the same content type, the last one is a different content type.
/// NOTE: The content items themselves are 'Invariant' but their properties are 'Variant' by culture.
/// Normally in Umbraco this is prohibited but our APIs and database do actually support that behavior.
/// It is simpler to have these tests run this way, else we would need to use WithCultureInfos
/// for each item and pass in name values for all cultures we are supporting and then specify the
/// default VariationContextAccessor.VariationContext value to be a default culture instead of "".
/// </remarks>
private IEnumerable<ContentNodeKit> CreateCache(IDataType[] dataTypes, out ContentType[] contentTypes)
{
var result = new List<ContentNodeKit>();
var propertyDataTypes = new Dictionary<string, IDataType>
{
// we only have one data type for this test which will be resolved with string empty.
[string.Empty] = dataTypes[0]
};
var contentType1 = new ContentType(ShortStringHelper, -1);
ContentData item1Data = new ContentDataBuilder()
.WithName("Content 1")
.WithProperties(new PropertyDataBuilder()
.WithPropertyData("welcomeText", "Welcome")
.WithPropertyData("welcomeText", "Welcome", "en-US")
.WithPropertyData("welcomeText", "Willkommen", "de")
.WithPropertyData("welcomeText", "Welkom", "nl")
.WithPropertyData("welcomeText2", "Welcome")
.WithPropertyData("welcomeText2", "Welcome", "en-US")
.WithPropertyData("noprop", "xxx")
.Build())
// build with a dynamically created content type
.Build(ShortStringHelper, propertyDataTypes, contentType1, "ContentType1");
ContentNodeKit item1 = ContentNodeKitBuilder.CreateWithContent(
contentType1.Id,
1, "-1,1",
draftData: item1Data,
publishedData: item1Data);
result.Add(item1);
ContentData item2Data = new ContentDataBuilder()
.WithName("Content 2")
.WithProperties(new PropertyDataBuilder()
.WithPropertyData("welcomeText", "Welcome")
.WithPropertyData("welcomeText", "Welcome", "en-US")
.WithPropertyData("noprop", "xxx")
.Build())
// build while dynamically updating the same content type
.Build(ShortStringHelper, propertyDataTypes, contentType1);
ContentNodeKit item2 = ContentNodeKitBuilder.CreateWithContent(
contentType1.Id,
2, "-1,1,2",
parentContentId: 1,
draftData: item2Data,
publishedData: item2Data);
result.Add(item2);
var contentType2 = new ContentType(ShortStringHelper, -1);
ContentData item3Data = new ContentDataBuilder()
.WithName("Content 3")
.WithProperties(new PropertyDataBuilder()
.WithPropertyData("prop3", "Oxxo")
.WithPropertyData("prop3", "Oxxo", "en-US")
.Build())
// build with a dynamically created content type
.Build(ShortStringHelper, propertyDataTypes, contentType2, "ContentType2");
ContentNodeKit item3 = ContentNodeKitBuilder.CreateWithContent(
contentType2.Id,
3, "-1,1,2,3",
parentContentId: 2,
draftData: item3Data,
publishedData: item3Data);
result.Add(item3);
contentTypes = new[] { contentType1, contentType2 };
return result;
}
[Test]
public void Can_Get_Content_For_Populated_Requested_Language()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First();
var value = content.Value(Mock.Of<IPublishedValueFallback>(), "welcomeText", "en-US");
Assert.AreEqual("Welcome", value);
}
[Test]
public void Can_Get_Content_For_Populated_Requested_Non_Default_Language()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First();
var value = content.Value(Mock.Of<IPublishedValueFallback>(), "welcomeText", "de");
Assert.AreEqual("Willkommen", value);
}
[Test]
public void Do_Not_Get_Content_For_Unpopulated_Requested_Language_Without_Fallback()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First();
var value = content.Value(Mock.Of<IPublishedValueFallback>(), "welcomeText", "fr");
Assert.IsNull(value);
}
[Test]
public void Do_Not_Get_Content_For_Unpopulated_Requested_Language_With_Fallback_Unless_Requested()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First();
var value = content.Value(Mock.Of<IPublishedValueFallback>(), "welcomeText", "es");
Assert.IsNull(value);
}
[Test]
public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First();
var value = content.Value(PublishedValueFallback, "welcomeText", "es", fallback: Fallback.ToLanguage);
Assert.AreEqual("Welcome", value);
}
[Test]
public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback_Over_Two_Levels()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First();
var value = content.Value(PublishedValueFallback, "welcomeText", "it", fallback: Fallback.To(Fallback.Language, Fallback.Ancestors));
Assert.AreEqual("Welcome", value);
}
[Test]
public void Do_Not_GetContent_For_Unpopulated_Requested_Language_With_Fallback_Over_That_Loops()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First();
var value = content.Value(Mock.Of<IPublishedValueFallback>(), "welcomeText", "no", fallback: Fallback.ToLanguage);
Assert.IsNull(value);
}
[Test]
public void Do_Not_Get_Content_Recursively_Unless_Requested()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First().Children.First();
var value = content.Value(Mock.Of<IPublishedValueFallback>(), "welcomeText2");
Assert.IsNull(value);
}
[Test]
public void Can_Get_Content_Recursively()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First().Children.First();
var value = content.Value(PublishedValueFallback, "welcomeText2", fallback: Fallback.ToAncestors);
Assert.AreEqual("Welcome", value);
}
[Test]
public void Do_Not_Get_Content_Recursively_Unless_Requested2()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First().Children.First().Children.First();
Assert.IsNull(content.GetProperty("welcomeText2"));
var value = content.Value(Mock.Of<IPublishedValueFallback>(), "welcomeText2");
Assert.IsNull(value);
}
[Test]
public void Can_Get_Content_Recursively2()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First().Children.First().Children.First();
Assert.IsNull(content.GetProperty("welcomeText2"));
var value = content.Value(PublishedValueFallback, "welcomeText2", fallback: Fallback.ToAncestors);
Assert.AreEqual("Welcome", value);
}
[Test]
public void Can_Get_Content_Recursively3()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First().Children.First().Children.First();
Assert.IsNull(content.GetProperty("noprop"));
var value = content.Value(PublishedValueFallback, "noprop", fallback: Fallback.ToAncestors);
// property has no value - based on the converter
// but we still get the value (ie, the converter would do something)
Assert.AreEqual("xxx", value.ToString());
}
[Test]
public void Can_Get_Content_With_Recursive_Priority()
{
VariationContextAccessor.VariationContext = new VariationContext("nl");
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First().Children.First();
var value = content.Value(PublishedValueFallback, "welcomeText", "nl", fallback: Fallback.To(Fallback.Ancestors, Fallback.Language));
// No Dutch value is directly assigned. Check has fallen back to Dutch value from parent.
Assert.AreEqual("Welkom", value);
}
[Test]
public void Can_Get_Content_With_Fallback_Language_Priority()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First().Children.First();
var value = content.Value(PublishedValueFallback, "welcomeText", "nl", fallback: Fallback.ToLanguage);
// No Dutch value is directly assigned. Check has fallen back to English value from language variant.
Assert.AreEqual("Welcome", value);
}
[Test]
public void Throws_For_Non_Supported_Fallback()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First().Children.First();
Assert.Throws<NotSupportedException>(() => content.Value(PublishedValueFallback, "welcomeText", "nl", fallback: Fallback.To(999)));
}
[Test]
public void Can_Fallback_To_Default_Value()
{
var snapshot = GetPublishedSnapshot();
var content = snapshot.Content.GetAtRoot().First().Children.First();
// no Dutch value is assigned, so getting null
var value = content.Value(PublishedValueFallback, "welcomeText", "nl");
Assert.IsNull(value);
// even if we 'just' provide a default value
value = content.Value(PublishedValueFallback, "welcomeText", "nl", defaultValue: "woop");
Assert.IsNull(value);
// but it works with proper fallback settings
value = content.Value(PublishedValueFallback, "welcomeText", "nl", fallback: Fallback.ToDefaultValue, defaultValue: "woop");
Assert.AreEqual("woop", value);
}
}
}

View File

@@ -1,193 +1,108 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Media;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Core.Templates;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.Serialization;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web.Composing;
namespace Umbraco.Tests.PublishedContent
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache
{
/// <summary>
/// Tests the methods on IPublishedContent using the DefaultPublishedContentStore
/// </summary>
[TestFixture]
[UmbracoTest(TypeLoader = UmbracoTestOptions.TypeLoader.PerFixture)]
public class PublishedContentTests : PublishedContentTestBase
public class PublishedContentTests : PublishedSnapshotServiceTestBase
{
protected override void Compose()
{
base.Compose();
_publishedSnapshotAccessorMock = new Mock<IPublishedSnapshotAccessor>();
Builder.Services.AddUnique<IPublishedSnapshotAccessor>(_publishedSnapshotAccessorMock.Object);
Builder.Services.AddUnique<IPublishedModelFactory>(f => new PublishedModelFactory(f.GetRequiredService<TypeLoader>().GetTypes<PublishedContentModel>(), f.GetRequiredService<IPublishedValueFallback>()));
Builder.Services.AddUnique<IPublishedContentTypeFactory, PublishedContentTypeFactory>();
Builder.Services.AddUnique<IPublishedValueFallback, PublishedValueFallback>();
var loggerFactory = NullLoggerFactory.Instance;
var mediaService = Mock.Of<IMediaService>();
var contentTypeBaseServiceProvider = Mock.Of<IContentTypeBaseServiceProvider>();
var umbracoContextAccessor = Mock.Of<IUmbracoContextAccessor>();
var backOfficeSecurityAccessor = Mock.Of<IBackOfficeSecurityAccessor>();
var publishedUrlProvider = Mock.Of<IPublishedUrlProvider>();
var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider);
var serializer = new ConfigurationEditorJsonSerializer();
var mediaFileService = new MediaFileManager(Mock.Of<IFileSystem>(), Mock.Of<IMediaPathScheme>(),
loggerFactory.CreateLogger<MediaFileManager>(), Mock.Of<IShortStringHelper>());
var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger<RichTextEditorPastedImages>(), HostingEnvironment, mediaService, contentTypeBaseServiceProvider, mediaFileService, ShortStringHelper, publishedUrlProvider, serializer);
var linkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider);
var dataTypeService = new TestObjects.TestDataTypeService(
new DataType(new VoidEditor(DataValueEditorFactory), serializer) { Id = 1 },
new DataType(new TrueFalsePropertyEditor(DataValueEditorFactory, IOHelper), serializer) { Id = 1001 },
new DataType(new RichTextPropertyEditor(DataValueEditorFactory, backOfficeSecurityAccessor, imageSourceParser, linkParser, pastedImages, IOHelper, Mock.Of<IImageUrlGenerator>()), serializer) { Id = 1002 },
new DataType(new IntegerPropertyEditor(DataValueEditorFactory), serializer) { Id = 1003 },
new DataType(new TextboxPropertyEditor(DataValueEditorFactory, IOHelper), serializer) { Id = 1004 },
new DataType(new MediaPickerPropertyEditor(DataValueEditorFactory, IOHelper), serializer) { Id = 1005 });
Builder.Services.AddUnique<IDataTypeService>(f => dataTypeService);
}
protected override void Initialize()
{
base.Initialize();
var factory = Factory.GetRequiredService<IPublishedContentTypeFactory>() as PublishedContentTypeFactory;
// need to specify a custom callback for unit tests
// AutoPublishedContentTypes generates properties automatically
// when they are requested, but we must declare those that we
// explicitely want to be here...
IEnumerable<IPublishedPropertyType> CreatePropertyTypes(IPublishedContentType contentType)
{
// AutoPublishedContentType will auto-generate other properties
yield return factory.CreatePropertyType(contentType, "umbracoNaviHide", 1001);
yield return factory.CreatePropertyType(contentType, "selectedNodes", 1);
yield return factory.CreatePropertyType(contentType, "umbracoUrlAlias", 1);
yield return factory.CreatePropertyType(contentType, "content", 1002);
yield return factory.CreatePropertyType(contentType, "testRecursive", 1);
}
var compositionAliases = new[] { "MyCompositionAlias" };
var anythingType = new AutoPublishedContentType(Guid.NewGuid(), 0, "anything", compositionAliases, CreatePropertyTypes);
var homeType = new AutoPublishedContentType(Guid.NewGuid(), 0, "home", compositionAliases, CreatePropertyTypes);
ContentTypesCache.GetPublishedContentTypeByAlias = alias => alias.InvariantEquals("home") ? homeType : anythingType;
}
protected override TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, ILogger<TypeLoader> logger, IProfilingLogger profilingLogger , IHostingEnvironment hostingEnvironment)
{
var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, profilingLogger , hostingEnvironment);
return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, profilingLogger , false,
// this is so the model factory looks into the test assembly
baseLoader.AssembliesToScan
.Union(new[] { typeof(PublishedContentTests).Assembly })
.ToList());
}
private readonly Guid _node1173Guid = Guid.NewGuid();
private Mock<IPublishedSnapshotAccessor> _publishedSnapshotAccessorMock;
private PublishedModelFactory _publishedModelFactory;
private DataType[] _dataTypes;
protected override string GetXmlContent(int templateId)
[SetUp]
public override void Setup()
{
return @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE root[
<!ELEMENT Home ANY>
<!ATTLIST Home id ID #REQUIRED>
<!ELEMENT CustomDocument ANY>
<!ATTLIST CustomDocument id ID #REQUIRED>
]>
<root id=""-1"">
<Home id=""1046"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-06-12T14:13:17"" updateDate=""2012-07-20T18:50:43"" nodeName=""Home"" urlName=""home"" writerName=""admin"" creatorName=""admin"" path=""-1,1046"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoUrlAlias><![CDATA[this/is/my/alias, anotheralias]]></umbracoUrlAlias>
<umbracoNaviHide>1</umbracoNaviHide>
<testRecursive><![CDATA[This is the recursive val]]></testRecursive>
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""" key=""" + _node1173Guid + @""">
<content><![CDATA[<div>This is some content</div>]]></content>
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
<testRecursive><![CDATA[]]></testRecursive>
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc="""">
<content><![CDATA[]]></content>
<umbracoUrlAlias><![CDATA[only/one/alias]]></umbracoUrlAlias>
<creatorName><![CDATA[Custom data with same property name as the member name]]></creatorName>
<testRecursive><![CDATA[]]></testRecursive>
</Home>
<CustomDocument id=""117"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2018-07-18T10:06:37"" updateDate=""2018-07-18T10:06:37"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,117"" isDoc="""" />
<CustomDocument id=""1177"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub 1"" urlName=""custom-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1177"" isDoc="""" />
<CustomDocument id=""1178"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""4"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-16T14:23:35"" nodeName=""custom sub 2"" urlName=""custom-sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178"" isDoc="""">
<CustomDocument id=""1179"" parentID=""1178"" level=""4"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""custom sub sub 1"" urlName=""custom-sub-sub-1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1178,1179"" isDoc="""" />
</CustomDocument>
<Home id=""1176"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""5"" createDate=""2012-07-20T18:08:08"" updateDate=""2012-07-20T19:10:52"" nodeName=""Sub 3"" urlName=""sub-3"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1176"" isDoc="""" key=""CDB83BBC-A83B-4BA6-93B8-AADEF67D3C09"">
<content><![CDATA[]]></content>
<umbracoNaviHide>1</umbracoNaviHide>
</Home>
</Home>
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub 2"" urlName=""sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1175"" isDoc=""""><content><![CDATA[]]></content>
</Home>
<CustomDocument id=""4444"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,4444"" isDoc="""">
<selectedNodes><![CDATA[1172,1176,1173]]></selectedNodes>
</CustomDocument>
</Home>
<CustomDocument id=""1172"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1234"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test-page"" writerName=""admin"" creatorName=""admin"" path=""-1,1172"" isDoc="""" />
</root>";
base.Setup();
string xml = PublishedContentXml.PublishedContentTestXml(1234, _node1173Guid);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
_dataTypes = dataTypes;
// configure the Home content type to be composed of another for tests.
var compositionType = new ContentType(TestHelper.ShortStringHelper, -1)
{
Alias = "MyCompositionAlias"
};
contentTypes.First(x => x.Alias == "Home").AddContentType(compositionType);
InitializedCache(kits, contentTypes, dataTypes: dataTypes);
}
internal IPublishedContent GetNode(int id)
// override to specify our own factory with custom types
protected override IPublishedModelFactory PublishedModelFactory
=> _publishedModelFactory ??= new PublishedModelFactory(
new[] { typeof(Home), typeof(Anything), typeof(CustomDocument) },
PublishedValueFallback);
[PublishedModel("Home")]
internal class Home : PublishedContentModel
{
var ctx = GetUmbracoContext("/test");
var doc = ctx.Content.GetById(id);
Assert.IsNotNull(doc);
return doc;
public Home(IPublishedContent content, IPublishedValueFallback fallback)
: base(content, fallback)
{ }
public bool UmbracoNaviHide => this.Value<bool>(Mock.Of<IPublishedValueFallback>(), "umbracoNaviHide");
}
[PublishedModel("anything")]
internal class Anything : PublishedContentModel
{
public Anything(IPublishedContent content, IPublishedValueFallback fallback)
: base(content, fallback)
{ }
}
[PublishedModel("CustomDocument")]
internal class CustomDocument : PublishedContentModel
{
public CustomDocument(IPublishedContent content, IPublishedValueFallback fallback)
: base(content, fallback)
{ }
}
[Test]
public void GetNodeByIds()
{
var ctx = GetUmbracoContext("/test");
var contentById = ctx.Content.GetById(1173);
var snapshot = GetPublishedSnapshot();
var contentById = snapshot.Content.GetById(1173);
Assert.IsNotNull(contentById);
var contentByGuid = ctx.Content.GetById(_node1173Guid);
var contentByGuid = snapshot.Content.GetById(_node1173Guid);
Assert.IsNotNull(contentByGuid);
Assert.AreEqual(contentById.Id, contentByGuid.Id);
Assert.AreEqual(contentById.Key, contentByGuid.Key);
contentById = ctx.Content.GetById(666);
contentById = snapshot.Content.GetById(666);
Assert.IsNull(contentById);
contentByGuid = ctx.Content.GetById(Guid.NewGuid());
contentByGuid = snapshot.Content.GetById(Guid.NewGuid());
Assert.IsNull(contentByGuid);
}
[Test]
public void Is_Last_From_Where_Filter_Dynamic_Linq()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var items = doc.Children(VariationContextAccessor).Where(x => x.IsVisible(Mock.Of<IPublishedValueFallback>())).ToIndexedArray();
@@ -195,11 +110,11 @@ namespace Umbraco.Tests.PublishedContent
{
if (item.Content.Id != 1178)
{
Assert.IsFalse(item.IsLast());
Assert.IsFalse(item.IsLast(), $"The item {item.Content.Id} is last");
}
else
{
Assert.IsTrue(item.IsLast());
Assert.IsTrue(item.IsLast(), $"The item {item.Content.Id} is not last");
}
}
}
@@ -207,7 +122,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Is_Last_From_Where_Filter()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var items = doc
.Children(VariationContextAccessor)
@@ -243,30 +158,14 @@ namespace Umbraco.Tests.PublishedContent
}
}
[PublishedModel("Home")]
internal class Home : PublishedContentModel
{
public Home(IPublishedContent content, IPublishedValueFallback fallback)
: base(content, fallback)
{}
}
[PublishedModel("anything")]
internal class Anything : PublishedContentModel
{
public Anything(IPublishedContent content, IPublishedValueFallback fallback)
: base(content, fallback)
{ }
}
[Test]
public void Is_Last_From_Where_Filter2()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var ct = doc.ContentType;
var items = doc.Children(VariationContextAccessor)
.Select(x => x.CreateModel(Current.PublishedModelFactory)) // linq, returns IEnumerable<IPublishedContent>
.Select(x => x.CreateModel(PublishedModelFactory)) // linq, returns IEnumerable<IPublishedContent>
// only way around this is to make sure every IEnumerable<T> extension
// explicitely returns a PublishedContentSet, not an IEnumerable<T>
@@ -295,7 +194,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Is_Last_From_Take()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var items = doc.Children(VariationContextAccessor).Take(4).ToIndexedArray();
@@ -315,7 +214,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Is_Last_From_Skip()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
foreach (var d in doc.Children(VariationContextAccessor).Skip(1).ToIndexedArray())
{
@@ -333,10 +232,10 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Is_Last_From_Concat()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var items = doc.Children(VariationContextAccessor)
.Concat(new[] { GetNode(1175), GetNode(4444) })
.Concat(new[] { GetContent(1175), GetContent(4444) })
.ToIndexedArray();
foreach (var item in items)
@@ -355,7 +254,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Descendants_Ordered_Properly()
{
var doc = GetNode(1046);
var doc = GetContent(1046);
var expected = new[] { 1046, 1173, 1174, 117, 1177, 1178, 1179, 1176, 1175, 4444, 1172 };
var exindex = 0;
@@ -370,9 +269,11 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Get_Property_Value_Recursive()
{
var doc = GetNode(1174);
var rVal = doc.Value(Factory.GetRequiredService<IPublishedValueFallback>(), "testRecursive", fallback: Fallback.ToAncestors);
var nullVal = doc.Value(Factory.GetRequiredService<IPublishedValueFallback>(), "DoNotFindThis", fallback: Fallback.ToAncestors);
// TODO: We need to use a different fallback?
var doc = GetContent(1174);
var rVal = doc.Value(PublishedValueFallback, "testRecursive", fallback: Fallback.ToAncestors);
var nullVal = doc.Value(PublishedValueFallback, "DoNotFindThis", fallback: Fallback.ToAncestors);
Assert.AreEqual("This is the recursive val", rVal);
Assert.AreEqual(null, nullVal);
}
@@ -380,17 +281,17 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Get_Property_Value_Uses_Converter()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var propVal = doc.Value(Mock.Of<IPublishedValueFallback>(), "content");
var propVal = doc.Value(PublishedValueFallback, "content");
Assert.IsInstanceOf(typeof(IHtmlEncodedString), propVal);
Assert.AreEqual("<div>This is some content</div>", propVal.ToString());
var propVal2 = doc.Value<IHtmlEncodedString>(Mock.Of<IPublishedValueFallback>(), "content");
var propVal2 = doc.Value<IHtmlEncodedString>(PublishedValueFallback, "content");
Assert.IsInstanceOf(typeof(IHtmlEncodedString), propVal2);
Assert.AreEqual("<div>This is some content</div>", propVal2.ToString());
var propVal3 = doc.Value(Mock.Of<IPublishedValueFallback>(), "Content");
var propVal3 = doc.Value(PublishedValueFallback, "Content");
Assert.IsInstanceOf(typeof(IHtmlEncodedString), propVal3);
Assert.AreEqual("<div>This is some content</div>", propVal3.ToString());
}
@@ -398,12 +299,12 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Complex_Linq()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var result = doc.Ancestors().OrderBy(x => x.Level)
.Single()
.Descendants(Mock.Of<IVariationContextAccessor>())
.FirstOrDefault(x => x.Value<string>(Mock.Of<IPublishedValueFallback>(), "selectedNodes", defaultValue: "").Split(',').Contains("1173"));
.FirstOrDefault(x => x.Value<string>(PublishedValueFallback, "selectedNodes", fallback: Fallback.ToDefaultValue, defaultValue: "").Split(',').Contains("1173"));
Assert.IsNotNull(result);
}
@@ -411,16 +312,16 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Children_GroupBy_DocumentTypeAlias()
{
var home = new AutoPublishedContentType(Guid.NewGuid(), 22, "Home", new PublishedPropertyType[] { });
var custom = new AutoPublishedContentType(Guid.NewGuid(), 23, "CustomDocument", new PublishedPropertyType[] { });
var contentTypes = new Dictionary<string, PublishedContentType>
{
{ home.Alias, home },
{ custom.Alias, custom }
};
ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias];
//var home = new AutoPublishedContentType(Guid.NewGuid(), 22, "Home", new PublishedPropertyType[] { });
//var custom = new AutoPublishedContentType(Guid.NewGuid(), 23, "CustomDocument", new PublishedPropertyType[] { });
//var contentTypes = new Dictionary<string, PublishedContentType>
//{
// { home.Alias, home },
// { custom.Alias, custom }
//};
//ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias];
var doc = GetNode(1046);
var doc = GetContent(1046);
var found1 = doc.Children(VariationContextAccessor).GroupBy(x => x.ContentType.Alias).ToArray();
@@ -432,16 +333,16 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Children_Where_DocumentTypeAlias()
{
var home = new AutoPublishedContentType(Guid.NewGuid(), 22, "Home", new PublishedPropertyType[] { });
var custom = new AutoPublishedContentType(Guid.NewGuid(), 23, "CustomDocument", new PublishedPropertyType[] { });
var contentTypes = new Dictionary<string, PublishedContentType>
{
{ home.Alias, home },
{ custom.Alias, custom }
};
ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias];
//var home = new AutoPublishedContentType(Guid.NewGuid(), 22, "Home", new PublishedPropertyType[] { });
//var custom = new AutoPublishedContentType(Guid.NewGuid(), 23, "CustomDocument", new PublishedPropertyType[] { });
//var contentTypes = new Dictionary<string, PublishedContentType>
//{
// { home.Alias, home },
// { custom.Alias, custom }
//};
//ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias];
var doc = GetNode(1046);
var doc = GetContent(1046);
var found1 = doc.Children(VariationContextAccessor).Where(x => x.ContentType.Alias == "CustomDocument");
var found2 = doc.Children(VariationContextAccessor).Where(x => x.ContentType.Alias == "Home");
@@ -453,7 +354,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Children_Order_By_Update_Date()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var ordered = doc.Children(VariationContextAccessor).OrderBy(x => x.UpdateDate);
@@ -468,12 +369,12 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void FirstChild()
{
var doc = GetNode(1173); // has child nodes
var doc = GetContent(1173); // has child nodes
Assert.IsNotNull(doc.FirstChild(Mock.Of<IVariationContextAccessor>()));
Assert.IsNotNull(doc.FirstChild(Mock.Of<IVariationContextAccessor>(), x => true));
Assert.IsNotNull(doc.FirstChild<IPublishedContent>(Mock.Of<IVariationContextAccessor>()));
doc = GetNode(1175); // does not have child nodes
doc = GetContent(1175); // does not have child nodes
Assert.IsNull(doc.FirstChild(Mock.Of<IVariationContextAccessor>()));
Assert.IsNull(doc.FirstChild(Mock.Of<IVariationContextAccessor>(), x => true));
Assert.IsNull(doc.FirstChild<IPublishedContent>(Mock.Of<IVariationContextAccessor>()));
@@ -482,7 +383,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void FirstChildAsT()
{
var doc = GetNode(1046); // has child nodes
var doc = GetContent(1046); // has child nodes
var model = doc.FirstChild<Home>(Mock.Of<IVariationContextAccessor>(), x => true); // predicate
@@ -491,7 +392,7 @@ namespace Umbraco.Tests.PublishedContent
Assert.IsInstanceOf<Home>(model);
Assert.IsInstanceOf<IPublishedContent>(model);
doc = GetNode(1175); // does not have child nodes
doc = GetContent(1175); // does not have child nodes
Assert.IsNull(doc.FirstChild<Anything>(Mock.Of<IVariationContextAccessor>()));
Assert.IsNull(doc.FirstChild<Anything>(Mock.Of<IVariationContextAccessor>(), x => true));
}
@@ -499,7 +400,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void IsComposedOf()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var isComposedOf = doc.IsComposedOf("MyCompositionAlias");
@@ -509,7 +410,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void HasProperty()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var hasProp = doc.HasProperty(Constants.Conventions.Content.UrlAlias);
@@ -519,7 +420,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void HasValue()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var hasValue = doc.HasValue(Mock.Of<IPublishedValueFallback>(), Constants.Conventions.Content.UrlAlias);
var noValue = doc.HasValue(Mock.Of<IPublishedValueFallback>(), "blahblahblah");
@@ -531,7 +432,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Ancestors_Where_Visible()
{
var doc = GetNode(1174);
var doc = GetContent(1174);
var whereVisible = doc.Ancestors().Where(x => x.IsVisible(Mock.Of<IPublishedValueFallback>()));
Assert.AreEqual(1, whereVisible.Count());
@@ -541,8 +442,8 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Visible()
{
var hidden = GetNode(1046);
var visible = GetNode(1173);
var hidden = GetContent(1046);
var visible = GetContent(1173);
Assert.IsFalse(hidden.IsVisible(Mock.Of<IPublishedValueFallback>()));
Assert.IsTrue(visible.IsVisible(Mock.Of<IPublishedValueFallback>()));
@@ -551,7 +452,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Ancestor_Or_Self()
{
var doc = GetNode(1173);
var doc = GetContent(1173);
var result = doc.AncestorOrSelf();
@@ -564,7 +465,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void U4_4559()
{
var doc = GetNode(1174);
var doc = GetContent(1174);
var result = doc.AncestorOrSelf(1);
Assert.IsNotNull(result);
Assert.AreEqual(1046, result.Id);
@@ -573,27 +474,27 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Ancestors_Or_Self()
{
var doc = GetNode(1174);
var doc = GetContent(1174);
var result = doc.AncestorsOrSelf().ToArray();
Assert.IsNotNull(result);
Assert.AreEqual(3, result.Length);
Assert.IsTrue(result.Select(x => ((dynamic)x).GetId()).ContainsAll(new dynamic[] { 1174, 1173, 1046 }));
Assert.IsTrue(result.Select(x => x.Id).ContainsAll(new [] { 1174, 1173, 1046 }));
}
[Test]
public void Ancestors()
{
var doc = GetNode(1174);
var doc = GetContent(1174);
var result = doc.Ancestors().ToArray();
Assert.IsNotNull(result);
Assert.AreEqual(2, result.Length);
Assert.IsTrue(result.Select(x => ((dynamic)x).GetId()).ContainsAll(new dynamic[] { 1173, 1046 }));
Assert.IsTrue(result.Select(x => x.Id).ContainsAll(new [] { 1173, 1046 }));
}
[Test]
@@ -607,12 +508,12 @@ namespace Umbraco.Tests.PublishedContent
// -- Custom Doc4: 117 (parent 1173)
// - Custom Doc3: 1172 (no parent)
var home = GetNode(1173);
var root = GetNode(1046);
var customDoc = GetNode(1178);
var customDoc2 = GetNode(1179);
var customDoc3 = GetNode(1172);
var customDoc4 = GetNode(117);
var home = GetContent(1173);
var root = GetContent(1046);
var customDoc = GetContent(1178);
var customDoc2 = GetContent(1179);
var customDoc3 = GetContent(1172);
var customDoc4 = GetContent(117);
Assert.IsTrue(root.IsAncestor(customDoc4));
Assert.IsFalse(root.IsAncestor(customDoc3));
@@ -656,12 +557,12 @@ namespace Umbraco.Tests.PublishedContent
// -- Custom Doc4: 117 (parent 1173)
// - Custom Doc3: 1172 (no parent)
var home = GetNode(1173);
var root = GetNode(1046);
var customDoc = GetNode(1178);
var customDoc2 = GetNode(1179);
var customDoc3 = GetNode(1172);
var customDoc4 = GetNode(117);
var home = GetContent(1173);
var root = GetContent(1046);
var customDoc = GetContent(1178);
var customDoc2 = GetContent(1179);
var customDoc3 = GetContent(1172);
var customDoc4 = GetContent(117);
Assert.IsTrue(root.IsAncestorOrSelf(customDoc4));
Assert.IsFalse(root.IsAncestorOrSelf(customDoc3));
@@ -699,27 +600,27 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Descendants_Or_Self()
{
var doc = GetNode(1046);
var doc = GetContent(1046);
var result = doc.DescendantsOrSelf(Mock.Of<IVariationContextAccessor>()).ToArray();
Assert.IsNotNull(result);
Assert.AreEqual(10, result.Count());
Assert.IsTrue(result.Select(x => ((dynamic)x).GetId()).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175 }));
Assert.IsTrue(result.Select(x => x.Id).ContainsAll(new [] { 1046, 1173, 1174, 1176, 1175 }));
}
[Test]
public void Descendants()
{
var doc = GetNode(1046);
var doc = GetContent(1046);
var result = doc.Descendants(Mock.Of<IVariationContextAccessor>()).ToArray();
Assert.IsNotNull(result);
Assert.AreEqual(9, result.Count());
Assert.IsTrue(result.Select(x => ((dynamic)x).GetId()).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 }));
Assert.IsTrue(result.Select(x => x.Id).ContainsAll(new [] { 1173, 1174, 1176, 1175, 4444 }));
}
[Test]
@@ -733,12 +634,12 @@ namespace Umbraco.Tests.PublishedContent
// -- Custom Doc4: 117 (parent 1173)
// - Custom Doc3: 1172 (no parent)
var home = GetNode(1173);
var root = GetNode(1046);
var customDoc = GetNode(1178);
var customDoc2 = GetNode(1179);
var customDoc3 = GetNode(1172);
var customDoc4 = GetNode(117);
var home = GetContent(1173);
var root = GetContent(1046);
var customDoc = GetContent(1178);
var customDoc2 = GetContent(1179);
var customDoc3 = GetContent(1172);
var customDoc4 = GetContent(117);
Assert.IsFalse(root.IsDescendant(root));
Assert.IsFalse(root.IsDescendant(home));
@@ -782,12 +683,12 @@ namespace Umbraco.Tests.PublishedContent
// -- Custom Doc4: 117 (parent 1173)
// - Custom Doc3: 1172 (no parent)
var home = GetNode(1173);
var root = GetNode(1046);
var customDoc = GetNode(1178);
var customDoc2 = GetNode(1179);
var customDoc3 = GetNode(1172);
var customDoc4 = GetNode(117);
var home = GetContent(1173);
var root = GetContent(1046);
var customDoc = GetContent(1178);
var customDoc2 = GetContent(1179);
var customDoc3 = GetContent(1172);
var customDoc4 = GetContent(117);
Assert.IsTrue(root.IsDescendantOrSelf(root));
Assert.IsFalse(root.IsDescendantOrSelf(home));
@@ -830,39 +731,40 @@ namespace Umbraco.Tests.PublishedContent
// --- Level1.1.2: 117 (parent 1173)
// --- Level1.1.3: 1177 (parent 1173)
// --- Level1.1.4: 1178 (parent 1173)
// ---- Level1.1.4.1: 1179 (parent 1178)
// --- Level1.1.5: 1176 (parent 1173)
// -- Level1.2: 1175 (parent 1046)
// -- Level1.3: 4444 (parent 1046)
var root = GetNode(1046);
var level1_1 = GetNode(1173);
var level1_1_1 = GetNode(1174);
var level1_1_2 = GetNode(117);
var level1_1_3 = GetNode(1177);
var level1_1_4 = GetNode(1178);
var level1_1_5 = GetNode(1176);
var level1_2 = GetNode(1175);
var level1_3 = GetNode(4444);
// - Root : 1172 (no parent)
_publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot.Content.GetAtRoot(It.IsAny<string>())).Returns(new []{root});
var root = GetContent(1046);
var level1_1 = GetContent(1173);
var level1_1_1 = GetContent(1174);
var level1_1_2 = GetContent(117);
var level1_1_3 = GetContent(1177);
var level1_1_4 = GetContent(1178);
var level1_1_5 = GetContent(1176);
var level1_2 = GetContent(1175);
var level1_3 = GetContent(4444);
var root2 = GetContent(1172);
var variationContextAccessor = Factory.GetRequiredService<IVariationContextAccessor>();
var publishedSnapshot = _publishedSnapshotAccessorMock.Object.PublishedSnapshot;
var publishedSnapshot = GetPublishedSnapshot();
CollectionAssertAreEqual(new []{root}, root.SiblingsAndSelf(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual(new[] { root, root2 }, root.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual( new []{level1_1, level1_2, level1_3}, level1_1.SiblingsAndSelf(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1, level1_2, level1_3}, level1_2.SiblingsAndSelf(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1, level1_2, level1_3}, level1_3.SiblingsAndSelf(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1, level1_2, level1_3 }, level1_1.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1, level1_2, level1_3 }, level1_2.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1, level1_2, level1_3 }, level1_3.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_1.SiblingsAndSelf(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_2.SiblingsAndSelf(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_3.SiblingsAndSelf(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_4.SiblingsAndSelf(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_5.SiblingsAndSelf(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_1.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_2.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_3.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_4.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_5.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor));
}
[Test]
[Test]
public void Siblings()
{
// Structure:
@@ -872,40 +774,41 @@ namespace Umbraco.Tests.PublishedContent
// --- Level1.1.2: 117 (parent 1173)
// --- Level1.1.3: 1177 (parent 1173)
// --- Level1.1.4: 1178 (parent 1173)
// ---- Level1.1.4.1: 1179 (parent 1178)
// --- Level1.1.5: 1176 (parent 1173)
// -- Level1.2: 1175 (parent 1046)
// -- Level1.3: 4444 (parent 1046)
var root = GetNode(1046);
var level1_1 = GetNode(1173);
var level1_1_1 = GetNode(1174);
var level1_1_2 = GetNode(117);
var level1_1_3 = GetNode(1177);
var level1_1_4 = GetNode(1178);
var level1_1_5 = GetNode(1176);
var level1_2 = GetNode(1175);
var level1_3 = GetNode(4444);
// - Root : 1172 (no parent)
_publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot.Content.GetAtRoot(It.IsAny<string>())).Returns(new []{root});
var root = GetContent(1046);
var level1_1 = GetContent(1173);
var level1_1_1 = GetContent(1174);
var level1_1_2 = GetContent(117);
var level1_1_3 = GetContent(1177);
var level1_1_4 = GetContent(1178);
var level1_1_5 = GetContent(1176);
var level1_2 = GetContent(1175);
var level1_3 = GetContent(4444);
var root2 = GetContent(1172);
var variationContextAccessor = Factory.GetRequiredService<IVariationContextAccessor>();
var publishedSnapshot = _publishedSnapshotAccessorMock.Object.PublishedSnapshot;
var publishedSnapshot = GetPublishedSnapshot();
CollectionAssertAreEqual(new IPublishedContent[0], root.Siblings(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual(new[] { root2 }, root.Siblings(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual( new []{level1_2, level1_3}, level1_1.Siblings(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1, level1_3}, level1_2.Siblings(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1, level1_2}, level1_3.Siblings(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual(new[] { level1_2, level1_3 }, level1_1.Siblings(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1, level1_3 }, level1_2.Siblings(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1, level1_2 }, level1_3.Siblings(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual( new []{ level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_1.Siblings(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1_1, level1_1_3, level1_1_4, level1_1_5}, level1_1_2.Siblings(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_4, level1_1_5}, level1_1_3.Siblings(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_5}, level1_1_4.Siblings(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4}, level1_1_5.Siblings(publishedSnapshot, variationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_1.Siblings(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1_1, level1_1_3, level1_1_4, level1_1_5 }, level1_1_2.Siblings(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_4, level1_1_5 }, level1_1_3.Siblings(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_5 }, level1_1_4.Siblings(publishedSnapshot, VariationContextAccessor));
CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4 }, level1_1_5.Siblings(publishedSnapshot, VariationContextAccessor));
}
private void CollectionAssertAreEqual<T>(IEnumerable<T> expected, IEnumerable<T> actual)
where T: IPublishedContent
where T : IPublishedContent
{
var e = expected.Select(x => x.Id);
var a = actual.Select(x => x.Id);
@@ -915,37 +818,26 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void FragmentProperty()
{
var factory = Factory.GetRequiredService<IPublishedContentTypeFactory>() as PublishedContentTypeFactory;
IEnumerable<IPublishedPropertyType> CreatePropertyTypes(IPublishedContentType contentType)
{
yield return factory.CreatePropertyType(contentType, "detached", 1003);
yield return PublishedContentTypeFactory.CreatePropertyType(contentType, "detached", _dataTypes[0].Id);
}
var ct = factory.CreateContentType(Guid.NewGuid(), 0, "alias", CreatePropertyTypes);
var ct = PublishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 0, "alias", CreatePropertyTypes);
var pt = ct.GetPropertyType("detached");
var prop = new PublishedElementPropertyBase(pt, null, false, PropertyCacheLevel.None, 5548);
Assert.IsInstanceOf<int>(prop.GetValue());
Assert.AreEqual(5548, prop.GetValue());
}
public void Fragment1()
{
var type = ContentTypesCache.Get(PublishedItemType.Content, "detachedSomething");
var values = new Dictionary<string, object>();
var f = new PublishedElement(type, Guid.NewGuid(), values, false);
}
[Test]
public void Fragment2()
{
var factory = Factory.GetRequiredService<IPublishedContentTypeFactory>() as PublishedContentTypeFactory;
IEnumerable<IPublishedPropertyType> CreatePropertyTypes(IPublishedContentType contentType)
{
yield return factory.CreatePropertyType(contentType, "legend", 1004);
yield return factory.CreatePropertyType(contentType, "image", 1005);
yield return factory.CreatePropertyType(contentType, "size", 1003);
yield return PublishedContentTypeFactory.CreatePropertyType(contentType, "legend", _dataTypes[0].Id);
yield return PublishedContentTypeFactory.CreatePropertyType(contentType, "image", _dataTypes[0].Id);
yield return PublishedContentTypeFactory.CreatePropertyType(contentType, "size", _dataTypes[0].Id);
}
const string val1 = "boom bam";
@@ -954,7 +846,7 @@ namespace Umbraco.Tests.PublishedContent
var guid = Guid.NewGuid();
var ct = factory.CreateContentType(Guid.NewGuid(), 0, "alias", CreatePropertyTypes);
var ct = PublishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 0, "alias", CreatePropertyTypes);
var c = new ImageWithLegendModel(ct, guid, new Dictionary<string, object>
{
@@ -967,6 +859,87 @@ namespace Umbraco.Tests.PublishedContent
Assert.AreEqual(val3, c.Size);
}
[Test]
public void First()
{
var publishedSnapshot = GetPublishedSnapshot();
var content = publishedSnapshot.Content.GetAtRoot().First();
Assert.AreEqual("Home", content.Name(VariationContextAccessor));
}
[Test]
public void Distinct()
{
var items = GetContent(1173)
.Children(VariationContextAccessor)
.Distinct()
.Distinct()
.ToIndexedArray();
Assert.AreEqual(5, items.Length);
IndexedArrayItem<IPublishedContent> item = items[0];
Assert.AreEqual(1174, item.Content.Id);
Assert.IsTrue(item.IsFirst());
Assert.IsFalse(item.IsLast());
item = items[^1];
Assert.AreEqual(1176, item.Content.Id);
Assert.IsFalse(item.IsFirst());
Assert.IsTrue(item.IsLast());
}
[Test]
public void OfType1()
{
var publishedSnapshot = GetPublishedSnapshot();
var items = publishedSnapshot.Content.GetAtRoot()
.OfType<Home>()
.Distinct()
.ToIndexedArray();
Assert.AreEqual(1, items.Length);
Assert.IsInstanceOf<Home>(items.First().Content);
}
[Test]
public void OfType2()
{
var publishedSnapshot = GetPublishedSnapshot();
var content = publishedSnapshot.Content.GetAtRoot()
.OfType<CustomDocument>()
.Distinct()
.ToIndexedArray();
Assert.AreEqual(1, content.Length);
Assert.IsInstanceOf<CustomDocument>(content.First().Content);
}
[Test]
public void OfType()
{
var content = GetContent(1173)
.Children(VariationContextAccessor)
.OfType<Home>()
.First(x => x.UmbracoNaviHide == true);
Assert.AreEqual(1176, content.Id);
}
[Test]
public void Position()
{
var items = GetContent(1173).Children(VariationContextAccessor)
.Where(x => x.Value<int?>(Mock.Of<IPublishedValueFallback>(), "umbracoNaviHide") == 0)
.ToIndexedArray();
Assert.AreEqual(3, items.Length);
Assert.IsTrue(items.First().IsFirst());
Assert.IsFalse(items.First().IsLast());
Assert.IsFalse(items.Skip(1).First().IsFirst());
Assert.IsFalse(items.Skip(1).First().IsLast());
Assert.IsFalse(items.Skip(2).First().IsFirst());
Assert.IsTrue(items.Skip(2).First().IsLast());
}
class ImageWithLegendModel : PublishedElement
{
public ImageWithLegendModel(IPublishedContentType contentType, Guid fragmentKey, Dictionary<string, object> values, bool previewing)
@@ -980,5 +953,31 @@ namespace Umbraco.Tests.PublishedContent
public int Size => this.Value<int>(Mock.Of<IPublishedValueFallback>(), "size");
}
//[PublishedModel("ContentType2")]
//public class ContentType2 : PublishedContentModel
//{
// #region Plumbing
// public ContentType2(IPublishedContent content, IPublishedValueFallback fallback)
// : base(content, fallback)
// { }
// #endregion
// public int Prop1 => this.Value<int>(Mock.Of<IPublishedValueFallback>(), "prop1");
//}
//[PublishedModel("ContentType2Sub")]
//public class ContentType2Sub : ContentType2
//{
// #region Plumbing
// public ContentType2Sub(IPublishedContent content, IPublishedValueFallback fallback)
// : base(content, fallback)
// { }
// #endregion
//}
}
}

View File

@@ -0,0 +1,242 @@
using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
using Umbraco.Cms.Infrastructure.Serialization;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache
{
/// <summary>
/// Tests the typed extension methods on IPublishedContent using the DefaultPublishedMediaStore
/// </summary>
[TestFixture]
public class PublishedMediaTests : PublishedSnapshotServiceTestBase
{
[SetUp]
public override void Setup()
{
base.Setup();
var dataTypes = GetDefaultDataTypes().ToList();
var serializer = new ConfigurationEditorJsonSerializer();
var rteDataType = new DataType(new VoidEditor("RTE", Mock.Of<IDataValueEditorFactory>()), serializer) { Id = 4 };
dataTypes.Add(rteDataType);
_dataTypes = dataTypes.ToArray();
_propertyDataTypes = new()
{
// defaults will just use the first one
[string.Empty] = _dataTypes[0],
// content uses the RTE
["content"] = _dataTypes[1]
};
}
private Dictionary<string, IDataType> _propertyDataTypes;
private DataType[] _dataTypes;
private ContentNodeKit CreateRoot(out MediaType mediaType)
{
mediaType = new MediaType(ShortStringHelper, -1);
ContentData item1Data = new ContentDataBuilder()
.WithName("Content 1")
.WithProperties(new PropertyDataBuilder()
.WithPropertyData("content", "<div>This is some content</div>")
.Build())
// build with a dynamically created media type
.Build(ShortStringHelper, _propertyDataTypes, mediaType, "image2");
ContentNodeKit item1 = ContentNodeKitBuilder.CreateWithContent(
mediaType.Id,
1, "-1,1",
draftData: item1Data,
publishedData: item1Data);
return item1;
}
private IEnumerable<ContentNodeKit> CreateChildren(
int startId,
ContentNodeKit parent,
IMediaType mediaType,
int count)
{
for (int i = 0; i < count; i++)
{
var id = startId + i + 1;
ContentData item1Data = new ContentDataBuilder()
.WithName("Child " + id)
.WithProperties(new PropertyDataBuilder()
.WithPropertyData("content", "<div>This is some content</div>")
.Build())
.Build();
var parentPath = parent.Node.Path;
ContentNodeKit item1 = ContentNodeKitBuilder.CreateWithContent(
mediaType.Id,
id, $"{parentPath},{id}",
draftData: item1Data,
publishedData: item1Data);
yield return item1;
}
}
private void InitializeWithHierarchy(
out int rootId,
out IReadOnlyList<ContentNodeKit> firstLevelChildren,
out IReadOnlyList<ContentNodeKit> secondLevelChildren)
{
var cache = new List<ContentNodeKit>();
var root = CreateRoot(out MediaType mediaType);
firstLevelChildren = CreateChildren(10, root, mediaType, 3).ToList();
secondLevelChildren = CreateChildren(20, firstLevelChildren[0], mediaType, 3).ToList();
cache.Add(root);
cache.AddRange(firstLevelChildren);
cache.AddRange(secondLevelChildren);
InitializedCache(null, null, _dataTypes, cache, new[] { mediaType });
rootId = root.Node.Id;
}
[Test]
public void Get_Property_Value_Uses_Converter()
{
var cache = CreateRoot(out MediaType mediaType);
InitializedCache(null, null, _dataTypes.ToArray(), new[] { cache }, new[] { mediaType });
var publishedMedia = GetMedia(1);
var propVal = publishedMedia.Value(PublishedValueFallback, "content");
Assert.IsInstanceOf<IHtmlEncodedString>(propVal);
Assert.AreEqual("<div>This is some content</div>", propVal.ToString());
var propVal2 = publishedMedia.Value<IHtmlEncodedString>(PublishedValueFallback, "content");
Assert.IsInstanceOf<IHtmlEncodedString>(propVal2);
Assert.AreEqual("<div>This is some content</div>", propVal2.ToString());
var propVal3 = publishedMedia.Value(PublishedValueFallback, "Content");
Assert.IsInstanceOf<IHtmlEncodedString>(propVal3);
Assert.AreEqual("<div>This is some content</div>", propVal3.ToString());
}
[Test]
public void Children()
{
InitializeWithHierarchy(
out var rootId,
out IReadOnlyList<ContentNodeKit> firstLevelChildren,
out IReadOnlyList<ContentNodeKit> secondLevelChildren);
var publishedMedia = GetMedia(rootId);
var rootChildren = publishedMedia.Children(VariationContextAccessor);
Assert.IsTrue(rootChildren.Select(x => x.Id).ContainsAll(firstLevelChildren.Select(x => x.Node.Id)));
var publishedChild1 = GetMedia(firstLevelChildren[0].Node.Id);
var subChildren = publishedChild1.Children(VariationContextAccessor);
Assert.IsTrue(subChildren.Select(x => x.Id).ContainsAll(secondLevelChildren.Select(x => x.Node.Id)));
}
[Test]
public void Descendants()
{
InitializeWithHierarchy(
out var rootId,
out IReadOnlyList<ContentNodeKit> firstLevelChildren,
out IReadOnlyList<ContentNodeKit> secondLevelChildren);
var publishedMedia = GetMedia(rootId);
var rootDescendants = publishedMedia.Descendants(VariationContextAccessor);
var descendentIds = firstLevelChildren.Select(x => x.Node.Id).Concat(secondLevelChildren.Select(x => x.Node.Id));
Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(descendentIds));
var publishedChild1 = GetMedia(firstLevelChildren[0].Node.Id);
var subDescendants = publishedChild1.Descendants(VariationContextAccessor);
Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(secondLevelChildren.Select(x => x.Node.Id)));
}
[Test]
public void DescendantsOrSelf()
{
InitializeWithHierarchy(
out var rootId,
out IReadOnlyList<ContentNodeKit> firstLevelChildren,
out IReadOnlyList<ContentNodeKit> secondLevelChildren);
var publishedMedia = GetMedia(rootId);
var rootDescendantsOrSelf = publishedMedia.DescendantsOrSelf(VariationContextAccessor);
var descendentAndSelfIds = firstLevelChildren.Select(x => x.Node.Id)
.Concat(secondLevelChildren.Select(x => x.Node.Id))
.Append(rootId);
Assert.IsTrue(rootDescendantsOrSelf.Select(x => x.Id).ContainsAll(descendentAndSelfIds));
var publishedChild1 = GetMedia(firstLevelChildren[0].Node.Id);
var subDescendantsOrSelf = publishedChild1.DescendantsOrSelf(VariationContextAccessor);
Assert.IsTrue(subDescendantsOrSelf.Select(x => x.Id).ContainsAll(
secondLevelChildren.Select(x => x.Node.Id).Append(firstLevelChildren[0].Node.Id)));
}
[Test]
public void Parent()
{
InitializeWithHierarchy(
out var rootId,
out IReadOnlyList<ContentNodeKit> firstLevelChildren,
out IReadOnlyList<ContentNodeKit> secondLevelChildren);
var publishedMedia = GetMedia(rootId);
Assert.AreEqual(null, publishedMedia.Parent);
var publishedChild1 = GetMedia(firstLevelChildren[0].Node.Id);
Assert.AreEqual(publishedMedia.Id, publishedChild1.Parent.Id);
var publishedSubChild1 = GetMedia(secondLevelChildren[0].Node.Id);
Assert.AreEqual(firstLevelChildren[0].Node.Id, publishedSubChild1.Parent.Id);
}
[Test]
public void Ancestors()
{
InitializeWithHierarchy(
out var rootId,
out IReadOnlyList<ContentNodeKit> firstLevelChildren,
out IReadOnlyList<ContentNodeKit> secondLevelChildren);
var publishedSubChild1 = GetMedia(secondLevelChildren[0].Node.Id);
Assert.IsTrue(publishedSubChild1.Ancestors().Select(x => x.Id)
.ContainsAll(new[] { firstLevelChildren[0].Node.Id, rootId }));
}
[Test]
public void AncestorsOrSelf()
{
InitializeWithHierarchy(
out var rootId,
out IReadOnlyList<ContentNodeKit> firstLevelChildren,
out IReadOnlyList<ContentNodeKit> secondLevelChildren);
var publishedSubChild1 = GetMedia(secondLevelChildren[0].Node.Id);
Assert.IsTrue(publishedSubChild1.AncestorsOrSelf().Select(x => x.Id)
.ContainsAll(new[] { secondLevelChildren[0].Node.Id, firstLevelChildren[0].Node.Id, rootId }));
}
}
}

View File

@@ -0,0 +1,198 @@
using System;
using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Services.Changes;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache
{
[TestFixture]
public class PublishedSnapshotServiceContentTests : PublishedSnapshotServiceTestBase
{
private ContentType _contentType;
private PropertyType _propertyType;
[SetUp]
public override void Setup()
{
base.Setup();
_propertyType = new PropertyType(TestHelper.ShortStringHelper, "Umbraco.Void.Editor", ValueStorageType.Nvarchar) { Alias = "prop", DataTypeId = 3, Variations = ContentVariation.Culture };
_contentType = new ContentType(TestHelper.ShortStringHelper, -1) { Id = 2, Alias = "alias-ct", Variations = ContentVariation.Culture };
_contentType.AddPropertyType(_propertyType);
var contentTypes = new[]
{
_contentType
};
InitializedCache(new[] { CreateKit() }, contentTypes);
}
private ContentNodeKit CreateKit()
{
var draftData = new ContentDataBuilder()
.WithName("It Works2!")
.WithPublished(false)
.WithProperties(new Dictionary<string, PropertyData[]>
{
["prop"] = new[]
{
new PropertyData { Culture = "", Segment = "", Value = "val2" },
new PropertyData { Culture = "fr-FR", Segment = "", Value = "val-fr2" },
new PropertyData { Culture = "en-UK", Segment = "", Value = "val-uk2" },
new PropertyData { Culture = "dk-DA", Segment = "", Value = "val-da2" },
new PropertyData { Culture = "de-DE", Segment = "", Value = "val-de2" }
}
})
.WithCultureInfos(new Dictionary<string, CultureVariation>
{
// draft data = everything, and IsDraft indicates what's edited
["fr-FR"] = new CultureVariation { Name = "name-fr2", IsDraft = true, Date = new DateTime(2018, 01, 03, 01, 00, 00) },
["en-UK"] = new CultureVariation { Name = "name-uk2", IsDraft = true, Date = new DateTime(2018, 01, 04, 01, 00, 00) },
["dk-DA"] = new CultureVariation { Name = "name-da2", IsDraft = true, Date = new DateTime(2018, 01, 05, 01, 00, 00) },
["de-DE"] = new CultureVariation { Name = "name-de1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) }
})
.Build();
var publishedData = new ContentDataBuilder()
.WithName("It Works1!")
.WithPublished(true)
.WithProperties(new Dictionary<string, PropertyData[]>
{
["prop"] = new[]
{
new PropertyData { Culture = "", Segment = "", Value = "val1" },
new PropertyData { Culture = "fr-FR", Segment = "", Value = "val-fr1" },
new PropertyData { Culture = "en-UK", Segment = "", Value = "val-uk1" }
}
})
.WithCultureInfos(new Dictionary<string, CultureVariation>
{
// published data = only what's actually published, and IsDraft has to be false
["fr-FR"] = new CultureVariation { Name = "name-fr1", IsDraft = false, Date = new DateTime(2018, 01, 01, 01, 00, 00) },
["en-UK"] = new CultureVariation { Name = "name-uk1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) },
["de-DE"] = new CultureVariation { Name = "name-de1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) }
})
.Build();
var kit = ContentNodeKitBuilder.CreateWithContent(
2,
1, "-1,1", 0,
draftData: draftData,
publishedData: publishedData);
return kit;
}
[Test]
public void Verifies_Variant_Data()
{
// this test implements a full standalone NuCache (based upon a test IDataSource, does not
// use any local db files, does not rely on any database) - and tests variations
// get a snapshot, get a published content
IPublishedSnapshot snapshot = GetPublishedSnapshot();
IPublishedContent publishedContent = snapshot.Content.GetById(1);
Assert.IsNotNull(publishedContent);
Assert.AreEqual("val1", publishedContent.Value<string>(Mock.Of<IPublishedValueFallback>(), "prop"));
Assert.AreEqual("val-fr1", publishedContent.Value<string>(Mock.Of<IPublishedValueFallback>(), "prop", "fr-FR"));
Assert.AreEqual("val-uk1", publishedContent.Value<string>(Mock.Of<IPublishedValueFallback>(), "prop", "en-UK"));
Assert.IsNull(publishedContent.Name(VariationContextAccessor)); // no invariant name for varying content
Assert.AreEqual("name-fr1", publishedContent.Name(VariationContextAccessor, "fr-FR"));
Assert.AreEqual("name-uk1", publishedContent.Name(VariationContextAccessor, "en-UK"));
var draftContent = snapshot.Content.GetById(true, 1);
Assert.AreEqual("val2", draftContent.Value<string>(Mock.Of<IPublishedValueFallback>(), "prop"));
Assert.AreEqual("val-fr2", draftContent.Value<string>(Mock.Of<IPublishedValueFallback>(), "prop", "fr-FR"));
Assert.AreEqual("val-uk2", draftContent.Value<string>(Mock.Of<IPublishedValueFallback>(), "prop", "en-UK"));
Assert.IsNull(draftContent.Name(VariationContextAccessor)); // no invariant name for varying content
Assert.AreEqual("name-fr2", draftContent.Name(VariationContextAccessor, "fr-FR"));
Assert.AreEqual("name-uk2", draftContent.Name(VariationContextAccessor, "en-UK"));
// now french is default
VariationContextAccessor.VariationContext = new VariationContext("fr-FR");
Assert.AreEqual("val-fr1", publishedContent.Value<string>(Mock.Of<IPublishedValueFallback>(), "prop"));
Assert.AreEqual("name-fr1", publishedContent.Name(VariationContextAccessor));
Assert.AreEqual(new DateTime(2018, 01, 01, 01, 00, 00), publishedContent.CultureDate(VariationContextAccessor));
// now uk is default
VariationContextAccessor.VariationContext = new VariationContext("en-UK");
Assert.AreEqual("val-uk1", publishedContent.Value<string>(Mock.Of<IPublishedValueFallback>(), "prop"));
Assert.AreEqual("name-uk1", publishedContent.Name(VariationContextAccessor));
Assert.AreEqual(new DateTime(2018, 01, 02, 01, 00, 00), publishedContent.CultureDate(VariationContextAccessor));
// invariant needs to be retrieved explicitly, when it's not default
Assert.AreEqual("val1", publishedContent.Value<string>(Mock.Of<IPublishedValueFallback>(), "prop", culture: ""));
// but,
// if the content type / property type does not vary, then it's all invariant again
// modify the content type and property type, notify the snapshot service
_contentType.Variations = ContentVariation.Nothing;
_propertyType.Variations = ContentVariation.Nothing;
SnapshotService.Notify(new[] { new ContentTypeCacheRefresher.JsonPayload("IContentType", publishedContent.ContentType.Id, ContentTypeChangeTypes.RefreshMain) });
// get a new snapshot (nothing changed in the old one), get the published content again
var anotherSnapshot = SnapshotService.CreatePublishedSnapshot(previewToken: null);
var againContent = anotherSnapshot.Content.GetById(1);
Assert.AreEqual(ContentVariation.Nothing, againContent.ContentType.Variations);
Assert.AreEqual(ContentVariation.Nothing, againContent.ContentType.GetPropertyType("prop").Variations);
// now, "no culture" means "invariant"
Assert.AreEqual("It Works1!", againContent.Name(VariationContextAccessor));
Assert.AreEqual("val1", againContent.Value<string>(Mock.Of<IPublishedValueFallback>(), "prop"));
}
[Test]
public void Verifies_Published_And_Draft_Content()
{
// get the published published content
var snapshot = GetPublishedSnapshot();
var c1 = snapshot.Content.GetById(1);
// published content = nothing is draft here
Assert.IsFalse(c1.IsDraft("fr-FR"));
Assert.IsFalse(c1.IsDraft("en-UK"));
Assert.IsFalse(c1.IsDraft("dk-DA"));
Assert.IsFalse(c1.IsDraft("de-DE"));
// and only those with published name, are published
Assert.IsTrue(c1.IsPublished("fr-FR"));
Assert.IsTrue(c1.IsPublished("en-UK"));
Assert.IsFalse(c1.IsDraft("dk-DA"));
Assert.IsTrue(c1.IsPublished("de-DE"));
// get the draft published content
var c2 = snapshot.Content.GetById(true, 1);
// draft content = we have drafts
Assert.IsTrue(c2.IsDraft("fr-FR"));
Assert.IsTrue(c2.IsDraft("en-UK"));
Assert.IsTrue(c2.IsDraft("dk-DA"));
Assert.IsFalse(c2.IsDraft("de-DE")); // except for the one that does not
// and only those with published name, are published
Assert.IsTrue(c2.IsPublished("fr-FR"));
Assert.IsTrue(c2.IsPublished("en-UK"));
Assert.IsFalse(c2.IsPublished("dk-DA"));
Assert.IsTrue(c2.IsPublished("de-DE"));
}
}
}

View File

@@ -0,0 +1,52 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Tests.Common.Published;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache
{
[TestFixture]
public class RootNodeTests : PublishedSnapshotServiceTestBase
{
[SetUp]
public override void Setup()
{
base.Setup();
string xml = PublishedContentXml.TestWithDatabaseXml(1234);
IEnumerable<ContentNodeKit> kits = PublishedContentXmlAdapter.GetContentNodeKits(
xml,
TestHelper.ShortStringHelper,
out ContentType[] contentTypes,
out DataType[] dataTypes).ToList();
InitializedCache(kits, contentTypes, dataTypes);
}
[Test]
public void PublishedContentHasNoRootNode()
{
var snapshot = GetPublishedSnapshot();
// there is no content node with ID -1
var content = snapshot.Content.GetById(-1);
Assert.IsNull(content);
// content at root has null parent
content = snapshot.Content.GetById(1046);
Assert.IsNotNull(content);
Assert.AreEqual(1, content.Level);
Assert.IsNull(content.Parent);
// non-existing content is null
content = snapshot.Content.GetById(666);
Assert.IsNull(content);
}
}
}

Some files were not shown because too many files have changed in this diff Show More