2026-09-15 22:51:33 +02:00
using Microsoft.Data.Sqlite ;
using VoiceCat.Server.Data ;
2026-09-22 16:54:49 +02:00
using Voicecat.V1 ;
2026-09-15 22:51:33 +02:00
namespace VoiceCat.Tests ;
public sealed class AccountStoreTests
{
[Fact]
public void UnsupportedSchemaIsRejectedWithoutCreatingAccountTables ()
{
string path = Path . Combine ( Path . GetTempPath (), "voicecat-future-" + Guid . NewGuid (). ToString ( "N" ) + ".db" );
try
{
SQLitePCL . Batteries_V2 . Init ();
using var connection = new SqliteConnection ( new SqliteConnectionStringBuilder { DataSource = path , Pooling = false }. ToString ());
connection . Open ();
using var command = connection . CreateCommand ();
command . CommandText = "CREATE TABLE server_meta (key TEXT PRIMARY KEY,value TEXT NOT NULL); INSERT INTO server_meta VALUES ('schema_version','99');" ;
command . ExecuteNonQuery ();
Assert . Throws < InvalidDataException >(() => new AccountStore ( path ));
command . CommandText = "SELECT COUNT(*) FROM sqlite_master WHERE name='accounts'" ;
Assert . Equal ( 0L , command . ExecuteScalar ());
command . CommandText = "SELECT value FROM server_meta WHERE key='schema_version'" ;
Assert . Equal ( "99" , command . ExecuteScalar ());
}
finally { File . Delete ( path ); File . Delete ( path + "-wal" ); File . Delete ( path + "-shm" ); }
}
[Fact]
public async Task AccountsSurviveRestartAndFailedAuthDoesNotChangeLastLogin ()
{
string directory = Path . Combine ( Path . GetTempPath (), "voicecat-db-" + Guid . NewGuid (). ToString ( "N" ));
Directory . CreateDirectory ( directory );
string path = Path . Combine ( directory , "voicecat.db" );
try
{
Account account ;
using ( var store = new AccountStore ( path )) account = await store . CreateAccountAsync ( "admin'" , "secret" , true );
using ( var store = new AccountStore ( path ))
{
Assert . Null ( await store . AuthenticateAsync ( "admin'" , "wrong" ));
Assert . Null ( await store . AuthenticateAsync ( "missing" , "secret" ));
using var connection = new SqliteConnection ( new SqliteConnectionStringBuilder { DataSource = path , Pooling = false }. ToString ());
connection . Open ();
using var command = connection . CreateCommand ();
command . CommandText = "SELECT last_login FROM accounts WHERE id=$id" ;
command . Parameters . AddWithValue ( "$id" , account . Id );
Assert . Equal ( 0L , command . ExecuteScalar ());
Account authenticated = Assert . IsType < Account >( await store . AuthenticateAsync ( "admin'" , "secret" ));
Assert . Equal ( account . Id , authenticated . Id );
Assert . True ( authenticated . IsAdmin );
Assert . True ( authenticated . LastLogin > 0 );
}
}
finally { Directory . Delete ( directory , true ); }
}
2026-09-22 14:11:36 +02:00
[Fact]
2026-09-22 16:54:49 +02:00
public void VersionTwoDatabaseMigratesDredAndAdaptiveLossAsDisabled ()
2026-09-22 14:11:36 +02:00
{
string directory = Path . Combine ( Path . GetTempPath (), "voicecat-v2-" + Guid . NewGuid (). ToString ( "N" ));
Directory . CreateDirectory ( directory );
string path = Path . Combine ( directory , "voicecat.db" );
try
{
using ( var store = new AccountStore ( path )) store . LoadChannels ();
using ( var connection = new SqliteConnection ( new SqliteConnectionStringBuilder { DataSource = path , Pooling = false }. ToString ()))
{
connection . Open ();
using var command = connection . CreateCommand ();
2026-09-22 16:54:49 +02:00
command . CommandText = "ALTER TABLE channels DROP COLUMN audio_dred; ALTER TABLE channels DROP COLUMN audio_packet_loss_mode; UPDATE server_meta SET value='2' WHERE key='schema_version';" ;
2026-09-22 14:11:36 +02:00
command . ExecuteNonQuery ();
}
using ( var migrated = new AccountStore ( path ))
2026-09-22 16:54:49 +02:00
Assert . All ( migrated . LoadChannels (), channel =>
{
Assert . False ( channel . Audio . Dred );
Assert . Equal ( PacketLossMode . PacketLossManual , channel . Audio . PacketLossMode );
});
2026-09-22 14:11:36 +02:00
using var verify = new SqliteConnection ( new SqliteConnectionStringBuilder { DataSource = path , Pooling = false }. ToString ());
verify . Open ();
using var query = verify . CreateCommand ();
query . CommandText = "SELECT value FROM server_meta WHERE key='schema_version'" ;
2026-09-22 16:54:49 +02:00
Assert . Equal ( "4" , query . ExecuteScalar ());
2026-09-22 14:11:36 +02:00
}
finally { Directory . Delete ( directory , true ); }
}
2026-09-15 22:51:33 +02:00
}