add tests for settleSendCoins

This commit is contained in:
Claus-Peter Huebner 2023-09-13 02:46:47 +02:00
parent 27ccb3b3e9
commit 0a61b61c63
5 changed files with 294 additions and 137 deletions

View File

@ -4,11 +4,12 @@ import { createTestClient } from 'apollo-server-testing'
import createServer from '@/server/createServer'
import { Community as DbCommunity } from '@entity/Community'
import CONFIG from '@/config'
import { Connection } from '@dbTools/typeorm'
let query: any
// to do: We need a setup for the tests that closes the connection
let con: any
let con: Connection
CONFIG.FEDERATION_API = '1_0'

View File

@ -9,6 +9,11 @@ import { GraphQLError } from 'graphql'
import { cleanDB, testEnvironment } from '@test/helpers'
import { logger } from '@test/testSetup'
import { Connection } from '@dbTools/typeorm'
import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTransaction'
import Decimal from 'decimal.js-light'
import { calculateRecipientBalance } from '../util/calculateRecipientBalance'
import { PendingTransactionState } from '../enum/PendingTransactionState'
import { TransactionTypeId } from '../enum/TransactionTypeId'
let mutate: ApolloServerTestClient['mutate'], con: Connection
// let query: ApolloServerTestClient['query']
@ -89,6 +94,29 @@ describe('SendCoinsResolver', () => {
}
`
const settleSendCoinsMutation = `
mutation (
$communityReceiverIdentifier: String!
$userReceiverIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$communitySenderIdentifier: String!
$userSenderIdentifier: String!
$userSenderName: String!
) {
settleSendCoins(
communityReceiverIdentifier: $communityReceiverIdentifier
userReceiverIdentifier: $userReceiverIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
communitySenderIdentifier: $communitySenderIdentifier
userSenderIdentifier: $userSenderIdentifier
userSenderName: $userSenderName
)
}
`
describe('voteForSendCoins', () => {
let homeCom: DbCommunity
let foreignCom: DbCommunity
@ -353,4 +381,146 @@ describe('SendCoinsResolver', () => {
})
})
})
describe('settleSendCoins', () => {
let homeCom: DbCommunity
let foreignCom: DbCommunity
let sendUser: DbUser
let recipUser: DbUser
let pendingTx: DbPendingTransaction
const creationDate = new Date()
beforeEach(async () => {
await cleanDB()
homeCom = DbCommunity.create()
homeCom.foreign = false
homeCom.url = 'homeCom-url'
homeCom.name = 'homeCom-Name'
homeCom.description = 'homeCom-Description'
homeCom.creationDate = new Date()
homeCom.publicKey = Buffer.from('homeCom-publicKey')
homeCom.communityUuid = 'homeCom-UUID'
await DbCommunity.insert(homeCom)
foreignCom = DbCommunity.create()
foreignCom.foreign = true
foreignCom.url = 'foreignCom-url'
foreignCom.name = 'foreignCom-Name'
foreignCom.description = 'foreignCom-Description'
foreignCom.creationDate = new Date()
foreignCom.publicKey = Buffer.from('foreignCom-publicKey')
foreignCom.communityUuid = 'foreignCom-UUID'
await DbCommunity.insert(foreignCom)
sendUser = DbUser.create()
sendUser.alias = 'sendUser-alias'
sendUser.firstName = 'sendUser-FirstName'
sendUser.gradidoID = 'sendUser-GradidoID'
sendUser.lastName = 'sendUser-LastName'
await DbUser.insert(sendUser)
recipUser = DbUser.create()
recipUser.alias = 'recipUser-alias'
recipUser.firstName = 'recipUser-FirstName'
recipUser.gradidoID = 'recipUser-GradidoID'
recipUser.lastName = 'recipUser-LastName'
await DbUser.insert(recipUser)
pendingTx = DbPendingTransaction.create()
pendingTx.amount = new Decimal(100)
pendingTx.balanceDate = creationDate
// pendingTx.balance = new Decimal(0)
pendingTx.linkedUserId = sendUser.id
pendingTx.linkedUserCommunityUuid = foreignCom.communityUuid
pendingTx.linkedUserGradidoID = sendUser.gradidoID
pendingTx.state = PendingTransactionState.NEW
pendingTx.typeId = TransactionTypeId.RECEIVE
pendingTx.memo = 'X-Com-TX memo'
pendingTx.userId = recipUser.id
pendingTx.userCommunityUuid = homeCom.communityUuid
pendingTx.userGradidoID = recipUser.gradidoID
await DbPendingTransaction.insert(pendingTx)
})
describe('unknown recipient community', () => {
it('throws an error', async () => {
jest.clearAllMocks()
expect(
await mutate({
mutation: settleSendCoinsMutation,
variables: {
communityReceiverIdentifier: 'invalid foreignCom',
userReceiverIdentifier: recipUser.gradidoID,
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: foreignCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [new GraphQLError('settleSendCoins with wrong communityReceiverIdentifier')],
}),
)
})
})
describe('unknown recipient user', () => {
it('throws an error', async () => {
jest.clearAllMocks()
expect(
await mutate({
mutation: settleSendCoinsMutation,
variables: {
communityReceiverIdentifier: homeCom.communityUuid,
userReceiverIdentifier: 'invalid recipient',
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: foreignCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [
new GraphQLError(
'settleSendCoins with unknown userReceiverIdentifier in the community=',
),
],
}),
)
})
})
describe('valid X-Com-TX settled', () => {
it('throws an error', async () => {
jest.clearAllMocks()
expect(
await mutate({
mutation: settleSendCoinsMutation,
variables: {
communityReceiverIdentifier: homeCom.communityUuid,
userReceiverIdentifier: recipUser.gradidoID,
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: foreignCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
data: {
settleSendCoins: true,
},
}),
)
})
})
})
})

View File

@ -12,7 +12,7 @@ import { calculateRecipientBalance } from '../util/calculateRecipientBalance'
import Decimal from 'decimal.js-light'
import { fullName } from '@/graphql/util/fullName'
import { settlePendingReceiveTransaction } from '../util/settlePendingReceiveTransaction'
import { checkTradingLevel } from '@/graphql/util/checkTradingLevel'
// import { checkTradingLevel } from '@/graphql/util/checkTradingLevel'
import { revertSettledReceiveTransaction } from '../util/revertSettledReceiveTransaction'
@Resolver()
@ -176,50 +176,70 @@ export class SendCoinsResolver {
userSenderName,
}: SendCoinsArgs,
): Promise<boolean> {
logger.debug(`settleSendCoins() via apiVersion=1_0 ...`)
try {
const pendingTx = await DbPendingTransaction.findOneBy({
userCommunityUuid: communityReceiverIdentifier,
userGradidoID: userReceiverIdentifier,
state: PendingTransactionState.NEW,
typeId: TransactionTypeId.RECEIVE,
balanceDate: new Date(creationDate),
linkedUserCommunityUuid: communitySenderIdentifier,
linkedUserGradidoID: userSenderIdentifier,
logger.debug(
`settleSendCoins() via apiVersion=1_0 ...userCommunityUuid=${communityReceiverIdentifier}, userGradidoID=${userReceiverIdentifier}, balanceDate=${creationDate},amount=${amount.valueOf()}, memo=${memo}, linkedUserCommunityUuid = ${communitySenderIdentifier}, userSenderIdentifier=${userSenderIdentifier}, userSenderName=${userSenderName}`,
)
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: communityReceiverIdentifier,
})
if (!homeCom) {
throw new LogError(
`settleSendCoins with wrong communityReceiverIdentifier`,
communityReceiverIdentifier,
)
}
// second check if receiver user exists in this community
const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier })
if (!receiverUser) {
throw new LogError(
`settleSendCoins with unknown userReceiverIdentifier in the community=`,
homeCom.name,
)
}
// try {
const pendingTx = await DbPendingTransaction.findOneBy({
userCommunityUuid: communityReceiverIdentifier,
userGradidoID: userReceiverIdentifier,
state: PendingTransactionState.NEW,
typeId: TransactionTypeId.RECEIVE,
balanceDate: new Date(creationDate),
linkedUserCommunityUuid: communitySenderIdentifier,
linkedUserGradidoID: userSenderIdentifier,
})
logger.debug('XCom: settleSendCoins found pendingTX=', pendingTx?.toString())
if (pendingTx && pendingTx.amount.toString() === amount.toString() && pendingTx.memo === memo) {
logger.debug('XCom: settleSendCoins matching pendingTX for settlement...')
const homeCom = await DbCommunity.findOneByOrFail({
communityUuid: communityReceiverIdentifier,
})
logger.debug('XCom: settleSendCoins found pendingTX=', pendingTx)
if (pendingTx && pendingTx.amount === amount && pendingTx.memo === memo) {
logger.debug('XCom: settleSendCoins matching pendingTX for settlement...')
const receiverUser = await DbUser.findOneByOrFail({ gradidoID: userReceiverIdentifier })
const homeCom = await DbCommunity.findOneByOrFail({
communityUuid: communityReceiverIdentifier,
})
const receiverUser = await DbUser.findOneByOrFail({ gradidoID: userReceiverIdentifier })
await settlePendingReceiveTransaction(homeCom, receiverUser, pendingTx)
logger.debug(`XCom: settlePendingReceiveTransaction()-1_0... successfull`)
return true
} else {
logger.debug(
'XCom: settlePendingReceiveTransaction NOT matching pendingTX for settlement...',
)
throw new LogError(
`Can't find in settlePendingReceiveTransaction the pending receiver TX for args=`,
communityReceiverIdentifier,
userReceiverIdentifier,
PendingTransactionState.NEW,
TransactionTypeId.RECEIVE,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
)
}
await settlePendingReceiveTransaction(homeCom, receiverUser, pendingTx)
logger.debug(`XCom: settlePendingReceiveTransaction()-1_0... successfull`)
return true
} else {
logger.debug('XCom: settlePendingReceiveTransaction NOT matching pendingTX for settlement...')
throw new LogError(
`Can't find in settlePendingReceiveTransaction the pending receiver TX for args=`,
communityReceiverIdentifier,
userReceiverIdentifier,
PendingTransactionState.NEW,
TransactionTypeId.RECEIVE,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
)
}
/*
} catch (err) {
throw new LogError(`Error in settlePendingReceiveTransaction: `, err)
}
*/
}
@Mutation(() => Boolean)
@ -236,64 +256,66 @@ export class SendCoinsResolver {
userSenderName,
}: SendCoinsArgs,
): Promise<boolean> {
try {
logger.debug(`revertSettledSendCoins() via apiVersion=1_0 ...`)
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: communityReceiverIdentifier,
})
if (!homeCom) {
throw new LogError(
`revertSettledSendCoins with wrong communityReceiverIdentifier`,
communityReceiverIdentifier,
)
// try {
logger.debug(`revertSettledSendCoins() via apiVersion=1_0 ...`)
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: communityReceiverIdentifier,
})
if (!homeCom) {
throw new LogError(
`revertSettledSendCoins with wrong communityReceiverIdentifier`,
communityReceiverIdentifier,
)
}
// second check if receiver user exists in this community
const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier })
if (!receiverUser) {
throw new LogError(
`revertSettledSendCoins with unknown userReceiverIdentifier in the community=`,
homeCom.name,
)
}
const pendingTx = await DbPendingTransaction.findOneBy({
userCommunityUuid: communityReceiverIdentifier,
userGradidoID: userReceiverIdentifier,
state: PendingTransactionState.SETTLED,
typeId: TransactionTypeId.RECEIVE,
balanceDate: new Date(creationDate),
linkedUserCommunityUuid: communitySenderIdentifier,
linkedUserGradidoID: userSenderIdentifier,
})
logger.debug('XCom: revertSettledSendCoins found pendingTX=', pendingTx)
if (pendingTx && pendingTx.amount === amount && pendingTx.memo === memo) {
logger.debug('XCom: revertSettledSendCoins matching pendingTX for remove...')
try {
await revertSettledReceiveTransaction(homeCom, receiverUser, pendingTx)
logger.debug('XCom: revertSettledSendCoins pendingTX successfully')
} catch (err) {
throw new LogError('Error in revertSettledSendCoins of receiver: ', err)
}
// second check if receiver user exists in this community
const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier })
if (!receiverUser) {
throw new LogError(
`revertSettledSendCoins with unknown userReceiverIdentifier in the community=`,
homeCom.name,
)
}
const pendingTx = await DbPendingTransaction.findOneBy({
userCommunityUuid: communityReceiverIdentifier,
userGradidoID: userReceiverIdentifier,
state: PendingTransactionState.SETTLED,
typeId: TransactionTypeId.RECEIVE,
balanceDate: new Date(creationDate),
linkedUserCommunityUuid: communitySenderIdentifier,
linkedUserGradidoID: userSenderIdentifier,
})
logger.debug('XCom: revertSettledSendCoins found pendingTX=', pendingTx)
if (pendingTx && pendingTx.amount === amount && pendingTx.memo === memo) {
logger.debug('XCom: revertSettledSendCoins matching pendingTX for remove...')
try {
await revertSettledReceiveTransaction(homeCom, receiverUser, pendingTx)
logger.debug('XCom: revertSettledSendCoins pendingTX successfully')
} catch (err) {
throw new LogError('Error in revertSettledSendCoins of receiver: ', err)
}
} else {
logger.debug('XCom: revertSettledSendCoins NOT matching pendingTX...')
throw new LogError(
`Can't find in revertSettledSendCoins the pending receiver TX for args=`,
communityReceiverIdentifier,
userReceiverIdentifier,
PendingTransactionState.SETTLED,
TransactionTypeId.RECEIVE,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
)
}
logger.debug(`revertSendCoins()-1_0... successfull`)
return true
} else {
logger.debug('XCom: revertSettledSendCoins NOT matching pendingTX...')
throw new LogError(
`Can't find in revertSettledSendCoins the pending receiver TX for args=`,
communityReceiverIdentifier,
userReceiverIdentifier,
PendingTransactionState.SETTLED,
TransactionTypeId.RECEIVE,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
)
}
logger.debug(`revertSendCoins()-1_0... successfull`)
return true
/*
} catch (err) {
throw new LogError(`Error in revertSendCoins: `, err)
}
*/
}
}

