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

Address code duplication in Access API tests and error handling #140

Merged
merged 25 commits into from
Nov 7, 2024

Conversation

lealobanov
Copy link
Collaborator

@lealobanov lealobanov commented Oct 30, 2024

Closes: #138

Description

Addresses code duplication in error handling and tests related to the FlowAccessApi and AsyncFlowAccessApi classes (see issue #138)

  • Also addressed refactoring comments suggested by Code Rabbit

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 new methods for retrieving full collections and protocol state snapshots by ID and height.
    • Added utility functions for improved error handling in API calls.
  • Bug Fixes

    • Streamlined error handling in various API methods to reduce redundancy.
  • Refactor

    • Refactored existing tests to utilize new helper functions for better maintainability and readability.
    • Enhanced the structure and clarity of the test code by centralizing mock object creation.
  • Chores

    • Updated visibility of mock response factory for broader access in tests.

Copy link
Contributor

coderabbitai bot commented Oct 30, 2024

Walkthrough

The changes introduced in this pull request focus on enhancing error handling and reducing code duplication across various API interaction tests and implementations. A new private utility function, safelyHandle, has been added to streamline error management in test cases. Additionally, the AsyncFlowAccessApiImpl class has been refactored to centralize API call handling through a new method, handleApiCall. The test classes have been updated to utilize new mock creation methods, improving consistency and readability in the test code.

Changes

File Change Summary
sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt Introduced safelyHandle function for error handling; refactored existing tests to use this function.
sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt Added handleApiCall method for centralized API call handling; refactored multiple API methods to utilize this method; marked several methods as deprecated.
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt Added helper functions for mock creation; updated MockResponseFactory visibility; refactored tests to improve mock response handling.
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt Added companion object methods for mock creation; standardized error handling across tests; refactored tests to use new mock creation methods.
java-example/README.md Added new examples for retrieving collections by ID.
java-example/src/main/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnector.java Introduced getFullCollectionById method for retrieving full collections of transactions.
java-example/src/main/java/org/onflow/examples/java/getProtocolState/GetProtocolStateAccessAPIConnector.java Added class for retrieving protocol state snapshots with three public methods.
java-example/src/test/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnectorTest.java Added test for getFullCollectionById functionality.
java-example/src/test/java/org/onflow/examples/java/getProtocolState/GetProtocolStateAccessAPIConnectorTest.java Introduced a new test class for the GetProtocolStateAccessAPIConnector.
kotlin-example/README.md Added new features related to retrieving collections by ID.
kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnector.kt Added getFullCollectionById method for retrieving collections.
kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnector.kt Introduced class for retrieving protocol state snapshots with three public methods.
kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt Added test for fetching full collection by ID.
kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getNetworkParams/GetNetworkParamsAccessAPIConnectorTest.kt Updated test class name for consistency.
kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt Introduced test class for GetProtocolStateAccessAPIConnector.
sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt Added new methods for retrieving full collections and protocol state snapshots; deprecated an existing method.
sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt Added new function declarations for retrieving collections and snapshots.
sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt Implemented new methods for retrieving collections and protocol state snapshots; deprecated an existing method.
sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt Added new test cases for the new API methods.

Assessment against linked issues

Objective Addressed Explanation
Address duplication in error handling (138)
Address duplication in unit tests (138)

Possibly related PRs

  • Access API refactoring + exception handling #55: This PR involves significant refactoring of the Access API, including the introduction of new methods for retrieving transactions and results by block ID, which relates to the main PR's focus on enhancing error handling and API interaction.
  • Access api methods - aggregate changes into main branch #63: This PR aggregates changes to the Access API methods, including the addition of new methods for retrieving transactions and results by block ID, which aligns with the main PR's updates to error handling and API response management.
  • Add fullBlockResponse param to Access API block requests #135: This PR adds a fullBlockResponse parameter to block retrieval methods, enhancing the functionality of the Access API, which is directly related to the main PR's focus on improving API interactions and error handling.
  • FlowBlockSeal protobuf updates #122: This PR updates the FlowBlockSeal and introduces a new FlowAggregatedSignature, which enhances the structure of the API responses, relevant to the main PR's focus on improving error handling and response management.
  • #106/ TransactionResult type differs from protobuf schema #116: This PR addresses discrepancies in the TransactionResult type, which is relevant to the main PR's focus on enhancing error handling and ensuring consistency in API responses.

Suggested reviewers

  • jribbink

Poem

In the code where bunnies play,
Errors once led us astray.
Now with safelyHandle in sight,
Our tests are clean, our code is bright!
Hopping through functions, all in a row,
With each little change, our confidence grows! 🐇✨


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.

Copy link

github-actions bot commented Oct 30, 2024

Unit Test Results

  62 files  ±0    62 suites  ±0   25s ⏱️ ±0s
389 tests ±0  389 ✔️ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit a8a17a4. ± Comparison against base commit a8a17a4.

♻️ This comment has been updated with latest results.

Copy link

github-actions bot commented Oct 30, 2024

SDK Examples Unit Test Results

43 files  43 suites   8m 30s ⏱️
96 tests 96 ✔️ 0 💤 0 ❌

Results for commit 36d0930.

♻️ This comment has been updated with latest results.

Copy link

github-actions bot commented Oct 30, 2024

Common Integration Test Results

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

Results for commit 36d0930.

♻️ This comment has been updated with latest results.

Copy link

github-actions bot commented Oct 30, 2024

Integration Test Results

  6 files  ±0    6 suites  ±0   3m 30s ⏱️ ±0s
41 tests ±0  41 ✔️ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit a8a17a4. ± Comparison against base commit a8a17a4.

♻️ This comment has been updated with latest results.

@lealobanov lealobanov changed the title WIP: continue with code duplication changes Address code duplication in Access API tests and error handling Oct 31, 2024
@lealobanov lealobanov marked this pull request as ready for review October 31, 2024 06:50
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: 5

🧹 Outside diff range and nitpick comments (8)
sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (2)

Line range hint 77-306: Maintain consistency in helper method usage across tests.

While many test methods use the new helper methods, some still contain inline error handling. For example, getNodeVersionInfo and getAccountByAddress tests could use helper methods.

Consider extracting these into helper methods for consistency:

private fun getNodeVersionInfo(): FlowNodeVersionInfo =
    safelyHandle(
        { handleResult(accessAPI.getNodeVersionInfo(), "Failed to get node version info") },
        "Failed to retrieve node version info"
    )

private fun getAccountByAddress(address: FlowAddress): FlowAccount =
    safelyHandle(
        { handleResult(accessAPI.getAccountByAddress(address), "Failed to get account by address") },
        "Failed to retrieve account by address"
    )

Line range hint 1-306: Overall architectural improvements align with PR objectives.

The introduction of safelyHandle and helper methods successfully addresses code duplication in the Access API tests. The changes make the code more maintainable and consistent with the PR objectives.

However, consider the following architectural improvements:

  1. Create an error handling module that can be shared across different test classes
  2. Consider using a test fixture pattern to reduce setup code duplication
  3. Add documentation for the error handling pattern to help other contributors
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (1)

87-112: LGTM! Consider adding KDoc comments.

The helper functions are well-structured and provide comprehensive mock data. They effectively support test cases by creating reusable mock responses.

Consider adding KDoc comments to document the purpose and return values of these utility functions:

/**
 * Creates a mock node version info response for testing.
 * @return Access.GetNodeVersionInfoResponse with predefined test values
 */
fun createMockNodeVersionInfo(): Access.GetNodeVersionInfoResponse

/**
 * Creates a mock transactions response containing the provided transactions.
 * @param transactions List of FlowTransaction to include in the response
 * @return Access.TransactionsResponse containing the provided transactions
 */
fun createTransactionsResponse(transactions: List<FlowTransaction>): Access.TransactionsResponse
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (3)

Line range hint 737-749: Consider extracting common error handling test logic.

These error handling test blocks contain duplicated verification logic. Consider extracting this pattern into a helper method to reduce duplication.

private suspend fun verifyErrorChannel(errorChannel: ReceiveChannel<Throwable>, expectedMessage: String) {
    var receivedException: Throwable? = null
    val job = launch {
        receivedException = errorChannel.receiveCatching().getOrNull()
    }
    advanceUntilIdle()
    job.join()

    if (receivedException != null) {
        assertEquals(expectedMessage, receivedException!!.message)
    } else {
        fail("Expected error but got success")
    }
    
    errorChannel.cancel()
}

Then use it in the test cases:

verifyErrorChannel(errorChannel, testException.message!!)

Also applies to: 760-772, 806-818, 855-867


405-405: Consider strengthening account verification.

The account verification logic in these test cases could be strengthened by also verifying the code field of the FlowAccount.

 assertResultSuccess(result) {
     assertEquals(flowAccount.address, it.address)
     assertEquals(flowAccount.keys, it.keys)
     assertEquals(flowAccount.contracts, it.contracts)
     assertEquals(flowAccount.balance.stripTrailingZeros(), it.balance.stripTrailingZeros())
+    assertEquals(flowAccount.code, it.code)
 }

Also applies to: 421-421, 437-437


Line range hint 876-882: Consider enhancing assertResultSuccess helper method.

The helper method could be enhanced to provide more detailed error information by including the actual error message in the exception.

 private fun <T> assertResultSuccess(result: FlowAccessApi.AccessApiCallResponse<T>, assertions: (T) -> Unit) {
     when (result) {
         is FlowAccessApi.AccessApiCallResponse.Success -> assertions(result.data)
-        is FlowAccessApi.AccessApiCallResponse.Error -> throw IllegalStateException("Request failed: ${result.message}", result.throwable)
+        is FlowAccessApi.AccessApiCallResponse.Error -> throw IllegalStateException(
+            "Request failed: ${result.message}. Error details: ${result.throwable?.message}",
+            result.throwable
+        )
     }
 }
sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt (2)

437-440: Simplify compatibleRange Initialization

The initialization of compatibleRange can be simplified using Kotlin's safe-call operator and let function, enhancing code readability.

Apply this diff to streamline the code:

 val compatibleRange = if (response.info.hasCompatibleRange()) {
     FlowCompatibleRange(response.info.compatibleRange.startHeight, response.info.compatibleRange.endHeight)
-} else { null }
+} else null

