From b853403c3b2f44c618250fbaac28af2697c8f0b4 Mon Sep 17 00:00:00 2001 From: boufni95 Date: Tue, 11 Mar 2025 21:05:03 +0000 Subject: [PATCH] storage tests --- src/tests/spamMixedPayments.spec.ts | 4 +- src/tests/testStorage.spec.ts | 163 ++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 src/tests/testStorage.spec.ts diff --git a/src/tests/spamMixedPayments.spec.ts b/src/tests/spamMixedPayments.spec.ts index 2fefa08a..4851ab2c 100644 --- a/src/tests/spamMixedPayments.spec.ts +++ b/src/tests/spamMixedPayments.spec.ts @@ -48,6 +48,4 @@ const testSpamExternalPayment = async (T: TestBase) => { T.d("user1 balance is now 490 (2000 - (500 + 3 fee + 1 routing + (500 + 3fee) * 2))") expect(owner.balance_sats).to.be.equal(9) T.d("app balance is 9 sats")*/ - -} - +} \ No newline at end of file diff --git a/src/tests/testStorage.spec.ts b/src/tests/testStorage.spec.ts new file mode 100644 index 00000000..ae98f6c8 --- /dev/null +++ b/src/tests/testStorage.spec.ts @@ -0,0 +1,163 @@ +import { User } from '../services/storage/entity/User.js' +import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js' +import { runSanityCheck, safelySetUserBalance, TestBase } from './testBase.js' +import { FindOptionsWhere } from 'typeorm' +export const ignore = false +export const dev = false + +export default async (T: TestBase) => { + await testCanReadUser(T) + await testConcurrentReads(T) + await testTransactionIsolation(T) + await testUserCRUD(T) + await testErrorHandling(T) +} + +const testCanReadUser = async (T: TestBase) => { + const u = await T.main.storage.dbs.FindOne('User', { where: { user_id: T.user1.userId } }) + T.expect(u).to.not.be.equal(null) + T.expect(u?.user_id).to.be.equal(T.user1.userId) +} + +const testConcurrentReads = async (T: TestBase) => { + // Test multiple concurrent read operations + const promises = [ + T.main.storage.dbs.FindOne('User', { where: { user_id: T.user1.userId } }), + T.main.storage.dbs.FindOne('User', { where: { user_id: T.user2.userId } }), + T.main.storage.dbs.Find('User', {}) + ] as const + + const results = await Promise.all(promises) + + // Type assertions to handle possible null values + const [user1, user2, allUsers] = results + + T.expect(user1?.user_id).to.be.equal(T.user1.userId) + T.expect(user2?.user_id).to.be.equal(T.user2.userId) + T.expect(allUsers).to.not.be.equal(null) + T.expect(allUsers.length).to.be.greaterThan(1) +} + +const testTransactionIsolation = async (T: TestBase) => { + // Start a transaction + const txId = await T.main.storage.dbs.StartTx('test-transaction') + + try { + // Update user balance in transaction + const initialBalance = 1000 + const where: FindOptionsWhere = { user_id: T.user1.userId } + + await T.main.storage.dbs.Update('User', + where, + { balance_sats: initialBalance }, + txId + ) + + // Verify balance is updated in transaction + const userInTx = await T.main.storage.dbs.FindOne('User', + { where }, + txId + ) + T.expect(userInTx?.balance_sats).to.be.equal(initialBalance) + + // Verify balance is not visible outside transaction + const userOutsideTx = await T.main.storage.dbs.FindOne('User', + { where } + ) + T.expect(userOutsideTx?.balance_sats).to.not.equal(initialBalance) + + // Commit the transaction + await T.main.storage.dbs.EndTx(txId, true, null) + + // Verify balance is now visible + const userAfterCommit = await T.main.storage.dbs.FindOne('User', + { where } + ) + T.expect(userAfterCommit?.balance_sats).to.be.equal(initialBalance) + } catch (error) { + // Rollback on error + await T.main.storage.dbs.EndTx(txId, false, error instanceof Error ? error.message : 'Unknown error') + throw error + } +} + +const testUserCRUD = async (T: TestBase) => { + // Create + const newUser = { + user_id: 'test-user-' + Date.now(), + balance_sats: 0, + locked: false, + } + + await T.main.storage.dbs.CreateAndSave('User', newUser) + + // Read + const createdUser = await T.main.storage.dbs.FindOne('User', + { where: { user_id: newUser.user_id } as FindOptionsWhere } + ) + T.expect(createdUser).to.not.be.equal(null) + T.expect(createdUser?.user_id).to.be.equal(newUser.user_id) + + // Update + const newBalance = 500 + await T.main.storage.dbs.Update('User', + { user_id: newUser.user_id } as FindOptionsWhere, + { balance_sats: newBalance } + ) + + const updatedUser = await T.main.storage.dbs.FindOne('User', + { where: { user_id: newUser.user_id } as FindOptionsWhere } + ) + T.expect(updatedUser?.balance_sats).to.be.equal(newBalance) + + // Delete + await T.main.storage.dbs.Delete('User', + { user_id: newUser.user_id } as FindOptionsWhere + ) + + const deletedUser = await T.main.storage.dbs.FindOne('User', + { where: { user_id: newUser.user_id } as FindOptionsWhere } + ) + T.expect(deletedUser).to.be.equal(null) +} + +const testErrorHandling = async (T: TestBase) => { + // Test null result (not an error) + const nonExistentUser = await T.main.storage.dbs.FindOne('User', + { where: { user_id: 'does-not-exist' } as FindOptionsWhere } + ) + T.expect(nonExistentUser).to.be.equal(null) + + // Test actual error case - invalid column name should throw an error + try { + await T.main.storage.dbs.Update('User', + { user_id: T.user1.userId } as FindOptionsWhere, + { nonexistent_column: 'value' } as any + ) + T.expect.fail('Should have thrown an error') + } catch (error) { + T.expect(error).to.not.be.equal(null) + } + + // Test transaction rollback + const txId = await T.main.storage.dbs.StartTx('test-error-transaction') + try { + // Try to update with an invalid column which should cause an error + await T.main.storage.dbs.Update('User', + { user_id: T.user1.userId } as FindOptionsWhere, + { invalid_column: 'test' } as any, + txId + ) + await T.main.storage.dbs.EndTx(txId, false, 'Rolling back test transaction') + + // Verify no changes were made + const user = await T.main.storage.dbs.FindOne('User', + { where: { user_id: T.user1.userId } } + ) + T.expect(user).to.not.be.equal(null) + T.expect((user as any).invalid_column).to.be.equal(undefined) + } catch (error) { + await T.main.storage.dbs.EndTx(txId, false, error instanceof Error ? error.message : 'Unknown error') + T.expect(error).to.not.be.equal(null) + } +}