Browse Source

LoadTests.

pull/403/head
Sebastian Stehle 7 years ago
parent
commit
2a3d213f0e
  1. 4
      tools/GenerateLanguages/GenerateLanguages.csproj
  2. 75
      tools/LoadTest/ClientQueryFixture.cs
  3. 23
      tools/LoadTest/LoadTest.csproj
  4. 25
      tools/LoadTest/LoadTest.sln
  5. 146
      tools/LoadTest/QueryBenchmarks.cs
  6. 34
      tools/LoadTest/TestClient.cs
  7. 22
      tools/LoadTest/TestEntity.cs

4
tools/GenerateLanguages/GenerateLanguages.csproj

@ -3,6 +3,10 @@
<TargetFramework>netcoreapp2.2</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\Squidex.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>

75
tools/LoadTest/ClientQueryFixture.cs

@ -0,0 +1,75 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Squidex.ClientLibrary;
using Squidex.ClientLibrary.Management;
namespace LoadTest
{
public sealed class ClientQueryFixture : IDisposable
{
public SquidexClient<TestEntity, TestEntityData> Client { get; } = TestClient.Build();
public ClientQueryFixture()
{
Task.Run(async () =>
{
var apps = TestClient.ClientManager.CreateAppsClient();
try
{
await apps.PostAppAsync(new CreateAppDto
{
Name = TestClient.TestAppName
});
var schemas = TestClient.ClientManager.CreateSchemasClient();
await schemas.PostSchemaAsync(TestClient.TestAppName, new CreateSchemaDto
{
Name = TestClient.TestSchemaName,
Fields = new List<UpsertSchemaFieldDto>
{
new UpsertSchemaFieldDto
{
Name = TestClient.TestSchemaName,
Properties = new NumberFieldPropertiesDto()
}
},
IsPublished = true
});
}
catch (SquidexManagementException ex)
{
if (ex.StatusCode != 400)
{
throw;
}
}
var contents = await Client.GetAllAsync();
foreach (var content in contents.Items)
{
await Client.DeleteAsync(content);
}
for (var i = 10; i > 0; i--)
{
await Client.CreateAsync(new TestEntityData { Value = i }, true);
}
}).Wait();
}
public void Dispose()
{
}
}
}

23
tools/LoadTest/LoadTest.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.ClientLibrary" Version="3.9.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\Squidex.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" />
</ItemGroup>
</Project>

25
tools/LoadTest/LoadTest.sln

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29123.88
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoadTest", "LoadTest.csproj", "{EC732B4F-576E-4853-880D-AA676966D017}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EC732B4F-576E-4853-880D-AA676966D017}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC732B4F-576E-4853-880D-AA676966D017}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC732B4F-576E-4853-880D-AA676966D017}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC732B4F-576E-4853-880D-AA676966D017}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8ABC073D-D6C6-47F0-AFB6-D42F177D468A}
EndGlobalSection
EndGlobal

146
tools/LoadTest/QueryBenchmarks.cs