Or use safe-call with let:

+val compatibleRange = response.info.compatibleRange?.let {
+    FlowCompatibleRange(it.startHeight, it.endHeight)
+}

26-41: Use Specific Exception Types in Catch Blocks

Catching the general Exception class in the handleApiCall method may obscure the root cause of errors. Using more specific exception types can aid in debugging and provide clearer error handling.

Consider catching specific exceptions like IOException, GrpcException, or any other relevant exceptions expected from the API calls.

-} catch (e: Exception) {
+} catch (e: IOException) {

Adjust the exception types based on the exceptions that apiCall() might throw.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 662759b and 36c22b2.

📒 Files selected for processing (4)
  • sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (7 hunks)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt (1 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (6 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (31 hunks)
🧰 Additional context used
📓 Learnings (1)
sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (2)
Learnt from: lealobanov
PR: onflow/flow-jvm-sdk#55
File: src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt:95-106
Timestamp: 2024-07-03T12:30:04.496Z
Learning: In the `TransactionIntegrationTest` class, exception handling is implemented using `IntegrationTestUtils.handleResult`.
Learnt from: lealobanov
PR: onflow/flow-jvm-sdk#55
File: src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt:95-106
Timestamp: 2024-10-08T17:04:37.869Z
Learning: In the `TransactionIntegrationTest` class, exception handling is implemented using `IntegrationTestUtils.handleResult`.
🔇 Additional comments (7)
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (3)

15-15: LGTM! Good use of shared test utilities.

The import of createMockAccount from FlowAccessApiImplTest.Companion helps reduce code duplication between test classes, which aligns well with the PR objectives.


121-130: LGTM! Good refactoring of test utilities.

Making MockResponseFactory public and adding new account response factory methods improves code reuse across test classes, which aligns with the PR's goal of reducing duplication.


Line range hint 468-503: LGTM! Effective reduction of test code duplication.

The account-related test methods have been successfully refactored to use the shared createMockAccount utility, which:

  • Reduces code duplication
  • Maintains comprehensive assertions
  • Improves consistency across test cases
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (3)

14-22: LGTM! Good refactoring of imports.

The imports have been organized to leverage shared test utilities from AsyncFlowAccessApiImplTest, which helps reduce code duplication across test classes.


55-58: Well-structured utility methods in companion object.

Good addition of utility methods createMockTransaction and createMockAccount to centralize mock object creation. This promotes code reuse and maintains consistency in test data creation.


87-87: Consistent error handling pattern across test cases.

Good use of shared testException across error test cases. This standardizes error handling and makes the tests more maintainable.

Also applies to: 106-106, 142-142, 172-172, 204-204, 290-290, 322-322, 391-391

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

285-296: Validate Transactions Before Sending

In sendTransaction, ensuring that the transaction is valid before sending can prevent unnecessary API calls and potential errors.

Run the following script to verify the transaction's validity:

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 36c22b2 and 9f3f7d5.

📒 Files selected for processing (1)
  • sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (7 hunks)
🧰 Additional context used
📓 Learnings (1)
sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (2)
Learnt from: lealobanov
PR: onflow/flow-jvm-sdk#55
File: src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt:95-106
Timestamp: 2024-07-03T12:30:04.496Z
Learning: In the `TransactionIntegrationTest` class, exception handling is implemented using `IntegrationTestUtils.handleResult`.
Learnt from: lealobanov
PR: onflow/flow-jvm-sdk#55
File: src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt:95-106
Timestamp: 2024-10-08T17:04:37.869Z
Learning: In the `TransactionIntegrationTest` class, exception handling is implemented using `IntegrationTestUtils.handleResult`.
🔇 Additional comments (2)
sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (2)

22-24: Well-implemented error handling utility!

The safelyHandle function effectively simplifies error handling by combining Result handling with exception handling. This implementation addresses the previous feedback about reducing error handling complexity.


27-52: Previous suggestion about error message duplication remains valid.

The helper methods consistently use both handleResult and safelyHandle, but there's still duplication in error messages as noted in the previous review.

@lealobanov lealobanov self-assigned this Nov 5, 2024
…ints

Add GetProtocolStateSnapshotByBlockID and GetProtocolStateSnapshotByHeight to the SDK
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: 11

🧹 Outside diff range and nitpick comments (23)
kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnector.kt (1)

15-19: Consider using domain-specific exceptions.

Using a raw Exception makes it harder for clients to handle specific error cases. Consider creating domain-specific exceptions that better represent the failure modes.

Example implementation:

sealed class CollectionApiException(message: String, cause: Throwable? = null) : Exception(message, cause) {
    class CollectionNotFound(id: FlowId, cause: Throwable? = null) : 
        CollectionApiException("Collection not found: $id", cause)
    class ApiError(message: String, cause: Throwable? = null) : 
        CollectionApiException(message, cause)
}

Then update the error handling:

- throw Exception(response.message, response.throwable)
+ throw CollectionApiException.ApiError(response.message, response.throwable)
kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnector.kt (1)

7-9: Add KDoc documentation for the class.

Consider adding KDoc documentation to describe the purpose and usage of this connector class.

+/**
+ * Internal connector class that provides a higher-level interface for retrieving protocol state
+ * snapshots through the Flow Access API.
+ *
+ * @property accessAPI The Flow Access API implementation used for making the actual API calls.
+ */
 internal class GetProtocolStateAccessAPIConnector(
     private val accessAPI: FlowAccessApi
 )
java-example/src/main/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnector.java (3)

28-36: Consider creating a custom exception type.

Using RuntimeException is too generic and loses type safety. This makes it harder for clients to handle specific error cases.

Consider creating a custom exception:

public class CollectionNotFoundException extends RuntimeException {
    private final FlowId collectionId;

    public CollectionNotFoundException(FlowId collectionId, String message, Throwable cause) {
        super(message, cause);
        this.collectionId = collectionId;
    }

    public FlowId getCollectionId() {
        return collectionId;
    }
}

28-28: Add method documentation.

The new method lacks JavaDoc documentation explaining its purpose, parameters, return value, and potential exceptions.

Consider adding documentation:

+    /**
+     * Retrieves a full collection of transactions by ID.
+     *
+     * @param collectionId The ID of the collection to retrieve
+     * @return List of transactions in the collection
+     * @throws RuntimeException if the collection cannot be retrieved
+     */
     public List<FlowTransaction> getFullCollectionById(FlowId collectionId) {

28-29: Add parameter validation.

The method should validate the collectionId parameter before making the API call.

Add parameter validation:

     public List<FlowTransaction> getFullCollectionById(FlowId collectionId) {
+        if (collectionId == null) {
+            throw new IllegalArgumentException("collectionId cannot be null");
+        }
         AccessApiCallResponse<List<FlowTransaction>> response = accessAPI.getFullCollectionById(collectionId);
kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt (1)

25-51: Enhance test coverage with additional assertions and error scenarios.

The current tests only verify that the snapshots are non-null. Consider:

  1. Adding assertions to validate snapshot properties
  2. Adding tests for error scenarios (e.g., invalid blockId/height)
  3. Testing edge cases (e.g., height = 0)

Example enhancement for the blockId test:

@Test
fun `Can get protocol state snapshot by blockId`() {
    block = getLatestBlockOrThrow()
    val snapshot = protocolStateConnector.getProtocolStateSnapshotByBlockId(block.id)
    
    assertNotNull(snapshot)
    assertEquals(block.height, snapshot.height)
    // Add more relevant assertions
}

@Test
fun `Should handle invalid blockId`() {
    val invalidBlockId = "invalid-id"
    assertThrows<Exception> {
        protocolStateConnector.getProtocolStateSnapshotByBlockId(invalidBlockId)
    }
}
java-example/src/test/java/org/onflow/examples/java/getProtocolState/GetProtocolStateAccessAPIConnectorTest.java (2)

17-17: Consider initializing FlowBlock in setup

The block field is declared but not initialized in the setup method. Since it's used in multiple test methods, consider initializing it in the setup to avoid redundant calls to getLatestBlock().

 @BeforeEach
 public void setup() {
     protocolStateConnector = new GetProtocolStateAccessAPIConnector(accessAPI);
+    block = getLatestBlock();
 }

Also applies to: 22-24


13-14: Add class and method documentation

Consider adding Javadoc documentation to describe:

  1. The purpose of this test class
  2. The test scenarios covered
  3. The expected behavior for each test method

Example:

+/**
+ * Integration tests for GetProtocolStateAccessAPIConnector.
+ * Verifies the functionality of retrieving protocol state snapshots
+ * through different methods: latest, by block ID, and by height.
+ */
 @FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json")
 public class GetProtocolStateAccessAPIConnectorTest {
java-example/src/main/java/org/onflow/examples/java/getProtocolState/GetProtocolStateAccessAPIConnector.java (1)

7-7: Add class-level documentation.

Since this is a public API class, please add Javadoc documentation describing:

  • The purpose of this connector
  • The relationship with FlowAccessApi
  • Any important usage notes or considerations

Example:

/**
 * Connector class that provides methods to retrieve protocol state snapshots from the Flow blockchain
 * using the Flow Access API.
 * 
 * This class wraps the {@link FlowAccessApi} and provides convenient methods to retrieve protocol
 * state snapshots by different criteria (latest, block ID, or height).
 */
kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt (2)

11-11: Consider using explicit imports instead of wildcard imports.

While wildcard imports reduce verbosity, explicit imports make it clearer which classes are being used and help prevent potential naming conflicts.

-import org.onflow.flow.sdk.*
+import org.onflow.flow.sdk.FlowAccessApi
+import org.onflow.flow.sdk.FlowCollection
+import org.onflow.flow.sdk.FlowId
+import org.onflow.flow.sdk.FlowTransaction
+import org.onflow.flow.sdk.SignatureAlgorithm

54-64: Enhance test coverage with additional assertions and error scenarios.

While the basic validations are good, consider enhancing the test coverage:

  1. Add assertions for:
    • Expected number of transactions
    • Additional transaction properties (e.g., status, proposalKey)
  2. Add error scenario tests (e.g., invalid collection ID)

Here's a suggested enhancement:

 @Test
 fun `Can fetch full collection by ID`() {
     val collectionTransactions: List<FlowTransaction> = connector.getFullCollectionById(collectionId)

     assertNotNull(collectionTransactions, "Collection transactions should not be null")
     assertTrue(collectionTransactions.isNotEmpty(), "Collection transactions should not be empty")
+    assertEquals(1, collectionTransactions.size, "Expected exactly one transaction")

     val firstTransaction = collectionTransactions.first()
     assertNotNull(firstTransaction.id, "Transaction ID should not be null")
     assertNotNull(firstTransaction.script, "Transaction script should not be null")
+    assertNotNull(firstTransaction.proposalKey, "Transaction proposal key should not be null")
+    assertNotNull(firstTransaction.status, "Transaction status should not be null")
 }
+
+@Test
+fun `Should handle invalid collection ID`() {
+    val invalidId = FlowId("0000000000000000")
+    assertThrows<IllegalArgumentException>("Should throw exception for invalid collection ID") {
+        connector.getFullCollectionById(invalidId)
+    }
+}
java-example/src/test/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnectorTest.java (1)

57-67: Consider enhancing test coverage with additional assertions.

While the basic happy path is well tested, consider adding:

  1. Error case testing (e.g., invalid collection ID)
  2. Verification of all transactions in the collection
  3. Additional transaction properties validation beyond ID and script

Example assertions to add:

// Verify all transactions in collection
fullCollectionResponse.forEach(tx -> {
    assertNotNull(tx.getId(), "All transaction IDs should be non-null");
    assertNotNull(tx.getScript(), "All transaction scripts should be non-null");
});

// Verify collection size matches expected
assertEquals(expectedSize, fullCollectionResponse.size(), "Collection should contain expected number of transactions");
sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt (1)

47-48: LGTM! Consider adding KDoc documentation.

The new getFullCollectionById method is a logical addition that complements the existing getCollectionById method by providing direct access to the collection's transactions.

Consider adding KDoc documentation to clarify:

  • The relationship between this method and getCollectionById
  • When to use one over the other
  • Any performance implications of retrieving full transaction details
+    /**
+     * Retrieves all transactions in a collection by its ID.
+     * Unlike [getCollectionById], this method returns the complete transaction details.
+     *
+     * @param id The ID of the collection
+     * @return A response containing the list of transactions in the collection
+     */
     fun getFullCollectionById(id: FlowId): AccessApiCallResponse<List<FlowTransaction>>
sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt (1)

35-36: Add documentation to clarify the difference between getCollectionById and getFullCollectionById.

The interface now has two methods for retrieving collections:

  • getCollectionById returning FlowCollection?
  • getFullCollectionById returning List<FlowTransaction>

Please add KDoc comments to explain:

  • The difference between these methods
  • When to use each method
  • The relationship between FlowCollection and the list of transactions
kotlin-example/README.md (1)

74-76: Enhance documentation clarity for collection retrieval methods.

While the additions accurately reflect the new functionality, consider expanding the documentation to better distinguish between the two methods and their use cases:

- Get collection by id
- Get full collection by id (returns all transactions in collection response)
+ Get collection by id - Retrieves basic collection information
+ Get full collection by id - Retrieves complete collection data including all associated transactions

Also consider adding:

  • Example usage scenarios for each method
  • Notes about error handling behavior
🧰 Tools
🪛 LanguageTool

[style] ~74-~74: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: .../GetCollectionAccessAPIConnector.kt) - Get collection by id - Get full collection ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt (2)

233-243: Add test cases for edge cases and error scenarios.

While the happy path is covered, consider adding test cases for:

  1. Empty collection
  2. Error response from the API
  3. Collection with multiple transactions

This would ensure comprehensive test coverage for the getFullCollectionById functionality.

@Test
fun `Test getFullCollectionById with empty collection`() {
    val flowAccessApi = mock(FlowAccessApi::class.java)
    val flowId = FlowId("01")
    `when`(flowAccessApi.getFullCollectionById(flowId))
        .thenReturn(FlowAccessApi.AccessApiCallResponse.Success(emptyList()))
    
    val result = flowAccessApi.getFullCollectionById(flowId)
    
    assertEquals(FlowAccessApi.AccessApiCallResponse.Success(emptyList()), result)
}

@Test
fun `Test getFullCollectionById with error`() {
    val flowAccessApi = mock(FlowAccessApi::class.java)
    val flowId = FlowId("01")
    val error = RuntimeException("API Error")
    `when`(flowAccessApi.getFullCollectionById(flowId))
        .thenReturn(FlowAccessApi.AccessApiCallResponse.Error("Failed to get collection", error))
    
    val result = flowAccessApi.getFullCollectionById(flowId)
    
    assertTrue(result is FlowAccessApi.AccessApiCallResponse.Error)
}

409-429: Enhance test data and validation for protocol state snapshots.

Consider the following improvements:

  1. Use more realistic test data instead of the simple "snapshot" string
  2. Add validation for the snapshot content
  3. Consider adding test cases for error scenarios
private companion object {
    val TEST_SNAPSHOT_DATA = ByteArray(32) { it.toByte() } // More realistic test data
}

@Test
fun `Test getProtocolStateSnapshotByBlockId`() {
    val flowAccessApi = mock(FlowAccessApi::class.java)
    val snapshot = FlowSnapshot(TEST_SNAPSHOT_DATA)
    `when`(flowAccessApi.getProtocolStateSnapshotByBlockId(blockId))
        .thenReturn(FlowAccessApi.AccessApiCallResponse.Success(snapshot))

    val result = flowAccessApi.getProtocolStateSnapshotByBlockId(blockId)

    assertTrue(result is FlowAccessApi.AccessApiCallResponse.Success)
    result.data.let { data ->
        assertArrayEquals(TEST_SNAPSHOT_DATA, data.bytes)
    }
}
sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt (1)

457-481: LGTM! Consider extracting common snapshot handling logic.

The implementation is correct and follows established patterns. However, there's an opportunity to reduce code duplication across the three snapshot-related methods (getLatestProtocolStateSnapshot, getProtocolStateSnapshotByBlockId, getProtocolStateSnapshotByHeight).

Consider extracting the common snapshot handling logic into a private method:

+ private fun handleSnapshotResponse(response: Access.ProtocolStateSnapshotResponse): FlowAccessApi.AccessApiCallResponse<FlowSnapshot> =
+     FlowAccessApi.AccessApiCallResponse.Success(FlowSnapshot(response.serializedSnapshot.toByteArray()))

  override fun getLatestProtocolStateSnapshot(): FlowAccessApi.AccessApiCallResponse<FlowSnapshot> =
      try {
          val ret = api.getLatestProtocolStateSnapshot(
              Access.GetLatestProtocolStateSnapshotRequest
                  .newBuilder()
                  .build()
          )
-         FlowAccessApi.AccessApiCallResponse.Success(FlowSnapshot(ret.serializedSnapshot.toByteArray()))
+         handleSnapshotResponse(ret)
      } catch (e: Exception) {
          FlowAccessApi.AccessApiCallResponse.Error("Failed to get latest protocol state snapshot", e)
      }

  override fun getProtocolStateSnapshotByBlockId(blockId: FlowId): FlowAccessApi.AccessApiCallResponse<FlowSnapshot> =
      try {
          val ret = api.getProtocolStateSnapshotByBlockID(
              Access.GetProtocolStateSnapshotByBlockIDRequest
                  .newBuilder()
                  .setBlockId(blockId.byteStringValue)
                  .build()
          )
-         FlowAccessApi.AccessApiCallResponse.Success(FlowSnapshot(ret.serializedSnapshot.toByteArray()))
+         handleSnapshotResponse(ret)
      } catch (e: Exception) {
          FlowAccessApi.AccessApiCallResponse.Error("Failed to get protocol state snapshot by block ID", e)
      }

  override fun getProtocolStateSnapshotByHeight(height: Long): FlowAccessApi.AccessApiCallResponse<FlowSnapshot> =
      try {
          val ret = api.getProtocolStateSnapshotByHeight(
              Access.GetProtocolStateSnapshotByHeightRequest
                  .newBuilder()
                  .setBlockHeight(height)
                  .build()
          )
-         FlowAccessApi.AccessApiCallResponse.Success(FlowSnapshot(ret.serializedSnapshot.toByteArray()))
+         handleSnapshotResponse(ret)
      } catch (e: Exception) {
          FlowAccessApi.AccessApiCallResponse.Error("Failed to get protocol state snapshot by height", e)
      }
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (1)

121-130: Consider adding validation for null parameters.

While the mock factory methods are well-structured, they should validate input parameters to fail fast during testing.

 object MockResponseFactory {
     fun accountResponse(mockAccount: FlowAccount) = Access.AccountResponse
+        .also { require(mockAccount != null) { "mockAccount cannot be null" } }
         .newBuilder()
         .setAccount(mockAccount.builder().build())
         .build()

     fun getAccountResponse(mockAccount: FlowAccount) = Access.GetAccountResponse
+        .also { require(mockAccount != null) { "mockAccount cannot be null" } }
         .newBuilder()
         .setAccount(mockAccount.builder().build())
         .build()
sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (3)

55-58: Consider enhancing mock object creation utilities.

While the utility methods provide consistent mock objects, they could be more robust with input validation and documentation.

Consider these improvements:

 companion object {
-    fun createMockTransaction(flowId: FlowId = FlowId("01")) = FlowTransaction(
+    /**
+     * Creates a mock transaction for testing purposes.
+     * @param flowId The ID for the transaction, defaults to "01"
+     * @throws IllegalArgumentException if flowId is empty
+     */
+    fun createMockTransaction(flowId: FlowId = FlowId("01")) = require(flowId.bytes.isNotEmpty()) {
+        "Flow ID cannot be empty"
+    }.let {
+        FlowTransaction(
         FlowScript("script"),
         emptyList(),
         flowId,
         123L,
         FlowTransactionProposalKey(FlowAddress("02"), 1, 123L),
         FlowAddress("02"),
         emptyList()
     )
+    }

402-408: Enhance error message specificity.

The error message could be more specific about what failed during the transaction result retrieval.

-        assertEquals("Failed to get transaction result by index", (result as FlowAccessApi.AccessApiCallResponse.Error).message)
+        assertEquals("Failed to get transaction result by index: ${flowId.base16Value}[${index}]", (result as FlowAccessApi.AccessApiCallResponse.Error).message)

592-623: Consider adding edge cases for protocol state snapshot tests.

While the happy path is well tested, consider adding test cases for:

  • Empty snapshots
  • Invalid block IDs
  • Error scenarios with specific error messages

Example additional test:

@Test
fun `Test getProtocolStateSnapshotByBlockId with empty snapshot`() {
    val emptySnapshot = FlowSnapshot(ByteArray(0))

    `when`(
        mockApi.getProtocolStateSnapshotByBlockID(any())
    ).thenReturn(AsyncFlowAccessApiImplTest.MockResponseFactory.protocolStateSnapshotResponse(emptySnapshot))

    val result = flowAccessApiImpl.getProtocolStateSnapshotByBlockId(blockId)
    assertResultSuccess(result) { assertEquals(emptySnapshot, it) }
}
sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt (1)

500-505: Extract complex transform logic into a private helper method for readability

The transform lambda in getNodeVersionInfo contains complex logic that spans multiple lines, which can reduce readability. Extracting this logic into a separate private method will enhance code clarity and maintainability.

Proposed refactor:

Create a private helper method:

private fun toFlowNodeVersionInfo(response: Access.GetNodeVersionInfoResponse): FlowNodeVersionInfo {
    val compatibleRange = if (response.info.hasCompatibleRange()) {
        FlowCompatibleRange(
            startHeight = response.info.compatibleRange.startHeight,
            endHeight = response.info.compatibleRange.endHeight
        )
    } else {
        null
    }
    return FlowNodeVersionInfo(
        semver = response.info.semver,
        commit = response.info.commit,
        sporkId = response.info.sporkId.toByteArray(),
        protocolVersion = response.info.protocolVersion,
        sporkRootBlockHeight = response.info.sporkRootBlockHeight,
        nodeRootBlockHeight = response.info.nodeRootBlockHeight,
        compatibleRange = compatibleRange
    )
}

Update the transform lambda in getNodeVersionInfo:

 transform = { response ->
-    val compatibleRange = if (response.info.hasCompatibleRange()) {
-        FlowCompatibleRange(response.info.compatibleRange.startHeight, response.info.compatibleRange.endHeight)
-    } else { null }
-    FlowNodeVersionInfo(response.info.semver, response.info.commit, response.info.sporkId.toByteArray(), response.info.protocolVersion, response.info.sporkRootBlockHeight, response.info.nodeRootBlockHeight, compatibleRange)
+    toFlowNodeVersionInfo(response)
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8731d91 and 36d0930.

📒 Files selected for processing (19)
  • java-example/README.md (1 hunks)
  • java-example/src/main/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnector.java (2 hunks)
  • java-example/src/main/java/org/onflow/examples/java/getProtocolState/GetProtocolStateAccessAPIConnector.java (1 hunks)
  • java-example/src/test/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnectorTest.java (2 hunks)
  • java-example/src/test/java/org/onflow/examples/java/getProtocolState/GetProtocolStateAccessAPIConnectorTest.java (1 hunks)
  • kotlin-example/README.md (1 hunks)
  • kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnector.kt (1 hunks)
  • kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnector.kt (1 hunks)
  • kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt (2 hunks)
  • kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getNetworkParams/GetNetworkParamsAccessAPIConnectorTest.kt (1 hunks)
  • kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt (1 hunks)
  • sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt (7 hunks)
  • sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt (2 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 (2 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt (3 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt (9 hunks)
  • sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt (30 hunks)
✅ Files skipped from review due to trivial changes (1)
  • kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getNetworkParams/GetNetworkParamsAccessAPIConnectorTest.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt
🧰 Additional context used
🪛 LanguageTool
java-example/README.md

[style] ~73-~73: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...etCollectionAccessAPIConnector.java) - Get collection by id - Get full collection ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

kotlin-example/README.md

[style] ~74-~74: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: .../GetCollectionAccessAPIConnector.kt) - Get collection by id - Get full collection ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (21)
kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnector.kt (1)

15-19: Verify consistent error handling across API implementations.

Since this PR aims to address error handling duplication, let's verify if similar patterns exist in other API implementations.

✅ Verification successful

Based on the shell script results, I can now generate the final response:

Error handling pattern is consistently implemented across the codebase

The error handling pattern for AccessApiCallResponse is consistently implemented across all API connectors and examples:

  • All implementations use the same when-expression pattern to handle Success and Error cases
  • Error cases consistently throw exceptions with the response message and throwable
  • The pattern in the reviewed file matches the established pattern in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for similar error handling patterns across API implementations
# Expected: Find other instances of AccessApiCallResponse handling to ensure consistent refactoring

# Look for similar when-expression patterns with AccessApiCallResponse
rg -l "AccessApiCallResponse" | xargs rg -A 3 "when.*AccessApiCallResponse"

# Look for similar exception throwing patterns
rg "throw.*Exception.*message.*throwable"

Length of output: 30669

kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnector.kt (1)

1-6: LGTM!

The package structure and imports are well-organized and follow Kotlin conventions.

java-example/src/main/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnector.java (1)

7-8: LGTM!

The added import is necessary for the new method's return type.

kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt (2)

1-19: LGTM! Class setup follows best practices.

The test class is properly structured with appropriate annotations and dependencies.


20-24: LGTM! Clean and focused setup.

The setup method is concise and properly initializes the test dependencies.

java-example/src/main/java/org/onflow/examples/java/getProtocolState/GetProtocolStateAccessAPIConnector.java (1)

1-12: LGTM! Clean class structure with proper dependency injection.

The class is well-organized with appropriate imports and follows good practices by using constructor injection for the FlowAccessApi dependency.

kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt (1)

54-64: Verify potential test duplication across Access API test files.

Given that one of the PR objectives is to address code duplication in Access API tests, we should verify if similar test methods exist in other test files.

java-example/src/test/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnectorTest.java (2)

14-14: LGTM!

The List import is correctly added and necessary for handling the collection of transactions in the new test method.


57-67: Verify potential test duplication across API test files.

While this test adds valuable coverage, we should ensure it doesn't introduce duplication, given the PR's objective to reduce test duplication in Access API.

✅ Verification successful

Let me gather more context about potential test duplication by examining the full test file content.


Let me check other test files in the codebase to see if there are similar test patterns or duplicated test logic.


Let me check the content of GetTransactionAccessAPIConnectorTest.java since it seems most relevant for potential test duplication.


No test duplication found - test methods serve distinct purposes

After analyzing the codebase, the test method canFetchFullCollectionById in GetCollectionAccessAPIConnectorTest.java is not duplicated. While there are similar assertion patterns across test files, they serve different purposes:

  • GetCollectionAccessAPIConnectorTest tests collection-specific functionality
  • GetTransactionAccessAPIConnectorTest tests individual transaction retrieval
  • Other test files use similar assertions but test different API endpoints

The test aligns with the PR's objective as it provides unique coverage for collection-related functionality.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for similar test patterns across test files
rg -l "getFullCollectionById" --type java
rg -l "canFetchFullCollection" --type java

# Look for similar assertion patterns
rg "Collection.*should not be (null|empty)" --type java

Length of output: 1043


Script:

#!/bin/bash
# Get the full content of the test file to analyze all test methods
cat "java-example/src/test/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnectorTest.java"

Length of output: 3095


Script:

#!/bin/bash
# Search for other test files that might contain similar test patterns
fd "Test.java$" --type f --exec rg -l "FlowCollection|FlowTransaction|getCollection" {}

# Look for similar assertion patterns in other test files
rg "assert.*Transaction.*should not be (null|empty)" --type java

Length of output: 2456


Script:

#!/bin/bash
# Get the content of GetTransactionAccessAPIConnectorTest.java to compare test patterns
cat "java-example/src/test/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnectorTest.java"

Length of output: 3142

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

81-84: LGTM! Methods follow consistent API patterns.

The new protocol state snapshot methods maintain consistency with existing API patterns and provide flexible ways to retrieve snapshots at specific points in the blockchain.

Let's verify the consistency of similar method pairs across the API:

✅ Verification successful

Based on the search results, I can now generate the final response as I have sufficient information to verify the API patterns.

Verified: API methods maintain consistent patterns across the codebase

The codebase shows consistent patterns for methods that fetch data by BlockId and Height:

  • Both getProtocolStateSnapshotByBlockId and getProtocolStateSnapshotByHeight follow the same return type pattern (AccessApiCallResponse<FlowSnapshot>)
  • Similar consistent patterns are seen in other method pairs like getBlockByHeight/getBlockById, maintaining the same return types and parameter structures
  • The implementation in both FlowAccessApiImpl and AsyncFlowAccessApiImpl maintains this consistency
  • Test coverage confirms the symmetrical behavior of these method pairs
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all "ByBlockId" and "ByHeight" method pairs follow consistent patterns
# Expected: Each "ByBlockId" method should have a corresponding "ByHeight" method with similar structure

# Search for method pairs
echo "Analyzing method pairs..."
rg "ByBlockId|ByHeight" --type kotlin

Length of output: 24177

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

35-36: LGTM! The new methods maintain interface consistency.

The additions:

  • Follow the established async pattern using CompletableFuture
  • Use consistent return type wrappers (AccessApiCallResponse)
  • Maintain logical grouping of related operations
  • Support the PR's objective of improving error handling

Also applies to: 69-72

java-example/README.md (1)

73-75: LGTM! Documentation accurately reflects the new collection retrieval capabilities.

The additions clearly document both the basic and full collection retrieval functionality, maintaining consistency with the rest of the README.

The repetitive "Get" beginnings are intentional and consistent with the documentation style throughout the README.

🧰 Tools
🪛 LanguageTool

[style] ~73-~73: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...etCollectionAccessAPIConnector.java) - Get collection by id - Get full collection ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

kotlin-example/README.md (1)

74-75: LGTM! Consistent bullet point format.

The repetitive use of "Get" at the beginning of each bullet point is acceptable and common in API documentation as it maintains consistency and clarity.

🧰 Tools
🪛 LanguageTool

[style] ~74-~74: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: .../GetCollectionAccessAPIConnector.kt) - Get collection by id - Get full collection ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

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

236-247: LGTM! Implementation follows established patterns.

The implementation is well-structured, follows the class's error handling patterns, and properly handles the conversion of protobuf responses to domain objects.

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

15-15: LGTM! Import added for shared mock creation method.

The import of createMockAccount from the companion class aligns with the PR objective of reducing code duplication.


87-106: LGTM! Well-structured mock creation helper function.

The createMockNodeVersionInfo function provides a comprehensive mock with all necessary fields and proper builder pattern usage.


108-112: LGTM! Concise helper function for transaction response creation.

The createTransactionsResponse function follows the builder pattern and handles list conversion properly.


161-164: LGTM! Consistent mock factory method for full collection response.

The method follows the established pattern and properly handles the transaction list conversion.


Line range hint 483-518: LGTM! Improved test maintainability through shared mock creation.

The refactoring to use createMockAccount across account-related tests reduces code duplication and improves maintainability, aligning with the PR objectives.

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

14-22: LGTM! Good use of shared test utilities.

Importing shared mock factories and constants from AsyncFlowAccessApiImplTest reduces code duplication between sync and async implementations.


Line range hint 1-924: Well-organized test suite with good code reuse.

The test suite effectively achieves the PR objective of reducing code duplication by:

  1. Utilizing shared mock responses and utilities
  2. Maintaining consistent error handling patterns
  3. Following a clear test organization structure

This improves maintainability and reduces the likelihood of inconsistencies between sync and async implementations.

Comment on lines +69 to +72
fun getProtocolStateSnapshotByBlockId(blockId: FlowId): CompletableFuture<FlowAccessApi.AccessApiCallResponse<FlowSnapshot>>

fun getProtocolStateSnapshotByHeight(height: Long): CompletableFuture<FlowAccessApi.AccessApiCallResponse<FlowSnapshot>>

Copy link
Contributor

@coderabbitai coderabbitai bot Nov 7, 2024

Choose a reason for hiding this comment

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

💡 Codebase verification

Based on the code review and search results, I can now generate the final response since we've verified:

  1. The implementation consistency across sync/async APIs
  2. The proper test coverage for all methods
  3. The data structure (FlowSnapshot) and its usage

Documentation needed for protocol state snapshot methods

The new methods follow a consistent implementation pattern but lack essential documentation. Please add KDoc comments explaining:

  • The purpose and contents of FlowSnapshot
  • The difference between getting latest vs specific snapshots
  • When to use block ID vs height-based retrieval
  • Common use cases for historical snapshots
🔗 Analysis chain

Add documentation and verify consistency with other snapshot-related code.

The new protocol state snapshot methods follow the interface's pattern, but documentation would help users understand:

  • What a protocol state snapshot contains
  • When to use these methods vs getLatestProtocolStateSnapshot
  • Common use cases for accessing historical snapshots

Let's verify the consistency of snapshot-related code:


Let me search for any documentation or comments about protocol state snapshots to better understand what they contain.


Let me try a different search pattern to find documentation about protocol state snapshots.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in snapshot-related code
# Test: Look for other snapshot-related code to ensure consistent implementation
rg -A 5 "ProtocolStateSnapshot|FlowSnapshot"

Length of output: 44324


Script:

#!/bin/bash
# Look for documentation or comments about protocol state snapshots
rg -i "protocol.*state.*snapshot" --type md
rg -B2 -A2 "\/\*\*.*protocol.*state.*snapshot" 
rg -B2 -A2 "\/\/.*protocol.*state.*snapshot"

Length of output: 339


Script:

#!/bin/bash
# Look for documentation about protocol state snapshots with fixed regex
rg -i "protocol.+state.+snapshot" --type md
rg -B2 -A2 "\*.+protocol.+state.+snapshot"
rg -B2 -A2 "//.+protocol.+state.+snapshot"

# Also check for FlowSnapshot class definition and documentation
rg -B5 -A2 "class FlowSnapshot"

Length of output: 711

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
Contributor

Choose a reason for hiding this comment

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

@lealobanov - the first doc suggestions seems reasonable, could apply that across new entities where there's not much doc yet. Covering that in a new PR is fine too. The rest i don't think are needed

@franklywatson franklywatson merged commit a8a17a4 into main Nov 7, 2024
6 checks passed
@franklywatson franklywatson deleted the access-api-code-duplication branch November 7, 2024 20:10
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.

Address code duplication in tests and error handling
2 participants