public void RandomSpin(int gameId, int level, string currencyCode, int numOfUsers, int numItrPerUser, decimal bet) { const int lines = Game.Lines; var timeStart = DateTime.Now; var module = SimulationHelper.GetModule(gameId); var configuration = new Configuration(); var targetRtpLevel = Math.Round(configuration.RtpLevels.FirstOrDefault(rl => rl.Level == level).Rtp, 2); var totalSummaryData = new SummaryData(); var users = SimulationHelper.GetUsers(gameId, numOfUsers, level); var spinBets = SimulationHelper.GetUserBets(users, bet, lines); var spinRequestContext = SimulationHelper.GetMockSpinRequestContext(gameId); var bonusRequestContext = SimulationHelper.GetMockBonusRequestContext(0, gameId); Parallel.ForEach(users, () => new SummaryData(), (key, state, summaryData) => { var spinBet = spinBets[key.UserId]; for (var ctr = 0; ctr < numItrPerUser; ctr++) { var spinResult = module.ExecuteSpin(level, null, spinRequestContext).Value as SpinResult; summaryData.Update(spinResult); if (spinResult.HasBonus) { var bonus = module.CreateBonus(spinResult).Value; while (!bonus.IsCompleted) { var bonusResult = SimulationHelper.ExecuteBonus(level, bonus, bonusRequestContext, configuration).Value; summaryData.UpdateBonus(bonusResult); bonus = bonusResult.Bonus; } } } return(summaryData); }, summaryData => { lock (totalSummaryData) { totalSummaryData.Sum(summaryData); } }); totalSummaryData.DisplayData(level, timeStart, targetRtpLevel); totalSummaryData.DisplayPayoutsData(bet, lines); var isWithinRtp = totalSummaryData.RtpData.OverallRtp >= targetRtpLevel - 1 && totalSummaryData.RtpData.OverallRtp <= targetRtpLevel + 1; Assert.True(isWithinRtp, $"RTP not matching. The result is {totalSummaryData.RtpData.OverallRtp}. Expected is {targetRtpLevel}"); }