From 184c614d35e74be1f412c30885d93f661bd672ee Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Sat, 9 Nov 2024 22:07:31 +0900 Subject: [PATCH 01/14] Add endpoints + testing for system transaction --- java-example/README.md | 2 ++ .../GetTransactionAccessAPIConnector.java | 20 +++++++++++++ kotlin-example/README.md | 2 ++ .../GetTransactionAccessAPIConnector.kt | 12 ++++++++ .../org/onflow/flow/sdk/AsyncFlowAccessApi.kt | 4 +++ .../org/onflow/flow/sdk/FlowAccessApi.kt | 4 +++ .../flow/sdk/impl/AsyncFlowAccessApiImpl.kt | 28 +++++++++++++++++ .../onflow/flow/sdk/impl/FlowAccessApiImpl.kt | 30 +++++++++++++++++++ .../org/onflow/flow/sdk/FlowAccessApiTest.kt | 24 +++++++++++++++ .../sdk/impl/AsyncFlowAccessApiImplTest.kt | 19 ++++++++++++ .../flow/sdk/impl/FlowAccessApiImplTest.kt | 22 ++++++++++++++ 11 files changed, 167 insertions(+) diff --git a/java-example/README.md b/java-example/README.md index f615dee..4d02fb5 100644 --- a/java-example/README.md +++ b/java-example/README.md @@ -86,7 +86,9 @@ Below is a list of all Java code examples currently supported in this repo: [Get transactions.](src/main/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnector.java) - Get transaction +- Get system transaction - Get transaction result +- Get system transaction result - Get transaction result by index #### Sending Transactions diff --git a/java-example/src/main/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnector.java b/java-example/src/main/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnector.java index e5dbf6b..3a7e468 100644 --- a/java-example/src/main/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnector.java +++ b/java-example/src/main/java/org/onflow/examples/java/getTransaction/GetTransactionAccessAPIConnector.java @@ -22,6 +22,16 @@ public FlowTransaction getTransaction(FlowId txID) { } } + public FlowTransaction getSystemTransaction(FlowId blockId) { + FlowAccessApi.AccessApiCallResponse response = accessAPI.getSystemTransaction(blockId); + if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) { + return ((FlowAccessApi.AccessApiCallResponse.Success) response).getData(); + } else { + FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response; + throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable()); + } + } + public FlowTransactionResult getTransactionResult(FlowId txID) { FlowAccessApi.AccessApiCallResponse response = accessAPI.getTransactionResultById(txID); if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) { @@ -32,6 +42,16 @@ public FlowTransactionResult getTransactionResult(FlowId txID) { } } + public FlowTransactionResult getSystemTransactionResult(FlowId blockId) { + FlowAccessApi.AccessApiCallResponse response = accessAPI.getSystemTransactionResult(blockId); + if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) { + return ((FlowAccessApi.AccessApiCallResponse.Success) response).getData(); + } else { + FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response; + throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable()); + } + } + public FlowTransactionResult getTransactionResultByIndex(FlowId blockId, Integer index) { FlowAccessApi.AccessApiCallResponse response = accessAPI.getTransactionResultByIndex(blockId, index); if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) { diff --git a/kotlin-example/README.md b/kotlin-example/README.md index a7d5436..1a26016 100644 --- a/kotlin-example/README.md +++ b/kotlin-example/README.md @@ -87,7 +87,9 @@ Below is a list of all Kotlin code examples currently supported in this repo: [Get transactions.](src/main/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnector.kt) - Get transaction +- Get system transaction - Get transaction result +- Get system transaction result - Get transaction result by index #### Sending Transactions diff --git a/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnector.kt b/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnector.kt index 6788dff..d6c059b 100644 --- a/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnector.kt +++ b/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnector.kt @@ -11,12 +11,24 @@ class GetTransactionAccessAPIConnector( is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) } + fun getSystemTransaction(blockId: FlowId): FlowTransaction = + when (val response = accessAPI.getSystemTransaction(blockId)) { + is FlowAccessApi.AccessApiCallResponse.Success -> response.data + is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) + } + fun getTransactionResult(txID: FlowId): FlowTransactionResult = when (val response = accessAPI.getTransactionResultById(txID)) { is FlowAccessApi.AccessApiCallResponse.Success -> response.data is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) } + fun getSystemTransactionResult(blockId: FlowId): FlowTransactionResult = + when (val response = accessAPI.getSystemTransactionResult(blockId)) { + is FlowAccessApi.AccessApiCallResponse.Success -> response.data + is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) + } + fun getTransactionResultByIndex(blockId: FlowId, index: Int): FlowTransactionResult = when (val response = accessAPI.getTransactionResultByIndex(blockId, index)) { is FlowAccessApi.AccessApiCallResponse.Success -> response.data diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt index 03af937..b08af06 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt @@ -40,6 +40,10 @@ interface AsyncFlowAccessApi { fun getTransactionResultById(id: FlowId): CompletableFuture> + fun getSystemTransaction(blockId: FlowId): CompletableFuture> + + fun getSystemTransactionResult(blockId: FlowId): CompletableFuture> + fun getTransactionResultByIndex(blockId: FlowId, index: Int): CompletableFuture> @Deprecated( diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt index ce8de86..5f92034 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt @@ -52,6 +52,10 @@ interface FlowAccessApi { fun getTransactionResultById(id: FlowId): AccessApiCallResponse + fun getSystemTransaction(blockId: FlowId): AccessApiCallResponse + + fun getSystemTransactionResult(blockId: FlowId): AccessApiCallResponse + fun getTransactionResultByIndex(blockId: FlowId, index: Int): AccessApiCallResponse @Deprecated( diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt index c7ff3eb..4631089 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt @@ -356,6 +356,34 @@ class AsyncFlowAccessApiImpl( errorMessage = "Failed to get transaction result by index" ) + override fun getSystemTransaction(blockId: FlowId): CompletableFuture> = + handleApiCall( + apiCall = { + api.getSystemTransaction( + Access.GetSystemTransactionRequest + .newBuilder() + .setBlockId(blockId.byteStringValue) + .build() + ) + }, + transform = { if (it.hasTransaction()) FlowTransaction.of(it.transaction) else null }, + errorMessage = "Failed to get system transaction by block ID" + ) + + override fun getSystemTransactionResult(blockId: FlowId): CompletableFuture> = + handleApiCall( + apiCall = { + api.getSystemTransactionResult( + Access.GetSystemTransactionResultRequest + .newBuilder() + .setBlockId(blockId.byteStringValue) + .build() + ) + }, + transform = { FlowTransactionResult.of(it) }, + errorMessage = "Failed to get system transaction result by block ID" + ) + private fun executeScript( apiCall: () -> ListenableFuture, errorMessage: String diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt index 6f8fd2b..aaaf02b 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt @@ -303,6 +303,36 @@ class FlowAccessApiImpl( FlowAccessApi.AccessApiCallResponse.Error("Failed to get transaction result by index", e) } + override fun getSystemTransaction(blockId: FlowId): FlowAccessApi.AccessApiCallResponse = + try { + val ret = api.getSystemTransaction( + Access.GetSystemTransactionRequest + .newBuilder() + .setBlockId(blockId.byteStringValue) + .build() + ) + if (ret.hasTransaction()) { + FlowAccessApi.AccessApiCallResponse.Success(FlowTransaction.of(ret.transaction)) + } else { + FlowAccessApi.AccessApiCallResponse.Error("System transaction not found") + } + } catch (e: Exception) { + FlowAccessApi.AccessApiCallResponse.Error("Failed to get system transaction by block ID", e) + } + + override fun getSystemTransactionResult(blockId: FlowId): FlowAccessApi.AccessApiCallResponse = + try { + val ret = api.getSystemTransactionResult( + Access.GetSystemTransactionResultRequest + .newBuilder() + .setBlockId(blockId.byteStringValue) + .build() + ) + FlowAccessApi.AccessApiCallResponse.Success(FlowTransactionResult.of(ret)) + } catch (e: Exception) { + FlowAccessApi.AccessApiCallResponse.Error("Failed to get system transaction result by block ID", e) + } + @Deprecated("Behaves identically to getAccountAtLatestBlock", replaceWith = ReplaceWith("getAccountAtLatestBlock")) override fun getAccountByAddress(addresss: FlowAddress): FlowAccessApi.AccessApiCallResponse = try { diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt index 422b1b2..54e348c 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt @@ -278,6 +278,30 @@ class FlowAccessApiTest { assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult), result) } + @Test + fun `Test getSystemTransaction`() { + val flowAccessApi = mock(FlowAccessApi::class.java) + val flowId = FlowId("01") + val flowTransaction = FlowTransaction.of(TransactionOuterClass.Transaction.getDefaultInstance()) + `when`(flowAccessApi.getSystemTransaction(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransaction)) + + val result = flowAccessApi.getSystemTransaction(flowId) + + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowTransaction), result) + } + + @Test + fun `Test getSystemTransactionResult`() { + val flowAccessApi = mock(FlowAccessApi::class.java) + val flowId = FlowId("01") + val flowTransactionResult = FlowTransactionResult.of(Access.TransactionResultResponse.getDefaultInstance()) + `when`(flowAccessApi.getSystemTransactionResult(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult)) + + val result = flowAccessApi.getSystemTransactionResult(flowId) + + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult), result) + } + @Test fun `Test getTransactionResultByIndex`() { val flowAccessApi = mock(FlowAccessApi::class.java) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt index dd87bbb..c3b9a1b 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt @@ -456,6 +456,25 @@ class AsyncFlowAccessApiImplTest { assertSuccess(result, flowTransactionResult) } + @Test + fun `test getSystemTransaction`() { + val flowTransaction = FlowTransaction(FlowScript("script"), emptyList(), flowId, 123L, FlowTransactionProposalKey(FlowAddress("02"), 1, 123L), FlowAddress("02"), emptyList()) + `when`(api.getSystemTransaction(any())).thenReturn(setupFutureMock(MockResponseFactory.transactionResponse(flowTransaction))) + + val result = asyncFlowAccessApi.getSystemTransaction(flowId).get() + assertSuccess(result, flowTransaction) + } + + @Test + fun `test getSystemTransactionResult`() { + val flowTransactionResult = FlowTransactionResult(FlowTransactionStatus.SEALED, 1, "message", emptyList(), flowId, HEIGHT, flowId, flowId, 1L) + + `when`(api.getSystemTransactionResult(any())).thenReturn(setupFutureMock(MockResponseFactory.transactionResultResponse())) + + val result = asyncFlowAccessApi.getSystemTransactionResult(flowId).get() + assertSuccess(result, flowTransactionResult) + } + @Test fun `test getTransactionResultByIndex success`() { val index = 0 diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt index 577c300..e360142 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt @@ -382,6 +382,28 @@ class FlowAccessApiImplTest { assertResultSuccess(result) { assertEquals(flowTransactionResult, it) } } + @Test + fun `Test getSystemTransaction`() { + val flowId = FlowId("01") + val flowTransaction = createMockTransaction(flowId) + + `when`(mockApi.getSystemTransaction(any())).thenReturn(AsyncFlowAccessApiImplTest.MockResponseFactory.transactionResponse(flowTransaction)) + + val result = flowAccessApiImpl.getSystemTransaction(flowId) + assertResultSuccess(result) { assertEquals(flowTransaction, it) } + } + + @Test + fun `Test getSystemTransactionResult`() { + val flowId = FlowId.of("id".toByteArray()) + val flowTransactionResult = FlowTransactionResult(FlowTransactionStatus.SEALED, 1, "message", emptyList(), flowId, 1L, flowId, flowId, 1L) + + `when`(mockApi.getSystemTransactionResult(any())).thenReturn(mockTransactionResponse) + + val result = flowAccessApiImpl.getSystemTransactionResult(flowId) + assertResultSuccess(result) { assertEquals(flowTransactionResult, it) } + } + @Test fun `Test getTransactionResultByIndex`() { val index = 0 From 2d02e32550f9809fcc73897ee7260d1f32bbd9a7 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Sat, 9 Nov 2024 22:43:01 +0900 Subject: [PATCH 02/14] Code rabbit changes --- .../flow/sdk/impl/AsyncFlowAccessApiImplTest.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt index c3b9a1b..4a5d6bd 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt @@ -465,6 +465,14 @@ class AsyncFlowAccessApiImplTest { assertSuccess(result, flowTransaction) } + @Test + fun `test getSystemTransaction failure`() { + `when`(api.getSystemTransaction(any())).thenThrow(testException) + + val result = asyncFlowAccessApi.getSystemTransaction(flowId).get() + assertFailure(result, "Failed to get system transaction by block ID", testException) + } + @Test fun `test getSystemTransactionResult`() { val flowTransactionResult = FlowTransactionResult(FlowTransactionStatus.SEALED, 1, "message", emptyList(), flowId, HEIGHT, flowId, flowId, 1L) @@ -475,6 +483,14 @@ class AsyncFlowAccessApiImplTest { assertSuccess(result, flowTransactionResult) } + @Test + fun `test getSystemTransactionResult failure`() { + `when`(api.getSystemTransactionResult(any())).thenThrow(testException) + + val result = asyncFlowAccessApi.getSystemTransactionResult(flowId).get() + assertFailure(result, "Failed to get system transaction result by block ID", testException) + } + @Test fun `test getTransactionResultByIndex success`() { val index = 0 From 9f2b5f5eb324ab4e5539b8e757f9fba8f9f7a7a1 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Mon, 11 Nov 2024 19:51:28 +0900 Subject: [PATCH 03/14] Refactoring subscription methods --- .../onflow/flow/sdk/impl/FlowAccessApiImpl.kt | 133 +++++++----------- 1 file changed, 52 insertions(+), 81 deletions(-) diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt index aaaf02b..07d2295 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt @@ -572,24 +572,22 @@ class FlowAccessApiImpl( FlowAccessApi.AccessApiCallResponse.Error("Failed to get execution result by block ID", e) } - override fun subscribeExecutionDataByBlockId( + private fun subscribeGeneric( scope: CoroutineScope, - blockId: FlowId - ): Triple, ReceiveChannel, Job> { - val responseChannel = Channel(Channel.UNLIMITED) + requestBuilder: () -> T, + responseHandler: (T) -> Iterator, + responseMapper: (R) -> M + ): Triple, ReceiveChannel, Job> { + val responseChannel = Channel(Channel.UNLIMITED) val errorChannel = Channel(Channel.UNLIMITED) val job = scope.launch { try { - val request = Executiondata.SubscribeExecutionDataFromStartBlockIDRequest - .newBuilder() - .setStartBlockId(blockId.byteStringValue) - .build() - - val responseIterator = executionDataApi.subscribeExecutionDataFromStartBlockID(request) + val request = requestBuilder() + val responseIterator = responseHandler(request) for (response in responseIterator) { - responseChannel.send(FlowBlockExecutionData.of(response.blockExecutionData)) + responseChannel.send(responseMapper(response)) } } catch (e: Exception) { errorChannel.send(e) @@ -598,97 +596,70 @@ class FlowAccessApiImpl( errorChannel.close() } } - return Triple(responseChannel, errorChannel, job) } + override fun subscribeExecutionDataByBlockId( + scope: CoroutineScope, + blockId: FlowId + ): Triple, ReceiveChannel, Job> = + subscribeGeneric( + scope, + requestBuilder = { + Executiondata.SubscribeExecutionDataFromStartBlockIDRequest + .newBuilder() + .setStartBlockId(blockId.byteStringValue) + .build() + }, + responseHandler = { executionDataApi.subscribeExecutionDataFromStartBlockID(it) }, + responseMapper = { FlowBlockExecutionData.of(it.blockExecutionData) } + ) + override fun subscribeExecutionDataByBlockHeight( scope: CoroutineScope, height: Long - ): Triple, ReceiveChannel, Job> { - val responseChannel = Channel(Channel.UNLIMITED) - val errorChannel = Channel(Channel.UNLIMITED) - - val job = scope.launch { - try { - val request = Executiondata.SubscribeExecutionDataFromStartBlockHeightRequest + ): Triple, ReceiveChannel, Job> = + subscribeGeneric( + scope, + requestBuilder = { + Executiondata.SubscribeExecutionDataFromStartBlockHeightRequest .newBuilder() .setStartBlockHeight(height) .build() - - val responseIterator = executionDataApi.subscribeExecutionDataFromStartBlockHeight(request) - - for (response in responseIterator) { - responseChannel.send(FlowBlockExecutionData.of(response.blockExecutionData)) - } - } catch (e: Exception) { - errorChannel.send(e) - } finally { - responseChannel.close() - errorChannel.close() - } - } - - return Triple(responseChannel, errorChannel, job) - } + }, + responseHandler = { executionDataApi.subscribeExecutionDataFromStartBlockHeight(it) }, + responseMapper = { FlowBlockExecutionData.of(it.blockExecutionData) } + ) override fun subscribeEventsByBlockId( scope: CoroutineScope, blockId: FlowId - ): Triple>, ReceiveChannel, Job> { - val responseChannel = Channel>(Channel.UNLIMITED) - val errorChannel = Channel(Channel.UNLIMITED) - - val job = scope.launch { - try { - val request = Executiondata.SubscribeEventsFromStartBlockIDRequest + ): Triple>, ReceiveChannel, Job> = + subscribeGeneric( + scope, + requestBuilder = { + Executiondata.SubscribeEventsFromStartBlockIDRequest .newBuilder() .setStartBlockId(blockId.byteStringValue) .build() - - val responseIterator = executionDataApi.subscribeEventsFromStartBlockID(request) - - for (response in responseIterator) { - responseChannel.send(response.eventsList.map { FlowEvent.of(it) }) - } - } catch (e: Exception) { - errorChannel.send(e) - } finally { - responseChannel.close() - errorChannel.close() - } - } - - return Triple(responseChannel, errorChannel, job) - } + }, + responseHandler = { executionDataApi.subscribeEventsFromStartBlockID(it) }, + responseMapper = { it.eventsList.map { event -> FlowEvent.of(event) } } + ) override fun subscribeEventsByBlockHeight( scope: CoroutineScope, height: Long - ): Triple>, ReceiveChannel, Job> { - val responseChannel = Channel>(Channel.UNLIMITED) - val errorChannel = Channel(Channel.UNLIMITED) - - val job = scope.launch { - try { - val request = Executiondata.SubscribeEventsFromStartHeightRequest + ): Triple>, ReceiveChannel, Job> = + subscribeGeneric( + scope, + requestBuilder = { + Executiondata.SubscribeEventsFromStartHeightRequest .newBuilder() .setStartBlockHeight(height) .build() - - val responseIterator = executionDataApi.subscribeEventsFromStartHeight(request) - - for (response in responseIterator) { - responseChannel.send(response.eventsList.map { FlowEvent.of(it) }) - } - } catch (e: Exception) { - errorChannel.send(e) - } finally { - responseChannel.close() - errorChannel.close() - } - } - - return Triple(responseChannel, errorChannel, job) - } + }, + responseHandler = { executionDataApi.subscribeEventsFromStartHeight(it) }, + responseMapper = { it.eventsList.map { event -> FlowEvent.of(event) } } + ) } From 9625eefeb1ef699c5d28bb8e1ead522d3067e568 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 12 Nov 2024 02:26:39 +0900 Subject: [PATCH 04/14] Refactor access API methods --- .../onflow/flow/sdk/impl/FlowAccessApiImpl.kt | 624 +++++++++--------- 1 file changed, 309 insertions(+), 315 deletions(-) diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt index 07d2295..2131ad2 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt @@ -24,367 +24,361 @@ class FlowAccessApiImpl( } } - override fun ping(): FlowAccessApi.AccessApiCallResponse = - try { - api.ping( - Access.PingRequest - .newBuilder() - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(Unit) + private fun executeWithResponse(action: () -> T, errorMessage: String): FlowAccessApi.AccessApiCallResponse { + return try { + FlowAccessApi.AccessApiCallResponse.Success(action()) } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to ping", e) + FlowAccessApi.AccessApiCallResponse.Error(errorMessage, e) } + } + + override fun ping(): FlowAccessApi.AccessApiCallResponse = + executeWithResponse( + action = { + api.ping( + Access.PingRequest.newBuilder().build() + ) + Unit + }, + errorMessage = "Failed to ping" + ) override fun getAccountKeyAtLatestBlock(address: FlowAddress, keyIndex: Int): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getAccountKeyAtLatestBlock( - Access.GetAccountKeyAtLatestBlockRequest - .newBuilder() - .setAddress(address.byteStringValue) - .setIndex(keyIndex) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(FlowAccountKey.of(ret.accountKey)) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key at latest block", e) - } + executeWithResponse( + action = { + val ret = api.getAccountKeyAtLatestBlock( + Access.GetAccountKeyAtLatestBlockRequest + .newBuilder() + .setAddress(address.byteStringValue) + .setIndex(keyIndex) + .build() + ) + FlowAccountKey.of(ret.accountKey) + }, + errorMessage = "Failed to get account key at latest block" + ) override fun getAccountKeyAtBlockHeight(address: FlowAddress, keyIndex: Int, height: Long): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getAccountKeyAtBlockHeight( - Access.GetAccountKeyAtBlockHeightRequest - .newBuilder() - .setAddress(address.byteStringValue) - .setIndex(keyIndex) - .setBlockHeight(height) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(FlowAccountKey.of(ret.accountKey)) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get account key at block height", e) - } + executeWithResponse( + action = { + val ret = api.getAccountKeyAtBlockHeight( + Access.GetAccountKeyAtBlockHeightRequest + .newBuilder() + .setAddress(address.byteStringValue) + .setIndex(keyIndex) + .setBlockHeight(height) + .build() + ) + FlowAccountKey.of(ret.accountKey) + }, + errorMessage = "Failed to get account key at block height" + ) override fun getAccountKeysAtLatestBlock(address: FlowAddress): FlowAccessApi.AccessApiCallResponse> = - try { - val ret = api.getAccountKeysAtLatestBlock( - Access.GetAccountKeysAtLatestBlockRequest - .newBuilder() - .setAddress(address.byteStringValue) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(ret.accountKeysList.map { FlowAccountKey.of(it) }) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get account keys at latest block", e) - } + executeWithResponse( + action = { + val ret = api.getAccountKeysAtLatestBlock( + Access.GetAccountKeysAtLatestBlockRequest + .newBuilder() + .setAddress(address.byteStringValue) + .build() + ) + ret.accountKeysList.map { FlowAccountKey.of(it) } + }, + errorMessage = "Failed to get account keys at latest block" + ) override fun getAccountKeysAtBlockHeight(address: FlowAddress, height: Long): FlowAccessApi.AccessApiCallResponse> = - try { - val ret = api.getAccountKeysAtBlockHeight( - Access.GetAccountKeysAtBlockHeightRequest - .newBuilder() - .setAddress(address.byteStringValue) - .setBlockHeight(height) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(ret.accountKeysList.map { FlowAccountKey.of(it) }) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get account keys at block height", e) - } + executeWithResponse( + action = { + val ret = api.getAccountKeysAtBlockHeight( + Access.GetAccountKeysAtBlockHeightRequest + .newBuilder() + .setAddress(address.byteStringValue) + .setBlockHeight(height) + .build() + ) + ret.accountKeysList.map { FlowAccountKey.of(it) } + }, + errorMessage = "Failed to get account keys at block height" + ) override fun getLatestBlockHeader(sealed: Boolean): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getLatestBlockHeader( - Access.GetLatestBlockHeaderRequest - .newBuilder() - .setIsSealed(sealed) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(FlowBlockHeader.of(ret.block)) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get latest block header", e) - } + executeWithResponse( + action = { + val ret = api.getLatestBlockHeader( + Access.GetLatestBlockHeaderRequest + .newBuilder() + .setIsSealed(sealed) + .build() + ) + FlowBlockHeader.of(ret.block) + }, + errorMessage = "Failed to get latest block header" + ) override fun getBlockHeaderById(id: FlowId): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getBlockHeaderByID( - Access.GetBlockHeaderByIDRequest - .newBuilder() - .setId(id.byteStringValue) - .build() - ) - if (ret.hasBlock()) { - FlowAccessApi.AccessApiCallResponse.Success(FlowBlockHeader.of(ret.block)) - } else { - FlowAccessApi.AccessApiCallResponse.Error("Block header not found") - } - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get block header by ID", e) - } + executeWithResponse( + action = { + val ret = api.getBlockHeaderByID( + Access.GetBlockHeaderByIDRequest + .newBuilder() + .setId(id.byteStringValue) + .build() + ) + if (ret.hasBlock()) FlowBlockHeader.of(ret.block) else throw Exception("Block header not found") + }, + errorMessage = "Failed to get block header by ID" + ) override fun getBlockHeaderByHeight(height: Long): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getBlockHeaderByHeight( - Access.GetBlockHeaderByHeightRequest - .newBuilder() - .setHeight(height) - .build() - ) - if (ret.hasBlock()) { - FlowAccessApi.AccessApiCallResponse.Success(FlowBlockHeader.of(ret.block)) - } else { - FlowAccessApi.AccessApiCallResponse.Error("Block header not found") - } - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get block header by height", e) - } + executeWithResponse( + action = { + val ret = api.getBlockHeaderByHeight( + Access.GetBlockHeaderByHeightRequest + .newBuilder() + .setHeight(height) + .build() + ) + if (ret.hasBlock()) FlowBlockHeader.of(ret.block) else throw Exception("Block header not found") + }, + errorMessage = "Failed to get block header by height" + ) + override fun getLatestBlock(sealed: Boolean, fullBlockResponse: Boolean): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getLatestBlock( - Access.GetLatestBlockRequest - .newBuilder() - .setIsSealed(sealed) - .setFullBlockResponse(fullBlockResponse) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(FlowBlock.of(ret.block)) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get latest block", e) - } + executeWithResponse( + action = { + val ret = api.getLatestBlock( + Access.GetLatestBlockRequest + .newBuilder() + .setIsSealed(sealed) + .setFullBlockResponse(fullBlockResponse) + .build() + ) + FlowBlock.of(ret.block) + }, + errorMessage = "Failed to get latest block" + ) override fun getAccountBalanceAtLatestBlock(address: FlowAddress): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getAccountBalanceAtLatestBlock( - Access.GetAccountBalanceAtLatestBlockRequest - .newBuilder() - .setAddress(address.byteStringValue) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(ret.balance) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at latest block", e) - } + executeWithResponse( + action = { + val ret = api.getAccountBalanceAtLatestBlock( + Access.GetAccountBalanceAtLatestBlockRequest + .newBuilder() + .setAddress(address.byteStringValue) + .build() + ) + ret.balance + }, + errorMessage = "Failed to get account balance at latest block" + ) override fun getAccountBalanceAtBlockHeight(address: FlowAddress, height: Long): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getAccountBalanceAtBlockHeight( - Access.GetAccountBalanceAtBlockHeightRequest - .newBuilder() - .setAddress(address.byteStringValue) - .setBlockHeight(height) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(ret.balance) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at block height", e) - } + executeWithResponse( + action = { + val ret = api.getAccountBalanceAtBlockHeight( + Access.GetAccountBalanceAtBlockHeightRequest + .newBuilder() + .setAddress(address.byteStringValue) + .setBlockHeight(height) + .build() + ) + ret.balance + }, + errorMessage = "Failed to get account balance at block height" + ) + override fun getBlockById(id: FlowId, fullBlockResponse: Boolean): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getBlockByID( - Access.GetBlockByIDRequest - .newBuilder() - .setId(id.byteStringValue) - .setFullBlockResponse(fullBlockResponse) - .build() - ) - if (ret.hasBlock()) { - FlowAccessApi.AccessApiCallResponse.Success(FlowBlock.of(ret.block)) - } else { - FlowAccessApi.AccessApiCallResponse.Error("Block not found") - } - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get block by ID", e) - } + executeWithResponse( + action = { + val ret = api.getBlockByID( + Access.GetBlockByIDRequest + .newBuilder() + .setId(id.byteStringValue) + .setFullBlockResponse(fullBlockResponse) + .build() + ) + if (ret.hasBlock()) FlowBlock.of(ret.block) else throw Exception("Block not found") + }, + errorMessage = "Failed to get block by ID" + ) override fun getBlockByHeight(height: Long, fullBlockResponse: Boolean): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getBlockByHeight( - Access.GetBlockByHeightRequest - .newBuilder() - .setHeight(height) - .setFullBlockResponse(fullBlockResponse) - .build() - ) - if (ret.hasBlock()) { - FlowAccessApi.AccessApiCallResponse.Success(FlowBlock.of(ret.block)) - } else { - FlowAccessApi.AccessApiCallResponse.Error("Block not found") - } - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get block by height", e) - } + executeWithResponse( + action = { + val ret = api.getBlockByHeight( + Access.GetBlockByHeightRequest + .newBuilder() + .setHeight(height) + .setFullBlockResponse(fullBlockResponse) + .build() + ) + if (ret.hasBlock()) FlowBlock.of(ret.block) else throw Exception("Block not found") + }, + errorMessage = "Failed to get block by height" + ) override fun getCollectionById(id: FlowId): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getCollectionByID( - Access.GetCollectionByIDRequest - .newBuilder() - .setId(id.byteStringValue) - .build() - ) - if (ret.hasCollection()) { - FlowAccessApi.AccessApiCallResponse.Success(FlowCollection.of(ret.collection)) - } else { - FlowAccessApi.AccessApiCallResponse.Error("Collection not found") - } - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get collection by ID", e) - } + executeWithResponse( + action = { + val ret = api.getCollectionByID( + Access.GetCollectionByIDRequest + .newBuilder() + .setId(id.byteStringValue) + .build() + ) + if (ret.hasCollection()) FlowCollection.of(ret.collection) else throw Exception("Collection not found") + }, + errorMessage = "Failed to get collection by ID" + ) override fun getFullCollectionById(id: FlowId): FlowAccessApi.AccessApiCallResponse> = - try { - val ret = api.getFullCollectionByID( - Access.GetFullCollectionByIDRequest - .newBuilder() - .setId(id.byteStringValue) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(ret.transactionsList.map { FlowTransaction.of(it) }) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get full collection by ID", e) - } + executeWithResponse( + action = { + val ret = api.getFullCollectionByID( + Access.GetFullCollectionByIDRequest + .newBuilder() + .setId(id.byteStringValue) + .build() + ) + ret.transactionsList.map { FlowTransaction.of(it) } + }, + errorMessage = "Failed to get full collection by ID" + ) override fun sendTransaction(transaction: FlowTransaction): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.sendTransaction( - Access.SendTransactionRequest - .newBuilder() - .setTransaction(transaction.builder().build()) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(FlowId.of(ret.id.toByteArray())) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to send transaction", e) - } + executeWithResponse( + action = { + val ret = api.sendTransaction( + Access.SendTransactionRequest + .newBuilder() + .setTransaction(transaction.builder().build()) + .build() + ) + FlowId.of(ret.id.toByteArray()) + }, + errorMessage = "Failed to send transaction" + ) override fun getTransactionById(id: FlowId): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getTransaction( - Access.GetTransactionRequest - .newBuilder() - .setId(id.byteStringValue) - .build() - ) - if (ret.hasTransaction()) { - FlowAccessApi.AccessApiCallResponse.Success(FlowTransaction.of(ret.transaction)) - } else { - FlowAccessApi.AccessApiCallResponse.Error("Transaction not found") - } - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get transaction by ID", e) - } + executeWithResponse( + action = { + val ret = api.getTransaction( + Access.GetTransactionRequest + .newBuilder() + .setId(id.byteStringValue) + .build() + ) + if (ret.hasTransaction()) FlowTransaction.of(ret.transaction) else throw Exception("Transaction not found") + }, + errorMessage = "Failed to get transaction by ID" + ) + override fun getTransactionResultById(id: FlowId): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getTransactionResult( - Access.GetTransactionRequest - .newBuilder() - .setId(id.byteStringValue) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(FlowTransactionResult.of(ret)) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get transaction result by ID", e) - } + executeWithResponse( + action = { + val ret = api.getTransactionResult( + Access.GetTransactionRequest + .newBuilder() + .setId(id.byteStringValue) + .build() + ) + FlowTransactionResult.of(ret) + }, + errorMessage = "Failed to get transaction result by ID" + ) override fun getTransactionResultByIndex(blockId: FlowId, index: Int): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getTransactionResultByIndex( - Access.GetTransactionByIndexRequest - .newBuilder() - .setBlockId(blockId.byteStringValue) - .setIndex(index) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(FlowTransactionResult.of(ret)) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get transaction result by index", e) - } + executeWithResponse( + action = { + val ret = api.getTransactionResultByIndex( + Access.GetTransactionByIndexRequest + .newBuilder() + .setBlockId(blockId.byteStringValue) + .setIndex(index) + .build() + ) + FlowTransactionResult.of(ret) + }, + errorMessage = "Failed to get transaction result by index" + ) override fun getSystemTransaction(blockId: FlowId): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getSystemTransaction( - Access.GetSystemTransactionRequest - .newBuilder() - .setBlockId(blockId.byteStringValue) - .build() - ) - if (ret.hasTransaction()) { - FlowAccessApi.AccessApiCallResponse.Success(FlowTransaction.of(ret.transaction)) - } else { - FlowAccessApi.AccessApiCallResponse.Error("System transaction not found") - } - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get system transaction by block ID", e) - } + executeWithResponse( + action = { + val ret = api.getSystemTransaction( + Access.GetSystemTransactionRequest + .newBuilder() + .setBlockId(blockId.byteStringValue) + .build() + ) + if (ret.hasTransaction()) FlowTransaction.of(ret.transaction) else throw Exception("System transaction not found") + }, + errorMessage = "Failed to get system transaction by block ID" + ) override fun getSystemTransactionResult(blockId: FlowId): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getSystemTransactionResult( - Access.GetSystemTransactionResultRequest - .newBuilder() - .setBlockId(blockId.byteStringValue) - .build() - ) - FlowAccessApi.AccessApiCallResponse.Success(FlowTransactionResult.of(ret)) - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get system transaction result by block ID", e) - } + executeWithResponse( + action = { + val ret = api.getSystemTransactionResult( + Access.GetSystemTransactionResultRequest + .newBuilder() + .setBlockId(blockId.byteStringValue) + .build() + ) + FlowTransactionResult.of(ret) + }, + errorMessage = "Failed to get system transaction result by block ID" + ) + @Deprecated("Behaves identically to getAccountAtLatestBlock", replaceWith = ReplaceWith("getAccountAtLatestBlock")) - override fun getAccountByAddress(addresss: FlowAddress): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getAccount( - Access.GetAccountRequest - .newBuilder() - .setAddress(addresss.byteStringValue) - .build() - ) - if (ret.hasAccount()) { - FlowAccessApi.AccessApiCallResponse.Success(FlowAccount.of(ret.account)) - } else { - FlowAccessApi.AccessApiCallResponse.Error("Account not found") - } - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get account by address", e) - } + override fun getAccountByAddress(address: FlowAddress): FlowAccessApi.AccessApiCallResponse = + executeWithResponse( + action = { + val ret = api.getAccount( + Access.GetAccountRequest + .newBuilder() + .setAddress(address.byteStringValue) + .build() + ) + if (ret.hasAccount()) FlowAccount.of(ret.account) else throw Exception("Account not found") + }, + errorMessage = "Failed to get account by address" + ) - override fun getAccountAtLatestBlock(addresss: FlowAddress): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getAccountAtLatestBlock( - Access.GetAccountAtLatestBlockRequest - .newBuilder() - .setAddress(addresss.byteStringValue) - .build() - ) - if (ret.hasAccount()) { - FlowAccessApi.AccessApiCallResponse.Success(FlowAccount.of(ret.account)) - } else { - FlowAccessApi.AccessApiCallResponse.Error("Account not found") - } - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get account at latest block", e) - } + override fun getAccountAtLatestBlock(address: FlowAddress): FlowAccessApi.AccessApiCallResponse = + executeWithResponse( + action = { + val ret = api.getAccountAtLatestBlock( + Access.GetAccountAtLatestBlockRequest + .newBuilder() + .setAddress(address.byteStringValue) + .build() + ) + if (ret.hasAccount()) FlowAccount.of(ret.account) else throw Exception("Account not found") + }, + errorMessage = "Failed to get account at latest block" + ) - override fun getAccountByBlockHeight(addresss: FlowAddress, height: Long): FlowAccessApi.AccessApiCallResponse = - try { - val ret = api.getAccountAtBlockHeight( - Access.GetAccountAtBlockHeightRequest - .newBuilder() - .setAddress(addresss.byteStringValue) - .setBlockHeight(height) - .build() - ) - if (ret.hasAccount()) { - FlowAccessApi.AccessApiCallResponse.Success(FlowAccount.of(ret.account)) - } else { - FlowAccessApi.AccessApiCallResponse.Error("Account not found") - } - } catch (e: Exception) { - FlowAccessApi.AccessApiCallResponse.Error("Failed to get account by block height", e) - } + override fun getAccountByBlockHeight(address: FlowAddress, height: Long): FlowAccessApi.AccessApiCallResponse = + executeWithResponse( + action = { + val ret = api.getAccountAtBlockHeight( + Access.GetAccountAtBlockHeightRequest + .newBuilder() + .setAddress(address.byteStringValue) + .setBlockHeight(height) + .build() + ) + if (ret.hasAccount()) FlowAccount.of(ret.account) else throw Exception("Account not found") + }, + errorMessage = "Failed to get account by block height" + ) override fun executeScriptAtLatestBlock(script: FlowScript, arguments: Iterable): FlowAccessApi.AccessApiCallResponse = try { From cf7a14c1285194c47f84e2e4703d558588817163 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 12 Nov 2024 02:39:10 +0900 Subject: [PATCH 05/14] Lint --- .../kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt index 2131ad2..2cfa508 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt @@ -24,13 +24,12 @@ class FlowAccessApiImpl( } } - private fun executeWithResponse(action: () -> T, errorMessage: String): FlowAccessApi.AccessApiCallResponse { - return try { + private fun executeWithResponse(action: () -> T, errorMessage: String): FlowAccessApi.AccessApiCallResponse = + try { FlowAccessApi.AccessApiCallResponse.Success(action()) } catch (e: Exception) { FlowAccessApi.AccessApiCallResponse.Error(errorMessage, e) } - } override fun ping(): FlowAccessApi.AccessApiCallResponse = executeWithResponse( @@ -145,7 +144,6 @@ class FlowAccessApiImpl( errorMessage = "Failed to get block header by height" ) - override fun getLatestBlock(sealed: Boolean, fullBlockResponse: Boolean): FlowAccessApi.AccessApiCallResponse = executeWithResponse( action = { @@ -190,7 +188,6 @@ class FlowAccessApiImpl( errorMessage = "Failed to get account balance at block height" ) - override fun getBlockById(id: FlowId, fullBlockResponse: Boolean): FlowAccessApi.AccessApiCallResponse = executeWithResponse( action = { @@ -277,7 +274,6 @@ class FlowAccessApiImpl( errorMessage = "Failed to get transaction by ID" ) - override fun getTransactionResultById(id: FlowId): FlowAccessApi.AccessApiCallResponse = executeWithResponse( action = { @@ -335,7 +331,6 @@ class FlowAccessApiImpl( errorMessage = "Failed to get system transaction result by block ID" ) - @Deprecated("Behaves identically to getAccountAtLatestBlock", replaceWith = ReplaceWith("getAccountAtLatestBlock")) override fun getAccountByAddress(address: FlowAddress): FlowAccessApi.AccessApiCallResponse = executeWithResponse( From 5499b03f5edc6f950e2c0665ff045b76ca6a1c8e Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 12 Nov 2024 03:19:49 +0900 Subject: [PATCH 06/14] Further refactoring --- .../org/onflow/flow/sdk/FlowAccessApiTest.kt | 250 ++++++------------ 1 file changed, 82 insertions(+), 168 deletions(-) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt index 54e348c..159a9fb 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt @@ -1,227 +1,188 @@ package org.onflow.flow.sdk import com.google.protobuf.ByteString +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.consumeEach import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.Mockito.* import org.onflow.flow.sdk.impl.AsyncFlowAccessApiImplTest.Companion.HEIGHT import org.onflow.flow.sdk.impl.AsyncFlowAccessApiImplTest.Companion.blockId +import org.onflow.flow.sdk.impl.AsyncFlowAccessApiImplTest.Companion.mockAccountKey +import org.onflow.flow.sdk.impl.AsyncFlowAccessApiImplTest.Companion.mockAccountKeys +import org.onflow.flow.sdk.impl.AsyncFlowAccessApiImplTest.Companion.mockBlock +import org.onflow.flow.sdk.impl.AsyncFlowAccessApiImplTest.Companion.mockBlockHeader +import org.onflow.flow.sdk.impl.AsyncFlowAccessApiImplTest.Companion.testException +import org.onflow.flow.sdk.impl.FlowAccessApiImplTest.Companion.createMockAccount +import org.onflow.flow.sdk.impl.FlowAccessApiImplTest.Companion.createMockTransaction import org.onflow.protobuf.access.Access -import org.onflow.protobuf.entities.AccountOuterClass import org.onflow.protobuf.entities.BlockExecutionDataOuterClass -import org.onflow.protobuf.entities.BlockHeaderOuterClass -import org.onflow.protobuf.entities.BlockOuterClass import org.onflow.protobuf.entities.EventOuterClass -import org.onflow.protobuf.entities.TransactionOuterClass class FlowAccessApiTest { + private lateinit var flowAccessApi: FlowAccessApi + private val address = FlowAddress("01") + private val keyIndex = 0 + private val height = HEIGHT + private val expectedBalance = 1000L + private val account = createMockAccount(address) + private val transaction = createMockTransaction() + + @BeforeEach + fun setUp() { + flowAccessApi = mock(FlowAccessApi::class.java) + } + @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)) + `when`(flowAccessApi.getAccountKeyAtLatestBlock(address, keyIndex)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(mockAccountKey)) val result = flowAccessApi.getAccountKeyAtLatestBlock(address, keyIndex) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(accountKey), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(mockAccountKey), 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)) + `when`(flowAccessApi.getAccountKeyAtBlockHeight(address, keyIndex, height)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(mockAccountKey)) val result = flowAccessApi.getAccountKeyAtBlockHeight(address, keyIndex, height) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(accountKey), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(mockAccountKey), 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)) + `when`(flowAccessApi.getAccountKeysAtLatestBlock(address)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(mockAccountKeys)) val result = flowAccessApi.getAccountKeysAtLatestBlock(address) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(accountKeys), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(mockAccountKeys), 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)) + `when`(flowAccessApi.getAccountKeysAtBlockHeight(address, height)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(mockAccountKeys)) val result = flowAccessApi.getAccountKeysAtBlockHeight(address, height) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(accountKeys), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(mockAccountKeys), result) verify(flowAccessApi).getAccountKeysAtBlockHeight(address, height) } @Test fun `Test getLatestBlockHeader`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val latestBlockHeader = FlowBlockHeader.of(BlockHeaderOuterClass.BlockHeader.getDefaultInstance()) - `when`(flowAccessApi.getLatestBlockHeader(true)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(latestBlockHeader)) + `when`(flowAccessApi.getLatestBlockHeader(true)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(mockBlockHeader)) val result = flowAccessApi.getLatestBlockHeader() - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(latestBlockHeader), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(mockBlockHeader), result) } @Test fun `Test getBlockHeaderById`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val blockId = FlowId("01") - val blockHeader = FlowBlockHeader.of(BlockHeaderOuterClass.BlockHeader.getDefaultInstance()) - `when`(flowAccessApi.getBlockHeaderById(blockId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(blockHeader)) + `when`(flowAccessApi.getBlockHeaderById(blockId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(mockBlockHeader)) val result = flowAccessApi.getBlockHeaderById(blockId) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(blockHeader), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(mockBlockHeader), result) } @Test fun `Test getBlockHeaderByHeight`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val height = 123L - val blockHeader = FlowBlockHeader.of(BlockHeaderOuterClass.BlockHeader.getDefaultInstance()) - `when`(flowAccessApi.getBlockHeaderByHeight(height)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(blockHeader)) + `when`(flowAccessApi.getBlockHeaderByHeight(height)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(mockBlockHeader)) val result = flowAccessApi.getBlockHeaderByHeight(height) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(blockHeader), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(mockBlockHeader), result) } @Test fun `Test getLatestBlock`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val latestBlock = FlowBlock.of(BlockOuterClass.Block.getDefaultInstance()) - `when`(flowAccessApi.getLatestBlock(true)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(latestBlock)) + `when`(flowAccessApi.getLatestBlock(true)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(mockBlock)) val result = flowAccessApi.getLatestBlock() - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(latestBlock), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(mockBlock), result) } @Test fun `Test getBlockById`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val blockId = FlowId("01") - val block = FlowBlock.of(BlockOuterClass.Block.getDefaultInstance()) - `when`(flowAccessApi.getBlockById(blockId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(block)) + `when`(flowAccessApi.getBlockById(blockId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(mockBlock)) val result = flowAccessApi.getBlockById(blockId) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(block), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(mockBlock), result) } @Test fun `Test getBlockByHeight`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val height = 123L - val block = FlowBlock.of(BlockOuterClass.Block.getDefaultInstance()) - `when`(flowAccessApi.getBlockByHeight(height)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(block)) + `when`(flowAccessApi.getBlockByHeight(height)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(mockBlock)) val result = flowAccessApi.getBlockByHeight(height) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(block), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(mockBlock), result) } @Test fun `Test getAccountBalanceAtLatestBlock success`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowAddress = FlowAddress("01") - val expectedBalance = 1000L val response = FlowAccessApi.AccessApiCallResponse.Success(expectedBalance) - `when`(flowAccessApi.getAccountBalanceAtLatestBlock(flowAddress)).thenReturn(response) + `when`(flowAccessApi.getAccountBalanceAtLatestBlock(address)).thenReturn(response) - val result = flowAccessApi.getAccountBalanceAtLatestBlock(flowAddress) + val result = flowAccessApi.getAccountBalanceAtLatestBlock(address) assertEquals(response, result) - verify(flowAccessApi).getAccountBalanceAtLatestBlock(flowAddress) + verify(flowAccessApi).getAccountBalanceAtLatestBlock(address) } @Test fun `Test getAccountBalanceAtLatestBlock failure`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowAddress = FlowAddress("01") - val exception = RuntimeException("Test exception") - val response = FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at latest block", exception) + val response = FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at latest block", testException) - `when`(flowAccessApi.getAccountBalanceAtLatestBlock(flowAddress)).thenReturn(response) + `when`(flowAccessApi.getAccountBalanceAtLatestBlock(address)).thenReturn(response) - val result = flowAccessApi.getAccountBalanceAtLatestBlock(flowAddress) + val result = flowAccessApi.getAccountBalanceAtLatestBlock(address) assertEquals(response, result) - verify(flowAccessApi).getAccountBalanceAtLatestBlock(flowAddress) + verify(flowAccessApi).getAccountBalanceAtLatestBlock(address) } @Test fun `Test getAccountBalanceAtBlockHeight success`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowAddress = FlowAddress("01") - val blockHeight = 123L - val expectedBalance = 1000L val response = FlowAccessApi.AccessApiCallResponse.Success(expectedBalance) - `when`(flowAccessApi.getAccountBalanceAtBlockHeight(flowAddress, blockHeight)).thenReturn(response) + `when`(flowAccessApi.getAccountBalanceAtBlockHeight(address, height)).thenReturn(response) - val result = flowAccessApi.getAccountBalanceAtBlockHeight(flowAddress, blockHeight) + val result = flowAccessApi.getAccountBalanceAtBlockHeight(address, height) assertEquals(response, result) - verify(flowAccessApi).getAccountBalanceAtBlockHeight(flowAddress, blockHeight) + verify(flowAccessApi).getAccountBalanceAtBlockHeight(address, height) } @Test fun `Test getAccountBalanceAtBlockHeight failure`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowAddress = FlowAddress("01") - val blockHeight = 123L - val exception = RuntimeException("Test exception") - val response = FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at block height", exception) + val response = FlowAccessApi.AccessApiCallResponse.Error("Failed to get account balance at block height", testException) - `when`(flowAccessApi.getAccountBalanceAtBlockHeight(flowAddress, blockHeight)).thenReturn(response) + `when`(flowAccessApi.getAccountBalanceAtBlockHeight(address, height)).thenReturn(response) - val result = flowAccessApi.getAccountBalanceAtBlockHeight(flowAddress, blockHeight) + val result = flowAccessApi.getAccountBalanceAtBlockHeight(address, height) assertEquals(response, result) - verify(flowAccessApi).getAccountBalanceAtBlockHeight(flowAddress, blockHeight) + verify(flowAccessApi).getAccountBalanceAtBlockHeight(address, height) } @Test fun `Test getCollectionById`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowId = FlowId("01") + val flowId = blockId val flowCollection = FlowCollection(flowId, emptyList()) `when`(flowAccessApi.getCollectionById(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowCollection)) @@ -232,44 +193,37 @@ class FlowAccessApiTest { @Test fun `Test getFullCollectionById`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowId = FlowId("01") - val flowTransaction = FlowTransaction.of(TransactionOuterClass.Transaction.getDefaultInstance()) - `when`(flowAccessApi.getFullCollectionById(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(listOf(flowTransaction))) + val flowId = blockId + `when`(flowAccessApi.getFullCollectionById(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(listOf(transaction))) val result = flowAccessApi.getFullCollectionById(flowId) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(listOf(flowTransaction)), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(listOf(transaction)), result) } @Test fun `Test sendTransaction`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowTransaction = FlowTransaction.of(TransactionOuterClass.Transaction.getDefaultInstance()) - val flowId = FlowId("01") - `when`(flowAccessApi.sendTransaction(flowTransaction)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowId)) + val flowId = blockId + `when`(flowAccessApi.sendTransaction(transaction)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowId)) - val result = flowAccessApi.sendTransaction(flowTransaction) + val result = flowAccessApi.sendTransaction(transaction) assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowId), result) } @Test fun `Test getTransactionById`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowId = FlowId("01") - val flowTransaction = FlowTransaction.of(TransactionOuterClass.Transaction.getDefaultInstance()) - `when`(flowAccessApi.getTransactionById(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransaction)) + val flowId = blockId + `when`(flowAccessApi.getTransactionById(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(transaction)) val result = flowAccessApi.getTransactionById(flowId) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowTransaction), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(transaction), result) } @Test fun `Test getTransactionResultById`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowId = FlowId("01") + val flowId = blockId val flowTransactionResult = FlowTransactionResult.of(Access.TransactionResultResponse.getDefaultInstance()) `when`(flowAccessApi.getTransactionResultById(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult)) @@ -280,20 +234,17 @@ class FlowAccessApiTest { @Test fun `Test getSystemTransaction`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowId = FlowId("01") - val flowTransaction = FlowTransaction.of(TransactionOuterClass.Transaction.getDefaultInstance()) - `when`(flowAccessApi.getSystemTransaction(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransaction)) + val flowId = blockId + `when`(flowAccessApi.getSystemTransaction(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(transaction)) val result = flowAccessApi.getSystemTransaction(flowId) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowTransaction), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(transaction), result) } @Test fun `Test getSystemTransactionResult`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowId = FlowId("01") + val flowId = blockId val flowTransactionResult = FlowTransactionResult.of(Access.TransactionResultResponse.getDefaultInstance()) `when`(flowAccessApi.getSystemTransactionResult(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult)) @@ -304,46 +255,35 @@ class FlowAccessApiTest { @Test fun `Test getTransactionResultByIndex`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowId = FlowId("01") - val index = 0 - + val flowId = blockId val flowTransactionResult = FlowTransactionResult.of(Access.TransactionResultResponse.getDefaultInstance()) - `when`(flowAccessApi.getTransactionResultByIndex(flowId, index)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult)) + `when`(flowAccessApi.getTransactionResultByIndex(flowId, keyIndex)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult)) - val result = flowAccessApi.getTransactionResultByIndex(flowId, index) + val result = flowAccessApi.getTransactionResultByIndex(flowId, keyIndex) assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowTransactionResult), result) } @Test fun `Test getAccountAtLatestBlock`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowAddress = FlowAddress("01") - val flowAccount = FlowAccount.of(AccountOuterClass.Account.getDefaultInstance()) - `when`(flowAccessApi.getAccountAtLatestBlock(flowAddress)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowAccount)) + `when`(flowAccessApi.getAccountAtLatestBlock(address)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(account)) - val result = flowAccessApi.getAccountAtLatestBlock(flowAddress) + val result = flowAccessApi.getAccountAtLatestBlock(address) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowAccount), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(account), result) } @Test fun `Test getAccountByBlockHeight`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowAddress = FlowAddress("01") - val height = 123L - val flowAccount = FlowAccount.of(AccountOuterClass.Account.getDefaultInstance()) - `when`(flowAccessApi.getAccountByBlockHeight(flowAddress, height)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(flowAccount)) + `when`(flowAccessApi.getAccountByBlockHeight(address, height)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(account)) - val result = flowAccessApi.getAccountByBlockHeight(flowAddress, height) + val result = flowAccessApi.getAccountByBlockHeight(address, height) - assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowAccount), result) + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(account), result) } @Test fun `Test executeScriptAtLatestBlock`() { - val flowAccessApi = mock(FlowAccessApi::class.java) val script = FlowScript("script") val arguments = listOf(ByteString.copyFromUtf8("argument1")) val response = FlowScriptResponse("response".toByteArray()) @@ -356,9 +296,7 @@ class FlowAccessApiTest { @Test fun `Test executeScriptAtBlockId`() { - val flowAccessApi = mock(FlowAccessApi::class.java) val script = FlowScript("script") - val blockId = FlowId("01") val arguments = listOf(ByteString.copyFromUtf8("argument1")) val response = FlowScriptResponse("response".toByteArray()) `when`(flowAccessApi.executeScriptAtBlockId(script, blockId, arguments)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(response)) @@ -370,9 +308,7 @@ class FlowAccessApiTest { @Test fun `Test executeScriptAtBlockHeight`() { - val flowAccessApi = mock(FlowAccessApi::class.java) val script = FlowScript("script") - val height = 123L val arguments = listOf(ByteString.copyFromUtf8("argument1")) val response = FlowScriptResponse("response".toByteArray()) `when`(flowAccessApi.executeScriptAtBlockHeight(script, height, arguments)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(response)) @@ -384,7 +320,6 @@ class FlowAccessApiTest { @Test fun `Test getEventsForHeightRange`() { - val flowAccessApi = mock(FlowAccessApi::class.java) val type = "eventType" val range = 100L..200L val eventResults = listOf(FlowEventResult.of(Access.EventsResponse.Result.getDefaultInstance()), FlowEventResult.of(Access.EventsResponse.Result.getDefaultInstance())) @@ -397,7 +332,6 @@ class FlowAccessApiTest { @Test fun `Test getEventsForBlockIds`() { - val flowAccessApi = mock(FlowAccessApi::class.java) val type = "eventType" val ids = setOf(FlowId("01"), FlowId("02")) val eventResults = listOf(FlowEventResult.of(Access.EventsResponse.Result.getDefaultInstance()), FlowEventResult.of(Access.EventsResponse.Result.getDefaultInstance())) @@ -410,7 +344,6 @@ class FlowAccessApiTest { @Test fun `Test getNetworkParameters`() { - val flowAccessApi = mock(FlowAccessApi::class.java) val chainId = FlowChainId.TESTNET `when`(flowAccessApi.getNetworkParameters()).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(chainId)) @@ -421,7 +354,6 @@ class FlowAccessApiTest { @Test fun `Test getLatestProtocolStateSnapshot`() { - val flowAccessApi = mock(FlowAccessApi::class.java) val snapshot = FlowSnapshot("snapshot".toByteArray()) `when`(flowAccessApi.getLatestProtocolStateSnapshot()).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(snapshot)) @@ -432,7 +364,6 @@ class FlowAccessApiTest { @Test fun `Test getProtocolStateSnapshotByBlockId`() { - val flowAccessApi = mock(FlowAccessApi::class.java) val snapshot = FlowSnapshot("snapshot".toByteArray()) `when`(flowAccessApi.getProtocolStateSnapshotByBlockId(blockId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(snapshot)) @@ -443,7 +374,6 @@ class FlowAccessApiTest { @Test fun `Test getProtocolStateSnapshotByHeight`() { - val flowAccessApi = mock(FlowAccessApi::class.java) val snapshot = FlowSnapshot("snapshot".toByteArray()) `when`(flowAccessApi.getProtocolStateSnapshotByHeight(HEIGHT)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(snapshot)) @@ -454,9 +384,7 @@ class FlowAccessApiTest { @Test fun `Test getTransactionsByBlockId`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val blockId = FlowId("01") - val transactions = listOf(FlowTransaction.of(TransactionOuterClass.Transaction.getDefaultInstance())) + val transactions = listOf(transaction) `when`(flowAccessApi.getTransactionsByBlockId(blockId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(transactions)) val result = flowAccessApi.getTransactionsByBlockId(blockId) @@ -466,9 +394,6 @@ class FlowAccessApiTest { @Test fun `Test getTransactionsByBlockId with multiple results`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val blockId = FlowId("01") - val transaction1 = FlowTransaction(FlowScript("script1"), emptyList(), FlowId.of("01".toByteArray()), 123L, FlowTransactionProposalKey(FlowAddress("02"), 1, 123L), FlowAddress("02"), emptyList()) val transaction2 = FlowTransaction(FlowScript("script2"), emptyList(), FlowId.of("02".toByteArray()), 456L, FlowTransactionProposalKey(FlowAddress("03"), 2, 456L), FlowAddress("03"), emptyList()) @@ -488,8 +413,6 @@ class FlowAccessApiTest { @Test fun `Test getTransactionResultsByBlockId`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val blockId = FlowId("01") val transactionResults = listOf(FlowTransactionResult.of(Access.TransactionResultResponse.getDefaultInstance())) `when`(flowAccessApi.getTransactionResultsByBlockId(blockId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(transactionResults)) @@ -500,8 +423,7 @@ class FlowAccessApiTest { @Test fun `Test getTransactionResultsByBlockId with multiple results`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val flowId = FlowId("01") + val flowId = blockId val transactionResult1 = FlowTransactionResult( FlowTransactionStatus.SEALED, @@ -548,8 +470,6 @@ class FlowAccessApiTest { @Test fun `Test getExecutionResultByBlockId`() { - val flowAccessApi = mock(FlowAccessApi::class.java) - val blockId = FlowId("01") val executionResult = FlowExecutionResult.of(Access.ExecutionResultByIDResponse.getDefaultInstance()) `when`(flowAccessApi.getExecutionResultByBlockId(blockId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(executionResult)) @@ -560,8 +480,6 @@ class FlowAccessApiTest { @Test fun `Test subscribeExecutionDataByBlockId`(): Unit = runBlocking { - val flowAccessApi = mock(FlowAccessApi::class.java) - val blockId = FlowId("01") val scope = this val responseChannel = Channel(Channel.UNLIMITED) val errorChannel = Channel(Channel.UNLIMITED) @@ -594,7 +512,6 @@ class FlowAccessApiTest { @Test fun `Test subscribeExecutionDataByBlockHeight`(): Unit = runBlocking { - val flowAccessApi = mock(FlowAccessApi::class.java) val blockHeight = 100L val scope = this val responseChannel = Channel(Channel.UNLIMITED) @@ -628,8 +545,6 @@ class FlowAccessApiTest { @Test fun `Test subscribeEventsByBlockId`(): Unit = runBlocking { - val flowAccessApi = mock(FlowAccessApi::class.java) - val blockId = FlowId("01") val scope = this val responseChannel = Channel>(Channel.UNLIMITED) val errorChannel = Channel(Channel.UNLIMITED) @@ -662,7 +577,6 @@ class FlowAccessApiTest { @Test fun `Test subscribeEventsByBlockHeight`(): Unit = runBlocking { - val flowAccessApi = mock(FlowAccessApi::class.java) val blockHeight = 100L val scope = this val responseChannel = Channel>(Channel.UNLIMITED) From 4e3652ceb0926384c777288e5bbadd7829a273dd Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 12 Nov 2024 03:23:25 +0900 Subject: [PATCH 07/14] Further refactoring --- .../org/onflow/flow/sdk/FlowAccessApiTest.kt | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt index 159a9fb..23f51a6 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt @@ -1,7 +1,6 @@ package org.onflow.flow.sdk import com.google.protobuf.ByteString -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.consumeEach @@ -32,6 +31,10 @@ class FlowAccessApiTest { private val expectedBalance = 1000L private val account = createMockAccount(address) private val transaction = createMockTransaction() + private val script = FlowScript("script") + private val arguments = listOf(ByteString.copyFromUtf8("argument1")) + private val response = FlowScriptResponse("response".toByteArray()) + private val snapshot = FlowSnapshot("snapshot".toByteArray()) @BeforeEach fun setUp() { @@ -284,9 +287,6 @@ class FlowAccessApiTest { @Test fun `Test executeScriptAtLatestBlock`() { - val script = FlowScript("script") - val arguments = listOf(ByteString.copyFromUtf8("argument1")) - val response = FlowScriptResponse("response".toByteArray()) `when`(flowAccessApi.executeScriptAtLatestBlock(script, arguments)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(response)) val result = flowAccessApi.executeScriptAtLatestBlock(script, arguments) @@ -296,9 +296,6 @@ class FlowAccessApiTest { @Test fun `Test executeScriptAtBlockId`() { - val script = FlowScript("script") - val arguments = listOf(ByteString.copyFromUtf8("argument1")) - val response = FlowScriptResponse("response".toByteArray()) `when`(flowAccessApi.executeScriptAtBlockId(script, blockId, arguments)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(response)) val result = flowAccessApi.executeScriptAtBlockId(script, blockId, arguments) @@ -308,9 +305,6 @@ class FlowAccessApiTest { @Test fun `Test executeScriptAtBlockHeight`() { - val script = FlowScript("script") - val arguments = listOf(ByteString.copyFromUtf8("argument1")) - val response = FlowScriptResponse("response".toByteArray()) `when`(flowAccessApi.executeScriptAtBlockHeight(script, height, arguments)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(response)) val result = flowAccessApi.executeScriptAtBlockHeight(script, height, arguments) @@ -354,7 +348,6 @@ class FlowAccessApiTest { @Test fun `Test getLatestProtocolStateSnapshot`() { - val snapshot = FlowSnapshot("snapshot".toByteArray()) `when`(flowAccessApi.getLatestProtocolStateSnapshot()).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(snapshot)) val result = flowAccessApi.getLatestProtocolStateSnapshot() @@ -364,7 +357,6 @@ class FlowAccessApiTest { @Test fun `Test getProtocolStateSnapshotByBlockId`() { - val snapshot = FlowSnapshot("snapshot".toByteArray()) `when`(flowAccessApi.getProtocolStateSnapshotByBlockId(blockId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(snapshot)) val result = flowAccessApi.getProtocolStateSnapshotByBlockId(blockId) @@ -374,7 +366,6 @@ class FlowAccessApiTest { @Test fun `Test getProtocolStateSnapshotByHeight`() { - val snapshot = FlowSnapshot("snapshot".toByteArray()) `when`(flowAccessApi.getProtocolStateSnapshotByHeight(HEIGHT)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(snapshot)) val result = flowAccessApi.getProtocolStateSnapshotByHeight(HEIGHT) @@ -430,7 +421,7 @@ class FlowAccessApiTest { 1, "message1", emptyList(), - flowId, + blockId, 1L, flowId, flowId, @@ -442,7 +433,7 @@ class FlowAccessApiTest { 2, "message2", emptyList(), - flowId, + blockId, 1L, flowId, flowId, From e7499184084f95189b54c5cde35a2b2bd21b942c Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 12 Nov 2024 23:02:18 +0900 Subject: [PATCH 08/14] Add retry mechanism to getLatestBlock --- .../examples/kotlin/AccessAPIConnectorTest.kt | 2 ++ ...GetAccountBalanceAccessAPIConnectorTest.kt | 32 +++++++------------ .../GetCollectionAccessAPIConnectorTest.kt | 7 ++-- .../GetProtocolStateAccessAPIConnectorTest.kt | 11 ++----- .../GetTransactionAccessAPIConnectorTest.kt | 23 ++++++++++--- 5 files changed, 37 insertions(+), 38 deletions(-) diff --git a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/AccessAPIConnectorTest.kt b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/AccessAPIConnectorTest.kt index cb5ec87..72d53a6 100644 --- a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/AccessAPIConnectorTest.kt +++ b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/AccessAPIConnectorTest.kt @@ -15,6 +15,7 @@ import java.math.BigDecimal @FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json") internal class AccessAPIConnectorTest { + // user key pairs using all supported signing algorithms private val userKeyPairs = arrayOf( Crypto.generateKeyPair(SignatureAlgorithm.ECDSA_P256), @@ -62,6 +63,7 @@ internal class AccessAPIConnectorTest { accessAPIConnector.transferTokens(sender, to, amount) } + @Test fun `Can transfer tokens to other account`() { val amount = BigDecimal("10.00000001") diff --git a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.kt b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.kt index 923f07b..a0e56d2 100644 --- a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.kt +++ b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getAccountBalance/GetAccountBalanceAccessAPIConnectorTest.kt @@ -3,11 +3,13 @@ package org.onflow.examples.kotlin.getAccountBalance import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.onflow.examples.kotlin.getTransaction.GetTransactionAccessAPIConnectorTest import org.onflow.flow.common.test.FlowEmulatorProjectTest import org.onflow.flow.common.test.FlowServiceAccountCredentials import org.onflow.flow.common.test.FlowTestClient import org.onflow.flow.common.test.TestAccount import org.onflow.flow.sdk.FlowAccessApi +import org.onflow.flow.sdk.FlowBlock @FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json") internal class GetAccountBalanceAccessAPIConnectorTest { @@ -18,10 +20,12 @@ internal class GetAccountBalanceAccessAPIConnectorTest { lateinit var accessAPI: FlowAccessApi private lateinit var balanceAPIConnector: GetAccountBalanceAccessAPIConnector + private lateinit var latestBlock: FlowBlock @BeforeEach fun setup() { balanceAPIConnector = GetAccountBalanceAccessAPIConnector(accessAPI) + latestBlock = GetTransactionAccessAPIConnectorTest.fetchLatestBlockWithRetries(accessAPI) } @Test @@ -36,17 +40,10 @@ internal class GetAccountBalanceAccessAPIConnectorTest { @Test fun `Can fetch account balance at a specific block height`() { val address = serviceAccount.flowAddress - val latestBlock = accessAPI.getLatestBlock(true) // Fetch the latest sealed block + val balanceAtHeight = balanceAPIConnector.getBalanceAtBlockHeight(address, latestBlock.height) - when (latestBlock) { - is FlowAccessApi.AccessApiCallResponse.Success -> { - val balanceAtHeight = balanceAPIConnector.getBalanceAtBlockHeight(address, latestBlock.data.height) - - Assertions.assertNotNull(balanceAtHeight, "Balance at specific block height should not be null") - Assertions.assertTrue(balanceAtHeight >= 0, "Balance at specific block height should be non-negative") - } - is FlowAccessApi.AccessApiCallResponse.Error -> Assertions.fail("Failed to retrieve the latest block: ${latestBlock.message}") - } + Assertions.assertNotNull(balanceAtHeight, "Balance at specific block height should not be null") + Assertions.assertTrue(balanceAtHeight >= 0, "Balance at specific block height should be non-negative") } @Test @@ -56,18 +53,11 @@ internal class GetAccountBalanceAccessAPIConnectorTest { // Fetch balance at latest block val balanceAtLatest = balanceAPIConnector.getBalanceAtLatestBlock(address) - // Fetch latest block height - val latestBlock = accessAPI.getLatestBlock(true) - when (latestBlock) { - is FlowAccessApi.AccessApiCallResponse.Success -> { - val blockHeight = latestBlock.data.height + val blockHeight = latestBlock.height - // Fetch balance at the same block height - val balanceAtHeight = balanceAPIConnector.getBalanceAtBlockHeight(address, blockHeight) + // Fetch balance at the same block height + val balanceAtHeight = balanceAPIConnector.getBalanceAtBlockHeight(address, blockHeight) - Assertions.assertEquals(balanceAtLatest, balanceAtHeight, "Balance at latest block and specific block height should match") - } - is FlowAccessApi.AccessApiCallResponse.Error -> Assertions.fail("Failed to retrieve the latest block: ${latestBlock.message}") - } + Assertions.assertEquals(balanceAtLatest, balanceAtHeight, "Balance at latest block and specific block height should match") } } diff --git a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt index 53545f9..c427d42 100644 --- a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt +++ b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.onflow.examples.kotlin.AccessAPIConnector +import org.onflow.examples.kotlin.getTransaction.GetTransactionAccessAPIConnectorTest import org.onflow.flow.common.test.FlowEmulatorProjectTest import org.onflow.flow.common.test.FlowServiceAccountCredentials import org.onflow.flow.common.test.FlowTestClient @@ -23,6 +24,7 @@ class GetCollectionAccessAPIConnectorTest { private lateinit var accessAPIConnector: AccessAPIConnector private lateinit var collectionId: FlowId + lateinit var block: FlowBlock @BeforeEach fun setup() { @@ -36,10 +38,7 @@ class GetCollectionAccessAPIConnectorTest { publicKey ) - val block = when (val response = accessAPI.getLatestBlock()) { - is FlowAccessApi.AccessApiCallResponse.Success -> response.data - is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) - } + block = GetTransactionAccessAPIConnectorTest.fetchLatestBlockWithRetries(accessAPI) collectionId = block.collectionGuarantees.first().id } diff --git a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt index f59b6aa..0c57231 100644 --- a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt +++ b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt @@ -3,6 +3,7 @@ package org.onflow.examples.kotlin.getProtocolState import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.onflow.examples.kotlin.getTransaction.GetTransactionAccessAPIConnectorTest import org.onflow.flow.common.test.FlowEmulatorProjectTest import org.onflow.flow.common.test.FlowTestClient import org.onflow.flow.sdk.FlowAccessApi @@ -20,6 +21,7 @@ internal class GetProtocolStateAccessAPIConnectorTest { @BeforeEach fun setup() { protocolStateConnector = GetProtocolStateAccessAPIConnector(accessAPI) + block = GetTransactionAccessAPIConnectorTest.fetchLatestBlockWithRetries(accessAPI) } @Test @@ -30,21 +32,12 @@ internal class GetProtocolStateAccessAPIConnectorTest { @Test fun `Can get protocol state snapshot by blockId`() { - block = when (val response = accessAPI.getLatestBlock()) { - is FlowAccessApi.AccessApiCallResponse.Success -> response.data - is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) - } - val latestSnapshot: FlowSnapshot = protocolStateConnector.getProtocolStateSnapshotByBlockId(block.id) assertNotNull(latestSnapshot, ("Snapshot should not be null")) } @Test fun `Can get protocol state snapshot by height`() { - block = when (val response = accessAPI.getLatestBlock()) { - is FlowAccessApi.AccessApiCallResponse.Success -> response.data - is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) - } val latestSnapshot: FlowSnapshot = protocolStateConnector.getProtocolStateSnapshotByHeight(block.height) assertNotNull(latestSnapshot, ("Snapshot should not be null")) diff --git a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt index 9395c7c..1524374 100644 --- a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt +++ b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt @@ -1,9 +1,12 @@ package org.onflow.examples.kotlin.getTransaction +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.onflow.examples.kotlin.AccessAPIConnector +import org.onflow.examples.kotlin.AccessAPIConnectorTest import org.onflow.flow.common.test.FlowEmulatorProjectTest import org.onflow.flow.common.test.FlowServiceAccountCredentials import org.onflow.flow.common.test.FlowTestClient @@ -37,10 +40,7 @@ internal class GetTransactionAccessAPIConnectorTest { publicKey ) - block = when (val response = accessAPI.getLatestBlock()) { - is FlowAccessApi.AccessApiCallResponse.Success -> response.data - is FlowAccessApi.AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) - } + block = fetchLatestBlockWithRetries(accessAPI) } @Test @@ -66,4 +66,19 @@ internal class GetTransactionAccessAPIConnectorTest { assertNotNull(transactionResult, "Transaction result should not be null") assertTrue(transactionResult.status === FlowTransactionStatus.SEALED, "Transaction should be sealed") } + + companion object { + fun fetchLatestBlockWithRetries(accessAPI : FlowAccessApi, retries: Int = 5, delayMillis: Long = 500): FlowBlock { + repeat(retries) { attempt -> + when (val response = accessAPI.getLatestBlock()) { + is FlowAccessApi.AccessApiCallResponse.Success -> return response.data + is FlowAccessApi.AccessApiCallResponse.Error -> { + println("Attempt ${attempt + 1} failed: ${response.message}. Retrying...") + runBlocking { delay(delayMillis) } + } + } + } + throw Exception("Failed to retrieve the latest block after $retries attempts.") + } + } } From 6c5cab3a416cf4aaec854b4beede814358088607 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 12 Nov 2024 23:10:31 +0900 Subject: [PATCH 09/14] Add retry mechanism to getLatestBlock --- .../org/onflow/examples/kotlin/AccessAPIConnectorTest.kt | 2 -- .../getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt | 1 - .../getTransaction/GetTransactionAccessAPIConnectorTest.kt | 3 +-- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/AccessAPIConnectorTest.kt b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/AccessAPIConnectorTest.kt index 72d53a6..cb5ec87 100644 --- a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/AccessAPIConnectorTest.kt +++ b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/AccessAPIConnectorTest.kt @@ -15,7 +15,6 @@ import java.math.BigDecimal @FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json") internal class AccessAPIConnectorTest { - // user key pairs using all supported signing algorithms private val userKeyPairs = arrayOf( Crypto.generateKeyPair(SignatureAlgorithm.ECDSA_P256), @@ -63,7 +62,6 @@ internal class AccessAPIConnectorTest { accessAPIConnector.transferTokens(sender, to, amount) } - @Test fun `Can transfer tokens to other account`() { val amount = BigDecimal("10.00000001") diff --git a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt index 0c57231..bbddbe9 100644 --- a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt +++ b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getProtocolState/GetProtocolStateAccessAPIConnectorTest.kt @@ -38,7 +38,6 @@ internal class GetProtocolStateAccessAPIConnectorTest { @Test fun `Can get protocol state snapshot by height`() { - val latestSnapshot: FlowSnapshot = protocolStateConnector.getProtocolStateSnapshotByHeight(block.height) assertNotNull(latestSnapshot, ("Snapshot should not be null")) } diff --git a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt index 1524374..a240d7f 100644 --- a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt +++ b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getTransaction/GetTransactionAccessAPIConnectorTest.kt @@ -6,7 +6,6 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.onflow.examples.kotlin.AccessAPIConnector -import org.onflow.examples.kotlin.AccessAPIConnectorTest import org.onflow.flow.common.test.FlowEmulatorProjectTest import org.onflow.flow.common.test.FlowServiceAccountCredentials import org.onflow.flow.common.test.FlowTestClient @@ -68,7 +67,7 @@ internal class GetTransactionAccessAPIConnectorTest { } companion object { - fun fetchLatestBlockWithRetries(accessAPI : FlowAccessApi, retries: Int = 5, delayMillis: Long = 500): FlowBlock { + fun fetchLatestBlockWithRetries(accessAPI: FlowAccessApi, retries: Int = 5, delayMillis: Long = 500): FlowBlock { repeat(retries) { attempt -> when (val response = accessAPI.getLatestBlock()) { is FlowAccessApi.AccessApiCallResponse.Success -> return response.data From 3facb9e118aa3809b7d03549132ebefbf6cdb45f Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 12 Nov 2024 23:28:00 +0900 Subject: [PATCH 10/14] Add retry mechanism to getLatestBlock --- .../org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt index 4a5d6bd..6e80663 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt @@ -487,7 +487,7 @@ class AsyncFlowAccessApiImplTest { fun `test getSystemTransactionResult failure`() { `when`(api.getSystemTransactionResult(any())).thenThrow(testException) - val result = asyncFlowAccessApi.getSystemTransactionResult(flowId).get() + val result = asyncFlowAccessApi.getSystemTransactionResult(FlowId.of("id_failure".toByteArray())).get() assertFailure(result, "Failed to get system transaction result by block ID", testException) } From e8230ebc3bd6b9c03f56d130679fedff7ae5f51f Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 12 Nov 2024 23:39:54 +0900 Subject: [PATCH 11/14] Add retry mechanism to getLatestBlock on int tests --- .../transaction/TransactionIntegrationTest.kt | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt b/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt index ee41865..dc8e87c 100644 --- a/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt +++ b/sdk/src/intTest/org/onflow/flow/sdk/transaction/TransactionIntegrationTest.kt @@ -1,5 +1,7 @@ package org.onflow.flow.sdk.transaction +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking import org.onflow.flow.sdk.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -43,8 +45,22 @@ class TransactionIntegrationTest { fail("$errorMessage: ${e.message}") } - private fun getLatestBlock(): FlowBlock = - safelyHandle({ Result.success(handleResult(accessAPI.getLatestBlock(true), LATEST_BLOCK_ERROR)) }, LATEST_BLOCK_ERROR) + private fun getLatestBlock(retries: Int = 5, delayMillis: Long = 500): FlowBlock { + repeat(retries) { attempt -> + try { + return safelyHandle( + { Result.success(handleResult(accessAPI.getLatestBlock(true), LATEST_BLOCK_ERROR)) }, + LATEST_BLOCK_ERROR + ) + } catch (e: Exception) { + if (attempt == retries - 1) { + throw Exception("$LATEST_BLOCK_ERROR after $retries attempts", e) + } + runBlocking { delay(delayMillis) } + } + } + throw Exception(LATEST_BLOCK_ERROR) + } private fun getAccountAtLatestBlock(address: FlowAddress): FlowAccount = safelyHandle({ Result.success(handleResult(accessAPI.getAccountAtLatestBlock(address), ACCOUNT_ERROR)) }, ACCOUNT_ERROR) From 49812496efae09fff7e209073d88c1e4ca5c8cd7 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 12 Nov 2024 23:49:11 +0900 Subject: [PATCH 12/14] Debug failing test --- .../sdk/impl/AsyncFlowAccessApiImplTest.kt | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt index 6e80663..47b16ad 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt @@ -475,19 +475,40 @@ class AsyncFlowAccessApiImplTest { @Test fun `test getSystemTransactionResult`() { - val flowTransactionResult = FlowTransactionResult(FlowTransactionStatus.SEALED, 1, "message", emptyList(), flowId, HEIGHT, flowId, flowId, 1L) + val flowTransactionResult = FlowTransactionResult( + FlowTransactionStatus.SEALED, + 1, + "message", + emptyList(), + flowId, + HEIGHT, + flowId, + flowId, + 1L + ) + + val successFlowId = FlowId.of("id_success".toByteArray()) + val successRequest = Access.GetSystemTransactionResultRequest.newBuilder() + .setBlockId(successFlowId.byteStringValue) + .build() - `when`(api.getSystemTransactionResult(any())).thenReturn(setupFutureMock(MockResponseFactory.transactionResultResponse())) + `when`(api.getSystemTransactionResult(eq(successRequest))) + .thenReturn(setupFutureMock(MockResponseFactory.transactionResultResponse())) - val result = asyncFlowAccessApi.getSystemTransactionResult(flowId).get() + val result = asyncFlowAccessApi.getSystemTransactionResult(successFlowId).get() assertSuccess(result, flowTransactionResult) } @Test fun `test getSystemTransactionResult failure`() { - `when`(api.getSystemTransactionResult(any())).thenThrow(testException) + val failureFlowId = FlowId.of("id_failure".toByteArray()) + val failureRequest = Access.GetSystemTransactionResultRequest.newBuilder() + .setBlockId(failureFlowId.byteStringValue) + .build() + + `when`(api.getSystemTransactionResult(eq(failureRequest))).thenThrow(testException) - val result = asyncFlowAccessApi.getSystemTransactionResult(FlowId.of("id_failure".toByteArray())).get() + val result = asyncFlowAccessApi.getSystemTransactionResult(failureFlowId).get() assertFailure(result, "Failed to get system transaction result by block ID", testException) } From b5c808ea276bad4e945f86affadca1b296714ce6 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 12 Nov 2024 23:55:20 +0900 Subject: [PATCH 13/14] Debug failing test --- .../org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt index 47b16ad..0d05d8b 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt @@ -488,7 +488,8 @@ class AsyncFlowAccessApiImplTest { ) val successFlowId = FlowId.of("id_success".toByteArray()) - val successRequest = Access.GetSystemTransactionResultRequest.newBuilder() + val successRequest = Access.GetSystemTransactionResultRequest + .newBuilder() .setBlockId(successFlowId.byteStringValue) .build() @@ -502,7 +503,8 @@ class AsyncFlowAccessApiImplTest { @Test fun `test getSystemTransactionResult failure`() { val failureFlowId = FlowId.of("id_failure".toByteArray()) - val failureRequest = Access.GetSystemTransactionResultRequest.newBuilder() + val failureRequest = Access.GetSystemTransactionResultRequest + .newBuilder() .setBlockId(failureFlowId.byteStringValue) .build() From 99f39fcca14dbf1f0f5b10e72c5ec532fd49ea0c Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Thu, 21 Nov 2024 15:05:05 +0100 Subject: [PATCH 14/14] Debug failing test --- .../sdk/impl/AsyncFlowAccessApiImplTest.kt | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt index 4a5d6bd..0d05d8b 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt @@ -475,19 +475,42 @@ class AsyncFlowAccessApiImplTest { @Test fun `test getSystemTransactionResult`() { - val flowTransactionResult = FlowTransactionResult(FlowTransactionStatus.SEALED, 1, "message", emptyList(), flowId, HEIGHT, flowId, flowId, 1L) + val flowTransactionResult = FlowTransactionResult( + FlowTransactionStatus.SEALED, + 1, + "message", + emptyList(), + flowId, + HEIGHT, + flowId, + flowId, + 1L + ) + + val successFlowId = FlowId.of("id_success".toByteArray()) + val successRequest = Access.GetSystemTransactionResultRequest + .newBuilder() + .setBlockId(successFlowId.byteStringValue) + .build() - `when`(api.getSystemTransactionResult(any())).thenReturn(setupFutureMock(MockResponseFactory.transactionResultResponse())) + `when`(api.getSystemTransactionResult(eq(successRequest))) + .thenReturn(setupFutureMock(MockResponseFactory.transactionResultResponse())) - val result = asyncFlowAccessApi.getSystemTransactionResult(flowId).get() + val result = asyncFlowAccessApi.getSystemTransactionResult(successFlowId).get() assertSuccess(result, flowTransactionResult) } @Test fun `test getSystemTransactionResult failure`() { - `when`(api.getSystemTransactionResult(any())).thenThrow(testException) + val failureFlowId = FlowId.of("id_failure".toByteArray()) + val failureRequest = Access.GetSystemTransactionResultRequest + .newBuilder() + .setBlockId(failureFlowId.byteStringValue) + .build() + + `when`(api.getSystemTransactionResult(eq(failureRequest))).thenThrow(testException) - val result = asyncFlowAccessApi.getSystemTransactionResult(flowId).get() + val result = asyncFlowAccessApi.getSystemTransactionResult(failureFlowId).get() assertFailure(result, "Failed to get system transaction result by block ID", testException) }