Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get account key endpoints #136

Merged
merged 18 commits into from
Oct 30, 2024
Merged

Get account key endpoints #136

merged 18 commits into from
Oct 30, 2024

Conversation

lealobanov
Copy link
Collaborator

@lealobanov lealobanov commented Oct 25, 2024

Closes: #126

Description

  • Add GetAccountKeyAtLatestBlock, GetAccountKeysAtLatestBlock, GetAccountKeyAtBlockHeight and GetAccountKeysAtBlockHeight methods to FlowAccessAPI

  • Add above 4 methods to AsyncFlowAccessAPI

  • Add new unit tests for above 4 methods

  • Add new integration tests for above 4 methods

  • Add examples for getAccountKeys

  • Update examples docs with new methods

  • Refactor AsyncFlowAccessAPI unit tests to remove code duplication where possible


For contributor use:

  • Targeted PR against master branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the standards mentioned here.
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

Summary by CodeRabbit

  • New Features
    • Introduced methods for retrieving account keys at the latest block and specific block heights in both Java and Kotlin implementations.
    • Added functionality to fetch all account keys at the latest block and at specified block heights.
    • New feature to retrieve transaction results by index in both Java and Kotlin implementations.
    • Enhanced documentation to reflect new functionalities for account keys and transaction results in both Java and Kotlin examples.
  • Bug Fixes
    • Enhanced error handling in API calls for retrieving account keys and transaction results.
  • Tests
    • Added comprehensive test coverage for new account key retrieval methods and transaction result retrieval, including success and error scenarios across various test classes.

Copy link
Contributor

coderabbitai bot commented Oct 25, 2024

Walkthrough

A new Java class GetAccountKeysAccessAPIConnector and a Kotlin counterpart have been added to facilitate interaction with the Flow blockchain's access API for retrieving account keys. Each class includes multiple methods to fetch account keys at the latest block or at specified block heights. Additionally, corresponding unit tests have been created for both Java and Kotlin implementations, ensuring comprehensive coverage of the new functionalities. The FlowAccessApi and AsyncFlowAccessApi interfaces have also been updated to include these new methods, along with extensive integration and unit tests across the SDK.

Changes

File Change Summary
java-example/src/main/java/org/onflow/examples/java/getAccountKeys/GetAccountKeysAccessAPIConnector.java Added class GetAccountKeysAccessAPIConnector with methods for retrieving account keys at various block heights.
java-example/src/test/java/org/onflow/examples/java/getAccountKeys/GetAccountKeysAccessAPIConnectorTest.java Added unit tests for GetAccountKeysAccessAPIConnector covering various retrieval scenarios.
kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountKeys/GetAccountKeysAccessAPIConnector.kt Added class GetAccountKeysAccessAPIConnector with methods for retrieving account keys at various block heights.
kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountKeys/GetAccountKeysAccessAPIConnectorTest.kt Added unit tests for GetAccountKeysAccessAPIConnector covering various retrieval scenarios.
sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt Updated to include new methods for account key retrieval at latest block and specified block height.
sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt Updated to include new methods for account key retrieval at latest block and specified block height.
sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt Implemented new methods for account key retrieval in AsyncFlowAccessApiImpl.
sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt Implemented new methods for account key retrieval in FlowAccessApiImpl.
sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt Added tests for new account key retrieval methods in FlowAccessApi.
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt Added tests for new account key retrieval methods in AsyncFlowAccessApiImpl.
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt Added tests for new account key retrieval methods in FlowAccessApiImpl.
sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt Added integration tests for account key retrieval methods.

Assessment against linked issues

