Skip to content

Commit

Permalink
update load test
Browse files Browse the repository at this point in the history
  • Loading branch information
MHKarami97 committed Nov 17, 2024
1 parent cd42ac0 commit fda7b82
Showing 1 changed file with 181 additions and 1 deletion.
182 changes: 181 additions & 1 deletion _posts/2024-10-28-load_test_with_nbomber.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,4 +349,184 @@ public class ApiTest(ApiModel apiModel, LoadTestModel loadConfig, CreatorRule cr
ShowResult(loadConfig.Name);
}
}
```
```

طبق تجربه کدی که خودتان برای لود نوشته باشید بهتر از کتابخانه‌های دیگر جوابگو است. بطور مثال می‌توانید از کد زیر استفاده کنید:

```csharp
using System.Collections.Concurrent;
using System.Diagnostics;
using Flurl.Http;
using LoadTest.Creator;
using LoadTest.Model;
using LoadTest.Model.LoadTestTypes;
using LoadTest.Model.OutPut;
using NBomber.Contracts;

namespace LoadTest.Test;

public class CustomApiTest(ApiModel apiModel, BaseLoadTestModel baseLoadTestModel, IInputModelCreator creator) : BaseTest
{
protected override ScenarioProps CreateStep()
{
if (baseLoadTestModel.LoadTestType != LoadTestType.Custom || baseLoadTestModel is not CustomLoadTestModel)
throw new ArgumentException("not valid param", nameof(baseLoadTestModel));

return null!;
}

protected override async Task RunStep(ScenarioProps props)
{
try
{
var responses = new ConcurrentQueue<string>();
var responseTimes = new ConcurrentQueue<TimeSpan>();
var errors = new ConcurrentQueue<Exception>();

if (baseLoadTestModel is not CustomLoadTestModel customLoadTestModel)
throw new ArgumentException("not valid param", nameof(baseLoadTestModel));

var stopwatch = new Stopwatch();
stopwatch.Start();

var threadCount = customLoadTestModel.ThreadCount;
var received500Error = false;

Console.Clear();
Console.WriteLine("Wait Until Test Complete...");

var tasks = new List<Task>();
do
{
if (received500Error)
break;

for (var i = 0; i < threadCount; i++)
{
await Task.Delay(1);

tasks.Add(Task.Run(async () =>
{
var localStopwatch = new Stopwatch();
localStopwatch.Start();

try
{
OutPutModel response;
var model = creator.Build();

switch (apiModel.Method)
{
case "GET":
response = await apiModel.Address
.WithTimeout(customLoadTestModel.TimeOut)
.WithHeader("Content-Type", "application/json")
.SetQueryParams(model)
.GetJsonAsync<OutPutModel>();
break;

case "POST":
response = await apiModel.Address
.WithTimeout(customLoadTestModel.TimeOut)
.WithHeader("Content-Type", "application/json")
.PostJsonAsync(model)
.ReceiveJson<OutPutModel>();
break;

default:
throw new ArgumentException("not valid api type", nameof(apiModel.Method));
}

responses.Enqueue(response.IsSuccess ? "ok" : "error");
}
catch (FlurlHttpException e)
{
received500Error = true;

if (customLoadTestModel.ShowErrors)
{
var error = await e.GetResponseStringAsync() ?? e.Message;

Console.WriteLine(error);
}

errors.Enqueue(e);
responses.Enqueue("error");
}
catch (Exception ex)
{
if (customLoadTestModel.ShowErrors)
Console.WriteLine(ex);

errors.Enqueue(ex);
responses.Enqueue("error");
}

localStopwatch.Stop();
responseTimes.Enqueue(localStopwatch.Elapsed);
}));
}

await Task.WhenAll(tasks);

if (customLoadTestModel.AutoIncreaseThreadCount && !received500Error)
{
threadCount += customLoadTestModel.IncreaseThreadCount;

Console.WriteLine("----------");
Console.WriteLine("----------");
Console.WriteLine($"Thread Count: {threadCount}");
Console.WriteLine($"Total responses: {responses.Count}");
Console.WriteLine($"Total exception: {errors.Count}");
Console.WriteLine("----------");
Console.WriteLine($"Avg responseTime: {responseTimes.Average(r => r.TotalMilliseconds)}");
Console.WriteLine($"Max responseTime: {responseTimes.Max(r => r.TotalMilliseconds)}");
Console.WriteLine($"Min responseTime: {responseTimes.Min(r => r.TotalMilliseconds)}");
Console.WriteLine("----------");
Console.WriteLine($"Total ok responses: {responses.Count(r => r == "ok")}");
Console.WriteLine($"Total error responses: {responses.Count(r => r == "error")}");
Console.WriteLine("----------");
Console.WriteLine("----------");
}
} while (customLoadTestModel.AutoIncreaseThreadCount && !received500Error);

await Task.WhenAll(tasks);
stopwatch.Stop();

Console.Clear();
Console.WriteLine("----------");
Console.WriteLine($"Thread Count: {threadCount}");
Console.WriteLine($"Total responses: {responses.Count}");
Console.WriteLine($"Total exception: {errors.Count}");
Console.WriteLine("----------");
Console.WriteLine($"Total elapsed time: {stopwatch.Elapsed}");
Console.WriteLine($"Avg responseTime: {responseTimes.Average(r => r.TotalMilliseconds)}");
Console.WriteLine($"Max responseTime: {responseTimes.Max(r => r.TotalMilliseconds)}");
Console.WriteLine($"Min responseTime: {responseTimes.Min(r => r.TotalMilliseconds)}");
Console.WriteLine("----------");
Console.WriteLine($"Total ok responses: {responses.Count(r => r == "ok")}");
Console.WriteLine($"Total error responses: {responses.Count(r => r == "error")}");
Console.WriteLine("----------");
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
```

در کد بالا از کانفیگ زیر استفاده شده است:

```csharp
new CustomLoadTestModel
{
Name = name,
ThreadCount = 1000,
IncreaseThreadCount = 100,
AutoIncreaseThreadCount = true,
ShowErrors = true
};
```

در این کانفیگ ابتدا 1000 ترد برای ارسال همزمان ایجاد می‌شود. در صورتی که تمام آنها با موفقیت جواب داده شوند 100 عدد بر روی آن قرار داده می‌شود. این سناریو تا زمانی که فراخوانی api با خطا مواجه شود ادامه پیدا می‌کند.

0 comments on commit fda7b82

Please sign in to comment.