Fix MicroProfile transaction queries: wrong endpoint, broken serialization, and JSON parsing errors#56
Conversation
67cea61 to
4d1f4ea
Compare
Ndacyayisenga-droid
left a comment
There was a problem hiding this comment.
Thanks @alejandroGM0. PR looks good.
Could you fix the formatting issues with mvn spotless:apply
And for some reason I can't be able to merge your Prs
…ation, and JSON parsing errors Fix all four MirrorNodeClientImpl transaction query methods that were hitting /api/v1/tokens instead of /api/v1/transactions, returning token listings instead of transaction data. Also fix enum serialization so the mirror-node receives correct parameter values. MirrorNodeClientImpl (MicroProfile): - Extract TRANSACTIONS_PATH, TOKENS_PATH, TOPICS_PATH constants - Fix endpoint: /api/v1/tokens -> /api/v1/transactions in all 4 methods - Fix queryTransactionsByAccountAndType: type -> type.getType() - Fix queryTransactionsByAccountAndResult: result -> result.name() - Fix queryTransactionsByAccountAndModification: type -> type.name() MirrorNodeJsonConverterImpl (MicroProfile): - Fix charged_tx_fee, amount, serial_number: getString+parseLong -> getJsonNumber - Fix bytes, entity_id, node: getString -> getNullableString helper - Fix parent_consensus_timestamp null check: use jsonObject.isNull() - Fix jsonArrayToStream: remove throw on empty arrays MirrorNodeClientImpl (Spring): - Extract ACCOUNTS_PATH, TRANSACTIONS_PATH, TOKENS_PATH, TOPICS_PATH constants New tests: - MirrorNodeClientImplPathTest: 5 unit tests verifying URL path construction - TransactionRepositoryTest: 5 integration tests matching Spring parity Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
`queryTransactionsByAccountAndType` had a 6-space continuation indent that failed `spotless:check` in CI. Bring it to 8 spaces to match the project format. Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
Run `mvn spotless:apply` over the files touched in this PR. Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
4088bd7 to
3baa7aa
Compare
Done |
HieroTestProducer is @ApplicationScoped and discovered automatically by CDI. Adding @AddBean(HieroTestProducer.class) registered it a second time, causing WELD-001409 Ambiguous dependencies for HieroTestUtils in TransactionRepositoryTest. Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
Previous run hit a flaky mirror-node indexing race in TransactionRepositoryTest.testFindTransactionByAccountId. Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
|
There seems to be a race condition in the tests causing the flow tests to fail randomly (not always): the test creates a new account and immediately asks the mirror node to list its transactions, but the "by account" index sometimes takes a few hundred ms longer to update than the "by tx-id" one, so the list comes back empty. I'm looking into this. |
HieroTestUtils.waitForMirrorNodeRecords() only polls the by-transaction-id index, but tests that assert on results obtained through the by-account index can still observe an empty page for a freshly created account because both indexes are updated independently. Add an overload that, after the existing wait, also polls queryTransactionsByAccount(accountId) until it returns data. Use it in the Spring and MicroProfile tests that assert assertFalse(data.isEmpty()). Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
@Ndacyayisenga-droid |
There was a problem hiding this comment.
Not part of your changes but throwing UnsupportedOperationException for now here makes more sense
| * A test subclass that captures the path passed to RestBasedPage without making any HTTP call. | ||
| * This lets us verify the URL path construction in isolation. | ||
| */ | ||
| static class PathCapturingMirrorNodeClient extends MirrorNodeClientImpl { |
There was a problem hiding this comment.
This is never referenced anywhere, and the comment describes capturing the path without HTTP, but nothing in the suite does that yet. That makes the class look like a leftover spike. I would suggest we remove if we dont use it anywhere
| } | ||
|
|
||
| @Test | ||
| void testFindTransactionByAccountIdGiveEmptyListForAccountIdWithZeroTransaction() |
There was a problem hiding this comment.
Method too long I would rename it to something like findByAccountReturnsEmptyWhenNoTransactions()
| final Page<TransactionInfo> page = | ||
| transactionRepository.findByAccountAndType( | ||
| account.accountId(), TransactionType.ACCOUNT_CREATE); | ||
| Assertions.assertNotNull(page); |
There was a problem hiding this comment.
assertNotNull(page) does not prove the repository or mirror client applied the filter, an empty page or wrong rows would still pass. Consider asserting page.getData() is non-empty when you expect activity, and that every returned TransactionInfo matches the requested type / result / modification (or assert on fields you trust from the mirror response).
| hieroTestUtils.waitForMirrorNodeRecords(); | ||
| final Page<TransactionInfo> page = | ||
| transactionRepository.findByAccountAndResult(account.accountId(), Result.SUCCESS); | ||
| Assertions.assertNotNull(page); |
| hieroTestUtils.waitForMirrorNodeRecords(); | ||
| final Page<TransactionInfo> page = | ||
| transactionRepository.findByAccountAndModification( | ||
| account.accountId(), BalanceModification.DEBIT); |
There was a problem hiding this comment.
I would instead use CREDIT as DEBIT often yields no rows for a brand-new id!
| final Page<TransactionInfo> page = | ||
| transactionRepository.findByAccountAndModification( | ||
| account.accountId(), BalanceModification.DEBIT); | ||
| Assertions.assertNotNull(page); |
| final Account account = accountClient.createAccount(1); | ||
| hieroTestUtils.waitForMirrorNodeRecords(account.accountId()); | ||
| final Page<TransactionInfo> page = transactionRepository.findByAccount(account.accountId()); | ||
| Assertions.assertNotNull(page); |
There was a problem hiding this comment.
If transactionRepository.findByAccount(...) guarantees a non-null Page, then assertNotNull(page) is redundant since page.getData() would already fail if null. Fine to keep for readability, otherwise you could rely on the getData() assertions alone.
Keep the PR focused on the maintainer feedback by tightening the MirrorNode query tests, centralizing null-check messages, and redacting test config values during local runs. Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
Keep the current PR focused on the maintainer-requested transaction query changes. The TestConfigSource logging change is being handled separately. Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
6511ce9 to
55cb10b
Compare
Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
Keep the null-check message extraction aligned with the repository formatting rules so the MicroProfile Spotless check passes in CI. Signed-off-by: Alejandro <26930485+alejandroGM0@users.noreply.github.com>
Fixes #55
Summary
Fixes all four
MirrorNodeClientImpltransaction query methods that were hitting/api/v1/tokensinstead of/api/v1/transactions, making them return token listings instead of transaction data. Also fixes enum serialization so the mirror-node receives the correct parameter values.Beyond the endpoint fix, the JSON response parser (
MirrorNodeJsonConverterImpl) crashes on live mirror-node transaction responses due to type mismatches and null handling errors. These are fixed together since the parser bugs are on the same code path and would be the immediate next failure after correcting the endpoint.Changes
MirrorNodeClientImpl.java(MicroProfile)TRANSACTIONS_PATH,TOKENS_PATH,TOPICS_PATHconstants/api/v1/tokens->/api/v1/transactionsin all 4 transaction query methodsqueryTransactionsByAccountAndType:type->type.getType()(sends protocol stringCRYPTOCREATEACCOUNTinstead of Java enumACCOUNT_CREATE)queryTransactionsByAccountAndResult:result->result.name()queryTransactionsByAccountAndModification:type->type.name()MirrorNodeJsonConverterImpl.java(MicroProfile)charged_tx_fee,amount,serial_numberparsing:Long.parseLong(getString(...))->getJsonNumber(...).longValue()(mirror-node returns JSON numbers)bytes,entity_id,nodeparsing:getString()->getNullableString()helper (mirror-node returns JSON null for these fields)parent_consensus_timestampnull check:.get(...).asJsonObject() == null->jsonObject.isNull(key)jsonArrayToStream: remove throw on empty array (empty result sets are valid)MirrorNodeClientImpl.java(Spring)ACCOUNTS_PATH,TRANSACTIONS_PATH,TOKENS_PATH,TOPICS_PATHconstants (consistency, no bug fix)New tests
MirrorNodeClientImplPathTest— 5 unit tests verifying path construction (no live network needed)TransactionRepositoryTest— 5 integration tests matching the existing SpringTransactionRepositoryTestHow verified
mvn test -pl hiero-enterprise-microprofile -Dtest=MirrorNodeClientImplPathTest(5/5)git show HEAD:...MirrorNodeClientImpl.javathat the original code uses/api/v1/tokens/api/v1/tokens?account.id=0.0.98returns token data, while/api/v1/transactions?account.id=0.0.98returns transaction datatransactiontype=ACCOUNT_CREATEbut acceptstransactiontype=CRYPTOCREATEACCOUNT