From 0e10dc5353480f0bd1b32a7add6376f342da4140 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 7 Dec 2023 21:25:40 +0100 Subject: [PATCH] add Account.test, increase coverage by 1% --- dlt-connector/jest.config.js | 2 +- dlt-connector/src/data/Account.factory.ts | 1 + dlt-connector/src/data/Account.test.ts | 180 ++++++++++++++++++++++ dlt-connector/src/utils/cryptoHelper.ts | 19 ++- dlt-connector/test/TestDB.ts | 1 + 5 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 dlt-connector/src/data/Account.test.ts diff --git a/dlt-connector/jest.config.js b/dlt-connector/jest.config.js index 1faef9414..2de18cf50 100644 --- a/dlt-connector/jest.config.js +++ b/dlt-connector/jest.config.js @@ -6,7 +6,7 @@ module.exports = { collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'], coverageThreshold: { global: { - lines: 70, + lines: 71, }, }, setupFiles: ['/test/testSetup.ts'], diff --git a/dlt-connector/src/data/Account.factory.ts b/dlt-connector/src/data/Account.factory.ts index 32ffe9ff1..493e394bb 100644 --- a/dlt-connector/src/data/Account.factory.ts +++ b/dlt-connector/src/data/Account.factory.ts @@ -27,6 +27,7 @@ export class AccountFactory { account.createdAt = createdAt account.balanceConfirmedAt = new Decimal(0) account.balanceCreatedAt = new Decimal(0) + account.balanceCreatedAtDate = createdAt return account } diff --git a/dlt-connector/src/data/Account.test.ts b/dlt-connector/src/data/Account.test.ts new file mode 100644 index 000000000..5a1e00277 --- /dev/null +++ b/dlt-connector/src/data/Account.test.ts @@ -0,0 +1,180 @@ +import 'reflect-metadata' +import { TestDB } from '@test/TestDB' +import { AccountFactory } from './Account.factory' +import { AddressType } from './proto/3_3/enum/AddressType' +import { generateKeyPair, generateMnemonic } from '@/utils/cryptoHelper' +import { Decimal } from 'decimal.js-light' +import { UserAccountDraft } from '@/graphql/input/UserAccountDraft' +import { AccountType } from '@/graphql/enum/AccountType' +import { UserIdentifier } from '@/graphql/input/UserIdentifier' +import { AccountRepository } from './Account.repository' +import { UserFactory } from './User.factory' +// eslint-disable-next-line n/no-extraneous-import +import { v4 as uuidv4 } from 'uuid' +import { UserLogic } from './User.logic' + +const con = TestDB.instance + +jest.mock('@typeorm/DataSource', () => ({ + getDataSource: jest.fn(() => TestDB.instance.dbConnect), +})) + +describe('data/Account test factory and repository', () => { + const now = new Date() + const keyPair1 = generateKeyPair(generateMnemonic('62ef251edc2416f162cd24ab1711982b')) + const keyPair2 = generateKeyPair(generateMnemonic('000a0000000002000000000003000070')) + const keyPair3 = generateKeyPair(generateMnemonic('00ba541a1000020000000000300bda70')) + const userGradidoID = '6be949ab-8198-4acf-ba63-740089081d61' + + describe('test factory methods', () => { + beforeAll(async () => { + await con.setupTestDB() + }) + afterAll(async () => { + await con.teardownTestDB() + }) + + it('test createAccount', () => { + const account = AccountFactory.createAccount(now, 1, AddressType.COMMUNITY_HUMAN, keyPair1) + expect(account).toMatchObject({ + derivationIndex: 1, + type: AddressType.COMMUNITY_HUMAN, + createdAt: now, + balanceCreatedAtDate: now, + balanceConfirmedAt: new Decimal(0), + balanceCreatedAt: new Decimal(0), + }) + }) + + it('test createAccountFromUserAccountDraft', () => { + const userAccountDraft = new UserAccountDraft() + userAccountDraft.createdAt = now.toISOString() + userAccountDraft.accountType = AccountType.COMMUNITY_HUMAN + userAccountDraft.user = new UserIdentifier() + userAccountDraft.user.accountNr = 1 + const account = AccountFactory.createAccountFromUserAccountDraft(userAccountDraft, keyPair1) + expect(account).toMatchObject({ + derivationIndex: 1, + type: AddressType.COMMUNITY_HUMAN, + createdAt: now, + balanceCreatedAtDate: now, + balanceConfirmedAt: new Decimal(0), + balanceCreatedAt: new Decimal(0), + }) + }) + + it('test createGmwAccount', () => { + const account = AccountFactory.createGmwAccount(keyPair1, now) + expect(account).toMatchObject({ + derivationIndex: 2147483649, + type: AddressType.COMMUNITY_GMW, + createdAt: now, + balanceCreatedAtDate: now, + balanceConfirmedAt: new Decimal(0), + balanceCreatedAt: new Decimal(0), + }) + }) + + it('test createAufAccount', () => { + const account = AccountFactory.createAufAccount(keyPair1, now) + expect(account).toMatchObject({ + derivationIndex: 2147483650, + type: AddressType.COMMUNITY_AUF, + createdAt: now, + balanceCreatedAtDate: now, + balanceConfirmedAt: new Decimal(0), + balanceCreatedAt: new Decimal(0), + }) + }) + }) + + describe('test repository functions', () => { + beforeAll(async () => { + await con.setupTestDB() + + await Promise.all([ + AccountFactory.createAufAccount(keyPair1, now).save(), + AccountFactory.createGmwAccount(keyPair1, now).save(), + AccountFactory.createAufAccount(keyPair2, now).save(), + AccountFactory.createGmwAccount(keyPair2, now).save(), + AccountFactory.createAufAccount(keyPair3, now).save(), + AccountFactory.createGmwAccount(keyPair3, now).save(), + ]) + const userAccountDraft = new UserAccountDraft() + userAccountDraft.accountType = AccountType.COMMUNITY_HUMAN + userAccountDraft.createdAt = now.toString() + userAccountDraft.user = new UserIdentifier() + userAccountDraft.user.accountNr = 1 + userAccountDraft.user.uuid = userGradidoID + const user = UserFactory.create(userAccountDraft, keyPair1) + const userLogic = new UserLogic(user) + const account = AccountFactory.createAccountFromUserAccountDraft( + userAccountDraft, + userLogic.calculateKeyPair(keyPair1), + ) + account.user = user + // user is set to cascade: ['insert'] will be saved together with account + await account.save() + }) + afterAll(async () => { + await con.teardownTestDB() + }) + it('test findAccountsByPublicKeys', async () => { + const accounts = await AccountRepository.findAccountsByPublicKeys([ + Buffer.from('6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', 'hex'), + Buffer.from('0fa996b73b624592fe326b8500cb1e3f10026112b374d84c87d097f4d489c019', 'hex'), + Buffer.from('0ffa996b73b624592f26b850b0cb1e3f1026112b374d84c87d017f4d489c0197', 'hex'), // invalid + ]) + expect(accounts).toHaveLength(2) + expect(accounts).toMatchObject( + expect.arrayContaining([ + expect.objectContaining({ + derivationIndex: 2147483649, + derive2Pubkey: Buffer.from( + '0fa996b73b624592fe326b8500cb1e3f10026112b374d84c87d097f4d489c019', + 'hex', + ), + type: AddressType.COMMUNITY_GMW, + }), + expect.objectContaining({ + derivationIndex: 2147483650, + derive2Pubkey: Buffer.from( + '6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', + 'hex', + ), + type: AddressType.COMMUNITY_AUF, + }), + ]), + ) + }) + + it('test findAccountByPublicKey', async () => { + expect( + await AccountRepository.findAccountByPublicKey( + Buffer.from('6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', 'hex'), + ), + ).toMatchObject({ + derivationIndex: 2147483650, + derive2Pubkey: Buffer.from( + '6c749f8693a4a58c948e5ae54df11e2db33d2f98673b56e0cf19c0132614ab59', + 'hex', + ), + type: AddressType.COMMUNITY_AUF, + }) + }) + + it('test findAccountByUserIdentifier', async () => { + const userIdentifier = new UserIdentifier() + userIdentifier.accountNr = 1 + userIdentifier.uuid = userGradidoID + expect(await AccountRepository.findAccountByUserIdentifier(userIdentifier)).toMatchObject({ + derivationIndex: 1, + derive2Pubkey: Buffer.from( + '2099c004a26e5387c9fbbc9bb0f552a9642d3fd7c710ae5802b775d24ff36f93', + 'hex', + ), + type: AddressType.COMMUNITY_HUMAN, + }) + }) + }) +}) diff --git a/dlt-connector/src/utils/cryptoHelper.ts b/dlt-connector/src/utils/cryptoHelper.ts index 1eb5db36d..467a85e85 100644 --- a/dlt-connector/src/utils/cryptoHelper.ts +++ b/dlt-connector/src/utils/cryptoHelper.ts @@ -1,6 +1,23 @@ import { KeyPair } from '@/data/KeyPair' -import { sign as ed25519Sign } from 'bip32-ed25519' +import { sign as ed25519Sign, generateFromSeed } from 'bip32-ed25519' +import { entropyToMnemonic, mnemonicToSeedSync } from 'bip39' +// eslint-disable-next-line camelcase +import { randombytes_buf } from 'sodium-native' export const sign = (message: Buffer, keyPair: KeyPair): Buffer => { return ed25519Sign(message, keyPair.getExtendPrivateKey()) } + +export const generateKeyPair = (mnemonic: string): KeyPair => { + const seedFromMnemonic = mnemonicToSeedSync(mnemonic) + return new KeyPair(generateFromSeed(seedFromMnemonic)) +} + +export const generateMnemonic = (seed?: Buffer | string): string => { + if (seed) { + return entropyToMnemonic(seed) + } + const entropy = Buffer.alloc(256) + randombytes_buf(entropy) + return entropyToMnemonic(entropy) +} diff --git a/dlt-connector/test/TestDB.ts b/dlt-connector/test/TestDB.ts index 457954f7d..75f362c65 100644 --- a/dlt-connector/test/TestDB.ts +++ b/dlt-connector/test/TestDB.ts @@ -6,6 +6,7 @@ import { entities } from '@entity/index' import { CONFIG } from '@/config' import { LogError } from '@/server/LogError' +// TODO: maybe use in memory db like here: https://dkzeb.medium.com/unit-testing-in-ts-jest-with-typeorm-entities-ad5de5f95438 export class TestDB { // eslint-disable-next-line no-use-before-define private static _instance: TestDB