Skip to content

Commit

Permalink
feat: add execute script V2 using ClearScript + V8 with HTTP request …
Browse files Browse the repository at this point in the history
…and context access (#210)

* feat: add execute script V2 with HTTP and context access

* style: code style

* test: add recursion benchmark test

* test: add arrow function tests

* style: code style

* style: code style

* test: add regex and array test case

* style: code style

* feat: add loggers for context and trace on request body error
  • Loading branch information
lucasoares authored Jun 6, 2024
1 parent ca8a46b commit 3b29656
Show file tree
Hide file tree
Showing 30 changed files with 3,075 additions and 5 deletions.
141 changes: 141 additions & 0 deletions src/Take.Blip.Builder.Benchmark/Actions/ExecuteScriptBenchmarkTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
using System;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Order;
using NSubstitute;
using Serilog;
using Take.Blip.Builder.Actions.ExecuteScript;
using Take.Blip.Builder.Actions.ExecuteScriptV2;
using Take.Blip.Builder.Benchmark.Context;
using Take.Blip.Builder.Hosting;
using Take.Blip.Builder.Utils;

namespace Take.Blip.Builder.Benchmark.Actions
{
/// <inheritdoc />
[MemoryDiagnoser]
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
public class ExecuteScriptBenchmarkTests : ActionTestsBase
{
private ExecuteScriptV2Action _v2Action;
private ExecuteScriptAction _v1Action;

/// <summary>
/// Setup the benchmark tests.
/// </summary>
[GlobalSetup]
public void Setup()
{
var configuration = new TestConfiguration();
var conventions = new ConventionsConfiguration();

configuration.ExecuteScriptV2Timeout = TimeSpan.FromMilliseconds(300);
configuration.ExecuteScriptV2MaxRuntimeHeapSize =
conventions.ExecuteScriptV2MaxRuntimeHeapSize;
configuration.ExecuteScriptV2MaxRuntimeStackUsage =
conventions.ExecuteScriptV2MaxRuntimeStackUsage;

configuration.ExecuteScriptTimeout = TimeSpan.FromMilliseconds(300);
configuration.ExecuteScriptLimitMemory = conventions.ExecuteScriptLimitMemory;
configuration.ExecuteScriptLimitRecursion = 100000;
configuration.ExecuteScriptMaxStatements = 0;

_v2Action = new ExecuteScriptV2Action(configuration, Substitute.For<IHttpClient>(),
Substitute.For<ILogger>());

_v1Action = new ExecuteScriptAction(configuration, Substitute.For<ILogger>());
}

/// <summary>
/// Execute a loop script using the V1 action.
/// </summary>
[Benchmark]
public async Task ExecuteScriptV1LoopScript()
{
await _v1Action.ExecuteAsync(Context, Settings._v1LoopSettings, CancellationToken);
}

/// <summary>
/// Execute a loop script using the V2 action.
/// </summary>
[Benchmark]
public async Task ExecuteScriptV2LoopScript()
{
await _v2Action.ExecuteAsync(Context, Settings._v2LoopSettings, CancellationToken);
}

/// <summary>
/// Execute a math script using the V1 action.
/// </summary>
[Benchmark]
public async Task ExecuteScriptV1MathScript()
{
await _v1Action.ExecuteAsync(Context, Settings._v1MathSettings, CancellationToken);
}

/// <summary>
/// Execute a math script using the V2 action.
/// </summary>
[Benchmark]
public async Task ExecuteScriptV2MathScript()
{
await _v2Action.ExecuteAsync(Context, Settings._v2MathSettings, CancellationToken);
}

/// <summary>
/// Execute a json script using the V1 action.
/// </summary>
[Benchmark]
public async Task ExecuteScriptV1JsonScript()
{
await _v1Action.ExecuteAsync(Context, Settings._v1JsonSettings, CancellationToken);
}

/// <summary>
/// Execute a json script using the V2 action.
/// </summary>
[Benchmark]
public async Task ExecuteScriptV2JsonScript()
{
await _v2Action.ExecuteAsync(Context, Settings._v2JsonSettings, CancellationToken);
}

/// <summary>
/// Execute a simple script using the V1 action.
/// </summary>
[Benchmark]
public async Task ExecuteScriptV1SimpleScript()
{
await _v1Action.ExecuteAsync(Context, Settings._v1SimpleSettings, CancellationToken);
}

/// <summary>
/// Execute a simple script using the V2 action.
/// </summary>
[Benchmark]
public async Task ExecuteScriptV2SimpleScript()
{
await _v2Action.ExecuteAsync(Context, Settings._v2SimpleSettings, CancellationToken);
}

/// <summary>
/// Execute a recursion loop script using the V1 action.
/// </summary>
[Benchmark]
public async Task ExecuteScriptV1RecursionLoopScript()
{
await _v1Action.ExecuteAsync(Context, Settings._v1RecursionLoopSettings,
CancellationToken);
}

/// <summary>
/// Execute a recursion loop script using the V2 action.
/// </summary>
[Benchmark]
public async Task ExecuteScriptV2RecursionLoopScript()
{
await _v2Action.ExecuteAsync(Context, Settings._v2RecursionLoopSettings,
CancellationToken);
}
}
}
157 changes: 157 additions & 0 deletions src/Take.Blip.Builder.Benchmark/Actions/Settings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
using Newtonsoft.Json.Linq;
using Take.Blip.Builder.Actions.ExecuteScript;
using Take.Blip.Builder.Actions.ExecuteScriptV2;

namespace Take.Blip.Builder.Benchmark.Actions;

internal static class Settings
{
private const string SIMPLE_SCRIPT = """
function run() {
return 'a';
}
""";

private const string LOOP_SCRIPT = """
function run() {
let a = 0;
while (a < 1000) {
a++;
}
return a;
}
""";

private const string RECURSION_LOOP_SCRIPT = """
function recursiveLoop(a) {
if (a < 1000) {
return recursiveLoop(a + 1);
}
return a;
}
function run() {
return recursiveLoop(0);
}
""";

private const string JSON_SCRIPT = """
function run() {
const json = { 'a': 1, 'b': 'c', 'd' : ['1', '2'], 'e': { 'f': 1 } };
let stringJson = JSON.stringify(json);
let parsedJson = JSON.parse(stringJson);
return parsedJson.a + parsedJson.e.f;
}
""";

private const string MATH_SCRIPT = """
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
function multiply(a, b) {
return a * b;
}
function divide(a, b) {
if (b == 0) {
throw 'Division by zero';
}
return a / b;
}
function calculate(a, b) {
let sum = add(a, b);
let difference = subtract(a, b);
let product = multiply(a, b);
let quotient = divide(a, b);
return {
'sum': sum,
'difference': difference,
'product': product,
'quotient': quotient
};
}
function run() {
let a = 10;
let b = 2;
let result = calculate(a, b);
let finalResult = result.sum * result.difference / result.quotient;
return finalResult;
}
""";

internal static readonly JObject _v1LoopSettings = JObject.FromObject(
new ExecuteScriptSettings
{
OutputVariable = "result", Function = "run", Source = LOOP_SCRIPT
});

internal static readonly JObject _v2LoopSettings = JObject.FromObject(
new ExecuteScriptV2Settings
{
OutputVariable = "result", Function = "run", Source = LOOP_SCRIPT
});

internal static readonly JObject _v1MathSettings = JObject.FromObject(
new ExecuteScriptSettings
{
OutputVariable = "result", Function = "run", Source = MATH_SCRIPT
});

internal static readonly JObject _v2MathSettings = JObject.FromObject(
new ExecuteScriptV2Settings
{
OutputVariable = "result", Function = "run", Source = MATH_SCRIPT
});

internal static readonly JObject _v1JsonSettings = JObject.FromObject(
new ExecuteScriptSettings
{
OutputVariable = "result", Function = "run", Source = JSON_SCRIPT
});

internal static readonly JObject _v2JsonSettings = JObject.FromObject(
new ExecuteScriptV2Settings
{
OutputVariable = "result", Function = "run", Source = JSON_SCRIPT
});

internal static readonly JObject _v1SimpleSettings = JObject.FromObject(
new ExecuteScriptSettings
{
OutputVariable = "result", Function = "run", Source = SIMPLE_SCRIPT
});

internal static readonly JObject _v2SimpleSettings = JObject.FromObject(
new ExecuteScriptV2Settings
{
OutputVariable = "result", Function = "run", Source = SIMPLE_SCRIPT
});

internal static readonly JObject _v1RecursionLoopSettings = JObject.FromObject(
new ExecuteScriptSettings
{
OutputVariable = "result", Function = "run", Source = RECURSION_LOOP_SCRIPT
});

internal static readonly JObject _v2RecursionLoopSettings = JObject.FromObject(
new ExecuteScriptV2Settings
{
OutputVariable = "result", Function = "run", Source = RECURSION_LOOP_SCRIPT
});
}
32 changes: 32 additions & 0 deletions src/Take.Blip.Builder.Benchmark/Actions/TestConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Take.Blip.Builder.Hosting;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

namespace Take.Blip.Builder.Benchmark.Actions
{
/// <inheritdoc />
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
public class TestConfiguration : IConfiguration
{
public TimeSpan InputProcessingTimeout { get; set; }
public int RedisDatabase { get; set; }
public string RedisKeyPrefix { get; set; }
public string InternalUris { get; set; }
public int MaxTransitionsByInput { get; set; }
public int TraceQueueBoundedCapacity { get; set; }
public int TraceQueueMaxDegreeOfParallelism { get; set; }
public TimeSpan TraceTimeout { get; set; }
public TimeSpan DefaultActionExecutionTimeout { get; set; }
public int ExecuteScriptLimitRecursion { get; set; }
public int ExecuteScriptMaxStatements { get; set; }
public long ExecuteScriptLimitMemory { get; set; }
public long ExecuteScriptLimitMemoryWarning { get; set; }
public TimeSpan ExecuteScriptTimeout { get; set; }
public TimeSpan ExecuteScriptV2Timeout { get; set; }
public int MaximumInputExpirationLoop { get; set; }
public long ExecuteScriptV2MaxRuntimeHeapSize { get; set; }
public long ExecuteScriptV2MaxRuntimeStackUsage { get; set; }
}
}
43 changes: 43 additions & 0 deletions src/Take.Blip.Builder.Benchmark/Context/ActionTestsBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Lime.Messaging.Contents;
using Lime.Protocol;
using Lime.Protocol.Serialization;
using Lime.Protocol.Serialization.Newtonsoft;
using NSubstitute;
using Take.Blip.Builder.Models;

namespace Take.Blip.Builder.Benchmark.Context;

/// <inheritdoc />
public class ActionTestsBase : ContextTestsBase
{
/// <inheritdoc />
protected ActionTestsBase()
{
Context.Flow.Returns(Flow);
From = UserIdentity.ToNode();
To = OwnerIdentity.ToNode();
Message = new Message()
{
From = From, To = To, Content = new PlainText { Text = "Hello BLiP" }
};
Input = new LazyInput(
Message,
UserIdentity,
new BuilderConfiguration(),
new DocumentSerializer(new DocumentTypeResolver()),
new EnvelopeSerializer(new DocumentTypeResolver()),
null,
CancellationToken);
Context.Input.Returns(Input);
Context.OwnerIdentity.Returns(OwnerIdentity);
Context.UserIdentity.Returns(UserIdentity);
}

private Node From { get; }

private Node To { get; }

private Message Message { get; }

private LazyInput Input { get; }
}
Loading

0 comments on commit 3b29656

Please sign in to comment.