mirror of
https://github.com/NecroticBamboo/QRBee.git
synced 2025-12-21 12:11:53 +00:00
DEEP-31 Transaction corruption anomaly added. New custom metrics added
This commit is contained in:
parent
f3979769e2
commit
ea1f2abb98
@ -18,4 +18,6 @@ internal class GeneratorSettings
|
|||||||
|
|
||||||
public Anomaly LoadSpike { get; set; } = new();
|
public Anomaly LoadSpike { get; set; } = new();
|
||||||
public Anomaly LargeAmount { get; set; } = new();
|
public Anomaly LargeAmount { get; set; } = new();
|
||||||
|
public Anomaly TransactionCorruption { get; set;} = new();
|
||||||
|
public Anomaly CoherentTransactionCorruption { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ internal class LoadGenerator : IHostedService
|
|||||||
private readonly Client _client;
|
private readonly Client _client;
|
||||||
private readonly ClientPool _clientPool;
|
private readonly ClientPool _clientPool;
|
||||||
private readonly PaymentRequestGenerator _paymentRequestGenerator;
|
private readonly PaymentRequestGenerator _paymentRequestGenerator;
|
||||||
|
private readonly TransactionDefiler _transactionDefiler;
|
||||||
private readonly ILogger<LoadGenerator> _logger;
|
private readonly ILogger<LoadGenerator> _logger;
|
||||||
private readonly IOptions<GeneratorSettings> _settings;
|
private readonly IOptions<GeneratorSettings> _settings;
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ internal class LoadGenerator : IHostedService
|
|||||||
QRBee.Core.Client.Client client,
|
QRBee.Core.Client.Client client,
|
||||||
ClientPool clientPool,
|
ClientPool clientPool,
|
||||||
PaymentRequestGenerator paymentRequestGenerator,
|
PaymentRequestGenerator paymentRequestGenerator,
|
||||||
|
TransactionDefiler transactionDefiler,
|
||||||
ILogger<LoadGenerator> logger,
|
ILogger<LoadGenerator> logger,
|
||||||
IOptions<GeneratorSettings> settings
|
IOptions<GeneratorSettings> settings
|
||||||
)
|
)
|
||||||
@ -29,6 +31,7 @@ internal class LoadGenerator : IHostedService
|
|||||||
_client = client;
|
_client = client;
|
||||||
_clientPool = clientPool;
|
_clientPool = clientPool;
|
||||||
_paymentRequestGenerator = paymentRequestGenerator;
|
_paymentRequestGenerator = paymentRequestGenerator;
|
||||||
|
_transactionDefiler = transactionDefiler;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
|
||||||
@ -204,6 +207,8 @@ internal class LoadGenerator : IHostedService
|
|||||||
GatewayTransactionId = res.GatewayTransactionId
|
GatewayTransactionId = res.GatewayTransactionId
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_transactionDefiler.CorruptPaymentConfirmation(paymentConfirmation);
|
||||||
|
|
||||||
var confirmationTask = _client.ConfirmPayAsync(paymentConfirmation);
|
var confirmationTask = _client.ConfirmPayAsync(paymentConfirmation);
|
||||||
_confirmationQueue.Add(confirmationTask);
|
_confirmationQueue.Add(confirmationTask);
|
||||||
}
|
}
|
||||||
@ -242,6 +247,8 @@ internal class LoadGenerator : IHostedService
|
|||||||
_rng.NextInRange(1, _settings.Value.NumberOfMerchants + 1)
|
_rng.NextInRange(1, _settings.Value.NumberOfMerchants + 1)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_transactionDefiler.CorruptPaymentRequest(req);
|
||||||
|
|
||||||
var resp = _client.PayAsync(req);
|
var resp = _client.PayAsync(req);
|
||||||
|
|
||||||
_responseQueue.Add(resp);
|
_responseQueue.Add(resp);
|
||||||
|
|||||||
@ -30,6 +30,7 @@ builder.ConfigureServices((context, services) =>
|
|||||||
.Configure<GeneratorSettings>(context.Configuration.GetSection("GeneratorSettings"))
|
.Configure<GeneratorSettings>(context.Configuration.GetSection("GeneratorSettings"))
|
||||||
.AddSingleton<ClientPool>()
|
.AddSingleton<ClientPool>()
|
||||||
.AddSingleton<PaymentRequestGenerator>()
|
.AddSingleton<PaymentRequestGenerator>()
|
||||||
|
.AddSingleton<TransactionDefiler>()
|
||||||
.AddSingleton<PrivateKeyHandlerFactory>(x => no => new PrivateKeyHandler(x.GetRequiredService<ILogger<ServerPrivateKeyHandler>>(), x.GetRequiredService<IConfiguration>(), no))
|
.AddSingleton<PrivateKeyHandlerFactory>(x => no => new PrivateKeyHandler(x.GetRequiredService<ILogger<ServerPrivateKeyHandler>>(), x.GetRequiredService<IConfiguration>(), no))
|
||||||
.AddSingleton<SecurityServiceFactory>(x => no => new AndroidSecurityService(x.GetRequiredService<PrivateKeyHandlerFactory>()(no)))
|
.AddSingleton<SecurityServiceFactory>(x => no => new AndroidSecurityService(x.GetRequiredService<PrivateKeyHandlerFactory>()(no)))
|
||||||
.AddHostedService<LoadGenerator>()
|
.AddHostedService<LoadGenerator>()
|
||||||
|
|||||||
84
QRBee.Load.Generator/TransactionDefiler.cs
Normal file
84
QRBee.Load.Generator/TransactionDefiler.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using QRBee.Core.Data;
|
||||||
|
|
||||||
|
namespace QRBee.Load.Generator
|
||||||
|
{
|
||||||
|
internal class TransactionDefiler
|
||||||
|
{
|
||||||
|
private readonly ILogger<TransactionDefiler> _logger;
|
||||||
|
private ThreadSafeRandom _rng = new ThreadSafeRandom();
|
||||||
|
private double _corruptionProbability;
|
||||||
|
private double _coherentCorruptionProbability;
|
||||||
|
private bool _multipleCorruption = false;
|
||||||
|
private int _sequenceLengthMin;
|
||||||
|
private int _sequenceLengthMax;
|
||||||
|
private int _sequenceLength;
|
||||||
|
private int _corruptionCounter = 0;
|
||||||
|
|
||||||
|
public TransactionDefiler(IOptions<GeneratorSettings> settings, ILogger<TransactionDefiler> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
|
var transactionCorruption = settings.Value.TransactionCorruption;
|
||||||
|
_corruptionProbability = transactionCorruption.Probability;
|
||||||
|
|
||||||
|
var coherentTransactionCorruption = settings.Value.CoherentTransactionCorruption;
|
||||||
|
_coherentCorruptionProbability = coherentTransactionCorruption.Probability;
|
||||||
|
if (_coherentCorruptionProbability > 0)
|
||||||
|
{
|
||||||
|
if (coherentTransactionCorruption.Parameters.TryGetValue("SequenceLengthMin", out var s))
|
||||||
|
_sequenceLengthMin = int.Parse(s);
|
||||||
|
if (coherentTransactionCorruption.Parameters.TryGetValue("SequenceLengthMax", out s))
|
||||||
|
_sequenceLengthMax = int.Parse(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_logger.LogDebug($"Transaction corruption configured: Probability={_corruptionProbability}");
|
||||||
|
_logger.LogDebug($"Coherent transaction corruption configured: Probability={_coherentCorruptionProbability}, SequenceLengthMin={_sequenceLengthMin}, SequenceLengthMax={_sequenceLengthMax}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CorruptPaymentRequest(PaymentRequest paymentRequest)
|
||||||
|
{
|
||||||
|
var dice = _rng.NextDouble();
|
||||||
|
if(_multipleCorruption)
|
||||||
|
{
|
||||||
|
_corruptionCounter++;
|
||||||
|
_logger.LogWarning($"Anomaly: Coherent corrupted transaction Dice={dice}, Corruption counter = {_corruptionCounter}, Sequence length = {_sequenceLength}");
|
||||||
|
paymentRequest.ClientResponse.MerchantRequest.Amount += 0.01M;
|
||||||
|
|
||||||
|
if (_corruptionCounter >= _sequenceLength)
|
||||||
|
{
|
||||||
|
_corruptionCounter = 0;
|
||||||
|
_multipleCorruption = false;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dice < _corruptionProbability)
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Anomaly: Corrupted transaction Dice={dice}");
|
||||||
|
paymentRequest.ClientResponse.MerchantRequest.Amount += 10M;
|
||||||
|
|
||||||
|
if(dice < _coherentCorruptionProbability && _multipleCorruption==false)
|
||||||
|
{
|
||||||
|
_sequenceLength = _rng.NextInRange(_sequenceLengthMin,_sequenceLengthMax);
|
||||||
|
_multipleCorruption = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CorruptPaymentConfirmation(PaymentConfirmation paymentConfirmation)
|
||||||
|
{
|
||||||
|
var dice = _rng.NextDouble();
|
||||||
|
if (dice < _corruptionProbability)
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"Anomaly: Corrupted transaction confirmation Dice={dice}");
|
||||||
|
paymentConfirmation.GatewayTransactionId = "BadGatewayTransactionId";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,22 +14,37 @@
|
|||||||
"GeneratorSettings": {
|
"GeneratorSettings": {
|
||||||
"NumberOfClients": 100,
|
"NumberOfClients": 100,
|
||||||
"NumberOfMerchants": 10,
|
"NumberOfMerchants": 10,
|
||||||
"NumberOfThreads": 10,
|
"NumberOfThreads": 5,
|
||||||
"DelayBetweenMessagesMSec": 300,
|
"DelayBetweenMessagesMSec": 500,
|
||||||
"DelayJitterMSec": 50,
|
"DelayJitterMSec": 50,
|
||||||
"MinAmount": 10,
|
"MinAmount": 10,
|
||||||
"MaxAmount": 100,
|
"MaxAmount": 100,
|
||||||
|
|
||||||
"LoadSpike": {
|
"LoadSpike": {
|
||||||
"Probability": 0.001,
|
"Probability": 0.004,
|
||||||
"Parameters": {
|
"Parameters": {
|
||||||
"Duration": "00:00:15",
|
"Duration": "00:00:15",
|
||||||
"Delay": "00:00:00.0100000"
|
"Delay": "00:00:00.0100000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"TransactionCorruption": {
|
||||||
|
"Probability": 0.004,
|
||||||
|
"Parameters": {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"CoherentTransactionCorruption": {
|
||||||
|
"Probability": 0.002,
|
||||||
|
"Parameters": {
|
||||||
|
"SequenceLengthMin": 2,
|
||||||
|
"SequenceLengthMax": 10
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"LargeAmount": {
|
"LargeAmount": {
|
||||||
"Probability": 0.03,
|
"Probability": 0.003,
|
||||||
"Parameters": {
|
"Parameters": {
|
||||||
"Value": "1000"
|
"Value": "1000"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,11 +37,19 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
|
||||||
|
<file value="log-file.txt" />
|
||||||
|
<appendToFile value="false" />
|
||||||
|
<layout type="log4net.Layout.PatternLayout">
|
||||||
|
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
|
||||||
<appender name="BufferingForwardingAppender" type="log4net.Appender.BufferingForwardingAppender" >
|
<appender name="BufferingForwardingAppender" type="log4net.Appender.BufferingForwardingAppender" >
|
||||||
<bufferSize value="1"/>
|
<bufferSize value="1"/>
|
||||||
<appender-ref ref="DebugAppender" />
|
<appender-ref ref="DebugAppender" />
|
||||||
<appender-ref ref="Console" />
|
<appender-ref ref="Console" />
|
||||||
<!-- <appender-ref ref="RollingFile" /> -->
|
<appender-ref ref="RollingFile" />
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<logger name="System.Net.Http">
|
<logger name="System.Net.Http">
|
||||||
|
|||||||
@ -8,6 +8,9 @@ namespace QRBee.Api.Services
|
|||||||
private Counter<int> MerchantResponseCounter { get; }
|
private Counter<int> MerchantResponseCounter { get; }
|
||||||
private Counter<int> SucceededTransactionsCounter { get; }
|
private Counter<int> SucceededTransactionsCounter { get; }
|
||||||
private Counter<int> FailedTransactionsCounter { get; }
|
private Counter<int> FailedTransactionsCounter { get; }
|
||||||
|
private Counter<int> CorruptTransactionsCounter { get; }
|
||||||
|
private Counter<int> SucceededPaymentConfirmationsCounter { get; }
|
||||||
|
private Counter<int> FailedPaymentConfirmationsCounter { get; }
|
||||||
private Counter<long> TotalCreditCardCheckTime { get; }
|
private Counter<long> TotalCreditCardCheckTime { get; }
|
||||||
private Counter<long> TotalPaymentTime { get; }
|
private Counter<long> TotalPaymentTime { get; }
|
||||||
|
|
||||||
@ -20,11 +23,16 @@ namespace QRBee.Api.Services
|
|||||||
|
|
||||||
MerchantRequestCounter = meter.CreateCounter<int>("merchant-requests", description: "Merchant has sent a request");
|
MerchantRequestCounter = meter.CreateCounter<int>("merchant-requests", description: "Merchant has sent a request");
|
||||||
MerchantResponseCounter = meter.CreateCounter<int>("merchant-responses");
|
MerchantResponseCounter = meter.CreateCounter<int>("merchant-responses");
|
||||||
|
|
||||||
SucceededTransactionsCounter = meter.CreateCounter<int>("transaction-succeeded", description: "Transaction succeeded");
|
SucceededTransactionsCounter = meter.CreateCounter<int>("transaction-succeeded", description: "Transaction succeeded");
|
||||||
FailedTransactionsCounter = meter.CreateCounter<int>("transaction-failed", description: "Transaction failed");
|
FailedTransactionsCounter = meter.CreateCounter<int>("transaction-failed", description: "Transaction failed");
|
||||||
|
CorruptTransactionsCounter = meter.CreateCounter<int>("transaction-corrupt", description: "Transaction was corrupted");
|
||||||
|
|
||||||
TotalCreditCardCheckTime = meter.CreateCounter<long>("Total-credit-card-check-time","msec");
|
SucceededPaymentConfirmationsCounter = meter.CreateCounter<int>("payment-confirmation-succeeded", description: "Payment confirmation succeeded");
|
||||||
TotalPaymentTime = meter.CreateCounter<long>("Total-payment-time","msec");
|
FailedPaymentConfirmationsCounter = meter.CreateCounter<int>("payment-confirmation-failed", description: "Payment confirmation failed");
|
||||||
|
|
||||||
|
TotalCreditCardCheckTime = meter.CreateCounter<long>("total-credit-card-check-time","msec");
|
||||||
|
TotalPaymentTime = meter.CreateCounter<long>("total-payment-time","msec");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -32,6 +40,9 @@ namespace QRBee.Api.Services
|
|||||||
public void AddMerchantResponse() => MerchantResponseCounter.Add(1);
|
public void AddMerchantResponse() => MerchantResponseCounter.Add(1);
|
||||||
public void AddSucceededTransaction() => SucceededTransactionsCounter.Add(1);
|
public void AddSucceededTransaction() => SucceededTransactionsCounter.Add(1);
|
||||||
public void AddFailedTransaction() => FailedTransactionsCounter.Add(1);
|
public void AddFailedTransaction() => FailedTransactionsCounter.Add(1);
|
||||||
|
public void AddCorruptTransaction() => CorruptTransactionsCounter.Add(1);
|
||||||
|
public void AddSucceededPaymentConfirmation() => SucceededPaymentConfirmationsCounter.Add(1);
|
||||||
|
public void AddFailedPaymentConfirmation() => FailedPaymentConfirmationsCounter.Add(1);
|
||||||
public void AddTotalCreditCardCheckTime(long milliseconds) => TotalCreditCardCheckTime.Add(milliseconds);
|
public void AddTotalCreditCardCheckTime(long milliseconds) => TotalCreditCardCheckTime.Add(milliseconds);
|
||||||
public void AddTotalPaymentTime(long milliseconds) => TotalPaymentTime.Add(milliseconds);
|
public void AddTotalPaymentTime(long milliseconds) => TotalPaymentTime.Add(milliseconds);
|
||||||
|
|
||||||
|
|||||||
@ -172,8 +172,17 @@ namespace QRBee.Api.Services
|
|||||||
var t4 = CheckTransaction(tid);
|
var t4 = CheckTransaction(tid);
|
||||||
|
|
||||||
//Parallel task execution
|
//Parallel task execution
|
||||||
await Task.WhenAll(t2, t3, t4);
|
try
|
||||||
_logger.LogInformation($"Transaction=\"{tid}\" Fully validated");
|
{
|
||||||
|
await Task.WhenAll(t2, t3, t4);
|
||||||
|
_logger.LogInformation($"Transaction=\"{tid}\" Fully validated");
|
||||||
|
}
|
||||||
|
catch(Exception)
|
||||||
|
{
|
||||||
|
_customMetrics.AddCorruptTransaction();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//5. Decrypt client card data
|
//5. Decrypt client card data
|
||||||
var creditCardCheckTime = Stopwatch.StartNew();
|
var creditCardCheckTime = Stopwatch.StartNew();
|
||||||
@ -206,17 +215,17 @@ namespace QRBee.Api.Services
|
|||||||
//9. Record transaction with result
|
//9. Record transaction with result
|
||||||
if (gatewayResponse.Success)
|
if (gatewayResponse.Success)
|
||||||
{
|
{
|
||||||
|
_customMetrics.AddSucceededTransaction();
|
||||||
|
|
||||||
info.Status=TransactionInfo.TransactionStatus.Succeeded;
|
info.Status=TransactionInfo.TransactionStatus.Succeeded;
|
||||||
info.GatewayTransactionId=gatewayResponse.GatewayTransactionId;
|
info.GatewayTransactionId=gatewayResponse.GatewayTransactionId;
|
||||||
|
|
||||||
_customMetrics.AddSucceededTransaction();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
_customMetrics.AddFailedTransaction();
|
||||||
|
|
||||||
info.Status = TransactionInfo.TransactionStatus.Rejected;
|
info.Status = TransactionInfo.TransactionStatus.Rejected;
|
||||||
info.RejectReason = gatewayResponse.ErrorMessage;
|
info.RejectReason = gatewayResponse.ErrorMessage;
|
||||||
|
|
||||||
_customMetrics.AddFailedTransaction();
|
|
||||||
}
|
}
|
||||||
await _storage.UpdateTransaction(info);
|
await _storage.UpdateTransaction(info);
|
||||||
_logger.LogInformation($"Transaction=\"{tid}\" complete Status=\"{info.Status}\"");
|
_logger.LogInformation($"Transaction=\"{tid}\" complete Status=\"{info.Status}\"");
|
||||||
@ -403,9 +412,11 @@ namespace QRBee.Api.Services
|
|||||||
trans.Status = TransactionInfo.TransactionStatus.Confirmed;
|
trans.Status = TransactionInfo.TransactionStatus.Confirmed;
|
||||||
await _storage.UpdateTransaction(trans);
|
await _storage.UpdateTransaction(trans);
|
||||||
_logger.LogInformation($"Transaction with MerchantTransactionId: {trans.MerchantTransactionId} confirmed");
|
_logger.LogInformation($"Transaction with MerchantTransactionId: {trans.MerchantTransactionId} confirmed");
|
||||||
|
_customMetrics.AddSucceededPaymentConfirmation();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
_customMetrics.AddFailedPaymentConfirmation();
|
||||||
throw new ApplicationException($"Transaction with gatewayTransactionId:{value.GatewayTransactionId} failed.");
|
throw new ApplicationException($"Transaction with gatewayTransactionId:{value.GatewayTransactionId} failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user