From cba2d32013844a5231cc894f0e2bb33c6900c750 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 6 Feb 2023 15:19:30 +0100 Subject: [PATCH] Fix locking. --- .../Scripting/ScriptExecutionContext.cs | 52 +++++++++--------- .../Assets/Queries/AssetQueryService.cs | 1 - .../Contents/Queries/ContentQueryService.cs | 1 - .../Schemas/Indexes/SchemasIndex.cs | 2 - .../Teams/Indexes/TeamsIndex.cs | 1 - .../Contents/Models/AllContentsByPostDto.cs | 1 - .../Squidex/Config/Domain/ContentsServices.cs | 1 - backend/src/Squidex/Config/Web/WebServices.cs | 1 - .../Scripting/JintScriptEngineTests.cs | 42 +++++++++++++-- .../TestHelpers/Mocks.cs | 1 - .../angular/pipes/highlight.pipe.spec.ts | 54 +++++++++++++++++++ 11 files changed, 117 insertions(+), 40 deletions(-) create mode 100644 frontend/src/app/framework/angular/pipes/highlight.pipe.spec.ts diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs index fcc9eeda7..250c2a40a 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs @@ -86,23 +86,21 @@ public sealed class ScriptExecutionContext : ScriptExecutionContext, ISchedul return; } - slimLock.EnterWriteLock(); - try + lock (Engine) { - TryStart(); + try + { + TryStart(); - Engine.ResetConstraints(); - action(); + Engine.ResetConstraints(); + action(); - TryComplete(default!); - } - catch (Exception ex) - { - TryFail(ex); - } - finally - { - slimLock.ExitWriteLock(); + TryComplete(default!); + } + catch (Exception ex) + { + TryFail(ex); + } } } @@ -113,23 +111,21 @@ public sealed class ScriptExecutionContext : ScriptExecutionContext, ISchedul return; } - slimLock.EnterWriteLock(); - try + lock (Engine) { - TryStart(); + try + { + TryStart(); - Engine.ResetConstraints(); - action(argument); + Engine.ResetConstraints(); + action(argument); - TryComplete(default!); - } - catch (Exception ex) - { - TryFail(ex); - } - finally - { - slimLock.ExitWriteLock(); + TryComplete(default!); + } + catch (Exception ex) + { + TryFail(ex); + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs index fe553b9c0..235d554ac 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs @@ -8,7 +8,6 @@ using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Infrastructure; -using System.Diagnostics; namespace Squidex.Domain.Apps.Entities.Assets.Queries; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs index 6d5ecc876..53bed5890 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Diagnostics; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Schemas; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs index 14436db6c..d1c9b26aa 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs @@ -13,8 +13,6 @@ using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.States; using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Validation; -using System.Diagnostics; -using System.Xml.Linq; namespace Squidex.Domain.Apps.Entities.Schemas.Indexes; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Teams/Indexes/TeamsIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Teams/Indexes/TeamsIndex.cs index f7ab34137..20446b7a9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Teams/Indexes/TeamsIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Teams/Indexes/TeamsIndex.cs @@ -7,7 +7,6 @@ using Squidex.Domain.Apps.Entities.Teams.Repositories; using Squidex.Infrastructure; -using System.Diagnostics; namespace Squidex.Domain.Apps.Entities.Teams.Indexes; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/AllContentsByPostDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/AllContentsByPostDto.cs index e81a56299..a33a57071 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/AllContentsByPostDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/AllContentsByPostDto.cs @@ -10,7 +10,6 @@ using System.Text.Json.Serialization; using NodaTime; using Squidex.Domain.Apps.Entities; using Squidex.Infrastructure; -using Squidex.Infrastructure.Queries; using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Validation; diff --git a/backend/src/Squidex/Config/Domain/ContentsServices.cs b/backend/src/Squidex/Config/Domain/ContentsServices.cs index 08cc0896e..93aa9d271 100644 --- a/backend/src/Squidex/Config/Domain/ContentsServices.cs +++ b/backend/src/Squidex/Config/Domain/ContentsServices.cs @@ -17,7 +17,6 @@ using Squidex.Domain.Apps.Entities.Contents.Validation; using Squidex.Domain.Apps.Entities.History; using Squidex.Domain.Apps.Entities.Search; using Squidex.Infrastructure.EventSourcing; -using Squidex.Web.GraphQL; namespace Squidex.Config.Domain; diff --git a/backend/src/Squidex/Config/Web/WebServices.cs b/backend/src/Squidex/Config/Web/WebServices.cs index 8e376ec03..1ae4eec5b 100644 --- a/backend/src/Squidex/Config/Web/WebServices.cs +++ b/backend/src/Squidex/Config/Web/WebServices.cs @@ -17,7 +17,6 @@ using Squidex.Config.Domain; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Contents.GraphQL; -using Squidex.Domain.Apps.Entities.Contents.Queries; using Squidex.Infrastructure.Caching; using Squidex.Infrastructure.Json.Objects; using Squidex.Pipeline.Plugins; diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs index 3f4620133..ef1a339f0 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs @@ -7,7 +7,6 @@ using System.Net; using System.Security.Claims; -using Jint.Native; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core.Contents; @@ -77,6 +76,15 @@ public class JintScriptEngineTests : IClassFixture scheduler.Run(callback); }); })); + + context.Engine.SetValue("setSyncTimeout", new Delay(callback => + { + context.Schedule((scheduler, ct) => + { + scheduler.Run(callback); + return Task.CompletedTask; + }); + })); } } @@ -628,7 +636,7 @@ public class JintScriptEngineTests : IClassFixture ["value"] = 13 }; - const string script1 = @" + const string script = @" var x = ctx.value; for (var i = 0; i < 100; i++) { setTimeout(function () { @@ -638,7 +646,35 @@ public class JintScriptEngineTests : IClassFixture } "; - await sut.ExecuteAsync(vars, script1, new ScriptOptions { AsContext = true }); + await sut.ExecuteAsync(vars, script, new ScriptOptions { AsContext = true }); + + Assert.Equal(113.0, vars["shared"]); + } + } + + [Fact] + public async Task Should_not_run_nested_callbacks_in_parallel() + { + for (var i = 0; i < 10; i++) + { + var vars = new DataScriptVars + { + ["value"] = 13 + }; + + const string script = @" + var x = ctx.value; + for (var i = 0; i < 100; i++) { + setSyncTimeout(function () { + setSyncTimeout(function () { + x++; + ctx.shared = x; + }); + }); + } + "; + + await sut.ExecuteAsync(vars, script, new ScriptOptions { AsContext = true }); Assert.Equal(113.0, vars["shared"]); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs index 3e62b56c5..613c5fbbe 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs @@ -6,7 +6,6 @@ // ========================================================================== using System.Security.Claims; -using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Apps; diff --git a/frontend/src/app/framework/angular/pipes/highlight.pipe.spec.ts b/frontend/src/app/framework/angular/pipes/highlight.pipe.spec.ts new file mode 100644 index 000000000..65576bd0f --- /dev/null +++ b/frontend/src/app/framework/angular/pipes/highlight.pipe.spec.ts @@ -0,0 +1,54 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { HighlightPipe } from './highlight.pipe'; + +describe('Hightlight', () => { + const pipe = new HighlightPipe(); + + [null, undefined, ''].forEach(search => { + it('should not highlight if no search passed', () => { + const input = 'Hello World'; + + const result = pipe.transform(input, search); + + expect(result).toEqual(input); + }); + }); + + it('should encode html if no search specified', () => { + const input = '

Hello World

'; + + const result = pipe.transform(input, null); + + expect(result).toEqual('<h1>Hello World</h1>'); + }); + + it('should highlight with search string', () => { + const input = 'Hello World'; + + const result = pipe.transform(input, 'ello'); + + expect(result).toEqual('Hello World'); + }); + + it('should highlight with search regex', () => { + const input = 'Hello World'; + + const result = pipe.transform(input, new RegExp('ello', 'i')); + + expect(result).toEqual('Hello World'); + }); + + it('should encode html if search specified', () => { + const input = '

Hello World

'; + + const result = pipe.transform(input, 'ello'); + + expect(result).toEqual('<h1>Hello World</h1>'); + }); +});