mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 01:46:07 +00:00
add test, increase coverage to 80%
This commit is contained in:
parent
ddbec0ae3b
commit
6c0c973cb8
@ -80,7 +80,7 @@ export class DltConnectorClient {
|
||||
*/
|
||||
public async transmitTransaction(
|
||||
transaction: DbTransaction,
|
||||
senderCommunityUuid: string,
|
||||
senderCommunityUuid = '',
|
||||
recipientCommunityUuid = '',
|
||||
): Promise<string> {
|
||||
const typeString = getTransactionTypeString(transaction.typeId)
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
|
||||
import { Connection } from '@dbTools/typeorm'
|
||||
import { Community } from '@entity/Community'
|
||||
import { DltTransaction } from '@entity/DltTransaction'
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||
@ -14,6 +15,7 @@ import { Decimal } from 'decimal.js-light'
|
||||
// import { Response } from 'graphql-request/dist/types'
|
||||
import { GraphQLClient } from 'graphql-request'
|
||||
import { Response } from 'graphql-request/dist/types'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { testEnvironment, cleanDB } from '@test/helpers'
|
||||
import { logger, i18n as localization } from '@test/testSetup'
|
||||
@ -80,6 +82,16 @@ let testEnv: {
|
||||
}
|
||||
*/
|
||||
|
||||
async function createHomeCommunity(): Promise<Community> {
|
||||
const homeCommunity = Community.create()
|
||||
homeCommunity.foreign = false
|
||||
homeCommunity.communityUuid = uuidv4()
|
||||
homeCommunity.url = 'localhost'
|
||||
homeCommunity.publicKey = Buffer.from('0x6e6a6c6d6feffe', 'hex')
|
||||
await Community.save(homeCommunity)
|
||||
return homeCommunity
|
||||
}
|
||||
|
||||
async function createTxCREATION1(verified: boolean): Promise<Transaction> {
|
||||
let tx = Transaction.create()
|
||||
tx.amount = new Decimal(1000)
|
||||
@ -358,9 +370,10 @@ describe('create and send Transactions to DltConnector', () => {
|
||||
txCREATION1 = await createTxCREATION1(false)
|
||||
txCREATION2 = await createTxCREATION2(false)
|
||||
txCREATION3 = await createTxCREATION3(false)
|
||||
await createHomeCommunity()
|
||||
|
||||
CONFIG.DLT_CONNECTOR = false
|
||||
await sendTransactionsToDltConnector('senderCommunityUuid')
|
||||
await sendTransactionsToDltConnector()
|
||||
expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...')
|
||||
|
||||
// Find the previous created transactions of sendCoin mutation
|
||||
@ -413,6 +426,7 @@ describe('create and send Transactions to DltConnector', () => {
|
||||
txCREATION1 = await createTxCREATION1(false)
|
||||
txCREATION2 = await createTxCREATION2(false)
|
||||
txCREATION3 = await createTxCREATION3(false)
|
||||
await createHomeCommunity()
|
||||
|
||||
CONFIG.DLT_CONNECTOR = true
|
||||
|
||||
@ -429,7 +443,7 @@ describe('create and send Transactions to DltConnector', () => {
|
||||
} as Response<unknown>
|
||||
})
|
||||
|
||||
await sendTransactionsToDltConnector('senderCommunityUuid')
|
||||
await sendTransactionsToDltConnector()
|
||||
|
||||
expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...')
|
||||
|
||||
@ -481,6 +495,7 @@ describe('create and send Transactions to DltConnector', () => {
|
||||
txCREATION1 = await createTxCREATION1(true)
|
||||
txCREATION2 = await createTxCREATION2(true)
|
||||
txCREATION3 = await createTxCREATION3(true)
|
||||
await createHomeCommunity()
|
||||
|
||||
txSEND1to2 = await createTxSend1ToReceive2(false)
|
||||
txRECEIVE2From1 = await createTxReceive2FromSend1(false)
|
||||
@ -507,7 +522,7 @@ describe('create and send Transactions to DltConnector', () => {
|
||||
} as Response<unknown>
|
||||
})
|
||||
|
||||
await sendTransactionsToDltConnector('senderCommunityUuid')
|
||||
await sendTransactionsToDltConnector()
|
||||
|
||||
expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...')
|
||||
|
||||
|
||||
@ -6,10 +6,9 @@ import { DltConnectorClient } from '@/apis/DltConnectorClient'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
import { Monitor, MonitorNames } from '@/util/Monitor'
|
||||
|
||||
export async function sendTransactionsToDltConnector(
|
||||
senderCommunityUuid: string,
|
||||
recipientCommunityUuid = '',
|
||||
): Promise<void> {
|
||||
import { getHomeCommunityUuid } from './communities'
|
||||
|
||||
export async function sendTransactionsToDltConnector(): Promise<void> {
|
||||
logger.info('sendTransactionsToDltConnector...')
|
||||
// check if this logic is still occupied, no concurrecy allowed
|
||||
if (!Monitor.isLocked(MonitorNames.SEND_DLT_TRANSACTIONS)) {
|
||||
@ -19,6 +18,9 @@ export async function sendTransactionsToDltConnector(
|
||||
try {
|
||||
await createDltTransactions()
|
||||
const dltConnector = DltConnectorClient.getInstance()
|
||||
// TODO: get actual communities from users
|
||||
const senderCommunityUuid = await getHomeCommunityUuid()
|
||||
const recipientCommunityUuid = ''
|
||||
if (dltConnector) {
|
||||
logger.debug('with sending to DltConnector...')
|
||||
const dltTransactions = await DltTransaction.find({
|
||||
@ -26,6 +28,7 @@ export async function sendTransactionsToDltConnector(
|
||||
relations: ['transaction'],
|
||||
order: { createdAt: 'ASC', id: 'ASC' },
|
||||
})
|
||||
|
||||
for (const dltTx of dltTransactions) {
|
||||
if (!dltTx.transaction) {
|
||||
continue
|
||||
|
||||
@ -1 +0,0 @@
|
||||
validator
|
||||
@ -9,4 +9,4 @@ IOTA_API_URL=https://chrysalis-nodes.iota.org
|
||||
IOTA_COMMUNITY_ALIAS=GRADIDO: TestHelloWelt2
|
||||
|
||||
# DLT-Connector
|
||||
DLT_CONNECTOR_PORT=6000
|
||||
DLT_CONNECTOR_PORT=6010
|
||||
@ -16,7 +16,7 @@ ENV BUILD_COMMIT="0000000"
|
||||
## SET NODE_ENV
|
||||
ENV NODE_ENV="production"
|
||||
## App relevant Envs
|
||||
ENV PORT="6000"
|
||||
ENV PORT="6010"
|
||||
|
||||
# Labels
|
||||
LABEL org.label-schema.build-date="${BUILD_DATE}"
|
||||
|
||||
@ -6,7 +6,7 @@ module.exports = {
|
||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
lines: 63,
|
||||
lines: 77,
|
||||
},
|
||||
},
|
||||
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
||||
@ -14,6 +14,8 @@ module.exports = {
|
||||
modulePathIgnorePatterns: ['<rootDir>/build/'],
|
||||
moduleNameMapper: {
|
||||
'@/(.*)': '<rootDir>/src/$1',
|
||||
'@arg/(.*)': '<rootDir>/src/graphql/arg/$1',
|
||||
'@controller/(.*)': '<rootDir>/src/controller/$1',
|
||||
'@enum/(.*)': '<rootDir>/src/graphql/enum/$1',
|
||||
'@resolver/(.*)': '<rootDir>/src/graphql/resolver/$1',
|
||||
'@input/(.*)': '<rootDir>/src/graphql/input/$1',
|
||||
@ -30,6 +32,7 @@ module.exports = {
|
||||
process.env.NODE_ENV === 'development'
|
||||
? '<rootDir>/../database/src/$1'
|
||||
: '<rootDir>/../database/build/src/$1',
|
||||
'@validator/(.*)': '<rootDir>/src/graphql/validator/$1',
|
||||
},
|
||||
}
|
||||
/*
|
||||
|
||||
@ -23,7 +23,7 @@ const iota = {
|
||||
}
|
||||
|
||||
const dltConnector = {
|
||||
DLT_CONNECTOR_PORT: process.env.DLT_CONNECTOR_PORT || 6000,
|
||||
DLT_CONNECTOR_PORT: process.env.DLT_CONNECTOR_PORT || 6010,
|
||||
}
|
||||
|
||||
// Check config version
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
export class Community {
|
||||
|
||||
}
|
||||
162
dlt-connector/src/controller/TransactionBody.test.ts
Normal file
162
dlt-connector/src/controller/TransactionBody.test.ts
Normal file
@ -0,0 +1,162 @@
|
||||
import 'reflect-metadata'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { create, determineCrossGroupType, determineOtherGroup } from './TransactionBody'
|
||||
import { UserIdentifier } from '@/graphql/input/UserIdentifier'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType'
|
||||
import { CrossGroupType } from '@/graphql/enum/CrossGroupType'
|
||||
import { TransactionType } from '@/graphql/enum/TransactionType'
|
||||
import Decimal from 'decimal.js-light'
|
||||
|
||||
describe('test controller/TransactionBody', () => {
|
||||
describe('test create ', () => {
|
||||
const senderUser = new UserIdentifier()
|
||||
const recipientUser = new UserIdentifier()
|
||||
it('test with contribution transaction', () => {
|
||||
const transactionDraft = new TransactionDraft()
|
||||
transactionDraft.senderUser = senderUser
|
||||
transactionDraft.recipientUser = recipientUser
|
||||
transactionDraft.type = TransactionType.CREATION
|
||||
transactionDraft.amount = new Decimal(1000)
|
||||
transactionDraft.createdAt = '2022-01-02T19:10:34.121'
|
||||
transactionDraft.targetDate = '2021-12-01T10:05:00.191'
|
||||
const body = create(transactionDraft)
|
||||
|
||||
expect(body.creation).toBeDefined()
|
||||
expect(body).toMatchObject({
|
||||
createdAt: {
|
||||
seconds: 1641150634,
|
||||
nanoSeconds: 121000000,
|
||||
},
|
||||
versionNumber: '3.3',
|
||||
type: CrossGroupType.LOCAL,
|
||||
otherGroup: '',
|
||||
creation: {
|
||||
recipient: {
|
||||
amount: '1000',
|
||||
},
|
||||
targetDate: {
|
||||
seconds: 1638353100,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
it('test with local send transaction send part', () => {
|
||||
const transactionDraft = new TransactionDraft()
|
||||
transactionDraft.senderUser = senderUser
|
||||
transactionDraft.recipientUser = recipientUser
|
||||
transactionDraft.type = TransactionType.SEND
|
||||
transactionDraft.amount = new Decimal(1000)
|
||||
transactionDraft.createdAt = '2022-01-02T19:10:34.121'
|
||||
const body = create(transactionDraft)
|
||||
|
||||
expect(body.transfer).toBeDefined()
|
||||
expect(body).toMatchObject({
|
||||
createdAt: {
|
||||
seconds: 1641150634,
|
||||
nanoSeconds: 121000000,
|
||||
},
|
||||
versionNumber: '3.3',
|
||||
type: CrossGroupType.LOCAL,
|
||||
otherGroup: '',
|
||||
transfer: {
|
||||
sender: {
|
||||
amount: '1000',
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('test with local send transaction receive part', () => {
|
||||
const transactionDraft = new TransactionDraft()
|
||||
transactionDraft.senderUser = senderUser
|
||||
transactionDraft.recipientUser = recipientUser
|
||||
transactionDraft.type = TransactionType.RECEIVE
|
||||
transactionDraft.amount = new Decimal(1000)
|
||||
transactionDraft.createdAt = '2022-01-02T19:10:34.121'
|
||||
const body = create(transactionDraft)
|
||||
|
||||
expect(body.transfer).toBeDefined()
|
||||
expect(body).toMatchObject({
|
||||
createdAt: {
|
||||
seconds: 1641150634,
|
||||
nanoSeconds: 121000000,
|
||||
},
|
||||
versionNumber: '3.3',
|
||||
type: CrossGroupType.LOCAL,
|
||||
otherGroup: '',
|
||||
transfer: {
|
||||
sender: {
|
||||
amount: '1000',
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
describe('test determineCrossGroupType', () => {
|
||||
const transactionDraft = new TransactionDraft()
|
||||
transactionDraft.senderUser = new UserIdentifier()
|
||||
transactionDraft.recipientUser = new UserIdentifier()
|
||||
|
||||
it('local transaction', () => {
|
||||
expect(determineCrossGroupType(transactionDraft)).toEqual(CrossGroupType.LOCAL)
|
||||
})
|
||||
|
||||
it('test with with invalid input', () => {
|
||||
transactionDraft.recipientUser.communityUuid = 'a72a4a4a-aa12-4f6c-b3d8-7cc65c67e24a'
|
||||
expect(() => determineCrossGroupType(transactionDraft)).toThrow(
|
||||
new TransactionError(
|
||||
TransactionErrorType.NOT_IMPLEMENTED_YET,
|
||||
'cannot determine CrossGroupType',
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
it('inbound transaction (send to sender community)', () => {
|
||||
transactionDraft.type = TransactionType.SEND
|
||||
expect(determineCrossGroupType(transactionDraft)).toEqual(CrossGroupType.INBOUND)
|
||||
})
|
||||
|
||||
it('outbound transaction (send to recipient community)', () => {
|
||||
transactionDraft.type = TransactionType.RECEIVE
|
||||
expect(determineCrossGroupType(transactionDraft)).toEqual(CrossGroupType.OUTBOUND)
|
||||
})
|
||||
})
|
||||
|
||||
describe('test determineOtherGroup', () => {
|
||||
const transactionDraft = new TransactionDraft()
|
||||
transactionDraft.senderUser = new UserIdentifier()
|
||||
transactionDraft.recipientUser = new UserIdentifier()
|
||||
|
||||
it('for inbound transaction, other group is from recipient, missing community id for recipient', () => {
|
||||
expect(() => determineOtherGroup(CrossGroupType.INBOUND, transactionDraft)).toThrowError(
|
||||
new TransactionError(
|
||||
TransactionErrorType.MISSING_PARAMETER,
|
||||
'missing recipient user community id for cross group transaction',
|
||||
),
|
||||
)
|
||||
})
|
||||
it('for inbound transaction, other group is from recipient', () => {
|
||||
transactionDraft.recipientUser.communityUuid = 'b8e9f00a-5a56-4b23-8c44-6823ac9e0d2d'
|
||||
expect(determineOtherGroup(CrossGroupType.INBOUND, transactionDraft)).toEqual(
|
||||
'b8e9f00a-5a56-4b23-8c44-6823ac9e0d2d',
|
||||
)
|
||||
})
|
||||
|
||||
it('for outbound transaction, other group is from sender, missing community id for sender', () => {
|
||||
expect(() => determineOtherGroup(CrossGroupType.OUTBOUND, transactionDraft)).toThrowError(
|
||||
new TransactionError(
|
||||
TransactionErrorType.MISSING_PARAMETER,
|
||||
'missing sender user community id for cross group transaction',
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
it('for outbound transaction, other group is from sender', () => {
|
||||
transactionDraft.senderUser.communityUuid = 'a72a4a4a-aa12-4f6c-b3d8-7cc65c67e24a'
|
||||
expect(determineOtherGroup(CrossGroupType.OUTBOUND, transactionDraft)).toEqual(
|
||||
'a72a4a4a-aa12-4f6c-b3d8-7cc65c67e24a',
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -16,18 +16,10 @@ export const create = (transaction: TransactionDraft): TransactionBody => {
|
||||
body.data = 'gradidoCreation'
|
||||
break
|
||||
case TransactionType.SEND:
|
||||
body.transfer = new GradidoTransfer(transaction)
|
||||
body.data = 'gradidoTransfer'
|
||||
break
|
||||
case TransactionType.RECEIVE:
|
||||
body.transfer = new GradidoTransfer(transaction)
|
||||
body.data = 'gradidoTransfer'
|
||||
break
|
||||
default:
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.NOT_IMPLEMENTED_YET,
|
||||
'transaction type unknown',
|
||||
)
|
||||
}
|
||||
return body
|
||||
}
|
||||
@ -62,13 +54,20 @@ export const determineOtherGroup = (
|
||||
case CrossGroupType.LOCAL:
|
||||
return ''
|
||||
case CrossGroupType.INBOUND:
|
||||
if (!recipientUser.communityUuid) {
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.MISSING_PARAMETER,
|
||||
'missing recipient user community id for cross group transaction',
|
||||
)
|
||||
}
|
||||
return recipientUser.communityUuid
|
||||
case CrossGroupType.OUTBOUND:
|
||||
if (!senderUser.communityUuid) {
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.MISSING_PARAMETER,
|
||||
'missing sender user community id for cross group transaction',
|
||||
)
|
||||
}
|
||||
return senderUser.communityUuid
|
||||
default:
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.NOT_IMPLEMENTED_YET,
|
||||
type.toString() + ' for enum CrossGroupType not implemented yet',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
|
||||
import { IsPositive, IsUUID } from 'class-validator'
|
||||
import { Field, Int, ArgsType } from 'type-graphql'
|
||||
|
||||
@ArgsType()
|
||||
export class User {
|
||||
@Field(() => String)
|
||||
@IsUUID('4')
|
||||
uuid: string
|
||||
|
||||
@Field(() => String)
|
||||
@IsUUID('4')
|
||||
communityUuid: string
|
||||
|
||||
@Field(() => Int, { defaultValue: 1 })
|
||||
@IsPositive()
|
||||
accountNr: number
|
||||
}
|
||||
@ -3,5 +3,5 @@ export enum CrossGroupType {
|
||||
INBOUND = 1,
|
||||
OUTBOUND = 2,
|
||||
// for cross group transaction which haven't a direction like group friend update
|
||||
CROSS = 3,
|
||||
// CROSS = 3,
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import { registerEnumType } from 'type-graphql'
|
||||
|
||||
export enum TransactionErrorType {
|
||||
NOT_IMPLEMENTED_YET = 'Not Implemented yet',
|
||||
MISSING_PARAMETER = 'Missing parameter',
|
||||
}
|
||||
|
||||
registerEnumType(TransactionErrorType, {
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
import { InputType, Field } from 'type-graphql'
|
||||
|
||||
import { isValidDateString } from '../validator/DateString'
|
||||
import { IsBoolean, IsUUID } from 'class-validator'
|
||||
|
||||
@InputType()
|
||||
export class AddCommunityDraft {
|
||||
@Field(() => String)
|
||||
@IsUUID('4')
|
||||
communityUuid: string
|
||||
|
||||
@Field(() => String)
|
||||
@isValidDateString()
|
||||
createdAt: string
|
||||
|
||||
@Field(() => Boolean)
|
||||
@IsBoolean()
|
||||
foreign: boolean
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
|
||||
import { IsUUID } from 'class-validator'
|
||||
import { isValidDateString } from '../validator/DateString'
|
||||
import { InputType, Field } from 'type-graphql'
|
||||
|
||||
@InputType()
|
||||
export class AddUserDraft {
|
||||
@Field(() => String)
|
||||
@IsUUID('4')
|
||||
uuid: string
|
||||
|
||||
@Field(() => String)
|
||||
@IsUUID('4')
|
||||
communityUuid: string
|
||||
|
||||
@Field(() => String)
|
||||
@isValidDateString()
|
||||
createdAt: string
|
||||
}
|
||||
@ -3,22 +3,22 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { TransactionType } from '@enum/TransactionType'
|
||||
import { InputType, Field } from 'type-graphql'
|
||||
import { User } from '@arg/User'
|
||||
import { isValidDateString } from '../validator/DateString'
|
||||
import { IsPositiveDecimal } from '../validator/Decimal'
|
||||
import { IsEnum, IsObject, ValidateNested, IsNumber, Min } from 'class-validator'
|
||||
import { UserIdentifier } from './UserIdentifier'
|
||||
import { isValidDateString } from '@validator/DateString'
|
||||
import { IsPositiveDecimal } from '@validator/Decimal'
|
||||
import { IsEnum, IsObject, ValidateNested } from 'class-validator'
|
||||
|
||||
@InputType()
|
||||
export class TransactionDraft {
|
||||
@Field(() => User)
|
||||
@Field(() => UserIdentifier)
|
||||
@IsObject()
|
||||
@ValidateNested()
|
||||
senderUser: User
|
||||
senderUser: UserIdentifier
|
||||
|
||||
@Field(() => User)
|
||||
@Field(() => UserIdentifier)
|
||||
@IsObject()
|
||||
@ValidateNested()
|
||||
recipientUser: User
|
||||
recipientUser: UserIdentifier
|
||||
|
||||
@Field(() => Decimal)
|
||||
@IsPositiveDecimal()
|
||||
@ -28,10 +28,9 @@ export class TransactionDraft {
|
||||
@IsEnum(TransactionType)
|
||||
type: TransactionType
|
||||
|
||||
@Field(() => Number)
|
||||
@IsNumber()
|
||||
@Min(9783072000000) // 01.01.2001
|
||||
createdAt: number // in milliseconds
|
||||
@Field(() => String)
|
||||
@isValidDateString()
|
||||
createdAt: string // in milliseconds
|
||||
|
||||
// only for creation transactions
|
||||
@Field(() => String, { nullable: true })
|
||||
|
||||
19
dlt-connector/src/graphql/input/UserIdentifier.ts
Normal file
19
dlt-connector/src/graphql/input/UserIdentifier.ts
Normal file
@ -0,0 +1,19 @@
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
|
||||
import { IsPositive, IsUUID } from 'class-validator'
|
||||
import { Field, Int, InputType } from 'type-graphql'
|
||||
|
||||
@InputType()
|
||||
export class UserIdentifier {
|
||||
@Field(() => String)
|
||||
@IsUUID('4')
|
||||
uuid: string
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
@IsUUID('4')
|
||||
communityUuid?: string
|
||||
|
||||
@Field(() => Int, { defaultValue: 1, nullable: true })
|
||||
@IsPositive()
|
||||
accountNr?: number
|
||||
}
|
||||
@ -2,10 +2,11 @@ import { ObjectType, Field } from 'type-graphql'
|
||||
import { TransactionErrorType } from '../enum/TransactionErrorType'
|
||||
|
||||
@ObjectType()
|
||||
export class TransactionError {
|
||||
export class TransactionError implements Error {
|
||||
constructor(type: TransactionErrorType, message: string) {
|
||||
this.type = type
|
||||
this.message = message
|
||||
this.name = type.toString()
|
||||
}
|
||||
|
||||
@Field(() => TransactionErrorType)
|
||||
@ -13,4 +14,7 @@ export class TransactionError {
|
||||
|
||||
@Field(() => String)
|
||||
message: string
|
||||
|
||||
@Field(() => String)
|
||||
name: string
|
||||
}
|
||||
|
||||
@ -3,11 +3,9 @@ import { TransactionError } from './TransactionError'
|
||||
|
||||
@ObjectType()
|
||||
export class TransactionResult {
|
||||
constructor(content: TransactionError | Buffer | string) {
|
||||
constructor(content: TransactionError | string) {
|
||||
if (content instanceof TransactionError) {
|
||||
this.error = content
|
||||
} else if (content instanceof Buffer) {
|
||||
this.messageId = content.toString('hex')
|
||||
} else if (typeof content === 'string') {
|
||||
this.messageId = content
|
||||
}
|
||||
|
||||
@ -2,6 +2,9 @@ import 'reflect-metadata'
|
||||
import { ApolloServer } from '@apollo/server'
|
||||
import { createApolloTestServer } from '@test/ApolloServerMock'
|
||||
import assert from 'assert'
|
||||
import { TransactionResult } from '../model/TransactionResult'
|
||||
|
||||
let apolloTestServer: ApolloServer
|
||||
|
||||
jest.mock('@/client/IotaClient', () => {
|
||||
return {
|
||||
@ -11,8 +14,6 @@ jest.mock('@/client/IotaClient', () => {
|
||||
}
|
||||
})
|
||||
|
||||
let apolloTestServer: ApolloServer
|
||||
|
||||
describe('Transaction Resolver Test', () => {
|
||||
beforeAll(async () => {
|
||||
apolloTestServer = await createApolloTestServer()
|
||||
@ -31,30 +32,45 @@ describe('Transaction Resolver Test', () => {
|
||||
})
|
||||
it('test mocked sendTransaction', async () => {
|
||||
const response = await apolloTestServer.executeOperation({
|
||||
query: 'mutation ($input: TransactionInput!) { sendTransaction(data: $input) }',
|
||||
query:
|
||||
'mutation ($input: TransactionDraft!) { sendTransaction(data: $input) {error {type, message}, messageId} }',
|
||||
variables: {
|
||||
input: {
|
||||
senderUser: {
|
||||
uuid: '0ec72b74-48c2-446f-91ce-31ad7d9f4d65',
|
||||
},
|
||||
recipientUser: {
|
||||
uuid: 'ddc8258e-fcb5-4e48-8d1d-3a07ec371dbe',
|
||||
},
|
||||
type: 'SEND',
|
||||
amount: '10',
|
||||
createdAt: 1688992436,
|
||||
createdAt: '2012-04-17T17:12:00Z',
|
||||
},
|
||||
},
|
||||
})
|
||||
assert(response.body.kind === 'single')
|
||||
expect(response.body.singleResult.errors).toBeUndefined()
|
||||
expect(response.body.singleResult.data?.sendTransaction).toBe(
|
||||
const transactionResult = response.body.singleResult.data?.sendTransaction as TransactionResult
|
||||
expect(transactionResult.messageId).toBe(
|
||||
'5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710',
|
||||
)
|
||||
})
|
||||
|
||||
it('test mocked sendTransaction invalid transactionType ', async () => {
|
||||
const response = await apolloTestServer.executeOperation({
|
||||
query: 'mutation ($input: TransactionInput!) { sendTransaction(data: $input) }',
|
||||
query:
|
||||
'mutation ($input: TransactionDraft!) { sendTransaction(data: $input) {error {type, message}, messageId} }',
|
||||
variables: {
|
||||
input: {
|
||||
senderUser: {
|
||||
uuid: '0ec72b74-48c2-446f-91ce-31ad7d9f4d65',
|
||||
},
|
||||
recipientUser: {
|
||||
uuid: 'ddc8258e-fcb5-4e48-8d1d-3a07ec371dbe',
|
||||
},
|
||||
type: 'INVALID',
|
||||
amount: '10',
|
||||
createdAt: 1688992436,
|
||||
createdAt: '2012-04-17T17:12:00Z',
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -71,12 +87,19 @@ describe('Transaction Resolver Test', () => {
|
||||
|
||||
it('test mocked sendTransaction invalid amount ', async () => {
|
||||
const response = await apolloTestServer.executeOperation({
|
||||
query: 'mutation ($input: TransactionInput!) { sendTransaction(data: $input) }',
|
||||
query:
|
||||
'mutation ($input: TransactionDraft!) { sendTransaction(data: $input) {error {type, message}, messageId} }',
|
||||
variables: {
|
||||
input: {
|
||||
senderUser: {
|
||||
uuid: '0ec72b74-48c2-446f-91ce-31ad7d9f4d65',
|
||||
},
|
||||
recipientUser: {
|
||||
uuid: 'ddc8258e-fcb5-4e48-8d1d-3a07ec371dbe',
|
||||
},
|
||||
type: 'SEND',
|
||||
amount: 'no number',
|
||||
createdAt: 1688992436,
|
||||
createdAt: '2012-04-17T17:12:00Z',
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -93,12 +116,19 @@ describe('Transaction Resolver Test', () => {
|
||||
|
||||
it('test mocked sendTransaction invalid created date ', async () => {
|
||||
const response = await apolloTestServer.executeOperation({
|
||||
query: 'mutation ($input: TransactionInput!) { sendTransaction(data: $input) }',
|
||||
query:
|
||||
'mutation ($input: TransactionDraft!) { sendTransaction(data: $input) {error {type, message}, messageId} }',
|
||||
variables: {
|
||||
input: {
|
||||
senderUser: {
|
||||
uuid: '0ec72b74-48c2-446f-91ce-31ad7d9f4d65',
|
||||
},
|
||||
recipientUser: {
|
||||
uuid: 'ddc8258e-fcb5-4e48-8d1d-3a07ec371dbe',
|
||||
},
|
||||
type: 'SEND',
|
||||
amount: '10',
|
||||
createdAt: '2023-03-02T10:12:00',
|
||||
createdAt: 'not valid',
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -106,10 +136,47 @@ describe('Transaction Resolver Test', () => {
|
||||
expect(response.body.singleResult).toMatchObject({
|
||||
errors: [
|
||||
{
|
||||
message:
|
||||
'Variable "$input" got invalid value "2023-03-02T10:12:00" at "input.createdAt"; Float cannot represent non numeric value: "2023-03-02T10:12:00"',
|
||||
message: 'Argument Validation Error',
|
||||
extensions: {
|
||||
code: 'BAD_USER_INPUT',
|
||||
validationErrors: [
|
||||
{
|
||||
value: 'not valid',
|
||||
property: 'createdAt',
|
||||
constraints: {
|
||||
isValidDateString: 'createdAt must be a valid date string',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
it('test mocked sendTransaction missing creationDate for contribution', async () => {
|
||||
const response = await apolloTestServer.executeOperation({
|
||||
query:
|
||||
'mutation ($input: TransactionDraft!) { sendTransaction(data: $input) {error {type, message}, messageId} }',
|
||||
variables: {
|
||||
input: {
|
||||
senderUser: {
|
||||
uuid: '0ec72b74-48c2-446f-91ce-31ad7d9f4d65',
|
||||
},
|
||||
recipientUser: {
|
||||
uuid: 'ddc8258e-fcb5-4e48-8d1d-3a07ec371dbe',
|
||||
},
|
||||
type: 'CREATION',
|
||||
amount: '10',
|
||||
createdAt: '2012-04-17T17:12:00Z',
|
||||
},
|
||||
},
|
||||
})
|
||||
assert(response.body.kind === 'single')
|
||||
expect(response.body.singleResult.data?.sendTransaction).toMatchObject({
|
||||
error: {
|
||||
type: 'MISSING_PARAMETER',
|
||||
message: 'missing targetDate for contribution',
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -23,7 +23,7 @@ export class TransactionResolver {
|
||||
return '0.1'
|
||||
}
|
||||
|
||||
@Mutation(() => String)
|
||||
@Mutation(() => TransactionResult)
|
||||
async sendTransaction(
|
||||
@Arg('data')
|
||||
transaction: TransactionDraft,
|
||||
@ -37,8 +37,9 @@ export class TransactionResolver {
|
||||
} catch (error) {
|
||||
if (error instanceof TransactionError) {
|
||||
return new TransactionResult(error)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { GraphQLScalarType, Kind, ValueNode } from 'graphql'
|
||||
|
||||
export const DecimalScalar = new GraphQLScalarType<Decimal, string>({
|
||||
export const DecimalScalar = new GraphQLScalarType({
|
||||
name: 'Decimal',
|
||||
description: 'The `Decimal` scalar type to represent currency values',
|
||||
|
||||
|
||||
@ -9,5 +9,13 @@ export const schema = async (): Promise<GraphQLSchema> => {
|
||||
return buildSchema({
|
||||
resolvers: [TransactionResolver],
|
||||
scalarsMap: [{ type: Decimal, scalar: DecimalScalar }],
|
||||
validate: {
|
||||
validationError: { target: false },
|
||||
skipMissingProperties: true,
|
||||
skipNullProperties: true,
|
||||
skipUndefinedProperties: false,
|
||||
forbidUnknownValues: true,
|
||||
stopAtFirstError: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
../../../common/src/graphql/validator
|
||||
@ -1,4 +1,4 @@
|
||||
import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator'
|
||||
import { registerDecorator, ValidationOptions } from 'class-validator'
|
||||
|
||||
export function isValidDateString(validationOptions?: ValidationOptions) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
@ -9,11 +9,11 @@ export function isValidDateString(validationOptions?: ValidationOptions) {
|
||||
propertyName,
|
||||
options: validationOptions,
|
||||
validator: {
|
||||
validate(value: string) {
|
||||
validate(value: string): boolean {
|
||||
return new Date(value).toString() !== 'Invalid Date'
|
||||
},
|
||||
defaultMessage(args: ValidationArguments) {
|
||||
return `${propertyName} must be a valid date string, ${args.property}`
|
||||
defaultMessage(): string {
|
||||
return `${propertyName} must be a valid date string`
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -10,10 +10,10 @@ export function IsPositiveDecimal(validationOptions?: ValidationOptions) {
|
||||
propertyName,
|
||||
options: validationOptions,
|
||||
validator: {
|
||||
validate(value: Decimal) {
|
||||
validate(value: Decimal): boolean {
|
||||
return value.greaterThan(0)
|
||||
},
|
||||
defaultMessage(args: ValidationArguments) {
|
||||
defaultMessage(args: ValidationArguments): string {
|
||||
return `The ${propertyName} must be a positive value ${args.property}`
|
||||
},
|
||||
},
|
||||
20
dlt-connector/src/proto/3_3/GradidoCreation.test.ts
Normal file
20
dlt-connector/src/proto/3_3/GradidoCreation.test.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import 'reflect-metadata'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { GradidoCreation } from './GradidoCreation'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { TransactionErrorType } from '@enum/TransactionErrorType'
|
||||
|
||||
describe('proto/3.3/GradidoCreation', () => {
|
||||
it('test with missing targetDate', () => {
|
||||
const transactionDraft = new TransactionDraft()
|
||||
expect(() => {
|
||||
// eslint-disable-next-line no-new
|
||||
new GradidoCreation(transactionDraft)
|
||||
}).toThrowError(
|
||||
new TransactionError(
|
||||
TransactionErrorType.MISSING_PARAMETER,
|
||||
'missing targetDate for contribution',
|
||||
),
|
||||
)
|
||||
})
|
||||
})
|
||||
@ -3,6 +3,8 @@ import { Field, Message } from '@apollo/protobufjs'
|
||||
import { TimestampSeconds } from './TimestampSeconds'
|
||||
import { TransferAmount } from './TransferAmount'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType'
|
||||
|
||||
// need signature from group admin or
|
||||
// percent of group users another than the receiver
|
||||
@ -10,9 +12,15 @@ import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
export class GradidoCreation extends Message<GradidoCreation> {
|
||||
constructor(transaction: TransactionDraft) {
|
||||
if (!transaction.targetDate) {
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.MISSING_PARAMETER,
|
||||
'missing targetDate for contribution',
|
||||
)
|
||||
}
|
||||
super({
|
||||
recipient: new TransferAmount({ amount: transaction.amount.toString() }),
|
||||
targetDate: new TimestampSeconds(),
|
||||
targetDate: new TimestampSeconds(new Date(transaction.targetDate)),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
16
dlt-connector/src/proto/3_3/Timestamp.test.ts
Normal file
16
dlt-connector/src/proto/3_3/Timestamp.test.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Timestamp } from './Timestamp'
|
||||
|
||||
describe('test timestamp constructor', () => {
|
||||
it('with date input object', () => {
|
||||
const now = new Date('2011-04-17T12:01:10.109')
|
||||
const timestamp = new Timestamp(now)
|
||||
expect(timestamp.seconds).toEqual(1303041670)
|
||||
expect(timestamp.nanoSeconds).toEqual(109000000)
|
||||
})
|
||||
|
||||
it('with milliseconds number input', () => {
|
||||
const timestamp = new Timestamp(1303041670109)
|
||||
expect(timestamp.seconds).toEqual(1303041670)
|
||||
expect(timestamp.nanoSeconds).toEqual(109000000)
|
||||
})
|
||||
})
|
||||
14
dlt-connector/src/proto/3_3/TimestampSeconds.test.ts
Normal file
14
dlt-connector/src/proto/3_3/TimestampSeconds.test.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { TimestampSeconds } from './TimestampSeconds'
|
||||
|
||||
describe('test TimestampSeconds constructor', () => {
|
||||
it('with date input object', () => {
|
||||
const now = new Date('2011-04-17T12:01:10.109')
|
||||
const timestamp = new TimestampSeconds(now)
|
||||
expect(timestamp.seconds).toEqual(1303041670)
|
||||
})
|
||||
|
||||
it('with milliseconds number input', () => {
|
||||
const timestamp = new TimestampSeconds(1303041670109)
|
||||
expect(timestamp.seconds).toEqual(1303041670)
|
||||
})
|
||||
})
|
||||
@ -1,39 +0,0 @@
|
||||
import 'reflect-metadata'
|
||||
import { TransactionType } from '@enum/TransactionType'
|
||||
// import { TransactionInput } from '@input/TransactionInput'
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { TransactionBody } from './TransactionBody'
|
||||
import { TimestampSeconds } from './TimestampSeconds'
|
||||
|
||||
describe('proto/TransactionBodyTest', () => {
|
||||
it('test compatible with graphql/input/TransactionInput', async () => {
|
||||
// test data
|
||||
const type = TransactionType.SEND
|
||||
const amount = new Decimal('10')
|
||||
const createdAt = new TimestampSeconds()
|
||||
createdAt.seconds = 1688992436
|
||||
|
||||
// init both objects
|
||||
// graphql input object
|
||||
/* const transactionInput = new TransactionInput()
|
||||
transactionInput.type = type
|
||||
transactionInput.amount = amount
|
||||
transactionInput.createdAt = createdAt.seconds
|
||||
|
||||
// protobuf object
|
||||
const transactionBody = new TransactionBody()
|
||||
// transactionBody.type = type
|
||||
// transactionBody.amount = amount.toString()
|
||||
transactionBody.createdAt = createdAt
|
||||
|
||||
// create protobuf object from graphql Input object
|
||||
const message = TransactionBody.fromObject(transactionInput)
|
||||
// serialize both protobuf objects
|
||||
const messageBuffer = TransactionBody.encode(message).finish()
|
||||
const messageBuffer2 = TransactionBody.encode(transactionBody).finish()
|
||||
|
||||
// compare
|
||||
expect(messageBuffer).toStrictEqual(messageBuffer2)
|
||||
*/
|
||||
})
|
||||
})
|
||||
@ -18,7 +18,7 @@ export class TransactionBody extends Message<TransactionBody> {
|
||||
const type = determineCrossGroupType(transaction)
|
||||
super({
|
||||
memo: 'Not implemented yet',
|
||||
createdAt: new Timestamp(transaction.createdAt),
|
||||
createdAt: new Timestamp(new Date(transaction.createdAt)),
|
||||
versionNumber: '3.3',
|
||||
type,
|
||||
otherGroup: determineOtherGroup(type, transaction),
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { Field, Message } from '@apollo/protobufjs'
|
||||
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
|
||||
@ -57,6 +57,7 @@
|
||||
"@test/*": ["test/*"],
|
||||
"@proto/*" : ["src/proto/*"],
|
||||
"@controller/*": ["src/controller/*"],
|
||||
"@validator/*" : ["src/graphql/validator/*"]
|
||||
/* external */
|
||||
},
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -163,12 +163,12 @@ services:
|
||||
- internal-net
|
||||
- external-net
|
||||
ports:
|
||||
- 6000:6000
|
||||
- 6010:6010
|
||||
restart: always
|
||||
environment:
|
||||
# Envs used in Dockerfile
|
||||
# - DOCKER_WORKDIR="/app"
|
||||
- PORT=6000
|
||||
- PORT=6010
|
||||
- BUILD_DATE
|
||||
- BUILD_VERSION
|
||||
- BUILD_COMMIT
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user