Files
speckle-sharp-sdk/tests/Speckle.Core.Tests.Unit/Transports/SQLiteTransportTests.cs
T
Adam Hathcock 2269182922 fmt
2024-06-21 12:33:55 +01:00

164 lines
4.6 KiB
C#

using Microsoft.Data.Sqlite;
using NUnit.Framework;
using Speckle.Core.Common;
using Speckle.Core.Transports;
namespace Speckle.Core.Tests.Unit.Transports;
[TestFixture]
[TestOf(nameof(SQLiteTransport))]
public sealed class SQLiteTransportTests : TransportTests, IDisposable
{
protected override ITransport? Sut => _sqlite;
private SQLiteTransport? _sqlite;
private static readonly string s_basePath = $"./temp {Guid.NewGuid()}";
private const string APPLICATION_NAME = "Speckle Integration Tests";
[SetUp]
public void Setup()
{
_sqlite = new SQLiteTransport(s_basePath, APPLICATION_NAME);
}
[TearDown]
public void TearDown()
{
_sqlite?.Dispose();
SqliteConnection.ClearAllPools();
Directory.Delete(s_basePath, true);
_sqlite = null;
}
[Test]
public void DbCreated_AfterInitialization()
{
bool fileExists = File.Exists($"{s_basePath}/{APPLICATION_NAME}/Data.db");
Assert.That(fileExists, Is.True);
}
[Test]
[Description("Tests that an object can be updated")]
public async Task UpdateObject_AfterAdd()
{
const string PAYLOAD_ID = "MyTestObjectId";
const string PAYLOAD_DATA = "MyTestObjectData";
_sqlite.NotNull().SaveObject(PAYLOAD_ID, PAYLOAD_DATA);
await _sqlite.WriteComplete();
const string NEW_PAYLOAD = "MyEvenBetterObjectData";
_sqlite.UpdateObject(PAYLOAD_ID, NEW_PAYLOAD);
await _sqlite.WriteComplete();
var result = _sqlite.GetObject(PAYLOAD_ID);
Assert.That(result, Is.EqualTo(NEW_PAYLOAD));
}
[Test]
[Description("Tests that updating an object that hasn't been saved previously adds the object to the DB")]
public async Task UpdateObject_WhenMissing()
{
const string PAYLOAD_ID = "MyTestObjectId";
const string PAYLOAD_DATA = "MyTestObjectData";
var preUpdate = _sqlite.NotNull().GetObject(PAYLOAD_ID);
Assert.That(preUpdate, Is.Null);
_sqlite.UpdateObject(PAYLOAD_ID, PAYLOAD_DATA);
await _sqlite.WriteComplete();
var postUpdate = _sqlite.GetObject(PAYLOAD_ID);
Assert.That(postUpdate, Is.EqualTo(PAYLOAD_DATA));
}
[Test]
public void SaveAndRetrieveObject_Sync()
{
const string PAYLOAD_ID = "MyTestObjectId";
const string PAYLOAD_DATA = "MyTestObjectData";
var preAdd = Sut.NotNull().GetObject(PAYLOAD_ID);
Assert.That(preAdd, Is.Null);
_sqlite.NotNull().SaveObjectSync(PAYLOAD_ID, PAYLOAD_DATA);
{
var postAdd = Sut.GetObject(PAYLOAD_ID);
Assert.That(postAdd, Is.EqualTo(PAYLOAD_DATA));
}
}
[Test(
Description = "Tests that it is possible to enumerate through all objects of the transport while updating them, without getting stuck in an infinite loop"
)]
[Timeout(1000)]
public void UpdateObject_WhileEnumerating()
{
//I question if this is the behaviour we want, but AccountManager.GetObjects is relying on being able to update objects while enumerating over them
const string UPDATE_STRING = "_new";
Dictionary<string, string> testData =
new()
{
{ "a", "This is object a" },
{ "b", "This is object b" },
{ "c", "This is object c" },
{ "d", "This is object d" }
};
int length = testData.Values.First().Length;
foreach (var (key, data) in testData)
{
_sqlite.NotNull().SaveObjectSync(key, data);
}
foreach (var o in _sqlite.NotNull().GetAllObjects())
{
string newData = o + UPDATE_STRING;
string key = $"{o[length - 1]}";
_sqlite.UpdateObject(key, newData);
}
//Assert that objects were updated
Assert.That(_sqlite.GetAllObjects().ToList(), Has.All.Contains(UPDATE_STRING));
//Assert that objects were only updated once
Assert.That(_sqlite.GetAllObjects().ToList(), Has.All.Length.EqualTo(length + UPDATE_STRING.Length));
}
[Test]
[Repeat(10)]
[TestCase(6, 32)]
[Description(
$"Tests that the {nameof(SQLiteTransport.GetAllObjects)} function can be called concurrently from multiple threads"
)]
public void GetAllObjects_IsThreadSafe(int dataSize, int parallelism)
{
foreach (int i in Enumerable.Range(0, dataSize))
{
_sqlite.NotNull().SaveObjectSync(i.ToString(), Guid.NewGuid().ToString());
}
List<string>[] results = new List<string>[parallelism];
Parallel.ForEach(
Enumerable.Range(0, parallelism),
i =>
{
results[i] = _sqlite.NotNull().GetAllObjects().ToList();
}
);
foreach (var result in results)
{
Assert.That(result, Is.EquivalentTo(results[0]));
Assert.That(result, Has.Count.EqualTo(dataSize));
}
}
public void Dispose()
{
_sqlite?.Dispose();
}
}