Further async changes (#387)

* Further async changes
- SaveServer & Backup Server are now async
- Anything that ties in with SaveServer saving (Such as callbacks) are now async
- Various async util methods added
- Removed two wrapper methods and switched code over to use the actual method

* Update test
This commit is contained in:
Jesse
2025-06-09 21:09:12 +02:00
committed by GitHub
parent c8e1c48e98
commit 2c52012740
20 changed files with 125 additions and 80 deletions
@@ -54,15 +54,15 @@ public class GameCallbacks(
/// Save profiles on game close /// Save profiles on game close
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public ValueTask<string> GameLogout(string url, EmptyRequestData _, string sessionID) public async ValueTask<string> GameLogout(string url, EmptyRequestData _, string sessionID)
{ {
_saveServer.SaveProfile(sessionID); await _saveServer.SaveProfileAsync(sessionID);
return new ValueTask<string>(_httpResponseUtil.GetBody( return _httpResponseUtil.GetBody(
new GameLogoutResponseData new GameLogoutResponseData
{ {
Status = "ok" Status = "ok"
} }
)); );
} }
/// <summary> /// <summary>
@@ -26,10 +26,10 @@ public class LauncherCallbacks(
return new ValueTask<string>(output ?? "FAILED"); return new ValueTask<string>(output ?? "FAILED");
} }
public ValueTask<string> Register(string url, RegisterData info, string sessionID) public async ValueTask<string> Register(string url, RegisterData info, string sessionID)
{ {
var output = _launcherController.Register(info); var output = await _launcherController.Register(info);
return new ValueTask<string>(string.IsNullOrEmpty(output) ? "FAILED" : "OK"); return string.IsNullOrEmpty(output) ? "FAILED" : "OK";
} }
public ValueTask<string> Get(string url, LoginRequestData info, string sessionID) public ValueTask<string> Get(string url, LoginRequestData info, string sessionID)
@@ -43,26 +43,26 @@ public class LauncherV2Callbacks(
)); ));
} }
public ValueTask<string> Register(RegisterData info) public async ValueTask<string> Register(RegisterData info)
{ {
return new ValueTask<string>(_httpResponseUtil.NoBody( return _httpResponseUtil.NoBody(
new LauncherV2RegisterResponse new LauncherV2RegisterResponse
{ {
Response = _launcherV2Controller.Register(info), Response = await _launcherV2Controller.Register(info),
Profiles = _profileController.GetMiniProfiles() Profiles = _profileController.GetMiniProfiles()
} }
)); );
} }
public ValueTask<string> PasswordChange(ChangeRequestData info) public async ValueTask<string> PasswordChange(ChangeRequestData info)
{ {
return new ValueTask<string>(_httpResponseUtil.NoBody( return _httpResponseUtil.NoBody(
new LauncherV2PasswordChangeResponse new LauncherV2PasswordChangeResponse
{ {
Response = _launcherV2Controller.PasswordChange(info), Response = await _launcherV2Controller.PasswordChange(info),
Profiles = _profileController.GetMiniProfiles() Profiles = _profileController.GetMiniProfiles()
} }
)); );
} }
public ValueTask<string> Remove(LoginRequestData info) public ValueTask<string> Remove(LoginRequestData info)
@@ -31,10 +31,10 @@ public class PrestigeCallbacks(
/// <param name="info"></param> /// <param name="info"></param>
/// <param name="sessionID">Session/player id</param> /// <param name="sessionID">Session/player id</param>
/// <returns></returns> /// <returns></returns>
public ValueTask<string> ObtainPrestige(string url, ObtainPrestigeRequestList info, string sessionID) public async ValueTask<string> ObtainPrestige(string url, ObtainPrestigeRequestList info, string sessionID)
{ {
_prestigeController.ObtainPrestige(sessionID, info); await _prestigeController.ObtainPrestige(sessionID, info);
return new ValueTask<string>(_httpResponseUtil.NullResponse()); return _httpResponseUtil.NullResponse();
} }
} }
@@ -22,15 +22,15 @@ public class ProfileCallbacks(
/// Handle client/game/profile/create /// Handle client/game/profile/create
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public ValueTask<string> CreateProfile(string url, ProfileCreateRequestData info, string sessionID) public async ValueTask<string> CreateProfile(string url, ProfileCreateRequestData info, string sessionID)
{ {
var id = _profileController.CreateProfile(info, sessionID); var id = await _profileController.CreateProfile(info, sessionID);
return new ValueTask<string>(_httpResponse.GetBody( return _httpResponse.GetBody(
new CreateProfileResponse new CreateProfileResponse
{ {
UserId = id UserId = id
} }
)); );
} }
/// <summary> /// <summary>
@@ -20,19 +20,19 @@ public class SaveCallbacks(
public async Task OnLoad() public async Task OnLoad()
{ {
_backupService.StartBackupSystem(); _backupService.StartBackupSystem();
_saveServer.Load(); await _saveServer.LoadAsync();
} }
public Task<bool> OnUpdate(long secondsSinceLastRun) public async Task<bool> OnUpdate(long secondsSinceLastRun)
{ {
if (secondsSinceLastRun < _coreConfig.ProfileSaveIntervalInSeconds) if (secondsSinceLastRun < _coreConfig.ProfileSaveIntervalInSeconds)
{ {
// Not enough time has passed since last run, exit early // Not enough time has passed since last run, exit early
return Task.FromResult(false); return false;
} }
_saveServer.Save(); await _saveServer.SaveAsync();
return Task.FromResult(true); return true;
} }
} }
@@ -97,7 +97,7 @@ public class LauncherController(
/// </summary> /// </summary>
/// <param name="info"></param> /// <param name="info"></param>
/// <returns></returns> /// <returns></returns>
public string Register(RegisterData info) public async Task<string> Register(RegisterData info)
{ {
foreach (var kvp in _saveServer.GetProfiles()) foreach (var kvp in _saveServer.GetProfiles())
{ {
@@ -107,14 +107,14 @@ public class LauncherController(
} }
} }
return CreateAccount(info); return await CreateAccount(info);
} }
/// <summary> /// <summary>
/// </summary> /// </summary>
/// <param name="info"></param> /// <param name="info"></param>
/// <returns></returns> /// <returns></returns>
protected string CreateAccount(RegisterData info) protected async Task<string> CreateAccount(RegisterData info)
{ {
var profileId = GenerateProfileId(); var profileId = GenerateProfileId();
var scavId = GenerateProfileId(); var scavId = GenerateProfileId();
@@ -130,8 +130,8 @@ public class LauncherController(
}; };
_saveServer.CreateProfile(newProfileDetails); _saveServer.CreateProfile(newProfileDetails);
_saveServer.LoadProfile(profileId); await _saveServer.LoadProfileAsync(profileId);
_saveServer.SaveProfile(profileId); await _saveServer.SaveProfileAsync(profileId);
return profileId; return profileId;
} }
@@ -71,7 +71,7 @@ public class LauncherV2Controller(
/// </summary> /// </summary>
/// <param name="info"></param> /// <param name="info"></param>
/// <returns></returns> /// <returns></returns>
public bool Register(RegisterData info) public async Task<bool> Register(RegisterData info)
{ {
foreach (var session in _saveServer.GetProfiles()) foreach (var session in _saveServer.GetProfiles())
{ {
@@ -81,7 +81,7 @@ public class LauncherV2Controller(
} }
} }
CreateAccount(info); await CreateAccount(info);
return true; return true;
} }
@@ -90,7 +90,7 @@ public class LauncherV2Controller(
/// </summary> /// </summary>
/// <param name="info"></param> /// <param name="info"></param>
/// <returns></returns> /// <returns></returns>
public bool PasswordChange(ChangeRequestData info) public async Task<bool> PasswordChange(ChangeRequestData info)
{ {
var sessionId = GetSessionId(info); var sessionId = GetSessionId(info);
@@ -105,7 +105,7 @@ public class LauncherV2Controller(
} }
_saveServer.GetProfile(sessionId).ProfileInfo!.Password = info.Change; _saveServer.GetProfile(sessionId).ProfileInfo!.Password = info.Change;
_saveServer.SaveProfile(sessionId); await _saveServer.SaveProfileAsync(sessionId);
return true; return true;
} }
@@ -162,7 +162,7 @@ public class LauncherV2Controller(
/// </summary> /// </summary>
/// <param name="info"></param> /// <param name="info"></param>
/// <returns></returns> /// <returns></returns>
protected string CreateAccount(RegisterData info) protected async Task<string> CreateAccount(RegisterData info)
{ {
var profileId = GenerateProfileId(); var profileId = GenerateProfileId();
var scavId = GenerateProfileId(); var scavId = GenerateProfileId();
@@ -179,8 +179,8 @@ public class LauncherV2Controller(
_saveServer.CreateProfile(newProfileDetails); _saveServer.CreateProfile(newProfileDetails);
_saveServer.LoadProfile(profileId); await _saveServer.LoadProfileAsync(profileId);
_saveServer.SaveProfile(profileId); await _saveServer.SaveProfileAsync(profileId);
return profileId; return profileId;
} }
@@ -59,7 +59,7 @@ public class PrestigeController(
/// </list> /// </list>
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public void ObtainPrestige( public async Task ObtainPrestige(
string sessionId, string sessionId,
ObtainPrestigeRequestList request) ObtainPrestigeRequestList request)
{ {
@@ -75,7 +75,7 @@ public class PrestigeController(
profile.SptData.PendingPrestige = pendingPrestige; profile.SptData.PendingPrestige = pendingPrestige;
profile.ProfileInfo.IsWiped = true; profile.ProfileInfo.IsWiped = true;
_saveServer.SaveProfile(sessionId); await _saveServer.SaveProfileAsync(sessionId);
} }
} }
} }
@@ -118,9 +118,9 @@ public class ProfileController(
/// <param name="request">Create profile request</param> /// <param name="request">Create profile request</param>
/// <param name="sessionId">Player id</param> /// <param name="sessionId">Player id</param>
/// <returns>Player id</returns> /// <returns>Player id</returns>
public virtual string CreateProfile(ProfileCreateRequestData request, string sessionId) public virtual async ValueTask<string> CreateProfile(ProfileCreateRequestData request, string sessionId)
{ {
return _createProfileService.CreateProfile(sessionId, request); return await _createProfileService.CreateProfile(sessionId, request);
} }
/// <summary> /// <summary>
@@ -56,7 +56,7 @@ public class SaveServer(
/// <summary> /// <summary>
/// Load all profiles in /user/profiles folder into memory (this.profiles) /// Load all profiles in /user/profiles folder into memory (this.profiles)
/// </summary> /// </summary>
public void Load() public async Task LoadAsync()
{ {
// get files to load // get files to load
if (!_fileUtil.DirectoryExists(profileFilepath)) if (!_fileUtil.DirectoryExists(profileFilepath))
@@ -70,7 +70,7 @@ public class SaveServer(
var stopwatch = Stopwatch.StartNew(); var stopwatch = Stopwatch.StartNew();
foreach (var file in files) foreach (var file in files)
{ {
LoadProfile(_fileUtil.StripExtension(file)); await LoadProfileAsync(_fileUtil.StripExtension(file));
} }
stopwatch.Stop(); stopwatch.Stop();
@@ -83,13 +83,13 @@ public class SaveServer(
/// <summary> /// <summary>
/// Save changes for each profile from memory into user/profiles json /// Save changes for each profile from memory into user/profiles json
/// </summary> /// </summary>
public void Save() public async Task SaveAsync()
{ {
// Save every profile // Save every profile
var totalTime = 0L; var totalTime = 0L;
foreach (var sessionID in profiles) foreach (var sessionID in profiles)
{ {
totalTime += SaveProfile(sessionID.Key); totalTime += await SaveProfileAsync(sessionID.Key);
} }
if (_logger.IsLogEnabled(LogLevel.Debug)) if (_logger.IsLogEnabled(LogLevel.Debug))
@@ -196,14 +196,14 @@ public class SaveServer(
/// Execute saveLoadRouters callbacks after being loaded into memory. /// Execute saveLoadRouters callbacks after being loaded into memory.
/// </summary> /// </summary>
/// <param name="sessionID"> ID of profile to store in memory </param> /// <param name="sessionID"> ID of profile to store in memory </param>
public void LoadProfile(string sessionID) public async Task LoadProfileAsync(string sessionID)
{ {
var filename = $"{sessionID}.json"; var filename = $"{sessionID}.json";
var filePath = $"{profileFilepath}{filename}"; var filePath = $"{profileFilepath}{filename}";
if (_fileUtil.FileExists(filePath)) if (_fileUtil.FileExists(filePath))
// File found, store in profiles[] // File found, store in profiles[]
{ {
profiles[sessionID] = _jsonUtil.DeserializeFromFile<SptProfile>(filePath); profiles[sessionID] = await _jsonUtil.DeserializeFromFileAsync<SptProfile>(filePath);
} }
// Run callbacks // Run callbacks
@@ -220,7 +220,7 @@ public class SaveServer(
/// </summary> /// </summary>
/// <param name="sessionID"> Profile id (user/profiles/id.json) </param> /// <param name="sessionID"> Profile id (user/profiles/id.json) </param>
/// <returns> Time taken to save the profile in seconds </returns> /// <returns> Time taken to save the profile in seconds </returns>
public long SaveProfile(string sessionID) public async Task<long> SaveProfileAsync(string sessionID)
{ {
var filePath = $"{profileFilepath}{sessionID}.json"; var filePath = $"{profileFilepath}{sessionID}.json";
@@ -250,12 +250,12 @@ public class SaveServer(
var start = Stopwatch.StartNew(); var start = Stopwatch.StartNew();
var jsonProfile = _jsonUtil.Serialize(profiles[sessionID], !_configServer.GetConfig<CoreConfig>().Features.CompressProfile); var jsonProfile = _jsonUtil.Serialize(profiles[sessionID], !_configServer.GetConfig<CoreConfig>().Features.CompressProfile);
var fmd5 = _hashUtil.GenerateMd5ForData(jsonProfile); var fmd5 = await _hashUtil.GenerateHashForDataAsync(HashingAlgorithm.MD5, jsonProfile);
if (!saveMd5.TryGetValue(sessionID, out var currentMd5) || currentMd5 != fmd5) if (!saveMd5.TryGetValue(sessionID, out var currentMd5) || currentMd5 != fmd5)
{ {
saveMd5[sessionID] = fmd5; saveMd5[sessionID] = fmd5;
// save profile to disk // save profile to disk
_fileUtil.WriteFile(filePath, jsonProfile); await _fileUtil.WriteFileAsync(filePath, jsonProfile);
} }
start.Stop(); start.Stop();
@@ -46,22 +46,22 @@ public class BackupService
/// <summary> /// <summary>
/// Start the backup interval if enabled in config. /// Start the backup interval if enabled in config.
/// </summary> /// </summary>
public void StartBackupSystem() public async Task StartBackupSystem()
{ {
if (!_backupConfig.BackupInterval.Enabled) if (!_backupConfig.BackupInterval.Enabled)
{ {
// Not backing up at regular intervals, run once and exit // Not backing up at regular intervals, run once and exit
Init(); await Init();
return; return;
} }
_backupIntervalTimer = new Timer( _backupIntervalTimer = new Timer(async
_ => _ =>
{ {
try try
{ {
Init(); await Init();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -79,7 +79,7 @@ public class BackupService
/// This method orchestrates the profile backup service. Handles copying profiles to a backup directory and cleaning /// This method orchestrates the profile backup service. Handles copying profiles to a backup directory and cleaning
/// up old backups if the number exceeds the configured maximum. /// up old backups if the number exceeds the configured maximum.
/// </summary> /// </summary>
public void Init() public async Task Init()
{ {
if (!IsEnabled()) if (!IsEnabled())
{ {
@@ -129,7 +129,7 @@ public class BackupService
} }
// Write a copy of active mods. // Write a copy of active mods.
_fileUtil.WriteFile(Path.Combine(targetDir, "activeMods.json"), _jsonUtil.Serialize(_activeServerMods)); await _fileUtil.WriteFileAsync(Path.Combine(targetDir, "activeMods.json"), _jsonUtil.Serialize(_activeServerMods));
if (_logger.IsLogEnabled(LogLevel.Debug)) if (_logger.IsLogEnabled(LogLevel.Debug))
{ {
@@ -43,7 +43,7 @@ public class BundleHashCacheService(
public bool CalculateAndMatchHash(string bundlePath) public bool CalculateAndMatchHash(string bundlePath)
{ {
var fileContents = _fileUtil.ReadFile(bundlePath); var fileContents = _fileUtil.ReadFile(bundlePath);
var generatedHash = _hashUtil.GenerateMd5ForData(fileContents); var generatedHash = _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, fileContents);
return MatchWithStoredHash(bundlePath, generatedHash); return MatchWithStoredHash(bundlePath, generatedHash);
} }
@@ -51,7 +51,7 @@ public class BundleHashCacheService(
public void CalculateAndStoreHash(string bundlePath) public void CalculateAndStoreHash(string bundlePath)
{ {
var fileContents = _fileUtil.ReadFile(bundlePath); var fileContents = _fileUtil.ReadFile(bundlePath);
var generatedHash = _hashUtil.GenerateMd5ForData(fileContents); var generatedHash = _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, fileContents);
StoreValue(bundlePath, generatedHash); StoreValue(bundlePath, generatedHash);
} }
@@ -42,14 +42,14 @@ public class ModHashCacheService(
public bool CalculateAndCompareHash(string modName, string modContent) public bool CalculateAndCompareHash(string modName, string modContent)
{ {
var generatedHash = _hashUtil.GenerateSha1ForData(modContent); var generatedHash = _hashUtil.GenerateHashForData(HashingAlgorithm.SHA1, modContent);
return MatchWithStoredHash(modName, generatedHash); return MatchWithStoredHash(modName, generatedHash);
} }
public void CalculateAndStoreHash(string modName, string modContent) public void CalculateAndStoreHash(string modName, string modContent)
{ {
var generatedHash = _hashUtil.GenerateSha1ForData(modContent); var generatedHash = _hashUtil.GenerateHashForData(HashingAlgorithm.SHA1, modContent);
StoreValue(modName, generatedHash); StoreValue(modName, generatedHash);
} }
@@ -549,7 +549,7 @@ public class CircleOfCultistService(
// Key is sacrificed items separated by commas, a dash, then the rewards separated by commas // Key is sacrificed items separated by commas, a dash, then the rewards separated by commas
var key = $"{{{required}-{reward}}}"; var key = $"{{{required}-{reward}}}";
return _hashUtil.GenerateMd5ForData(key); return _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, key);
} }
/// <summary> /// <summary>
@@ -887,7 +887,7 @@ public class CircleOfCultistService(
protected string CreateSacrificeCacheKey(IEnumerable<string> requiredItems) protected string CreateSacrificeCacheKey(IEnumerable<string> requiredItems)
{ {
var concat = string.Join(",", requiredItems.OrderBy(item => item)); var concat = string.Join(",", requiredItems.OrderBy(item => item));
return _hashUtil.GenerateMd5ForData(concat); return _hashUtil.GenerateHashForData(HashingAlgorithm.MD5, concat);
} }
/// <summary> /// <summary>
@@ -40,7 +40,7 @@ public class CreateProfileService(
MailSendService _mailSendService MailSendService _mailSendService
) )
{ {
public string CreateProfile(string sessionId, ProfileCreateRequestData request) public async ValueTask<string> CreateProfile(string sessionId, ProfileCreateRequestData request)
{ {
var account = _cloner.Clone(_saveServer.GetProfile(sessionId)); var account = _cloner.Clone(_saveServer.GetProfile(sessionId));
var profileTemplateClone = _cloner.Clone(_profileHelper.GetProfileTemplateForSide(account.ProfileInfo.Edition, request.Side)); var profileTemplateClone = _cloner.Clone(_profileHelper.GetProfileTemplateForSide(account.ProfileInfo.Edition, request.Side));
@@ -207,12 +207,12 @@ public class CreateProfileService(
_saveServer.GetProfile(sessionId).CharacterData.ScavData = _playerScavGenerator.Generate(sessionId); _saveServer.GetProfile(sessionId).CharacterData.ScavData = _playerScavGenerator.Generate(sessionId);
// Store minimal profile and reload it // Store minimal profile and reload it
_saveServer.SaveProfile(sessionId); await _saveServer.SaveProfileAsync(sessionId);
_saveServer.LoadProfile(sessionId); await _saveServer.LoadProfileAsync(sessionId);
// Completed account creation // Completed account creation
_saveServer.GetProfile(sessionId).ProfileInfo.IsWiped = false; _saveServer.GetProfile(sessionId).ProfileInfo.IsWiped = false;
_saveServer.SaveProfile(sessionId); await _saveServer.SaveProfileAsync(sessionId);
return pmcData.Id; return pmcData.Id;
} }
@@ -722,7 +722,7 @@ public class LocationLifecycleService
pmcProfile.Info.LastTimePlayedAsSavage = _timeUtil.GetTimeStamp(); pmcProfile.Info.LastTimePlayedAsSavage = _timeUtil.GetTimeStamp();
// Force a profile save // Force a profile save
_saveServer.SaveProfile(sessionId); _saveServer.SaveProfileAsync(sessionId);
} }
/// <summary> /// <summary>
@@ -90,6 +90,31 @@ public class FileUtil()
File.WriteAllBytes(filePath, fileContent); File.WriteAllBytes(filePath, fileContent);
} }
public async Task WriteFileAsync(string filePath, string fileContent)
{
if (!DirectoryExists(Path.GetDirectoryName(filePath)))
{
CreateDirectory(Path.GetDirectoryName(filePath));
}
if (!FileExists(filePath))
{
CreateFile(filePath);
}
await File.WriteAllTextAsync(filePath, fileContent);
}
public async Task WriteFileAsync(string filePath, byte[] fileContent)
{
if (!FileExists(filePath))
{
CreateFile(filePath);
}
await File.WriteAllBytesAsync(filePath, fileContent);
}
private void CreateFile(string filePath) private void CreateFile(string filePath)
{ {
var stream = File.Create(filePath); var stream = File.Create(filePath);
@@ -50,16 +50,6 @@ public partial class HashUtil(RandomUtil _randomUtil)
return MongoIdRegex().IsMatch(stringToCheck); return MongoIdRegex().IsMatch(stringToCheck);
} }
public string GenerateMd5ForData(string data)
{
return GenerateHashForData(HashingAlgorithm.MD5, data);
}
public string GenerateSha1ForData(string data)
{
return GenerateHashForData(HashingAlgorithm.SHA1, data);
}
public uint GenerateCrc32ForData(string data) public uint GenerateCrc32ForData(string data)
{ {
return Crc32.HashToUInt32(new ArraySegment<byte>(Encoding.UTF8.GetBytes(data))); return Crc32.HashToUInt32(new ArraySegment<byte>(Encoding.UTF8.GetBytes(data)));
@@ -89,6 +79,36 @@ public partial class HashUtil(RandomUtil _randomUtil)
throw new NotImplementedException($"Provided hash algorithm: {algorithm} is not supported."); throw new NotImplementedException($"Provided hash algorithm: {algorithm} is not supported.");
} }
/// <summary>
/// Create a hash for the data parameter asynchronously
/// </summary>
/// <param name="algorithm">algorithm to use to hash</param>
/// <param name="data">data to be hashed</param>
/// <returns>A task which contains the hash value</returns>
/// <exception cref="NotImplementedException">thrown if the provided algorithm is not implemented</exception>
/// >
public async Task<string> GenerateHashForDataAsync(HashingAlgorithm algorithm, string data)
{
switch (algorithm)
{
case HashingAlgorithm.MD5:
{
await using var ms = new MemoryStream(Encoding.UTF8.GetBytes(data));
var md5HashData = await MD5.HashDataAsync(ms);
return Convert.ToHexString(md5HashData).Replace("-", string.Empty);
}
case HashingAlgorithm.SHA1:
{
await using var ms = new MemoryStream(Encoding.UTF8.GetBytes(data));
var sha1HashData = await SHA1.HashDataAsync(ms);
return Convert.ToHexString(sha1HashData).Replace("-", string.Empty);
}
}
throw new NotImplementedException($"Provided hash algorithm: {algorithm} is not supported.");
}
/// <summary> /// <summary>
/// Generates an account ID for a profile /// Generates an account ID for a profile
/// </summary> /// </summary>
+1 -1
View File
@@ -62,7 +62,7 @@ public class HashUtilTests
[DataRow("123456789", "25F9E794323B453885F5181F1B624D0B", "Not valid output, expected '25F9E794323B453885F5181F1B624D0B'")] [DataRow("123456789", "25F9E794323B453885F5181F1B624D0B", "Not valid output, expected '25F9E794323B453885F5181F1B624D0B'")]
public void GenerateValidMd5Test(string input, string expectedOutput, string failMessage) public void GenerateValidMd5Test(string input, string expectedOutput, string failMessage)
{ {
var result = _hashUtil.GenerateMd5ForData(input); var result = _hashUtil.GenerateHashForData(HashingAlgorithm.MD5,input);
Assert.AreEqual( Assert.AreEqual(
expectedOutput, expectedOutput,
result, result,