@ -0,0 +1,146 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Squidex.ClientLibrary;
using Xunit;
namespace LoadTest
{
public class QueryBenchmarks : IClassFixture<ClientQueryFixture>
{
public ClientQueryFixture Fixture { get; }
public QueryBenchmarks(ClientQueryFixture fixture)
{
Fixture = fixture;
}
public static IEnumerable<object[]> Loads()
{
int[] users = { 1, 5, 10, 20, 50, 100 };
int[] loads = { 5, 10, 20, 50, 100 };
foreach (var user in users)
{
foreach (var load in loads)
{
yield return new object[] { user, load };
}
}
}
[Theory]
[MemberData(nameof(Loads))]
public async Task Should_return_all(int numUsers, int numIterationsPerUser)
{
await Run(numUsers, numIterationsPerUser, async () =>
{
await Fixture.Client.GetAsync(new ODataQuery { OrderBy = "data/value/iv asc" });
});
}
[Theory]
[MemberData(nameof(Loads))]
public async Task Should_return_items_with_skip(int numUsers, int numIterationsPerUser)
{
await Run(numUsers, numIterationsPerUser, async () =>
{
await Fixture.Client.GetAsync(new ODataQuery { Skip = 5, OrderBy = "data/value/iv asc" });
});
}
[Theory]
[MemberData(nameof(Loads))]
public async Task Should_return_items_with_skip_and_top(int numUsers, int numIterationsPerUser)
{
await Run(numUsers, numIterationsPerUser, async () =>
{
await Fixture.Client.GetAsync(new ODataQuery { Skip = 2, Top = 5, OrderBy = "data/value/iv asc" });
});
}
[Theory]
[MemberData(nameof(Loads))]
public async Task Should_return_items_with_ordering(int numUsers, int numIterationsPerUser)
{
await Run(numUsers, numIterationsPerUser, async () =>
{
await Fixture.Client.GetAsync(new ODataQuery { Skip = 2, Top = 5, OrderBy = "data/value/iv desc" });
});
}
[Theory]
[MemberData(nameof(Loads))]
public async Task Should_return_items_with_filter(int numUsers, int numIterationsPerUser)
{
await Run(numUsers, numIterationsPerUser, async () =>
{
await Fixture.Client.GetAsync(new ODataQuery { Filter = "data/value/iv gt 3 and data/value/iv lt 7", OrderBy = "data/value/iv asc" });
});
}
private static async Task Run(int numUsers, int numIterationsPerUser, Func<Task> action, int expectedAvg = 100)
{
var elapsedMs = new ConcurrentBag<long>();
var errors = 0;
async Task RunAsync()
{
for (var i = 0; i < numIterationsPerUser; i++)
{
try
{
var watch = Stopwatch.StartNew();
await action();
watch.Stop();
elapsedMs.Add(watch.ElapsedMilliseconds);
}
catch
{
Interlocked.Increment(ref errors);
}
}
}
var tasks = new List<Task>();
for (var i = 0; i < numUsers; i++)
{
tasks.Add(Task.Run(RunAsync));
}
await Task.WhenAll(tasks);
var count = elapsedMs.Count;
var max = elapsedMs.Max();
var min = elapsedMs.Min();
var avg = elapsedMs.Average();
Assert.InRange(max, 0, expectedAvg * 10);
Assert.InRange(min, 0, expectedAvg);
Assert.InRange(avg, 0, expectedAvg);
Assert.Equal(0, errors);
Assert.Equal(count, numUsers * numIterationsPerUser);
}
}
}

34
tools/LoadTest/TestClient.cs

@ -0,0 +1,34 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.ClientLibrary;
namespace LoadTest
{
public static class TestClient
{
public const string ServerUrl = "http://localhost:5000";
public const string ClientId = "root";
public const string ClientSecret = "xeLd6jFxqbXJrfmNLlO2j1apagGGGSyZJhFnIuHp4I0=";
public const string TestAppName = "integration-tests";
public const string TestSchemaName = "numbers";
public const string TestSchemaField = "value";
public static readonly SquidexClientManager ClientManager =
new SquidexClientManager("http://localhost:5000", TestAppName, ClientId, ClientSecret)
{
ReadResponseAsString = true
};
public static SquidexClient<TestEntity, TestEntityData> Build()
{
return ClientManager.GetClient<TestEntity, TestEntityData>(TestSchemaName);
}
}
}

22
tools/LoadTest/TestEntity.cs

@ -0,0 +1,22 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Newtonsoft.Json;
using Squidex.ClientLibrary;
namespace LoadTest
{
public sealed class TestEntity : SquidexEntityBase<TestEntityData>
{
}
public sealed class TestEntityData
{
[JsonConverter(typeof(InvariantConverter))]
public int Value { get; set; }
}
}
Loading…
Cancel
Save