Objective Addressed Explanation
Add GetAccountKeyAtLatestBlock, GetAccountKeysAtLatestBlock, GetAccountBalanceAtBlockHeight and GetAccountKeysAtBlockHeight to the SDK (#[126])

Possibly related issues

Possibly related PRs

Suggested reviewers

  • franklywatson
  • jribbink

🐰 In the land of code, we hop and play,
New keys to fetch, in a seamless way.
With tests in place, we dance with glee,
Account keys await, come fetch with me!
🥕✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@lealobanov lealobanov changed the base branch from main to full-block-response-protobuf October 25, 2024 10:07
Copy link

github-actions bot commented Oct 25, 2024

Unit Test Results

  62 files  ±0    62 suites  ±0   24s ⏱️ ±0s
380 tests ±0  380 ✔️ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 662759b. ± Comparison against base commit 662759b.

♻️ This comment has been updated with latest results.

Copy link

github-actions bot commented Oct 25, 2024

SDK Examples Unit Test Results

41 files  41 suites   7m 49s ⏱️
88 tests 87 ✔️ 0 💤 1 ❌

For more details on these failures, see this check.

Results for commit 0a8e1c9.

♻️ This comment has been updated with latest results.

Copy link

github-actions bot commented Oct 25, 2024

Integration Test Results

  6 files  ±0    6 suites  ±0   3m 15s ⏱️ ±0s
38 tests ±0  38 ✔️ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 662759b. ± Comparison against base commit 662759b.

♻️ This comment has been updated with latest results.

Copy link

github-actions bot commented Oct 25, 2024

Common Integration Test Results

0 files  0 suites   0s ⏱️
0 tests 0 ✔️ 0 💤 0 ❌

Results for commit 0a8e1c9.

♻️ This comment has been updated with latest results.

Base automatically changed from full-block-response-protobuf to main October 25, 2024 16:06
@lealobanov lealobanov changed the title WIP: Get account key endpoints Get account key endpoints Oct 28, 2024
@lealobanov lealobanov marked this pull request as ready for review October 28, 2024 09:44
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

🧹 Outside diff range and nitpick comments (24)
kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountKeys/GetAccountKeysAccessAPIConnector.kt (2)

1-7: Consider using specific imports instead of wildcard import.

Replace the wildcard import with specific imports for better code clarity and to avoid potential naming conflicts.

-import org.onflow.flow.sdk.*
+import org.onflow.flow.sdk.FlowAccessApi
+import org.onflow.flow.sdk.FlowAddress
+import org.onflow.flow.sdk.FlowAccountKey

8-30: Add KDoc documentation for public methods.

Add documentation to describe method parameters, return values, and possible exceptions for better API understanding.

Example for one method:

/**
 * Retrieves an account key at the latest block.
 *
 * @param address The Flow address of the account
 * @param keyIndex The index of the key to retrieve
 * @return The account key at the specified index
 * @throws FlowKeyNotFoundException if the key is not found
 * @throws FlowApiException if the API call fails
 */
fun getAccountKeyAtLatestBlock(address: FlowAddress, keyIndex: Int): FlowAccountKey
sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt (1)

13-16: LGTM! Methods provide comprehensive account key access.

Both methods follow consistent patterns and complement the single-key retrieval methods. The return types correctly handle multiple keys, and the parameter naming is clear and consistent.

Consider implementing caching for these methods in the implementation class, especially for the latest block queries, to improve performance for frequent requests.

sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt (1)

21-28: Consider adding KDoc documentation.

While the method signatures are clear, adding KDoc documentation would help users understand:

  • Parameter constraints (e.g., valid key index ranges)
  • Error conditions that might occur
  • Example usage scenarios

Example documentation format:

/**
 * Retrieves an account key at the latest sealed block.
 *
 * @param address The Flow address to query
 * @param keyIndex The index of the key to retrieve (must be non-negative)
 * @return Success with FlowAccountKey if found, Error if key index is invalid or account not found
 */
fun getAccountKeyAtLatestBlock(address: FlowAddress, keyIndex: Int): AccessApiCallResponse<FlowAccountKey>
kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountKeys/GetAccountKeysAccessAPIConnectorTest.kt (1)

12-25: Add documentation for test environment setup requirements.

Consider adding KDoc comments to explain:

  • Required Flow emulator configuration
  • Purpose of the service account credentials
  • Test client configuration requirements

Example addition:

/**
 * Tests for GetAccountKeysAccessAPIConnector using Flow emulator.
 * Requires:
 * - Flow emulator running with configuration from "../flow/flow.json"
 * - Service account credentials configured in the emulator
 * - Test client with appropriate network access
 */
@FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json")
internal class GetAccountKeysAccessAPIConnectorTest {
java-example/src/test/java/org/onflow/examples/java/getAccountKeys/GetAccountKeysAccessAPIConnectorTest.java (1)

32-113: Consider adding edge case tests.

The current test suite covers the happy path well, but consider adding tests for:

  1. Invalid key indices
  2. Non-existent addresses
  3. Invalid block heights
  4. Error responses from the API

Would you like me to help generate these additional test cases?

sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (2)

58-74: Enhance test coverage with edge cases and additional assertions.

While the basic happy path is covered, consider adding:

  1. Test cases for invalid key indices
  2. Additional assertions for other key properties (e.g., publicKey, weight, revoked)
  3. Verification of the key's signing algorithm and hashing algorithm

Example additions:

// Test invalid key index
@Test
fun `Get account key at latest block with invalid index throws exception`() {
    val address = serviceAccount.flowAddress
    val invalidKeyIndex = 999

    assertThrows<Exception> {
        handleResult(
            accessAPI.getAccountKeyAtLatestBlock(address, invalidKeyIndex),
            "Should fail with invalid key index"
        )
    }
}

103-118: Strengthen assertions for account keys collection.

The current assertions only verify that the collection is non-null and non-empty. Consider:

  1. Verifying the expected number of keys
  2. Validating properties of individual keys in the collection
  3. Checking key ordering by sequence number

Example improvements:

assertThat(accountKeys).isNotNull
assertThat(accountKeys).isNotEmpty
// Add these assertions:
assertThat(accountKeys).hasSize(1) // Adjust size based on expected number of keys
assertThat(accountKeys).isSortedAccordingTo { a, b -> a.sequenceNumber.compareTo(b.sequenceNumber) }
assertThat(accountKeys[0].revoked).isFalse()
sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt (2)

21-34: Add error scenario test for getAccountKeyAtLatestBlock.

The test only covers the success scenario. Consider adding tests for error cases such as invalid address or key index.

Add a test like this:

@Test
fun `Test getAccountKeyAtLatestBlock error`() {
    val flowAccessApi = mock(FlowAccessApi::class.java)
    val address = FlowAddress("01")
    val keyIndex = 0
    val exception = RuntimeException("Key not found")
    
    `when`(flowAccessApi.getAccountKeyAtLatestBlock(address, keyIndex))
        .thenReturn(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key", exception))
    
    val result = flowAccessApi.getAccountKeyAtLatestBlock(address, keyIndex)
    
    assertTrue(result is FlowAccessApi.AccessApiCallResponse.Error)
    verify(flowAccessApi).getAccountKeyAtLatestBlock(address, keyIndex)
}

52-67: Enhance test data for getAccountKeysAtLatestBlock.

The test uses default instances for AccountKey, which doesn't validate actual key properties.

Consider using more realistic test data:

val accountKeys = listOf(
    FlowAccountKey.of(
        AccountOuterClass.AccountKey.newBuilder()
            .setIndex(0)
            .setPublicKey(ByteString.copyFrom("testKey1".toByteArray()))
            .setSignAlgo(SignatureAlgorithm.ECDSA_P256.value)
            .setHashAlgo(HashAlgorithm.SHA2_256.value)
            .setWeight(1000)
            .build()
    ),
    FlowAccountKey.of(
        AccountOuterClass.AccountKey.newBuilder()
            .setIndex(1)
            .setPublicKey(ByteString.copyFrom("testKey2".toByteArray()))
            .setSignAlgo(SignatureAlgorithm.ECDSA_P256.value)
            .setHashAlgo(HashAlgorithm.SHA2_256.value)
            .setWeight(500)
            .build()
    )
)
sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt (3)

53-66: Consider adding height parameter validation.

The implementation is correct, but consider validating that the height parameter is non-negative before making the API call.

 override fun getAccountKeyAtBlockHeight(address: FlowAddress, keyIndex: Int, height: Long): FlowAccessApi.AccessApiCallResponse<FlowAccountKey> =
     try {
+        require(height >= 0) { "Block height must be non-negative" }
         val ret = api.getAccountKeyAtBlockHeight(

81-93: Consider adding height parameter validation.

The implementation is correct, but like the single key retrieval method, consider validating the height parameter.

 override fun getAccountKeysAtBlockHeight(address: FlowAddress, height: Long): FlowAccessApi.AccessApiCallResponse<List<FlowAccountKey>> =
     try {
+        require(height >= 0) { "Block height must be non-negative" }
         val ret = api.getAccountKeysAtBlockHeight(

39-93: Well-structured implementation with consistent patterns.

The new account key retrieval methods are well-integrated into the codebase, following established patterns for:

  • Error handling using AccessApiCallResponse
  • Protocol buffer request building
  • Type conversion from protocol buffer objects
  • Exception handling with descriptive error messages

This consistency makes the code maintainable and easy to understand.

sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (4)

79-110: Consider enhancing test coverage with non-default account key data.

While the tests are well-structured, using AccountKey.getDefaultInstance() might not provide comprehensive coverage. Consider adding test cases with various account key configurations (e.g., different weights, signing algorithms, etc.).

val mockAccountKey = FlowAccountKey.of(
    AccountOuterClass.AccountKey.newBuilder()
        .setIndex(0)
        .setWeight(1000)
        .setSequenceNumber(1)
        .setPublicKey(ByteString.copyFromUtf8("test-public-key"))
        .build()
)

112-145: Consider adding edge case tests for block height.

The tests cover basic success and failure scenarios. Consider adding test cases for:

  • Block height 0 (genesis block)
  • Very large block heights
  • Invalid block heights (negative values)

147-215: Enhance list handling test coverage.

The tests verify basic list functionality. Consider adding test cases for:

  • Empty list of account keys
  • Large number of account keys
  • Keys with different properties (revoked, hashed, etc.)
// Example test data for various scenarios
val mockAccountKeys = listOf(
    FlowAccountKey.of(AccountOuterClass.AccountKey.newBuilder()
        .setIndex(0)
        .setRevoked(true)
        .build()),
    FlowAccountKey.of(AccountOuterClass.AccountKey.newBuilder()
        .setIndex(1)
        .setHashAlgo(HashAlgorithm.SHA2_256.ordinal)
        .build()),
    // Add more variations...
)

Line range hint 1-24: Consider organizing tests using nested classes.

The test file is well-structured but could be more organized. Consider using nested classes to group related tests:

class AsyncFlowAccessApiImplTest {
    private val api = mock(AccessAPIGrpc.AccessAPIFutureStub::class.java)
    private val asyncFlowAccessApi = AsyncFlowAccessApiImpl(api)

    @Nested
    inner class AccountKeyTests {
        // All account key related tests
    }

    @Nested
    inner class AccountTests {
        // All account related tests
    }

    @Nested
    inner class TransactionTests {
        // All transaction related tests
    }
}
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (3)

77-114: Consider enhancing test data with realistic account key properties.

While the tests are well-structured, they use default instance values for AccountKey. Consider using more realistic test data that includes actual key properties (e.g., public key, signing algorithm, weight) to ensure the serialization/deserialization handles real-world scenarios correctly.

Example enhancement:

-        val mockAccountKey = FlowAccountKey.of(AccountOuterClass.AccountKey.getDefaultInstance())
+        val mockAccountKey = FlowAccountKey.of(
+            AccountOuterClass.AccountKey.newBuilder()
+                .setPublicKey(ByteString.copyFrom("mock-public-key".toByteArray()))
+                .setSignAlgo(SignatureAlgorithm.ECDSA_P256.value)
+                .setHashAlgo(HashAlgorithm.SHA3_256.value)
+                .setWeight(1000)
+                .build()
+        )

116-156: Add boundary test cases for block height parameter.

Consider adding test cases for edge cases:

  • Block height = 0 (genesis block)
  • Very large block height values
  • Invalid block heights (negative values)

Would you like me to help generate these additional test cases?


158-195: Add test case for empty account keys list.

The current tests verify the handling of multiple keys, but it would be beneficial to explicitly test the scenario where an account has no keys.

+    @Test
+    fun `Test getAccountKeysAtLatestBlock with empty keys list`() {
+        val flowAddress = FlowAddress("01")
+        val response = Access.AccountKeysResponse.newBuilder().build()
+
+        `when`(mockApi.getAccountKeysAtLatestBlock(any())).thenReturn(response)
+
+        val result = flowAccessApiImpl.getAccountKeysAtLatestBlock(flowAddress)
+        assertResultSuccess(result) { assertTrue(it.isEmpty()) }
+    }
sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt (2)

46-70: LGTM! Consider standardizing error message format.

The implementation is correct and follows the established patterns. However, for better consistency across the API, consider standardizing the error message format.

Apply this change to align with other error messages in the codebase:

-                    return CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key at latest block", e))
+                    return CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key", e))

99-148: Consider adding batch size limit for large key sets.

The implementation correctly handles multiple account keys retrieval. However, for accounts with a large number of keys, consider adding a batch size limit to prevent potential memory issues or timeout problems.

Consider implementing one of these approaches:

  1. Add a parameter to limit the number of keys returned
  2. Implement pagination for large key sets
  3. Add a configuration option for maximum keys per request

Would you like me to provide a detailed implementation for any of these approaches?

java-example/src/main/java/org/onflow/examples/java/getAccountKeys/GetAccountKeysAccessAPIConnector.java (2)

1-1: Add a license header to the source file

It is a good practice to include a license header at the top of source files to specify the terms under which the code is distributed.

For example, you can add:

/* 
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

3-6: Optimize imports by removing unused ones

The import statement for org.onflow.flow.sdk.FlowAccountKey is necessary, but ensure that all imported classes are actually used in the code. If there are any unused imports, consider removing them for cleaner code.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 56be671 and 6f1b4c7.

📒 Files selected for processing (12)
  • java-example/src/main/java/org/onflow/examples/java/getAccountKeys/GetAccountKeysAccessAPIConnector.java (1 hunks)
  • java-example/src/test/java/org/onflow/examples/java/getAccountKeys/GetAccountKeysAccessAPIConnectorTest.java (1 hunks)
  • kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountKeys/GetAccountKeysAccessAPIConnector.kt (1 hunks)
  • kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountKeys/GetAccountKeysAccessAPIConnectorTest.kt (1 hunks)
  • sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (1 hunks)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt (1 hunks)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt (2 hunks)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt (1 hunks)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt (1 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt (1 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (2 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (1 hunks)
🔇 Additional comments (13)
kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getAccountKeys/GetAccountKeysAccessAPIConnector.kt (1)

1-31: Verify test coverage for error scenarios.

While the implementation looks good, ensure comprehensive test coverage for various error scenarios:

  • Invalid key indices
  • Non-existent accounts
  • Network failures
  • API errors
sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt (2)

9-10: LGTM! Method signature follows established patterns.

The method signature is well-designed with clear parameter names and appropriate return type for async operation.


11-12: Verify height parameter validation.

The method signature looks good. However, ensure that the implementation validates the height parameter to prevent requests for non-existent blocks.

sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt (2)

21-28: LGTM! Well-structured method signatures.

The new account key methods are well-designed with:

  • Consistent naming patterns matching existing API methods
  • Appropriate parameter types for addresses, key indices, and block heights
  • Clear separation between single and multiple key retrieval
  • Proper error handling through AccessApiCallResponse wrapper

21-28: Implementation successfully meets PR objectives.

The added methods fully satisfy the requirements from issue #126:

  • ✓ GetAccountKeyAtLatestBlock
  • ✓ GetAccountKeysAtLatestBlock
  • ✓ GetAccountKeyAtBlockHeight
  • ✓ GetAccountKeysAtBlockHeight
kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountKeys/GetAccountKeysAccessAPIConnectorTest.kt (1)

1-103: Verify test coverage against all API methods.

The test suite covers the core functionality, but let's verify coverage of all API methods mentioned in the PR objectives:

✅ Verification successful

Test coverage is comprehensive and matches all API methods

The verification shows complete test coverage:

  • All 4 API methods are implemented in both sync (FlowAccessApiImpl) and async (AsyncFlowAccessApiImpl) variants:

    • GetAccountKeyAtLatestBlock
    • GetAccountKeyAtBlockHeight
    • GetAccountKeysAtLatestBlock
    • GetAccountKeysAtBlockHeight
  • Each method has corresponding test coverage in:

    • Integration tests (TransactionIntegrationTest)
    • Example tests (GetAccountKeysAccessAPIConnectorTest)
    • Implementation tests (FlowAccessApiImplTest)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if all required API methods are tested
echo "Verifying test coverage for all API methods..."

# Search for API method declarations
echo "API Method Declarations:"
rg "GetAccountKey.*Block|GetAccountKeys.*Block" --type kotlin

# Search for corresponding test methods
echo "Test Method Coverage:"
rg "fun.*account key.*block" --type kotlin

Length of output: 3063

java-example/src/test/java/org/onflow/examples/java/getAccountKeys/GetAccountKeysAccessAPIConnectorTest.java (3)

1-26: LGTM! Well-structured test class setup.

The test class is properly configured with:

  • Appropriate test infrastructure using JUnit 5
  • Correct dependency injection for Flow SDK components
  • Clear separation of concerns

27-30: LGTM! Clean and focused setup method.

The setup method follows best practices by:

  • Using @beforeeach for proper test isolation
  • Minimal and focused initialization

32-113: LGTM! Comprehensive test coverage for new endpoints.

The test suite effectively covers all four new methods mentioned in the PR objectives:

  • GetAccountKeyAtLatestBlock
  • GetAccountKeysAtLatestBlock
  • GetAccountKeyAtBlockHeight
  • GetAccountKeysAtBlockHeight

Each method is tested for both successful execution and proper data validation.

sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt (2)

39-51: LGTM! Implementation follows established patterns.

The method correctly implements the account key retrieval at latest block with proper error handling and type conversion.


68-79: LGTM! Proper list handling implementation.

The method correctly implements bulk account keys retrieval with proper error handling and list conversion.

sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (1)

197-237: LGTM! Tests are comprehensive and well-structured.

The test cases for retrieving account keys at block height are thorough, covering both success and error scenarios. They maintain consistency with other test methods and align well with the PR objectives.

sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt (1)

72-97: LGTM! Implementation follows best practices.

The method correctly implements the retrieval of account keys at a specific block height with proper error handling and parameter validation.

Comment on lines +58 to +144
@Test
fun `Can get account key at latest block`() {
val address = serviceAccount.flowAddress
val keyIndex = 0

val accountKey = try {
handleResult(
accessAPI.getAccountKeyAtLatestBlock(address, keyIndex),
"Failed to get account key at latest block"
)
} catch (e: Exception) {
fail("Failed to retrieve account key at latest block: ${e.message}")
}

assertThat(accountKey).isNotNull
assertThat(accountKey.sequenceNumber).isEqualTo(keyIndex)
}

@Test
fun `Can get account key at block height`() {
val address = serviceAccount.flowAddress
val keyIndex = 0

val latestBlock = try {
handleResult(
accessAPI.getLatestBlock(true),
"Failed to get latest block"
)
} catch (e: Exception) {
fail("Failed to retrieve latest block: ${e.message}")
}

val accountKey = try {
handleResult(
accessAPI.getAccountKeyAtBlockHeight(address, keyIndex, latestBlock.height),
"Failed to get account key at block height"
)
} catch (e: Exception) {
fail("Failed to retrieve account key at block height: ${e.message}")
}

assertThat(accountKey).isNotNull
assertThat(accountKey.sequenceNumber).isEqualTo(keyIndex)
}

@Test
fun `Can get account keys at latest block`() {
val address = serviceAccount.flowAddress

val accountKeys = try {
handleResult(
accessAPI.getAccountKeysAtLatestBlock(address),
"Failed to get account keys at latest block"
)
} catch (e: Exception) {
fail("Failed to retrieve account keys at latest block: ${e.message}")
}

assertThat(accountKeys).isNotNull
assertThat(accountKeys).isNotEmpty
}

@Test
fun `Can get account keys at block height`() {
val address = serviceAccount.flowAddress

val latestBlock = try {
handleResult(
accessAPI.getLatestBlock(true),
"Failed to get latest block"
)
} catch (e: Exception) {
fail("Failed to retrieve latest block: ${e.message}")
}

val accountKeys = try {
handleResult(
accessAPI.getAccountKeysAtBlockHeight(address, latestBlock.height),
"Failed to get account keys at block height"
)
} catch (e: Exception) {
fail("Failed to retrieve account keys at block height: ${e.message}")
}

assertThat(accountKeys).isNotNull
assertThat(accountKeys).isNotEmpty
}
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider structural improvements for better maintainability.

The new tests follow good patterns but could benefit from:

  1. Extracting common setup code to reduce duplication
  2. Adding constants for shared values (e.g., keyIndex)
  3. Adding documentation to describe test scenarios and expected behavior

Consider these structural improvements:

class TransactionIntegrationTest {
    companion object {
        private const val DEFAULT_KEY_INDEX = 0
    }

    // Helper method for key retrieval
    private fun getLatestBlockAndKey(address: FlowAddress, keyIndex: Int = DEFAULT_KEY_INDEX): Pair<FlowBlock, FlowAccountKey> {
        val latestBlock = handleResult(
            accessAPI.getLatestBlock(true),
            "Failed to get latest block"
        )
        
        val accountKey = handleResult(
            accessAPI.getAccountKeyAtLatestBlock(address, keyIndex),
            "Failed to get account key"
        )
        
        return latestBlock to accountKey
    }

    // Tests can then be simplified...
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking into this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lealobanov, thank you for looking into this!

(_/)
( ^^)
(")
(")

Comment on lines +46 to +148
try {
api.getAccountKeyAtLatestBlock(
Access.GetAccountKeyAtLatestBlockRequest
.newBuilder()
.setAddress(address.byteStringValue)
.setIndex(keyIndex)
.build()
)
} catch (e: Exception) {
return CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key at latest block", e))
}
).handle { response, ex ->
if (ex != null) {
FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key at latest block", ex)
} else {
FlowAccessApi.AccessApiCallResponse.Success(FlowAccountKey.of(response.accountKey))
}
}
} catch (e: Exception) {
CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key at latest block", e))
}
}

override fun getAccountKeyAtBlockHeight(address: FlowAddress, keyIndex: Int, height: Long): CompletableFuture<FlowAccessApi.AccessApiCallResponse<FlowAccountKey>> {
return try {
completableFuture(
try {
api.getAccountKeyAtBlockHeight(
Access.GetAccountKeyAtBlockHeightRequest
.newBuilder()
.setAddress(address.byteStringValue)
.setIndex(keyIndex)
.setBlockHeight(height)
.build()
)
} catch (e: Exception) {
return CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key at block height", e))
}
).handle { response, ex ->
if (ex != null) {
FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key at block height", ex)
} else {
FlowAccessApi.AccessApiCallResponse.Success(FlowAccountKey.of(response.accountKey))
}
}
} catch (e: Exception) {
CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key at block height", e))
}
}

override fun getAccountKeysAtLatestBlock(address: FlowAddress): CompletableFuture<FlowAccessApi.AccessApiCallResponse<List<FlowAccountKey>>> {
return try {
completableFuture(
try {
api.getAccountKeysAtLatestBlock(
Access.GetAccountKeysAtLatestBlockRequest
.newBuilder()
.setAddress(address.byteStringValue)
.build()
)
} catch (e: Exception) {
return CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account keys at latest block", e))
}
).handle { response, ex ->
if (ex != null) {
FlowAccessApi.AccessApiCallResponse.Error("Failed to get account keys at latest block", ex)
} else {
FlowAccessApi.AccessApiCallResponse.Success(response.accountKeysList.map { FlowAccountKey.of(it) })
}
}
} catch (e: Exception) {
CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account keys at latest block", e))
}
}

override fun getAccountKeysAtBlockHeight(address: FlowAddress, height: Long): CompletableFuture<FlowAccessApi.AccessApiCallResponse<List<FlowAccountKey>>> {
return try {
completableFuture(
try {
api.getAccountKeysAtBlockHeight(
Access.GetAccountKeysAtBlockHeightRequest
.newBuilder()
.setAddress(address.byteStringValue)
.setBlockHeight(height)
.build()
)
} catch (e: Exception) {
return CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account keys at block height", e))
}
).handle { response, ex ->
if (ex != null) {
FlowAccessApi.AccessApiCallResponse.Error("Failed to get account keys at block height", ex)
} else {
FlowAccessApi.AccessApiCallResponse.Success(response.accountKeysList.map { FlowAccountKey.of(it) })
}
}
} catch (e: Exception) {
CompletableFuture.completedFuture(FlowAccessApi.AccessApiCallResponse.Error("Failed to get account keys at block height", e))
}
}
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider refactoring common error handling patterns.

The new methods follow consistent patterns but contain duplicated error handling code. Consider extracting common error handling logic into reusable functions.

Here's a suggested approach to reduce duplication:

private fun <T> handleApiCall(
    operation: String,
    apiCall: () -> ListenableFuture<T>,
    responseMapper: (T) -> FlowAccessApi.AccessApiCallResponse<*>
): CompletableFuture<FlowAccessApi.AccessApiCallResponse<*>> {
    return try {
        completableFuture(
            try {
                apiCall()
            } catch (e: Exception) {
                return CompletableFuture.completedFuture(
                    FlowAccessApi.AccessApiCallResponse.Error("Failed to $operation", e)
                )
            }
        ).handle { response, ex ->
            if (ex != null) {
                FlowAccessApi.AccessApiCallResponse.Error("Failed to $operation", ex)
            } else {
                responseMapper(response)
            }
        }
    } catch (e: Exception) {
        CompletableFuture.completedFuture(
            FlowAccessApi.AccessApiCallResponse.Error("Failed to $operation", e)
        )
    }
}

This would allow simplifying the methods to:

override fun getAccountKeyAtLatestBlock(
    address: FlowAddress,
    keyIndex: Int
): CompletableFuture<FlowAccessApi.AccessApiCallResponse<FlowAccountKey>> {
    return handleApiCall(
        "get account key at latest block",
        {
            api.getAccountKeyAtLatestBlock(
                Access.GetAccountKeyAtLatestBlockRequest
                    .newBuilder()
                    .setAddress(address.byteStringValue)
                    .setIndex(keyIndex)
                    .build()
            )
        }
    ) { response -> 
        FlowAccessApi.AccessApiCallResponse.Success(FlowAccountKey.of(response.accountKey))
    }
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lealobanov should we consider this suggestion?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@franklywatson Agree, the test files for the Access API endpoints are getting quite large too... I will have a look today to see where I can reduce duplication

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@franklywatson I have just pushed initial refactoring work for the AsyncFlowAccessAPI unit tests - will create a separate issue for refactoring of the remaining files as the size of the changes is quite large

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (14)
kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnector.kt (1)

20-24: The implementation looks good but could benefit from documentation and validation.

While the implementation follows the class's established pattern correctly, consider these improvements:

  1. Add KDoc documentation explaining the method's purpose and parameters
  2. Add validation for the index parameter to ensure it's non-negative

Consider adding documentation and validation:

+    /**
+     * Retrieves a transaction result at the specified index within a block
+     * @param blockId The ID of the block to query
+     * @param index The index of the transaction in the block (must be non-negative)
+     * @return The transaction result
+     * @throws IllegalArgumentException if index is negative
+     * @throws Exception if the API call fails
+     */
     fun getTransactionResultByIndex(blockId: FlowId, index: Int): FlowTransactionResult =
+        require(index >= 0) { "Transaction index must be non-negative" }
         when (val response = accessAPI.getTransactionResultByIndex(blockId, index)) {
             is FlowAccessApi.AccessApiCallResponse.Success -> response.data
             is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable)
         }
java-example/src/main/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnector.java (1)

35-36: Consider adding parameter validation.

The method could benefit from parameter validation to ensure robustness:

  • Validate that blockId is not null
  • Validate that index is not null and non-negative

Consider adding these checks:

 public FlowTransactionResult getTransactionResultByIndex(FlowId blockId, Integer index) {
+    if (blockId == null) {
+        throw new IllegalArgumentException("blockId cannot be null");
+    }
+    if (index == null) {
+        throw new IllegalArgumentException("index cannot be null");
+    }
+    if (index < 0) {
+        throw new IllegalArgumentException("index cannot be negative");
+    }
     FlowAccessApi.AccessApiCallResponse<FlowTransactionResult> response = accessAPI.getTransactionResultByIndex(blockId, index);

Also consider using primitive int instead of Integer for the index parameter since it cannot be null.

kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt (1)

40-43: Enhance error handling in block retrieval.

While the error handling works, it could be more robust and informative:

Consider this improvement:

 block = when (val response = accessAPI.getLatestBlock()) {
     is FlowAccessApi.AccessApiCallResponse.Success -> response.data
-    is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable)
+    is FlowAccessApi.AccessApiCallResponse.Error -> throw FlowTestException(
+        "Failed to fetch latest block: ${response.message}",
+        response.throwable
+    )
 }

Add this custom exception class at the top level:

class FlowTestException(message: String, cause: Throwable? = null) : Exception(message, cause)
java-example/src/test/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnectorTest.java (1)

24-24: Consider using a more descriptive field name.

The field name block could be more specific to indicate it represents the latest block, e.g., latestBlock.

-    private FlowBlock block;
+    private FlowBlock latestBlock;
sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt (1)

Line range hint 9-42: Overall implementation looks good with some suggestions for improvement.

The new methods are well-structured and follow the existing patterns in the API. Consider the following architectural improvements:

  1. Add comprehensive error handling documentation, especially for network-related failures
  2. Consider adding convenience methods that combine multiple calls (e.g., getting all keys for multiple accounts in one call)
  3. Consider adding rate limiting or pagination support for methods that might return large datasets
sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt (1)

21-28: LGTM! Consider adding KDoc documentation.

The new account key methods are well-designed and consistent with the existing API patterns. They follow the established naming conventions and parameter structures.

Consider adding KDoc documentation for these methods to describe:

  • Parameter constraints (e.g., valid keyIndex ranges)
  • Possible error conditions
  • Example usage
kotlin-example/README.md (1)

Line range hint 1-84: Missing documentation for new account key endpoints.

The PR introduces several new account key endpoints (GetAccountKeyAtLatestBlock, GetAccountKeysAtLatestBlock, GetAccountKeyAtBlockHeight, GetAccountKeysAtBlockHeight), but there's no documentation for these new features in the README.

Consider adding a new section under "Get Accounts" to document these new endpoints:

#### Get Accounts

[Get accounts by address.](src/main/kotlin/org/onflow/examples/kotlin/getAccount/GetAccountAccessAPIConnector.kt)

- Get account balance
- Get account from the latest block
- Get account from block by height
+ - Get account key at latest block
+ - Get account keys at latest block
+ - Get account key at block height
+ - Get account keys at block height
🧰 Tools
🪛 LanguageTool

[grammar] ~82-~82: This phrase is duplicated. You should probably use “Get transaction” only once.
Context: ...GetTransactionAccessAPIConnector.kt) - Get transaction - Get transaction result - Get transaction result by inde...

(PHRASE_REPETITION)

sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (1)

58-74: Enhance test coverage with additional assertions.

While the basic test structure is good, consider adding these assertions to make the tests more robust:

  1. Verify the key's public key format and validity
  2. Check other key properties (weight, revoked status, etc.)
  3. For multiple keys, verify they are properly ordered by sequence number

Example for single key test:

 assertThat(accountKey).isNotNull
 assertThat(accountKey.sequenceNumber).isEqualTo(keyIndex)
+assertThat(accountKey.publicKey).isNotEmpty()
+assertThat(accountKey.weight).isGreaterThan(0)
+assertThat(accountKey.revoked).isFalse()

Example for multiple keys test:

 assertThat(accountKeys).isNotNull
 assertThat(accountKeys).isNotEmpty
+assertThat(accountKeys).isSortedAccordingTo { a, b -> 
+    a.sequenceNumber.compareTo(b.sequenceNumber)
+}
+assertThat(accountKeys).allMatch { it.publicKey.isNotEmpty() }

Also applies to: 103-118

sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (4)

54-65: Consider using more meaningful test data values.

While the mock transaction response is functionally correct, using more descriptive test data would improve test readability and debugging.

-            .setBlockId(ByteString.copyFromUtf8("id"))
-            .setTransactionId(ByteString.copyFromUtf8("id"))
-            .setCollectionId(ByteString.copyFromUtf8("id"))
+            .setBlockId(ByteString.copyFromUtf8("mock_block_id"))
+            .setTransactionId(ByteString.copyFromUtf8("mock_transaction_id"))
+            .setCollectionId(ByteString.copyFromUtf8("mock_collection_id"))

170-193: Consider adding edge cases for account keys list.

While the basic functionality is well-tested, consider adding test cases for:

  1. Empty account keys list
  2. List with maximum allowed keys
  3. Keys with different weight values
@Test
fun `Test getAccountKeysAtLatestBlock with empty keys list`() {
    val flowAddress = FlowAddress("01")
    val response = Access.AccountKeysResponse.newBuilder().build()
    
    `when`(mockApi.getAccountKeysAtLatestBlock(any())).thenReturn(response)
    
    val result = flowAccessApiImpl.getAccountKeysAtLatestBlock(flowAddress)
    assertResultSuccess(result) { assertTrue(it.isEmpty()) }
}

472-484: Enhance result validation in getTransactionResultByIndex test.

Consider adding more specific assertions to validate individual fields of the transaction result:

         val result = flowAccessApiImpl.getTransactionResultByIndex(flowId, index)
-        assertResultSuccess(result) { assertEquals(flowTransactionResult, it) }
+        assertResultSuccess(result) { 
+            assertEquals(flowTransactionResult.status, it.status)
+            assertEquals(flowTransactionResult.statusCode, it.statusCode)
+            assertEquals(flowTransactionResult.errorMessage, it.errorMessage)
+            assertEquals(flowTransactionResult.blockId, it.blockId)
+            assertEquals(flowTransactionResult.blockHeight, it.blockHeight)
+        }

Line range hint 89-499: Consider adding KDoc documentation for test methods.

While the test method names are descriptive, adding KDoc documentation would improve maintainability by clearly stating:

  • The purpose of each test
  • The expected behavior
  • Any specific test conditions or assumptions

Example:

/**
 * Verifies that account keys can be successfully retrieved at the latest block.
 * Expected behavior:
 * 1. API call should return the mocked account key
 * 2. Request should be built with correct address and index
 */
@Test
fun `Test getAccountKeyAtLatestBlock`() {
    // ... existing test code ...
}
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (2)

Line range hint 476-484: Ensure Comprehensive Assertions in Transaction Result Tests

In the getTransactionResultByIndex tests, only limited fields of the FlowTransactionResult are being asserted. For thorough validation, consider asserting all relevant fields to ensure the object is correctly constructed and returned.

Also applies to: 486-515


91-107: Consistent Error Message Verification

Verify that the error messages asserted in failure tests match the actual messages produced by the implementation. This ensures that tests remain reliable even if error messages change due to implementation updates.

Also applies to: 109-122, 124-141, 143-157

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6f1b4c7 and 959e5e0.

📒 Files selected for processing (14)
  • java-example/README.md (1 hunks)
  • java-example/src/main/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnector.java (1 hunks)
  • java-example/src/test/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnectorTest.java (4 hunks)
  • kotlin-example/README.md (1 hunks)
  • kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnector.kt (1 hunks)
  • kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt (3 hunks)
  • sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (2 hunks)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt (2 hunks)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt (3 hunks)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt (2 hunks)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt (2 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt (2 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (5 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt
🔇 Additional comments (18)
kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnector.kt (1)

Line range hint 1-24: Verify the relevance of this change to PR objectives.

This file introduces transaction-related functionality, but the PR objectives specifically mention account key endpoints. Please clarify if this change is intentionally included in this PR or if it should be moved to a separate PR focused on transaction functionality.

Let's check if there are any related changes or dependencies:

java-example/src/main/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnector.java (2)

35-43: LGTM! Implementation follows established patterns.

The method implementation is consistent with the class's existing error handling patterns and correctly integrates with the FlowAccessAPI.


34-43: Verify the relevance of transaction result changes to PR objectives.

The PR objectives focus on adding account key endpoints, but this file introduces transaction result functionality. Could you clarify how these changes relate to the account key endpoints implementation described in the PR objectives?

Let's check for related changes:

kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt (2)

23-23: LGTM!

The property declaration follows Kotlin conventions and is appropriately scoped.


62-68: Improve test coverage and reliability.

The current test could be more comprehensive and reliable:

  1. It only tests index 0 and assumes a transaction exists
  2. It doesn't verify the actual transaction data
  3. Missing negative test cases

Consider adding:

  1. A check that the block actually contains transactions
  2. Multiple test cases with different indices
  3. Negative test cases for invalid indices
  4. Verification of transaction details
 @Test
 fun `Can fetch a transaction result by index`() {
+    // Verify block has transactions
+    assertTrue(block.collectionGuarantees.isNotEmpty(), "Block should contain transactions")
+
     val transactionResult = connector.getTransactionResultByIndex(block.id, 0)
 
     assertNotNull(transactionResult, "Transaction result should not be null")
     assertTrue(transactionResult.status === FlowTransactionStatus.SEALED, "Transaction should be sealed")
+    // Verify transaction details
+    assertNotNull(transactionResult.blockId, "Block ID should not be null")
+    assertEquals(block.id, transactionResult.blockId, "Block ID should match")
 }
+
+@Test
+fun `Should handle invalid transaction index`() {
+    assertThrows<IllegalArgumentException> {
+        connector.getTransactionResultByIndex(block.id, -1)
+    }
+}

Let me verify if the block consistently contains transactions:

java-example/src/test/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnectorTest.java (1)

10-10: LGTM! Import consolidation is acceptable in test files.

sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt (2)

41-42: Review return type nullability and add documentation.

The method getTransactionResultByIndex returns a non-nullable FlowTransactionResult while similar methods like getTransactionResultById return nullable FlowTransactionResult?. Please:

  1. Document why this method guarantees a non-null result
  2. Consider making the return type consistent with other similar methods
  3. Add KDoc documentation explaining the relationship between blockId and index parameters
#!/bin/bash
# Check for similar transaction result methods and their return types
rg "getTransaction.*Result.*:.*Flow.*Result" -A 1

9-16: Add KDoc documentation for the new account key methods.

The new methods would benefit from KDoc documentation describing:

  • Parameter constraints (e.g., valid ranges for keyIndex)
  • Return value details
  • Potential error conditions
  • Usage examples

Example format:

/**
 * Retrieves an account key at the latest sealed block.
 *
 * @param address The Flow address to query
 * @param keyIndex The index of the key to retrieve (must be non-negative)
 * @return A future containing the account key if found
 * @throws IllegalArgumentException if keyIndex is negative
 */

Consider adding parameter validation hints.

The keyIndex parameter should likely be non-negative. Consider using @IntRange annotation or documenting the valid range.

sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt (1)

53-54: Add documentation for the index parameter.

While the method signature is consistent with the API design, it would be helpful to document:

  • Valid ranges for the index parameter
  • How the index corresponds to transaction positions within a block
  • Relationship with getTransactionsByBlockId method

Let's check if there are any existing usages that might provide context:

sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (1)

76-101: Past review comments are still applicable.

The existing review comments about enhancing block height tests with historical validation remain valid and should be implemented.

Also applies to: 120-144

sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (1)

89-111: LGTM! Comprehensive test coverage for getAccountKeyAtLatestBlock.

The test properly verifies the successful retrieval of an account key, including request building and response handling.

sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (1)

63-73: Validate Initialization of mockTransactionResultResponse

The mockTransactionResultResponse is initialized with default or placeholder values. Ensure that all necessary fields are appropriately set to reflect realistic transaction results for accurate testing.

sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt (6)

46-70: LGTM

The implementation of getAccountKeyAtLatestBlock is correct and follows existing patterns.


72-96: LGTM

The implementation of getAccountKeyAtBlockHeight is correct and consistent with the existing codebase.


99-121: LGTM

The getAccountKeysAtLatestBlock method is implemented correctly and aligns with current coding practices.


124-147: LGTM

The getAccountKeysAtBlockHeight method is correctly implemented and follows the established patterns.


479-503: LGTM

The implementation of getTransactionResultByIndex is correct and adheres to existing conventions.


46-148: Consider refactoring to reduce code duplication

As previously noted, there is duplicated error handling code in these methods. Extracting common logic into reusable functions could enhance maintainability.

Also applies to: 479-503

java-example/README.md Show resolved Hide resolved
Comment on lines +21 to +85
@Test
fun `Test getAccountKeyAtLatestBlock`() {
val flowAccessApi = mock(FlowAccessApi::class.java)
val address = FlowAddress("01")
val keyIndex = 0
val accountKey = FlowAccountKey.of(AccountOuterClass.AccountKey.getDefaultInstance())

`when`(flowAccessApi.getAccountKeyAtLatestBlock(address, keyIndex)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(accountKey))

val result = flowAccessApi.getAccountKeyAtLatestBlock(address, keyIndex)

assertEquals(FlowAccessApi.AccessApiCallResponse.Success(accountKey), result)
verify(flowAccessApi).getAccountKeyAtLatestBlock(address, keyIndex)
}

@Test
fun `Test getAccountKeyAtBlockHeight`() {
val flowAccessApi = mock(FlowAccessApi::class.java)
val address = FlowAddress("01")
val keyIndex = 0
val height = 123L
val accountKey = FlowAccountKey.of(AccountOuterClass.AccountKey.getDefaultInstance())

`when`(flowAccessApi.getAccountKeyAtBlockHeight(address, keyIndex, height)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(accountKey))

val result = flowAccessApi.getAccountKeyAtBlockHeight(address, keyIndex, height)

assertEquals(FlowAccessApi.AccessApiCallResponse.Success(accountKey), result)
verify(flowAccessApi).getAccountKeyAtBlockHeight(address, keyIndex, height)
}

@Test
fun `Test getAccountKeysAtLatestBlock`() {
val flowAccessApi = mock(FlowAccessApi::class.java)
val address = FlowAddress("01")
val accountKeys = listOf(
FlowAccountKey.of(AccountOuterClass.AccountKey.getDefaultInstance()),
FlowAccountKey.of(AccountOuterClass.AccountKey.getDefaultInstance())
)

`when`(flowAccessApi.getAccountKeysAtLatestBlock(address)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(accountKeys))

val result = flowAccessApi.getAccountKeysAtLatestBlock(address)

assertEquals(FlowAccessApi.AccessApiCallResponse.Success(accountKeys), result)
verify(flowAccessApi).getAccountKeysAtLatestBlock(address)
}

@Test
fun `Test getAccountKeysAtBlockHeight`() {
val flowAccessApi = mock(FlowAccessApi::class.java)
val address = FlowAddress("01")
val height = 123L
val accountKeys = listOf(
FlowAccountKey.of(AccountOuterClass.AccountKey.getDefaultInstance()),
FlowAccountKey.of(AccountOuterClass.AccountKey.getDefaultInstance())
)

`when`(flowAccessApi.getAccountKeysAtBlockHeight(address, height)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(accountKeys))

val result = flowAccessApi.getAccountKeysAtBlockHeight(address, height)

assertEquals(FlowAccessApi.AccessApiCallResponse.Success(accountKeys), result)
verify(flowAccessApi).getAccountKeysAtBlockHeight(address, height)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance test coverage for account key methods.

The account key tests should be enhanced to align with the existing test patterns in the file:

  1. Add error scenario tests similar to getAccountBalanceAtLatestBlock failure
  2. Use meaningful test data instead of default instances
  3. Verify response properties in detail

Here's an example implementation for getAccountKeyAtLatestBlock:

 @Test
 fun `Test getAccountKeyAtLatestBlock`() {
     val flowAccessApi = mock(FlowAccessApi::class.java)
     val address = FlowAddress("01")
     val keyIndex = 0
-    val accountKey = FlowAccountKey.of(AccountOuterClass.AccountKey.getDefaultInstance())
+    val accountKey = FlowAccountKey(
+        publicKey = ByteString.copyFromUtf8("test-public-key"),
+        signAlgo = SignatureAlgorithm.ECDSA_P256,
+        hashAlgo = HashAlgorithm.SHA2_256,
+        weight = 1000,
+        sequenceNumber = 42,
+        revoked = false
+    )

     `when`(flowAccessApi.getAccountKeyAtLatestBlock(address, keyIndex))
         .thenReturn(FlowAccessApi.AccessApiCallResponse.Success(accountKey))

     val result = flowAccessApi.getAccountKeyAtLatestBlock(address, keyIndex)

     assertEquals(FlowAccessApi.AccessApiCallResponse.Success(accountKey), result)
+    assertEquals("test-public-key", result.data.publicKey.toStringUtf8())
+    assertEquals(SignatureAlgorithm.ECDSA_P256, result.data.signAlgo)
+    assertEquals(HashAlgorithm.SHA2_256, result.data.hashAlgo)
+    assertEquals(1000, result.data.weight)
+    assertEquals(42, result.data.sequenceNumber)
+    assertEquals(false, result.data.revoked)
     verify(flowAccessApi).getAccountKeyAtLatestBlock(address, keyIndex)
 }

+@Test
+fun `Test getAccountKeyAtLatestBlock failure`() {
+    val flowAccessApi = mock(FlowAccessApi::class.java)
+    val address = FlowAddress("01")
+    val keyIndex = 0
+    val exception = RuntimeException("Test exception")
+    val response = FlowAccessApi.AccessApiCallResponse.Error(
+        "Failed to get account key at latest block",
+        exception
+    )
+
+    `when`(flowAccessApi.getAccountKeyAtLatestBlock(address, keyIndex))
+        .thenReturn(response)
+
+    val result = flowAccessApi.getAccountKeyAtLatestBlock(address, keyIndex)
+
+    assertEquals(response, result)
+    verify(flowAccessApi).getAccountKeyAtLatestBlock(address, keyIndex)
+}

Committable suggestion was skipped due to low confidence.

Comment on lines +267 to +279
@Test
fun `Test getTransactionResultByIndex`() {
val flowAccessApi = mock(FlowAccessApi::class.java)
val flowId = FlowId("01")
val index = 0

val flowTransactionResult = FlowTransactionResult.of(Access.TransactionResultResponse.getDefaultInstance())
`when`(flowAccessApi.getTransactionResultByIndex(flowId, index)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult))

val result = flowAccessApi.getTransactionResultByIndex(flowId, index)

assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult), result)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance test coverage for transaction result retrieval.

The transaction result test should be enhanced to align with the existing test patterns in the file:

  1. Add error scenario test
  2. Use meaningful test data
  3. Verify response properties in detail

Here's an example implementation:

 @Test
 fun `Test getTransactionResultByIndex`() {
     val flowAccessApi = mock(FlowAccessApi::class.java)
     val flowId = FlowId("01")
     val index = 0
-    val flowTransactionResult = FlowTransactionResult.of(Access.TransactionResultResponse.getDefaultInstance())
+    val flowTransactionResult = FlowTransactionResult(
+        status = FlowTransactionStatus.SEALED,
+        statusCode = 0,
+        errorMessage = "",
+        events = listOf(
+            FlowEvent(
+                type = "TestEvent",
+                transactionId = flowId,
+                transactionIndex = index,
+                eventIndex = 0,
+                payload = ByteString.copyFromUtf8("test-payload")
+            )
+        ),
+        blockId = flowId,
+        blockHeight = 42L,
+        transactionId = flowId,
+        collectionId = flowId,
+        index = index
+    )

     `when`(flowAccessApi.getTransactionResultByIndex(flowId, index))
         .thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult))

     val result = flowAccessApi.getTransactionResultByIndex(flowId, index)

     assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult), result)
+    assertEquals(FlowTransactionStatus.SEALED, result.data.status)
+    assertEquals(0, result.data.statusCode)
+    assertEquals("", result.data.errorMessage)
+    assertEquals(1, result.data.events.size)
+    assertEquals("TestEvent", result.data.events[0].type)
+    assertEquals("test-payload", result.data.events[0].payload.toStringUtf8())
+    assertEquals(42L, result.data.blockHeight)
+    assertEquals(index, result.data.index)
 }

+@Test
+fun `Test getTransactionResultByIndex failure`() {
+    val flowAccessApi = mock(FlowAccessApi::class.java)
+    val flowId = FlowId("01")
+    val index = 0
+    val exception = RuntimeException("Test exception")
+    val response = FlowAccessApi.AccessApiCallResponse.Error(
+        "Failed to get transaction result by index",
+        exception
+    )
+
+    `when`(flowAccessApi.getTransactionResultByIndex(flowId, index))
+        .thenReturn(response)
+
+    val result = flowAccessApi.getTransactionResultByIndex(flowId, index)
+
+    assertEquals(response, result)
+    verify(flowAccessApi).getTransactionResultByIndex(flowId, index)
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
fun `Test getTransactionResultByIndex`() {
val flowAccessApi = mock(FlowAccessApi::class.java)
val flowId = FlowId("01")
val index = 0
val flowTransactionResult = FlowTransactionResult.of(Access.TransactionResultResponse.getDefaultInstance())
`when`(flowAccessApi.getTransactionResultByIndex(flowId, index)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult))
val result = flowAccessApi.getTransactionResultByIndex(flowId, index)
assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult), result)
}
@Test
fun `Test getTransactionResultByIndex`() {
val flowAccessApi = mock(FlowAccessApi::class.java)
val flowId = FlowId("01")
val index = 0
val flowTransactionResult = FlowTransactionResult(
status = FlowTransactionStatus.SEALED,
statusCode = 0,
errorMessage = "",
events = listOf(
FlowEvent(
type = "TestEvent",
transactionId = flowId,
transactionIndex = index,
eventIndex = 0,
payload = ByteString.copyFromUtf8("test-payload")
)
),
blockId = flowId,
blockHeight = 42L,
transactionId = flowId,
collectionId = flowId,
index = index
)
`when`(flowAccessApi.getTransactionResultByIndex(flowId, index))
.thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult))
val result = flowAccessApi.getTransactionResultByIndex(flowId, index)
assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult), result)
assertEquals(FlowTransactionStatus.SEALED, result.data.status)
assertEquals(0, result.data.statusCode)
assertEquals("", result.data.errorMessage)
assertEquals(1, result.data.events.size)
assertEquals("TestEvent", result.data.events[0].type)
assertEquals("test-payload", result.data.events[0].payload.toStringUtf8())
assertEquals(42L, result.data.blockHeight)
assertEquals(index, result.data.index)
}
@Test
fun `Test getTransactionResultByIndex failure`() {
val flowAccessApi = mock(FlowAccessApi::class.java)
val flowId = FlowId("01")
val index = 0
val exception = RuntimeException("Test exception")
val response = FlowAccessApi.AccessApiCallResponse.Error(
"Failed to get transaction result by index",
exception
)
`when`(flowAccessApi.getTransactionResultByIndex(flowId, index))
.thenReturn(response)
val result = flowAccessApi.getTransactionResultByIndex(flowId, index)
assertEquals(response, result)
verify(flowAccessApi).getTransactionResultByIndex(flowId, index)
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 959e5e0 and f42395e.

📒 Files selected for processing (3)
  • java-example/README.md (2 hunks)
  • kotlin-example/README.md (2 hunks)
  • sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • java-example/README.md
  • kotlin-example/README.md
🔇 Additional comments (3)
sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (3)

76-101: Implement historical validation as suggested in past reviews.

The tests for block height and latest block should be combined to verify consistency across blocks. This was previously suggested in past reviews and is still valid.

Also applies to: 103-118, 120-144


210-216: LGTM! Test name change reflects its purpose.

The test appropriately validates event parsing with specific assertions for event type and content.


58-74: 🛠️ Refactor suggestion

Enhance key validation and extract common test utilities.

The test could be improved by:

  1. Validating more key properties (e.g., publicKey, weight, etc.)
  2. Extracting common error handling logic

Consider this enhanced implementation:

private fun getAccountKeyAtLatestBlock(address: FlowAddress, keyIndex: Int = DEFAULT_KEY_INDEX): FlowAccountKey {
    return handleResult(
        accessAPI.getAccountKeyAtLatestBlock(address, keyIndex),
        "Failed to get account key at latest block"
    ) ?: fail("Account key should not be null")
}

@Test
fun `Can get account key at latest block`() {
    val address = serviceAccount.flowAddress
    val accountKey = getAccountKeyAtLatestBlock(address)
    
    assertThat(accountKey).isNotNull
    assertThat(accountKey.sequenceNumber).isEqualTo(DEFAULT_KEY_INDEX)
    assertThat(accountKey.publicKey).isNotNull
    assertThat(accountKey.weight).isGreaterThan(0)
}
⛔ Skipped due to learnings
Learnt from: franklywatson
PR: onflow/flow-jvm-sdk#55
File: src/intTest/org/onflow/flow/sdk/ExposeAccountKeyIssueTest.kt:151-152
Timestamp: 2024-07-04T05:15:46.310Z
Learning: When reviewing test code, avoid recommending additional exception handling if it might obscure the actual failure points and over-sensitize the process.
Learnt from: franklywatson
PR: onflow/flow-jvm-sdk#55
File: src/intTest/org/onflow/flow/sdk/ExposeAccountKeyIssueTest.kt:151-152
Timestamp: 2024-10-08T17:04:37.869Z
Learning: When reviewing test code, avoid recommending additional exception handling if it might obscure the actual failure points and over-sensitize the process.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Outside diff range and nitpick comments (1)
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (1)

227-230: Consolidate duplicate code in test setups

The declarations of flowAddress, keyIndex, and blockHeight are repeated in multiple tests. Consider extracting these into class-level constants or setup methods to adhere to the DRY (Don't Repeat Yourself) principle.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f42395e and 1efa6de.

📒 Files selected for processing (1)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (13 hunks)
🔇 Additional comments (12)
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (12)

11-11: Import eq is correctly added

The addition of import org.mockito.ArgumentMatchers.eq is appropriate and necessary for precise argument matching in your mock setups.


17-17: Import AccountOuterClass is appropriately included

The import of org.onflow.protobuf.entities.AccountOuterClass is required for creating mock account keys and is correctly added.


28-29: Initialization of mock API and AsyncFlowAccessApiImpl

The instantiation of api and asyncFlowAccessApi using Mockito mocks sets up the testing environment effectively.


63-75: Creation of mockBlock for block-related tests

The mockBlock object is properly constructed with relevant fields, facilitating comprehensive testing of block-related functionalities.


77-78: Declaration of flowId and blockId

The initialization of flowId and blockId provides clear identifiers for use in various test cases.


80-85: Setup of mock account keys and test exception

Mocking FlowAccountKey instances and defining a testException ensures that both success and failure scenarios are adequately tested.


94-156: Introduction of MockResponseFactory for reusable mock responses

The MockResponseFactory centralizes the creation of mock responses, reducing code duplication and enhancing maintainability of the test suite.


160-170: Helper functions enhance test clarity

The helper methods like createMockEventsResponse, createMockExecutionResult, and createMockTransaction improve readability and simplify test setups.


188-199: Assertion helpers streamline test validations

The assertSuccess and assertFailure functions provide a consistent approach to validating test outcomes, improving code clarity.


290-333: Exception handling in block-related tests

The block retrieval tests correctly handle potential exceptions and validate both success and failure scenarios, enhancing test coverage.


611-616: Effective testing of execution result retrieval

The getExecutionResultByBlockId test accurately verifies the functionality, ensuring correctness in execution result handling.


634-655: Helper method createMockNodeVersionInfo is well-constructed

The method effectively creates a mock NodeVersionInfo response, facilitating thorough testing of version information retrieval.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (1)
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (1)

67-67: Use fixed timestamp in tests to ensure consistent results

Using LocalDateTime.now() in tests can lead to non-deterministic behavior, making tests flaky. Consider using a fixed timestamp for consistency.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1efa6de and 0a8e1c9.

📒 Files selected for processing (1)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (13 hunks)
🧰 Additional context used
📓 Learnings (1)
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (2)
Learnt from: franklywatson
PR: onflow/flow-jvm-sdk#55
File: src/intTest/org/onflow/flow/sdk/ExposeAccountKeyIssueTest.kt:151-152
Timestamp: 2024-07-04T05:15:46.310Z
Learning: When reviewing test code, avoid recommending additional exception handling if it might obscure the actual failure points and over-sensitize the process.
Learnt from: franklywatson
PR: onflow/flow-jvm-sdk#55
File: src/intTest/org/onflow/flow/sdk/ExposeAccountKeyIssueTest.kt:151-152
Timestamp: 2024-10-08T17:04:37.869Z
Learning: When reviewing test code, avoid recommending additional exception handling if it might obscure the actual failure points and over-sensitize the process.

@lealobanov lealobanov merged commit 662759b into main Oct 30, 2024
3 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add GetAccountKey endpoints
2 participants