From b8509490ad26ff52f5dab6061b3e8bcc74395798 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Fri, 30 Jul 2021 14:19:10 +0530 Subject: [PATCH] retry count check build err fix retry condition testcase retryCount to maxRetryCount Signed-off-by: sapthasurendran --- .../scripts/generateEnv.sh | 2 + .../src/__mocks__/config.ts | 3 +- .../src/__mocks__/fabric-network.ts | 12 +++ .../src/__tests__/fabric.test.ts | 97 +++++++++++++++++++ .../rest-api-typescript/src/config.ts | 6 ++ .../rest-api-typescript/src/fabric.ts | 16 ++- .../rest-api-typescript/src/redis.ts | 17 ++++ 7 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index c0af2374..902397f8 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -21,6 +21,8 @@ PORT=3000 RETRY_DELAY=3000 +MAX_RETRY_COUNT=5 + HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c .) HLF_CERTIFICATE_ORG1="$(cat ${CERTIFICATE_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts index b3a2bc44..42dddbab 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts @@ -7,6 +7,7 @@ export const logLevel = 'info'; export const port = '3000'; export const retryDelay = '3000'; +export const maxRetryCount = 5; export const asLocalHost = true; @@ -46,7 +47,7 @@ export const redisHost = 'localhost'; export const redisPort = '6379'; -export const redisUsername = 'conga'; +export const redisUsername = ''; export const redisPassword = ''; diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts index 216baff7..9ae7e06e 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts @@ -32,10 +32,22 @@ mocked(Gateway.prototype.getNetwork).mockResolvedValue({ addBlockListener: jest.fn(), removeBlockListener: jest.fn(), }); +const getMockedNetwork = (getContract = jest.fn()) => { + return mocked(Gateway.prototype.getNetwork).mockResolvedValue({ + getGateway: jest.fn(), + getContract, + getChannel: jest.fn(), + addCommitListener: jest.fn(), + removeCommitListener: jest.fn(), + addBlockListener: jest.fn(), + removeBlockListener: jest.fn(), + }); +}; export { DefaultEventHandlerStrategies, DefaultQueryHandlerStrategies, Gateway, Wallets, + getMockedNetwork, }; diff --git a/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts b/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts new file mode 100644 index 00000000..16ec024d --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts @@ -0,0 +1,97 @@ +import { retryTransaction } from '../fabric'; + +import { getMockedNetwork } from '../__mocks__/fabric-network'; +import { Redis } from 'ioredis'; +import * as redis from '../redis'; +// import { Gateway, Gateway, Gateway } from 'fabric-network'; + +/** + * retryTransaction + */ +jest.mock('../config'); + + +describe('Testing retryTransaction', () => { + let contract: any = null; + const transaction = { + submit: jest.fn().mockRejectedValue({}), + }; + const mockedContact = { + deserializeTransaction: jest.fn().mockReturnValue(transaction), + }; + beforeAll(async () => { + const rejectableGetContract = jest.fn().mockImplementation( + () => + mockedContact + ); + + const network = getMockedNetwork(rejectableGetContract)(''); + contract = (await network).getContract(''); + + }); + + describe('Check retry condition ', () => { + const transactionId = + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; + const key = `txn:${transactionId}`; + const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; + const args = '["test111","red",400,"Jean",101]'; + const timestamp = 1628078044362; + const savedTransaction = { + timestamp: timestamp.toString(), + state: state, + retries: '', + args: args, + }; + + let data: Record = {}; + beforeEach(() => { + data = {}; + const clearTransactionDetails = jest.spyOn( + redis, + 'clearTransactionDetails' + ); + clearTransactionDetails.mockImplementation( + async (redis: Redis, transactionId: string) => { + const key = `txn:${transactionId}`; + delete data[key]; + } + ); + + const incrementRetryCount = jest.spyOn(redis, 'incrementRetryCount'); + incrementRetryCount.mockImplementation( + async (redis: Redis, transactionId: string) => { + const key = `txn:${transactionId}`; + data[key].retries = (parseInt(data[key].retries) + 1).toString(); + } + ); + }); + it('Transaction should exist if retry count is less then max rety count', async () => { + savedTransaction.retries = '3'; + data = { [key]: savedTransaction }; + await retryTransaction( + contract, + redis.redis, + transactionId, + savedTransaction + ); + expect(data[key]).toMatchObject({ + timestamp: timestamp.toString(), + state: state, + retries: '4', + args: args, + }); + }); + it('Clear transaction once retry reaches max retry count ', async () => { + savedTransaction.retries = '5'; + data = { [key]: savedTransaction }; + await retryTransaction( + contract, + redis.redis, + transactionId, + savedTransaction + ); + expect(data[key]).toBe(undefined); + }); + }); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index cc1b4216..375fc953 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -21,6 +21,12 @@ export const retryDelay = env .example('3000') .asIntPositive(); + export const maxRetryCount = env + .get('MAX_RETRY_COUNT') + .default('5') + .example('5') + .asIntPositive(); + export const asLocalHost = env .get('AS_LOCAL_HOST') .default('true') diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 4e642700..b28c6444 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -18,7 +18,11 @@ import { Request } from 'express'; import { Redis } from 'ioredis'; import * as config from './config'; import { logger } from './logger'; -import { storeTransactionDetails, clearTransactionDetails } from './redis'; +import { + storeTransactionDetails, + clearTransactionDetails, + incrementRetryCount, +} from './redis'; import { AssetExistsError, AssetNotFoundError, @@ -251,12 +255,12 @@ const handleError = (transactionId: string, err: Error): Error => { return new TransactionError('Transaction error', transactionId); }; -const retryTransaction = async ( +export const retryTransaction = async ( contract: Contract, redis: Redis, transactionId: string, savedTransaction: Record -) => { +): Promise => { logger.debug('Retrying transaction %s', transactionId); try { @@ -279,7 +283,11 @@ const retryTransaction = async ( savedTransaction.retries, transactionId ); - await (redis as Redis).hincrby(`txn:${transactionId}`, 'retries', 1); + if (parseInt(savedTransaction.retries) < config.maxRetryCount) { + await incrementRetryCount(redis, transactionId); + } else { + await clearTransactionDetails(redis, transactionId); + } } } }; diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.ts b/asset-transfer-basic/rest-api-typescript/src/redis.ts index d799d800..2077a68b 100644 --- a/asset-transfer-basic/rest-api-typescript/src/redis.ts +++ b/asset-transfer-basic/rest-api-typescript/src/redis.ts @@ -70,3 +70,20 @@ export const clearTransactionDetails = async ( }; // TODO add getTransaction etc. helpers? + +export const incrementRetryCount = async ( + redis: Redis, + transactionId: string +): Promise => { + const key = `txn:${transactionId}`; + logger.debug('Incrementing retries fortransaction Key: %s', key); + try { + await (redis as Redis).hincrby(`txn:${transactionId}`, 'retries', 1); + } catch (err) { + logger.error( + err, + 'Error incrementing retries for transaction ID %s', + transactionId + ); + } +};