View File

@ -15,7 +15,7 @@ import { federationLogger as logger } from '@/server/logger'
import { getLastTransaction } from '@/graphql/util/getLastTransaction'
import { TRANSACTIONS_LOCK } from '@/graphql/util/TRANSACTIONS_LOCK'
import { calculateRecepientBalance } from './calculateRecepientBalance'
import { calculateRecipientBalance } from './calculateRecipientBalance'
export async function settlePendingReceiveTransaction(
homeCom: DbCommunity,
@ -52,7 +52,7 @@ export async function settlePendingReceiveTransaction(
const lastTransaction = await getLastTransaction(receiverUser.id)
if (lastTransaction?.id !== pendingTx.previous) {
if (lastTransaction === undefined && lastTransaction.id !== pendingTx.previous) {
throw new LogError(
`X-Com: missmatching transaction order! lastTransationId=${lastTransaction?.id} != pendingTx.previous=${pendingTx.previous}`,
)
@ -69,7 +69,7 @@ export async function settlePendingReceiveTransaction(
transactionReceive.linkedUserGradidoID = pendingTx.linkedUserGradidoID
transactionReceive.linkedUserName = pendingTx.linkedUserName
transactionReceive.amount = pendingTx.amount
const receiveBalance = await calculateRecepientBalance(
const receiveBalance = await calculateRecipientBalance(
receiverUser.id,
pendingTx.amount,
pendingTx.balanceDate,

View File

@ -4,45 +4,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-return */
import { entities } from '@entity/index'
import { createTestClient } from 'apollo-server-testing'
/* <<<<<<< HEAD
import { createServer } from '@/server/createServer'
import { entities } from '@entity/index'
import { createTestClient } from 'apollo-server-testing'
import { logger } from './testSetup'
// import { createServer } from '@/server/createServer'
// import { i18n, logger } from './testSetup'
export const headerPushMock = jest.fn((t) => {
context.token = t.value
})
const context = {
token: '',
setHeaders: {
push: headerPushMock,
forEach: jest.fn(),
},
clientTimezoneOffset: 0,
}
export const cleanDB = async () => {
// this only works as long we do not have foreign key constraints
for (const entity of entities) {
await resetEntity(entity)
}
}
export const testEnvironment = async (testLogger = logger) => {
// , testI18n = i18n) => {
=======
*/
import { entities } from '@entity/index'
import { createTestClient } from 'apollo-server-testing'
import createServer from '@/server/createServer'
import { logger } from './testSetup'
@ -67,7 +32,6 @@ export const cleanDB = async () => {
}
export const testEnvironment = async (testLogger = logger) => {
// >>>>>>> refs/remotes/origin/master
const server = await createServer(testLogger) // context, testLogger, testI18n)
const con = server.con
const testClient = createTestClient(server.apollo)