UnitTests/SandbankTest.cs
using Sandbox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static TestClasses;
namespace SandbankDatabase;
[TestClass]
public partial class SandbankTest
{
[TestInitialize]
public void Initialise()
{
InitialisationController.Initialise();
}
[TestCleanup]
public void Cleanup()
{
ConfigController.OBFUSCATE_FILES = false;
Sandbank.DeleteAllData();
Sandbank.Shutdown().GetAwaiter().GetResult();
}
[TestMethod]
public void TextObfuscationWorks()
{
var text = Obfuscation.ObfuscateFileText( "Wow! I love bacon! 豚肉が美味しい!" );
text = Obfuscation.UnobfuscateFileText( text );
Assert.AreEqual( "Wow! I love bacon! 豚肉が美味しい!", text );
}
[TestMethod]
public void TextObfuscationWorks_WithRealisticExample()
{
var original = @"{
""UID"": ""76561197997412036"",
""Health"": 100,
""BankBalance"": 0,
""Cash"": 10000,
""LastOnline"": ""2024-09-08T02:40:07.3391207\u002B01:00"",
""PlayerName"": ""anthonysharpy"",
""JumpCount"": 0,
""LivingThingsKilledCount"": 0,
""Achievements"": [],
""Hunger"": 100,
""EnduranceSkillLevel"": 0,
""EnduranceSkillLastDeterioratedTime"": 0,
""CompletedQuests"": [],
""StoredItems"": [
{
""Rarity"": 1,
""BackgroundColour"": ""0.9071,0.79477,0.33716,0.3"",
""UniqueID"": ""a70f35fa-cbdf-420e-9523-efce79e9c4c1"",
""XPos"": -1,
""YPos"": -1,
""Durability"": 100,
""Price"": 0,
""ItemName"": ""Fists"",
""PickupDisabled"": false,
""AmmoInClip"": 0
},
{
""Rarity"": 1,
""BackgroundColour"": ""0.61983,0.48797,0.19491,0.3"",
""UniqueID"": ""51becde0-ab0d-4103-b0d0-689eecfc5e00"",
""XPos"": -1,
""YPos"": -1,
""Durability"": 100,
""Price"": 0,
""ItemName"": ""Item Placer"",
""PickupDisabled"": false,
""AmmoInClip"": 0
},
{
""Rarity"": 3,
""BackgroundColour"": ""0.15048,0.9476,0.72171,0.3"",
""UniqueID"": ""8a73055a-ae58-4759-9172-afeb5d73de61"",
""XPos"": 0,
""YPos"": 0,
""Durability"": 100,
""Price"": 0,
""ItemName"": ""Grenade"",
""PickupDisabled"": false,
""AmmoInClip"": 0
},
{
""Rarity"": 3,
""BackgroundColour"": ""0.78122,0.13411,0.26792,0.3"",
""UniqueID"": ""f859ae80-e14b-43f9-af88-3887635efc63"",
""XPos"": 1,
""YPos"": 0,
""Durability"": 100,
""Price"": 0,
""ItemName"": ""Grenade"",
""PickupDisabled"": false,
""AmmoInClip"": 0
},
{
""Rarity"": 3,
""BackgroundColour"": ""0.30573,0.77256,0.48727,0.3"",
""UniqueID"": ""cbe5b32d-7afb-4b09-98c5-0b1eec6688bb"",
""XPos"": 2,
""YPos"": 0,
""Durability"": 100,
""Price"": 0,
""ItemName"": ""MP5"",
""PickupDisabled"": false,
""AmmoInClip"": 0
},
{
""Rarity"": 3,
""BackgroundColour"": ""0.57136,0.81519,0.96548,0.3"",
""UniqueID"": ""dbe6f248-7eae-4e58-9ce4-800b6e73721b"",
""XPos"": 6,
""YPos"": 0,
""Durability"": 100,
""Price"": 0,
""ItemName"": ""Grenade"",
""PickupDisabled"": false,
""AmmoInClip"": 0
},
{
""Rarity"": 3,
""BackgroundColour"": ""0.17717,0.17827,0.75903,0.3"",
""UniqueID"": ""e6aa5962-c1bf-4326-b22e-1edee07f2d98"",
""XPos"": 0,
""YPos"": 1,
""Durability"": 100,
""Price"": 0,
""ItemName"": ""Grenade"",
""PickupDisabled"": false,
""AmmoInClip"": 0
},
{
""Rarity"": 3,
""BackgroundColour"": ""0.97016,0.52173,0.33395,0.3"",
""UniqueID"": ""2531c680-e2c5-49ad-aa88-b86446e518ea"",
""XPos"": 1,
""YPos"": 1,
""Durability"": 100,
""Price"": 0,
""ItemName"": ""Ammo"",
""PickupDisabled"": false,
""AmmoInClip"": 0
},
{
""Rarity"": 3,
""BackgroundColour"": ""0.87892,0.43858,0.34768,0.3"",
""UniqueID"": ""b2a04888-e0da-4d16-a877-89ca0e201e4d"",
""XPos"": 6,
""YPos"": 1,
""Durability"": 100,
""Price"": 0,
""ItemName"": ""Ammo"",
""PickupDisabled"": false,
""AmmoInClip"": 0
},
{
""Rarity"": 3,
""BackgroundColour"": ""0.04801,0.02349,0.17021,0.3"",
""UniqueID"": ""4f484a7c-d7b7-4df7-9557-cbce6188d3f9"",
""XPos"": 0,
""YPos"": 2,
""Durability"": 100,
""Price"": 0,
""ItemName"": ""Grenade"",
""PickupDisabled"": false,
""AmmoInClip"": 0
}
],
""EquippedItemID"": ""30cf9992-1c8e-4330-b79c-090681fcbeeb"",
""CurrentlyEquippedSlot"": -1,
""CurrentlyEquippedSlotIndex"": 0,
""Stamina"": 100
}";
var text = Obfuscation.ObfuscateFileText( original );
text = Obfuscation.UnobfuscateFileText( text );
Assert.AreEqual( original, text );
}
[TestMethod]
public void SelectingUnitialisedCollectionReturnsEmptyList()
{
var results = Sandbank.Select<TestClasses.ReadmeExample>( "players", x => x.Health == 50 );
Assert.AreEqual( 0, results.Count );
}
[TestMethod]
public void NullUIDWorks()
{
var document = new TestClasses.NullUIDClass();
Sandbank.Insert( "nulluidtest", document );
Assert.AreEqual( 32, document.UID.Length );
}
[TestMethod]
public void NoUIDThrowsException()
{
var document = new TestClasses.NoUIDClass();
var e = Assert.ThrowsException<SandbankException>( () => Sandbank.Insert( "nouidtest", document ) );
Assert.AreEqual( $"cannot handle a document without a \"UID\" property - make sure your data " +
"class has a public property called UID, like this: \"[Saved] public string UID { get; set; }\"", e.Message );
}
[TestMethod]
public void CantPutDifferentClassTypesInSameCollection()
{
var document1 = new TestClasses.ValidClass1();
Sandbank.Insert( "test2", document1 );
var document2 = new TestClasses.ValidClass2();
var e = Assert.ThrowsException<SandbankException>( () => Sandbank.Insert( "test2", document2 ) );
Assert.AreEqual( "there is no registered instance pool for the type TestClasses+ValidClass2 - " +
"are you using the wrong class type for this collection?", e.Message );
}
[TestMethod]
public void CopySavedData()
{
var document1 = new ClassWithNonSavedProperty();
document1.Health = 50;
document1.Name = "Steve";
var document2 = new ClassWithNonSavedProperty();
Assert.AreEqual( 0, document2.Health );
Assert.AreEqual( null, document2.Name );
Sandbank.CopySavedData<ClassWithNonSavedProperty>( document1, document2 );
Assert.AreEqual( 50, document2.Health );
Assert.AreEqual( null, document2.Name );
}
[TestMethod]
public void CopySavedData_WorksForAutoSavedProperties()
{
var document1 = new AutoSavedReadmeExample();
document1.Health = 50;
document1.Name = "Steve";
document1.UID = "blahblah";
document1.Items = new List<string>{ "banana", "gun", "shoe" };
var document2 = new AutoSavedReadmeExample();
Assert.AreEqual( 0, document2.Health );
Assert.AreEqual( null, document2.Name );
Assert.AreEqual( null, document2.UID );
Assert.AreEqual( 0, document2.Items.Count );
Sandbank.CopySavedData<AutoSavedReadmeExample>( document1, document2 );
Assert.AreEqual( 50, document2.Health );
Assert.AreEqual( "Steve", document2.Name );
Assert.AreEqual( "blahblah", document2.UID );
Assert.AreEqual( 3, document2.Items.Count );
}
[TestMethod]
public void CantGetDifferentClassTypesFromSameCollection()
{
var document1 = new TestClasses.ValidClass1();
document1.Health = 50;
Sandbank.Insert( "test3", document1 );
var e = Assert.ThrowsException<InvalidCastException>(
() => Sandbank.SelectOneWithID<TestClasses.ValidClass1Copy>( "test3", document1.UID ) );
Assert.AreEqual( "Unable to cast object of type 'ValidClass1' to type 'ValidClass1Copy'.",
e.Message );
}
[TestMethod]
public void ReadmeExampleWorks()
{
var readmeExample = new TestClasses.ReadmeExample();
Assert.AreEqual( null, readmeExample.UID );
readmeExample.Health = 100;
readmeExample.Name = "Bob";
Sandbank.Insert( "players", readmeExample );
Assert.AreEqual( 32, readmeExample.UID.Length );
var playerWith100Health = Sandbank.SelectOne<TestClasses.ReadmeExample>( "players",
x => x.Health == 100 );
Assert.AreEqual( "Bob", playerWith100Health.Name );
Sandbank.DeleteWithID<TestClasses.ReadmeExample>( "players", playerWith100Health.UID );
}
[TestMethod]
public void AutoSavedWorks()
{
var data = new AutoSavedReadmeExample();
data.Health = 57;
data.UID = "91246385";
// Mock all this since codegen doesn't seem to work during tests.
var property = new Sandbox.WrappedPropertySet<float>()
{
Setter = ( float value ) => data.Health = value,
Value = 57,
Object = data,
PropertyName = "Health",
Attributes = new Attribute[]
{
new AutoSaved("example")
}
};
SandbankAutoSavedEventHandler.AutoSave( property );
var fetchedData = Sandbank.Select<AutoSavedReadmeExample>( "example", x => x.Health == 57 );
Assert.AreEqual( 1, fetchedData.Count );
Assert.AreEqual( 8, fetchedData[0].UID.Length );
}
[TestMethod]
public void SavingAndLoadingWorksWithObfuscation()
{
ConfigController.OBFUSCATE_FILES = true;
var readmeExample = new TestClasses.ReadmeExample();
Assert.AreEqual( null, readmeExample.UID );
readmeExample.Health = 100;
readmeExample.Name = "Bob";
Sandbank.Insert( "players", readmeExample );
Assert.AreEqual( 32, readmeExample.UID.Length );
var playerWith100Health = Sandbank.SelectOne<TestClasses.ReadmeExample>( "players",
x => x.Health == 100 );
Assert.AreEqual( "Bob", playerWith100Health.Name );
Sandbank.DeleteWithID<TestClasses.ReadmeExample>( "players", playerWith100Health.UID );
}
[TestMethod]
public void DatabaseWorksWithoutInitialisation()
{
var readmeExample = new TestClasses.ReadmeExample();
Assert.AreEqual( null, readmeExample.UID );
readmeExample.Health = 100;
readmeExample.Name = "Bob";
Sandbank.Insert( "players", readmeExample );
Assert.AreEqual( 32, readmeExample.UID.Length );
var playerWith100Health = Sandbank.SelectOne<TestClasses.ReadmeExample>( "players",
x => x.Health == 100 );
Assert.AreEqual( "Bob", playerWith100Health.Name );
Sandbank.DeleteWithID<TestClasses.ReadmeExample>( "players", playerWith100Health.UID );
}
[TestMethod]
public void SelectUnsafeReferences_DocumentDoesntChangeAfterNewInsert()
{
var document1 = new TestClasses.ValidClass1();
document1.Health = 70;
Sandbank.Insert( "players", document1 );
var unsafeDocument = Sandbank.SelectUnsafeReferences<TestClasses.ValidClass1>("players",
x => x.Health == 70 ).First();
var safeDocument = Sandbank.SelectOne<TestClasses.ValidClass1>( "players",
x => x.Health == 70 );
safeDocument.Health = 80;
Sandbank.Insert( "players", safeDocument );
Assert.AreEqual( unsafeDocument.Health, 70 );
}
[TestMethod]
public void TestInsertAndSelectOne()
{
Sandbank.Insert<ReadmeExample>( "players", TestData.TestData1 );
Assert.IsFalse( TestData.TestData1.UID.Length <= 10 );
var data = Sandbank.SelectOne<ReadmeExample>( "players", x => x.UID == TestData.TestData1.UID );
Assert.IsFalse( data.Name != TestData.TestData1.Name );
}
[TestMethod]
public void TestInsertManyAndSelect()
{
var players = new List<ReadmeExample>{ TestData.TestData1, TestData.TestData2 };
Sandbank.InsertMany<ReadmeExample>( "players", players );
Assert.IsFalse( players[0].UID.Length <= 10 );
Assert.IsFalse( players[1].UID.Length <= 10 );
var data = Sandbank.Select<ReadmeExample>( "players", x => true );
Assert.IsFalse( data[0].Name != TestData.TestData1.Name && data[0].Name != TestData.TestData2.Name );
Assert.IsFalse( data[1].Name != TestData.TestData1.Name && data[1].Name != TestData.TestData2.Name );
}
[TestMethod]
public void TestSelectOneWithID()
{
Sandbank.Insert<ReadmeExample>( "players", TestData.TestData1 );
Assert.IsFalse( TestData.TestData1.UID.Length <= 10 );
var data = Sandbank.SelectOneWithID<ReadmeExample>( "players", TestData.TestData1.UID );
Assert.IsFalse( data?.Name != TestData.TestData1.Name );
}
[TestMethod]
public void TestDelete()
{
Sandbank.Insert<ReadmeExample>( "players", TestData.TestData1 );
Sandbank.Delete<ReadmeExample>( "players", x => x.UID == TestData.TestData1.UID );
var data = Sandbank.SelectOneWithID<ReadmeExample>( "players", TestData.TestData1.UID );
Assert.IsFalse( data != null );
}
/// <summary>
/// Ensure that when we receive an object from the database, modifying it doesn't
/// also modify the cache.
/// </summary>
[TestMethod]
public void TestReferenceDoesntModifyCache()
{
Sandbank.Insert<ReadmeExample>( "players", TestData.TestData1 );
var data = Sandbank.SelectOneWithID<ReadmeExample>( "players", TestData.TestData1.UID );
data.Level = 999;
data = Sandbank.SelectOneWithID<ReadmeExample>( "players", TestData.TestData1.UID );
Assert.IsFalse( data.Level == 999 );
}
[TestMethod]
public void AutoSavedWorks_MultiThreaded()
{
var objects = new List<AutoSavedReadmeExample>();
for (int i = 0; i < 10; i++ )
{
var data = new AutoSavedReadmeExample();
data.Health = 57;
data.UID = $"siffhdfdgf{i}";
objects.Add( data );
}
var tasks = new List<Task>();
// Make sure there's at least one auto save of each item.
for ( int i = 0; i < 10; i++ )
{
var item = objects[i];
tasks.Add( Task.Run( () =>
{
var property = new Sandbox.WrappedPropertySet<float>()
{
Setter = ( float value ) => item.Health = value,
Value = 57,
Object = item,
PropertyName = "Health",
Attributes = new Attribute[]
{
new AutoSaved("example")
}
};
SandbankAutoSavedEventHandler.AutoSave( property );
} ) );
}
for ( int i = 0; i < 1000; i++ )
{
var item = objects[Random.Shared.Int( 0, 9 )];
tasks.Add( Task.Run( () =>
{
var property = new Sandbox.WrappedPropertySet<float>()
{
Setter = ( float value ) => item.Health = value,
Value = 57,
Object = item,
PropertyName = "Health",
Attributes = new Attribute[]
{
new AutoSaved("example")
}
};
SandbankAutoSavedEventHandler.AutoSave( property );
} ) );
}
Task.WaitAll( tasks.ToArray() );
var fetchedData = Sandbank.Select<AutoSavedReadmeExample>( "example", x => x.Health == 57 );
Assert.AreEqual( 10, fetchedData.Count );
}
[TestMethod]
public void TestSpammingShutdownAndInitialise_DoesntCorruptData()
{
const int documents = 100;
Sandbank.Insert<ReadmeExample>( "players", new ReadmeExample()
{
UID = "",
Health = 100,
Name = "TestPlayer1",
Level = 10,
LastPlayTime = DateTime.UtcNow,
Items = new() { "gun", "frog", "banana" }
} );
// Warm the pool up to avoid console spam about not being able to load objects from the pool.
Task.Delay( 4000 ).GetAwaiter().GetResult();
var data = new List<ReadmeExample>();
for ( int i = 0; i < documents - 1; i++ )
{
data.Add( new ReadmeExample()
{
UID = "",
Health = 100,
Name = "TestPlayer1",
Level = 10,
LastPlayTime = DateTime.UtcNow,
Items = new() { "gun", "frog", "banana" }
} );
}
Sandbank.InsertMany<ReadmeExample>( "players", data );
Assert.AreEqual( documents, Sandbank.Select<ReadmeExample>( "players", x => x.Health == 100 ).Count() );
var tasks = new List<Task>();
for ( int i = 0; i < 100; i++ )
{
tasks.Add( Task.Run( InitialisationController.Initialise ) );
tasks.Add( Task.Run( Sandbank.Shutdown ) );
}
Task.WaitAll( tasks.ToArray() );
InitialisationController.Initialise();
Assert.AreEqual( documents, Sandbank.Select<ReadmeExample>( "players", x => x.Health == 100 ).Count() );
}
[TestMethod]
public void TestChangingTypeDefinition_DoesntLoseData()
{
Cache.DisableCacheWriting();
var document = new ReadmeExample()
{
UID = "",
Health = 100,
Name = "TestPlayer1",
Level = 10,
Items = new() { "gun", "frog", "banana" }
};
Sandbank.Insert<ReadmeExample>( "players", document );
var playerDocument = Sandbank.SelectOneWithID<ReadmeExample>( "players", document.UID );
Assert.AreEqual( 100, playerDocument.Health );
Assert.AreEqual( "TestPlayer1", playerDocument.Name );
Assert.AreEqual( 10, playerDocument.Level );
Assert.AreEqual( "gun", playerDocument.Items[0] );
Assert.AreEqual( "frog", playerDocument.Items[1] );
Assert.AreEqual( "banana", playerDocument.Items[2] );
// Force write this so we have it saved to file.
Cache.ForceFullWrite();
// Let's wipe the cache to remove any trace of this class, this will stop the data being
// written to disk when we shutdown the database in a moment.
Cache.WipeCaches();
// Overwrite with a document with different fields. We are checking that the other
// fields are not lost.
var smallerDocument = new ReadmeExampleWithFewerFields()
{
UID = document.UID,
Health = 50,
};
var ovewriteDocument =
new Document( smallerDocument, typeof(ReadmeExampleWithFewerFields), false, "players" );
// Now overwrite the data.
FileController.SaveDocument( ovewriteDocument );
// Shutdown in order to fully clear and re-fetch data and caches.
Sandbank.Shutdown().GetAwaiter().GetResult();
InitialisationController.Initialise();
// Now load the data using the original type - all the other data should be there, other
// than the changed health which was overwritten.
var finalDocument = Sandbank.SelectOneWithID<ReadmeExample>( "players", document.UID );
Assert.AreEqual( 50, finalDocument.Health );
Assert.AreEqual( "TestPlayer1", finalDocument.Name );
Assert.AreEqual( 10, finalDocument.Level );
Assert.AreEqual( "gun", finalDocument.Items[0] );
Assert.AreEqual( "frog", finalDocument.Items[1] );
Assert.AreEqual( "banana", finalDocument.Items[2] );
}
[TestMethod]
public void TestRestartingDatabase_DoesntCorruptData()
{
const int documents = 100;
Sandbank.Insert<ReadmeExample>( "players", new ReadmeExample()
{
UID = "",
Health = 100,
Name = "TestPlayer1",
Level = 10,
LastPlayTime = DateTime.UtcNow,
Items = new() { "gun", "frog", "banana" }
} );
// Warm the pool up to avoid console spam about not being able to load objects from the pool.
Task.Delay( 4000 ).GetAwaiter().GetResult();
var data = new List<ReadmeExample>();
for ( int i = 0; i < documents - 1; i++ )
{
data.Add( new ReadmeExample()
{
UID = "",
Health = 100,
Name = "TestPlayer1",
Level = 10,
LastPlayTime = DateTime.UtcNow,
Items = new() { "gun", "frog", "banana" }
} );
}
Sandbank.InsertMany<ReadmeExample>( "players", data );
Assert.AreEqual( documents, Sandbank.Select<ReadmeExample>( "players", x => x.Health == 100 ).Count() );
Sandbank.Shutdown().GetAwaiter().GetResult();
InitialisationController.Initialise();
Assert.AreEqual( documents, Sandbank.Select<ReadmeExample>( "players", x => x.Health == 100 ).Count() );
}
[TestMethod]
public void TestDeleteWithID()
{
Sandbank.Insert<ReadmeExample>( "players", TestData.TestData1 );
Sandbank.DeleteWithID<ReadmeExample>( "players", TestData.TestData1.UID );
var data = Sandbank.SelectOneWithID<ReadmeExample>( "players", TestData.TestData1.UID );
Assert.IsFalse( data != null );
}
[TestMethod]
public void TestAny()
{
Sandbank.Insert<ReadmeExample>( "players", TestData.TestData1 );
Assert.IsFalse( !Sandbank.Any<ReadmeExample>( "players", x => x.Level == TestData.TestData1.Level ) );
}
[TestMethod]
public void TestAnyWithID()
{
Sandbank.Insert<ReadmeExample>( "players", TestData.TestData1 );
Assert.IsFalse( !Sandbank.AnyWithID<ReadmeExample>( "players", TestData.TestData1.UID ) );
}
[TestMethod]
public void TestShutdown()
{
TestData.TestData1.UID = "";
Sandbank.Insert<ReadmeExample>( "players", TestData.TestData1 );
var collection = Cache.GetCollectionByName<ReadmeExample>( "players", false );
Assert.AreEqual( 1, Cache.GetDocumentsAwaitingWriteCount() );
Sandbank.Shutdown().GetAwaiter().GetResult();
Assert.AreEqual( 0, Cache.GetDocumentsAwaitingWriteCount() );
}
[TestMethod]
public void TestConcurrencySafety()
{
List<Task> tasks = new();
for ( int i = 0; i < 10; i++ )
{
tasks.Add( Task.Run( () =>
{
var data = new ReadmeExample()
{
UID = "",
Health = Game.Random.Next( 101 ),
Name = "TestPlayer1",
Level = 10,
LastPlayTime = DateTime.UtcNow,
Items = new() { "gun", "frog", "banana" }
};
Sandbank.InsertMany<ReadmeExample>( "players", new ReadmeExample[] { data, data, data, data } );
Sandbank.Insert<ReadmeExample>( "players", data );
var results = Sandbank.Select<ReadmeExample>( "players", x => x.Health > 90 );
if ( results.Count > 0 )
{
Sandbank.SelectOneWithID<ReadmeExample>( "players", results[0].UID );
Sandbank.DeleteWithID<ReadmeExample>( "players", results[0].UID );
}
Sandbank.Delete<ReadmeExample>( "players", x => x.Health <= 20 );
Sandbank.Any<ReadmeExample>( "players", x => x.Name == "Tim" );
} ) );
}
Task.WaitAll( tasks.ToArray() );
}
[TestMethod]
public void TestConcurrencySafety2()
{
List<Task> tasks = new();
List<ReadmeExample> loadsOfData = new();
for ( int i = 0; i < 10000; i++ )
{
loadsOfData.Add( new ReadmeExample()
{
UID = "",
Health = 100,
Name = "TestPlayer",
Level = Game.Random.Next( 10 ),
LastPlayTime = DateTime.UtcNow,
Items = new() { "gun", "frog", "banana" }
} );
}
for ( int i = 0; i < 10; i++ )
{
tasks.Add( Task.Run( () =>
{
for ( int j = 0; j < 10000; j++ )
{
var data = new ReadmeExample()
{
UID = "",
Health = 100,
Name = "TestPlayer",
Level = 10,
LastPlayTime = DateTime.UtcNow,
Items = new() { "gun", "frog", "banana" }
};
Sandbank.Insert<ReadmeExample>( "players", data );
Sandbank.Insert<ReadmeExample>( "players_two", data );
}
} ) );
tasks.Add( Task.Run( () =>
{
Sandbank.InsertMany<ReadmeExample>( "players", loadsOfData );
Sandbank.InsertMany<ReadmeExample>( "players_two", loadsOfData );
} ) );
tasks.Add( Task.Run( () =>
{
Sandbank.Select<ReadmeExample>( "players", x => x.Health == 100 );
Sandbank.Select<ReadmeExample>( "players_two", x => x.Name == "TestPlayer" );
} ) );
tasks.Add( Task.Run( () =>
{
Sandbank.Delete<ReadmeExample>( "players", x => x.Level == 5 || x.Level == 2 );
Sandbank.Delete<ReadmeExample>( "players_two", x => x.Level == 5 || x.Level == 2 );
} ) );
}
Task.WaitAll( tasks.ToArray() );
}
[TestMethod]
public void TestConcurrencySafety_SpamCollections()
{
List<Task> tasks = new();
List<ReadmeExample> loadsOfData = new();
for ( int i = 0; i < 100; i++ )
{
loadsOfData.Add( new ReadmeExample()
{
UID = "",
Health = 100,
Name = "TestPlayer",
Level = Game.Random.Next( 10 ),
LastPlayTime = DateTime.UtcNow,
Items = new() { "gun", "frog", "banana" }
} );
}
for ( int x = 0; x < 10; x++ )
{
for ( int i = 0; i < 100; i++ )
{
string collection = "collection" + i;
tasks.Add( Task.Run( () =>
{
for ( int i = 0; i < 100; i++ )
{
Sandbank.Insert<ReadmeExample>( collection, loadsOfData[i] );
}
} ) );
tasks.Add( Task.Run( () =>
{
Sandbank.Delete<ReadmeExample>( collection, x => x.Level == 5 || x.Level == 2 );
} ) );
}
}
Task.WaitAll( tasks.ToArray() );
}
}