wallet-storage
Version:
BRC100 conforming wallet, wallet storage and wallet signer components
832 lines (807 loc) • 37.4 kB
text/typescript
import { Base64String } from '@bsv/sdk'
import { _tu, TestSetup1 } from '../utils/TestUtilsWalletStorage'
import { sdk, StorageProvider, StorageKnex, table, verifyOne } from '../../src/index.all'
import { normalizeDate, setLogging, triggerForeignKeyConstraintError, triggerUniqueConstraintError, updateTable, validateUpdateTime, verifyValues } from '../utils/TestUtilsWalletStorage'
import { ProvenTx, ProvenTxReq, User, Certificate, CertificateField, OutputBasket, Transaction, Commission, Output, OutputTag, OutputTagMap, TxLabel, TxLabelMap, MonitorEvent, SyncState } from '../../src/storage/schema/tables'
setLogging(false)
describe('update tests', () => {
jest.setTimeout(99999999)
const storages: StorageProvider[] = []
const chain: sdk.Chain = 'test'
const setups: { setup: TestSetup1; storage: StorageProvider }[] = []
const env = _tu.getEnv(chain)
const databaseName = 'updateTest'
beforeAll(async () => {
const localSQLiteFile = await _tu.newTmpFile(`${databaseName}.sqlite`, false, false, true)
const knexSQLite = _tu.createLocalSQLite(localSQLiteFile)
storages.push(new StorageKnex({ ...StorageKnex.defaultOptions(), chain, knex: knexSQLite }))
if (!env.noMySQL) {
const knexMySQL = _tu.createLocalMySQL(`${databaseName}.mysql`)
storages.push(new StorageKnex({ ...StorageKnex.defaultOptions(), chain, knex: knexMySQL }))
}
for (const storage of storages) {
await storage.dropAllData()
await storage.migrate('insert tests', '1'.repeat(64))
setups.push({ storage, setup: await _tu.createTestSetup1(storage) })
}
})
afterAll(async () => {
for (const storage of storages) {
await storage.destroy()
}
})
test('0_update ProvenTx', async () => {
for (const { storage } of setups) {
const records = await storage.findProvenTxs({ partial: {} })
const time = new Date('2001-01-02T12:00:00.000Z')
for (const record of records) {
await storage.updateProvenTx(record.provenTxId, { blockHash: 'fred', updated_at: time })
const t = verifyOne(await storage.findProvenTxs({ partial: { provenTxId: record.provenTxId } }))
expect(t.provenTxId).toBe(record.provenTxId)
expect(t.blockHash).toBe('fred')
expect(t.updated_at.getTime()).toBe(time.getTime())
}
}
})
test('1_update ProvenTx', async () => {
const primaryKey = 'provenTxId'
for (const { storage } of setups) {
const referenceTime = new Date()
const records = await storage.findProvenTxs({ partial: {} })
for (const record of records) {
try {
const testValues: ProvenTx = {
provenTxId: record.provenTxId,
txid: 'mockTxid',
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
blockHash: 'mockBlockHash',
height: 12345,
index: 1,
merklePath: [1, 2, 3, 4],
merkleRoot: '1234',
rawTx: [4, 3, 2, 1]
}
await updateTable(storage.updateProvenTx.bind(storage), record[primaryKey], testValues)
const updatedTx = verifyOne(await storage.findProvenTxs({ partial: { [primaryKey]: record[primaryKey] } }))
verifyValues(updatedTx, testValues, referenceTime)
for (const [key, value] of Object.entries(testValues)) {
if (key === primaryKey) {
continue
}
if (typeof value === 'string') {
const validString = `valid${key}`
const r1 = await storage.updateProvenTx(record[primaryKey], { [key]: validString })
expect(r1).toBe(1)
const updatedRow = verifyOne(await storage.findProvenTxs({ partial: { [primaryKey]: record[primaryKey] } }))
expect(updatedRow[key]).toBe(validString)
}
if (typeof value === 'number') {
const validNumber = value + 1
const r1 = await storage.updateProvenTx(record[primaryKey], { [key]: validNumber })
expect(r1).toBe(1)
const updatedRow = verifyOne(await storage.findProvenTxs({ partial: { [primaryKey]: record[primaryKey] } }))
expect(updatedRow[key]).toBe(validNumber)
}
if (value instanceof Date) {
const validDate = new Date('2024-12-31T00:00:00Z')
const r1 = await storage.updateProvenTx(record[primaryKey], { [key]: validDate })
expect(r1).toBe(1)
const updatedRow = verifyOne(await storage.findProvenTxs({ partial: { [primaryKey]: record[primaryKey] } }))
expect(new Date(updatedRow[key]).toISOString()).toBe(validDate.toISOString())
}
if (Array.isArray(value)) {
const validArray = value.map(v => v + 1)
const r1 = await storage.updateProvenTx(record[primaryKey], { [key]: validArray })
expect(r1).toBe(1)
const updatedRow = verifyOne(await storage.findProvenTxs({ partial: { [primaryKey]: record[primaryKey] } }))
expect(updatedRow[key]).toEqual(validArray)
}
}
} catch (error: any) {
console.error(`Error updating or verifying ProvenTx record with ${primaryKey}=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('2_update ProvenTxReq', async () => {
const primaryKey = 'provenTxReqId'
for (const { storage } of setups) {
const records = await storage.findProvenTxReqs({ partial: {} })
for (const record of records) {
try {
const testValues: ProvenTxReq = {
provenTxReqId: record.provenTxReqId,
provenTxId: 1,
batch: `batch-001`,
status: 'completed',
txid: `mockTxid-${Date.now()}`,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
attempts: 3,
history: JSON.stringify({ validated: true, timestamp: Date.now() }),
inputBEEF: [5, 6, 7, 8],
notified: true,
notify: JSON.stringify({ email: 'test@example.com', sent: true }),
rawTx: [1, 2, 3, 4]
}
const r1 = await storage.updateProvenTxReq(record[primaryKey], testValues)
expect(r1).toBe(1)
const updatedRow = verifyOne(await storage.findProvenTxReqs({ partial: { [primaryKey]: record[primaryKey] } }))
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
if (typeof value === 'string' && value.startsWith('{') && value.endsWith('}')) {
expect(JSON.parse(actualValue)).toStrictEqual(JSON.parse(value))
continue
}
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
expect(actualValue).toBe(value)
continue
}
if (typeof actualValue === 'object' && actualValue?.type === 'Buffer') {
const actualArray = actualValue.data || actualValue
const expectedArray = Buffer.isBuffer(value) || Array.isArray(value) ? Array.from(value as ArrayLike<number>) : value
expect(actualArray).toStrictEqual(expectedArray)
continue
}
expect(JSON.stringify({ type: 'Buffer', data: actualValue })).toStrictEqual(JSON.stringify(value))
}
} catch (error: any) {
console.error(`Error updating or verifying ProvenTxReq record with ${primaryKey}=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('3_update User', async () => {
const primaryKey = 'userId'
for (const { storage } of setups) {
const records = await storage.findUsers({ partial: {} })
for (const record of records) {
try {
const testValues: User = {
userId: record.userId,
identityKey: `mockUpdatedIdentityKey-${record[primaryKey]}`,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z')
}
const updateResult = await storage.updateUser(record[primaryKey], testValues)
expect(updateResult).toBe(1)
const updatedRow = verifyOne(await storage.findUsers({ partial: { [primaryKey]: record[primaryKey] } }))
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
expect(actualValue).toBe(value)
}
} catch (error: any) {
console.error(`Error updating or verifying User record with ${primaryKey}=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('4_update Certificate', async () => {
for (const { storage } of setups) {
const primaryKey = 'certificateId'
const records = await storage.findCertificates({ partial: {} })
for (const record of records) {
try {
const testValues: Certificate = {
certificateId: record.certificateId,
userId: 1,
certifier: `mockCertifier${record.certificateId}`,
serialNumber: `mockSerialNumber${record.certificateId}`,
type: `mockType${record.certificateId}`,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
isDeleted: false,
revocationOutpoint: 'mockRevocationOutpoint',
signature: 'mockSignature',
subject: 'mockSubject'
}
const r1 = await storage.updateCertificate(record[primaryKey], testValues)
expect(r1).toBe(1)
const updatedRow = verifyOne(await storage.findCertificates({ partial: { [primaryKey]: record[primaryKey] } }))
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
if (typeof value === 'string' && value.startsWith('{') && value.endsWith('}')) {
expect(JSON.parse(actualValue)).toStrictEqual(JSON.parse(value))
continue
}
if (typeof actualValue === 'boolean') {
if (value === 1) {
expect(actualValue).toBe(true)
} else if (value === 0) {
expect(actualValue).toBe(false)
} else {
throw new Error(`Unexpected value for expectedValue: ${value}. Must be 0 or 1.`)
}
continue
}
if (typeof value === 'string' || typeof value === 'number') {
expect(actualValue).toBe(value)
continue
}
if (typeof actualValue === 'object' && actualValue?.type === 'Buffer') {
const actualArray = actualValue.data || actualValue
const expectedArray = Buffer.isBuffer(value) || Array.isArray(value) ? Array.from(value as ArrayLike<number>) : value
expect(actualArray).toStrictEqual(expectedArray)
continue
}
expect(JSON.stringify({ type: 'Buffer', data: actualValue })).toStrictEqual(JSON.stringify(value))
}
} catch (error: any) {
console.error(`Error updating or verifying Certificate record with ${primaryKey}=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('5_update CertificateField', async () => {
const primaryKey = 'certificateId'
for (const { storage } of setups) {
const records = await storage.findCertificateFields({ partial: { fieldName: 'bob' } })
for (const record of records) {
try {
const testValues: CertificateField = {
certificateId: record.certificateId,
userId: record.userId ?? 1,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
fieldName: record.fieldName || 'defaultFieldName',
fieldValue: 'your uncle',
masterKey: 'key'
}
const updateResult = await storage.updateCertificateField(record.certificateId, testValues.fieldName, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findCertificateFields({
partial: { certificateId: record.certificateId, fieldName: testValues.fieldName }
})
const updatedRow = verifyOne(updatedRecords, `Updated CertificateField with certificateId=${record.certificateId}, fieldName=${testValues.fieldName} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
expect(actualValue).toBe(value)
}
} catch (error: any) {
console.error(`Error updating or verifying CertificateField record with certificateId=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('6_update OutputBasket', async () => {
const primaryKey = 'basketId'
for (const { storage } of setups) {
const records = await storage.findOutputBaskets({ partial: {} })
for (const record of records) {
try {
const testValues: OutputBasket = {
basketId: record.basketId,
userId: record.userId ?? 1,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
name: record.name || 'defaultName',
numberOfDesiredUTXOs: 99,
minimumDesiredUTXOValue: 5000,
isDeleted: false
}
const updateResult = await storage.updateOutputBasket(record.basketId, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findOutputBaskets({
partial: { basketId: record.basketId, name: testValues.name }
})
const updatedRow = verifyOne(updatedRecords, `Updated OutputBasket with basketId=${record.basketId}, name=${testValues.name} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
if (typeof actualValue === 'boolean') {
if (value === 1) {
expect(actualValue).toBe(true)
} else if (value === 0) {
expect(actualValue).toBe(false)
} else {
throw new Error(`Unexpected value for expectedValue: ${value}. Must be 0 or 1.`)
}
continue
}
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
expect(actualValue).toBe(value)
}
} catch (error: any) {
console.error(`Error updating or verifying OutputBasket record with basketId=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('7_update Transaction', async () => {
const primaryKey = 'transactionId'
for (const { storage } of setups) {
const records = await storage.findTransactions({ partial: {} })
for (const record of records) {
try {
const testValues: Transaction = {
transactionId: record.transactionId,
userId: record.userId ?? 1,
provenTxId: 1,
reference: `updated_reference_string_${record.transactionId}==`,
status: 'confirmed' as sdk.TransactionStatus,
txid: `updated_txid_example_${record.transactionId}`,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
description: 'Updated transaction description',
isOutgoing: false,
lockTime: 600000000,
satoshis: 20000,
version: 2
}
const updateResult = await storage.updateTransaction(record.transactionId, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findTransactions({
partial: { transactionId: record.transactionId }
})
const updatedRow = verifyOne(updatedRecords, `Updated Transaction with transactionId=${record.transactionId} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
expect(actualValue).toBe(value)
}
} catch (error: any) {
console.error(`Error updating or verifying Transaction record with transactionId=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('7a updateTransactionStatus', async () => {
const { activeStorage: storage } = await _tu.createLegacyWalletSQLiteCopy('updateTransactionStatus6a')
let tx = verifyOne(await storage.findTransactions({ partial: { status: 'unproven' }, paged: { limit: 1 } }))
expect(tx.status).toBe('unproven')
await storage.updateTransactionStatus('completed', tx.transactionId)
tx = verifyOne(await storage.findTransactions({ partial: { transactionId: tx.transactionId } }))
expect(tx.status).toBe('completed')
await storage.destroy()
})
test('8_update Commission', async () => {
const primaryKey = 'commissionId'
for (const { storage } of setups) {
const records = await storage.findCommissions({ partial: {} })
for (const record of records) {
try {
const testValues: Commission = {
commissionId: record.commissionId,
userId: record.userId ?? 1,
transactionId: record.transactionId ?? 1,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
satoshis: 300,
keyOffset: `updated_key_offset_${record.commissionId}`,
isRedeemed: true,
lockingScript: [1, 2, 3, 4]
}
const updateResult = await storage.updateCommission(record.commissionId, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findCommissions({
partial: { commissionId: record.commissionId }
})
const updatedRow = verifyOne(updatedRecords, `Updated Commission with commissionId=${record.commissionId} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
if (Buffer.isBuffer(actualValue) || Array.isArray(actualValue)) {
expect(JSON.stringify({ type: 'Buffer', data: actualValue })).toStrictEqual(JSON.stringify(value))
continue
}
expect(actualValue).toBe(value)
}
} catch (error: any) {
console.error(`Error updating or verifying Commission record with commissionId=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('9_update Output', async () => {
const primaryKey = 'outputId'
for (const { storage } of setups) {
const records = await storage.findOutputs({ partial: {} })
for (const record of records) {
if (!record.transactionId) record.transactionId = 1
if (!record.basketId) record.basketId = 1
if (!record.userId || !record.transactionId || !record.basketId) {
throw new Error(`Missing required foreign keys for record ${JSON.stringify(record)}`)
}
}
for (const record of records) {
const existingRecords = await storage.findOutputs({ partial: {} })
const usedCombinations = new Set(existingRecords.map(r => `${r.transactionId}-${r.vout}-${r.userId}`))
let testTransactionId = record.transactionId
let testVout = record.vout + 1
let testUserId = record.userId
while (usedCombinations.has(`${testTransactionId}-${testVout}-${testUserId}`)) {
testVout += 1
}
try {
const testValues: Output = {
outputId: record.outputId,
basketId: record.basketId ?? 1,
transactionId: testTransactionId,
userId: testUserId,
vout: testVout,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
change: true,
customInstructions: 'Updated instructions',
derivationPrefix: 'updated_prefix==',
derivationSuffix: 'updated_suffix==',
lockingScript: [0x01, 0x02, 0x03, 0x04],
providedBy: 'you',
purpose: 'updated_purpose',
satoshis: 3000,
scriptLength: 150,
scriptOffset: 5,
senderIdentityKey: 'updated_sender_key',
sequenceNumber: 10,
spendingDescription: 'Updated spending description',
spendable: false,
spentBy: 3,
txid: 'updated_txid',
type: 'updated_type',
outputDescription: 'outputDescription'
}
const updateResult = await storage.updateOutput(record.outputId, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findOutputs({ partial: { outputId: record.outputId } })
const updatedRow = verifyOne(updatedRecords, `Updated Output with outputId=${record.outputId} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
if (Buffer.isBuffer(actualValue) || Array.isArray(actualValue)) {
expect(JSON.stringify({ type: 'Buffer', data: actualValue })).toStrictEqual(JSON.stringify(value))
continue
}
expect(actualValue).toBe(value)
}
} catch (error: any) {
console.error(`Error updating or verifying Output record with outputId=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('10_update OutputTag', async () => {
const primaryKey = 'outputTagId'
for (const { storage } of setups) {
const records = await storage.findOutputTags({ partial: {} })
for (const record of records) {
if (!record.userId) record.userId = 1
if (!record.tag) record.tag = `default_tag_${record.outputTagId}`
if (!record.userId || !record.tag) {
throw new Error(`Missing required fields for record ${JSON.stringify(record)}`)
}
}
for (const record of records) {
const uniqueTag = `updated_tag_${record.outputTagId}`
const testValues: OutputTag = {
outputTagId: record.outputTagId,
userId: record.userId,
tag: uniqueTag,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
isDeleted: false
}
try {
const updateResult = await storage.updateOutputTag(record.outputTagId, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findOutputTags({ partial: { outputTagId: record.outputTagId } })
const updatedRow = verifyOne(updatedRecords, `Updated OutputTag with outputTagId=${record.outputTagId} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
if (typeof actualValue === 'boolean') {
if (value === 1) {
expect(actualValue).toBe(true)
} else if (value === 0) {
expect(actualValue).toBe(false)
} else {
throw new Error(`Unexpected value for expectedValue: ${value}. Must be 0 or 1.`)
}
continue
}
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
expect(actualValue).toBe(value)
}
} catch (error: any) {
console.error(`Error updating or verifying OutputTag record with outputTagId=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('11_update OutputTagMap', async () => {
const primaryKey = ['outputTagId', 'outputId']
for (const { storage } of setups) {
const records = await storage.findOutputTagMaps({ partial: {} })
for (const record of records) {
if (!record.outputTagId) throw new Error(`Missing outputTagId for record: ${JSON.stringify(record)}`)
if (!record.outputId) throw new Error(`Missing outputId for record: ${JSON.stringify(record)}`)
try {
const testValues: OutputTagMap = {
outputTagId: record.outputTagId,
outputId: record.outputId,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
isDeleted: false
}
const updateResult = await storage.updateOutputTagMap(record.outputId, record.outputTagId, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findOutputTagMaps({ partial: { outputTagId: record.outputTagId, outputId: record.outputId } })
const updatedRow = verifyOne(updatedRecords, `Updated OutputTagMap with outputTagId=${record.outputTagId} and outputId=${record.outputId} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
if (typeof actualValue === 'boolean') {
if (value === 1) {
expect(actualValue).toBe(true)
} else if (value === 0) {
expect(actualValue).toBe(false)
} else {
throw new Error(`Unexpected value for expectedValue: ${value}. Must be 0 or 1.`)
}
continue
}
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
expect(actualValue).toBe(value)
}
} catch (error: any) {
console.error(`Error updating or verifying OutputTagMap record with outputTagId=${record.outputTagId} and outputId=${record.outputId}:`, error.message)
throw error
}
}
}
})
test('12_update TxLabel', async () => {
const primaryKey = 'txLabelId'
for (const { storage } of setups) {
const records = await storage.findTxLabels({ partial: {} })
for (const record of records) {
if (!record.userId) {
throw new Error(`Missing required foreign key userId for record ${JSON.stringify(record)}`)
}
}
for (const record of records) {
const uniqueLabel = `unique_label_${record.txLabelId}`
const testValues: TxLabel = {
txLabelId: record.txLabelId,
userId: record.userId,
label: uniqueLabel,
isDeleted: false,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z')
}
const existingLabel = await storage.findTxLabels({ partial: { label: testValues.label, userId: testValues.userId } })
if (existingLabel.length > 0) {
continue
}
const updateResult = await storage.updateTxLabel(record.txLabelId, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findTxLabels({ partial: { txLabelId: record.txLabelId } })
const updatedRow = verifyOne(updatedRecords, `Updated TxLabel with txLabelId=${record.txLabelId} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
if (typeof actualValue === 'boolean') {
if (value === 1) {
expect(actualValue).toBe(true)
} else if (value === 0) {
expect(actualValue).toBe(false)
} else {
throw new Error(`Unexpected value for expectedValue: ${value}. Must be 0 or 1.`)
}
continue
}
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
expect(actualValue).toBe(value)
}
}
}
})
test('13_update TxLabelMap', async () => {
const primaryKeyTransaction = 'transactionId'
const primaryKeyLabel = 'txLabelId'
for (const { storage, setup } of setups) {
const records = await storage.findTxLabelMaps({ partial: {} })
for (const record of records) {
if (!record.transactionId || !record.txLabelId) {
throw new Error(`Missing required foreign keys for record ${JSON.stringify(record)}`)
}
}
for (const record of records) {
const testValues: TxLabelMap = {
transactionId: record.transactionId,
txLabelId: record.txLabelId,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
isDeleted: false
}
const existingRecord = await storage.findTxLabelMaps({
partial: { transactionId: testValues.transactionId, txLabelId: testValues.txLabelId }
})
if (existingRecord.length > 0) {
continue
}
try {
const updateResult = await storage.updateTxLabelMap(record.transactionId, record.txLabelId, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findTxLabelMaps({
partial: { transactionId: record.transactionId, txLabelId: record.txLabelId }
})
const updatedRow = verifyOne(updatedRecords, `Updated TxLabelMap with transactionId=${record[primaryKeyTransaction]} and txLabelId=${record[primaryKeyLabel]} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
expect(actualValue).toBe(value)
}
} catch (error: any) {
console.error(`Error updating or verifying TxLabelMap record with transactionId=${record[primaryKeyTransaction]} and txLabelId=${record[primaryKeyLabel]}:`, error.message)
throw error
}
}
}
})
test('14_update MonitorEvent', async () => {
const primaryKey = 'id'
for (const { storage, setup } of setups) {
const records = await storage.findMonitorEvents({ partial: {} })
for (const record of records) {
try {
const testValues: MonitorEvent = {
id: record.id,
created_at: new Date('2024-12-30T23:00:00Z'),
updated_at: new Date('2024-12-30T23:05:00Z'),
event: 'updated_event',
details: 'Updated details'
}
const updateResult = await storage.updateMonitorEvent(record.id, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findMonitorEvents({ partial: { id: record.id } })
const updatedRow = verifyOne(updatedRecords, `Updated MonitorEvent with id=${record.id} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
const normalizedActual = normalizeDate(actualValue)
const normalizedExpected = normalizeDate(value)
if (normalizedActual && normalizedExpected) {
expect(normalizedActual).toBe(normalizedExpected)
continue
}
expect(actualValue).toBe(value)
}
} catch (error: any) {
console.error(`Error updating or verifying MonitorEvent record with id=${record[primaryKey]}:`, error.message)
throw error
}
}
}
})
test('15_update SyncState', async () => {
const primaryKey = 'syncStateId'
for (const { storage } of setups) {
const records = await storage.findSyncStates({ partial: {} })
for (const record of records) {
if (!record.userId) {
throw new Error(`Missing required foreign key userId for record ${JSON.stringify(record)}`)
}
}
for (const record of records) {
const testValues: SyncState = {
syncStateId: record.syncStateId,
userId: record.userId,
refNum: 'test_refNum',
created_at: new Date('2025-01-01T00:00:00.000Z'),
updated_at: new Date('2025-01-01T00:00:00.000Z'),
errorLocal: 'Example local error',
errorOther: 'Example other error',
init: false,
satoshis: 1000,
status: 'success',
storageIdentityKey: 'test_identity_key',
storageName: 'test_storage',
syncMap: '{}',
when: new Date('2025-01-01T02:00:00.000Z')
}
const updateResult = await storage.updateSyncState(record.syncStateId, testValues)
expect(updateResult).toBe(1)
const updatedRecords = await storage.findSyncStates({ partial: { syncStateId: record.syncStateId } })
const updatedRow = verifyOne(updatedRecords, `Updated SyncState with syncStateId=${record.syncStateId} was not unique or missing.`)
for (const [key, value] of Object.entries(testValues)) {
const actualValue = updatedRow[key]
if (typeof actualValue === 'boolean') {
if (value === 1) {
expect(actualValue).toBe(true)
} else if (value === 0) {
expect(actualValue).toBe(false)
} else {
throw new Error(`Unexpected value for expectedValue: ${value}. Must be 0 or 1.`)
}
continue
}
if (actualValue instanceof Date) {
const actualDate = new Date(actualValue)
const expectedDate = new Date(value)
expect(actualDate.getTime()).toBe(expectedDate.getTime())
continue
}
if (value === undefined || value === null) {
expect(actualValue).toBeNull()
continue
}
if (key === 'refNum') {
expect(actualValue).toBe('test_refNum')
continue
}
expect(actualValue).toStrictEqual(value)
}
}
}
})
})