From 93ecba93d0b8aa48a15c5b2ea5bf5b5f90beeb74 Mon Sep 17 00:00:00 2001 From: Hendrik Ebbers Date: Tue, 16 Jul 2024 10:07:28 +0200 Subject: [PATCH] tests, tests, tests --- .../openelements/hedera/base/FileClient.java | 13 +++ .../base/implementation/FileClientImpl.java | 105 ++++++++++++++++-- .../ProtocolLayerClientImpl.java | 54 ++++++++- .../base/protocol/FileContentsResponse.java | 4 +- .../base/protocol/FileCreateRequest.java | 17 ++- .../hedera/base/protocol/FileInfoRequest.java | 35 ++++++ .../base/protocol/FileInfoResponse.java | 7 ++ .../base/protocol/FileUpdateRequest.java | 39 +++++++ .../base/protocol/FileUpdateResult.java | 9 ++ .../base/protocol/ProtocolLayerClient.java | 13 ++- .../hedera/spring/test/FileClientTests.java | 79 +++++++++++++ .../spring/test/ProtocolLayerClientTests.java | 50 +++++++++ 12 files changed, 411 insertions(+), 14 deletions(-) create mode 100644 hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileInfoRequest.java create mode 100644 hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileInfoResponse.java create mode 100644 hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileUpdateRequest.java create mode 100644 hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileUpdateResult.java diff --git a/hedera-base/src/main/java/com/openelements/hedera/base/FileClient.java b/hedera-base/src/main/java/com/openelements/hedera/base/FileClient.java index 0b366ed5..db7c4513 100644 --- a/hedera-base/src/main/java/com/openelements/hedera/base/FileClient.java +++ b/hedera-base/src/main/java/com/openelements/hedera/base/FileClient.java @@ -2,6 +2,7 @@ import com.hedera.hashgraph.sdk.FileId; import edu.umd.cs.findbugs.annotations.NonNull; +import java.time.Instant; import java.util.Objects; /** @@ -18,6 +19,8 @@ public interface FileClient { @NonNull FileId createFile(@NonNull byte[] contents) throws HederaException; + FileId createFile(@NonNull byte[] contents, @NonNull Instant expirationTime) throws HederaException; + /** * Create a new file with the given contents. * @param fileId the ID of the file to update @@ -54,4 +57,14 @@ default void deleteFile(@NonNull String fileId) throws HederaException { * @throws HederaException if the file could not be deleted */ void deleteFile(@NonNull FileId fileId) throws HederaException; + + void updateFile(@NonNull FileId fileId, byte[] content) throws HederaException; + + void updateExpirationTime(@NonNull FileId fileId, @NonNull Instant expirationTime) throws HederaException; + + boolean isDeleted(@NonNull FileId fileId) throws HederaException; + + int getSize(@NonNull FileId fileId) throws HederaException; + + Instant getExpirationTime(@NonNull FileId fileId) throws HederaException; } diff --git a/hedera-base/src/main/java/com/openelements/hedera/base/implementation/FileClientImpl.java b/hedera-base/src/main/java/com/openelements/hedera/base/implementation/FileClientImpl.java index 80d72ed5..b2a252b1 100644 --- a/hedera-base/src/main/java/com/openelements/hedera/base/implementation/FileClientImpl.java +++ b/hedera-base/src/main/java/com/openelements/hedera/base/implementation/FileClientImpl.java @@ -10,8 +10,14 @@ import com.openelements.hedera.base.protocol.FileCreateRequest; import com.openelements.hedera.base.protocol.FileCreateResult; import com.openelements.hedera.base.protocol.FileDeleteRequest; +import com.openelements.hedera.base.protocol.FileInfoRequest; +import com.openelements.hedera.base.protocol.FileInfoResponse; +import com.openelements.hedera.base.protocol.FileUpdateRequest; +import com.openelements.hedera.base.protocol.FileUpdateResult; import com.openelements.hedera.base.protocol.ProtocolLayerClient; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.time.Instant; import java.util.Arrays; import java.util.Objects; import org.slf4j.Logger; @@ -29,26 +35,46 @@ public FileClientImpl(@NonNull final ProtocolLayerClient protocolLayerClient) { @Override public FileId createFile(byte[] contents) throws HederaException { + return createFileImpl(contents, null); + } + + @Override + public FileId createFile(@NonNull byte[] contents, @NonNull Instant expirationTime) throws HederaException { + return createFileImpl(contents, expirationTime); + } + + private FileId createFileImpl(@NonNull byte[] contents, @Nullable Instant expirationTime) throws HederaException { Objects.requireNonNull(contents, "fileId must not be null"); - if(contents.length <= FileCreateRequest.FILE_CREATE_MAX_BYTES) { - final FileCreateRequest request = FileCreateRequest.of(contents); + if(contents.length > FileCreateRequest.FILE_MAX_SIZE) { + throw new HederaException("File contents must be less than " + FileCreateRequest.FILE_MAX_SIZE + " bytes"); + } + if(expirationTime != null && expirationTime.isBefore(Instant.now())) { + throw new IllegalArgumentException("Expiration time must be in the future"); + } + if(contents.length <= FileCreateRequest.FILE_CREATE_MAX_SIZE) { + final FileCreateRequest request; + if(expirationTime != null) { + request = FileCreateRequest.of(contents, expirationTime); + } else { + request = FileCreateRequest.of(contents); + } final FileCreateResult result = protocolLayerClient.executeFileCreateTransaction(request); return result.fileId(); } else { if(log.isDebugEnabled()) { - final int appendCount = Math.floorDiv(contents.length, FileCreateRequest.FILE_CREATE_MAX_BYTES); + final int appendCount = Math.floorDiv(contents.length, FileCreateRequest.FILE_CREATE_MAX_SIZE); log.debug("Content of size {} is to big for 1 FileCreate transaction. Will append {} FileAppend transactions", contents.length, appendCount); } - byte[] start = Arrays.copyOf(contents, FileCreateRequest.FILE_CREATE_MAX_BYTES); + byte[] start = Arrays.copyOf(contents, FileCreateRequest.FILE_CREATE_MAX_SIZE); final FileCreateRequest request = FileCreateRequest.of(start); final FileCreateResult result = protocolLayerClient.executeFileCreateTransaction(request); FileId fileId = result.fileId(); - byte[] remaining = Arrays.copyOfRange(contents, FileCreateRequest.FILE_CREATE_MAX_BYTES, contents.length); + byte[] remaining = Arrays.copyOfRange(contents, FileCreateRequest.FILE_CREATE_MAX_SIZE, contents.length); while(remaining.length > 0) { - final int length = Math.min(remaining.length, FileCreateRequest.FILE_CREATE_MAX_BYTES); + final int length = Math.min(remaining.length, FileCreateRequest.FILE_CREATE_MAX_SIZE); byte[] next = Arrays.copyOf(remaining, length); final FileAppendRequest appendRequest = FileAppendRequest.of(fileId, next); - final FileAppendResult appendResult = protocolLayerClient.executeFileAppendRequestTransaction(appendRequest); + protocolLayerClient.executeFileAppendRequestTransaction(appendRequest); remaining = Arrays.copyOfRange(remaining, length, remaining.length); } return fileId; @@ -78,4 +104,69 @@ public void deleteFile(@NonNull FileId fileId) throws HederaException { throw new HederaException("Failed to delete file with fileId " + fileId, e); } } + + @Override + public void updateFile(@NonNull FileId fileId, byte[] content) throws HederaException { + Objects.requireNonNull(fileId, "fileId must not be null"); + Objects.requireNonNull(content, "content must not be null"); + if(content.length > FileCreateRequest.FILE_MAX_SIZE) { + throw new HederaException("File contents must be less than " + FileCreateRequest.FILE_MAX_SIZE + " bytes"); + } + if(content.length <= FileCreateRequest.FILE_CREATE_MAX_SIZE) { + final FileUpdateRequest request = FileUpdateRequest.of(fileId, content); + protocolLayerClient.executeFileUpdateRequestTransaction(request); + } else { + if(log.isDebugEnabled()) { + final int appendCount = Math.floorDiv(content.length, FileCreateRequest.FILE_CREATE_MAX_SIZE); + log.debug("Content of size {} is to big for 1 FileUpdate transaction. Will append {} FileAppend transactions", content.length, appendCount); + } + byte[] start = Arrays.copyOf(content, FileCreateRequest.FILE_CREATE_MAX_SIZE); + final FileUpdateRequest request = FileUpdateRequest.of(fileId, start); + protocolLayerClient.executeFileUpdateRequestTransaction(request); + byte[] remaining = Arrays.copyOfRange(content, FileCreateRequest.FILE_CREATE_MAX_SIZE, content.length); + while(remaining.length > 0) { + final int length = Math.min(remaining.length, FileCreateRequest.FILE_CREATE_MAX_SIZE); + byte[] next = Arrays.copyOf(remaining, length); + final FileAppendRequest appendRequest = FileAppendRequest.of(fileId, next); + protocolLayerClient.executeFileAppendRequestTransaction(appendRequest); + remaining = Arrays.copyOfRange(remaining, length, remaining.length); + } + } + } + + @Override + public void updateExpirationTime(@NonNull FileId fileId, @NonNull Instant expirationTime) throws HederaException { + Objects.requireNonNull(fileId, "fileId must not be null"); + Objects.requireNonNull(expirationTime, "expirationTime must not be null"); + + if(expirationTime.isBefore(Instant.now())) { + throw new IllegalArgumentException("Expiration time must be in the future"); + } + final FileUpdateRequest request = FileUpdateRequest.of(fileId, expirationTime); + protocolLayerClient.executeFileUpdateRequestTransaction(request); + } + + @Override + public boolean isDeleted(@NonNull FileId fileId) throws HederaException { + Objects.requireNonNull(fileId, "fileId must not be null"); + final FileInfoRequest request = FileInfoRequest.of(fileId); + final FileInfoResponse infoResponse = protocolLayerClient.executeFileInfoQuery(request); + return infoResponse.deleted(); + } + + @Override + public int getSize(@NonNull FileId fileId) throws HederaException { + Objects.requireNonNull(fileId, "fileId must not be null"); + final FileInfoRequest request = FileInfoRequest.of(fileId); + final FileInfoResponse infoResponse = protocolLayerClient.executeFileInfoQuery(request); + return infoResponse.size(); + } + + @Override + public Instant getExpirationTime(@NonNull FileId fileId) throws HederaException { + Objects.requireNonNull(fileId, "fileId must not be null"); + final FileInfoRequest request = FileInfoRequest.of(fileId); + final FileInfoResponse infoResponse = protocolLayerClient.executeFileInfoQuery(request); + return infoResponse.expirationTime(); + } } diff --git a/hedera-base/src/main/java/com/openelements/hedera/base/implementation/ProtocolLayerClientImpl.java b/hedera-base/src/main/java/com/openelements/hedera/base/implementation/ProtocolLayerClientImpl.java index 9cfc5aa7..b6d4f2de 100644 --- a/hedera-base/src/main/java/com/openelements/hedera/base/implementation/ProtocolLayerClientImpl.java +++ b/hedera-base/src/main/java/com/openelements/hedera/base/implementation/ProtocolLayerClientImpl.java @@ -11,6 +11,9 @@ import com.hedera.hashgraph.sdk.FileContentsQuery; import com.hedera.hashgraph.sdk.FileCreateTransaction; import com.hedera.hashgraph.sdk.FileDeleteTransaction; +import com.hedera.hashgraph.sdk.FileInfo; +import com.hedera.hashgraph.sdk.FileInfoQuery; +import com.hedera.hashgraph.sdk.FileUpdateTransaction; import com.hedera.hashgraph.sdk.Query; import com.hedera.hashgraph.sdk.Transaction; import com.hedera.hashgraph.sdk.TransactionReceipt; @@ -32,6 +35,10 @@ import com.openelements.hedera.base.protocol.FileCreateResult; import com.openelements.hedera.base.protocol.FileDeleteRequest; import com.openelements.hedera.base.protocol.FileDeleteResult; +import com.openelements.hedera.base.protocol.FileInfoRequest; +import com.openelements.hedera.base.protocol.FileInfoResponse; +import com.openelements.hedera.base.protocol.FileUpdateRequest; +import com.openelements.hedera.base.protocol.FileUpdateResult; import com.openelements.hedera.base.protocol.ProtocolLayerClient; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.List; @@ -68,24 +75,69 @@ public FileContentsResponse executeFileContentsQuery(FileContentsRequest request .setMaxQueryPayment(request.maxQueryPayment()); final ByteString byteString = executeQueryAndWait(query); final byte[] bytes = byteString.toByteArray(); - return new FileContentsResponse(bytes); + return new FileContentsResponse(request.fileId(), bytes); + } + + public FileInfoResponse executeFileInfoQuery(FileInfoRequest request) throws HederaException { + final FileInfoQuery query = new FileInfoQuery().setFileId(request.fileId()) + .setQueryPayment(request.queryPayment()) + .setMaxQueryPayment(request.maxQueryPayment()); + final FileInfo fileInfo = executeQueryAndWait(query); + if(fileInfo.size > Integer.MAX_VALUE) { + throw new HederaException("File size is too large to be represented as an integer"); + } + return new FileInfoResponse(request.fileId(), (int) fileInfo.size, fileInfo.isDeleted, fileInfo.expirationTime); } @Override public FileCreateResult executeFileCreateTransaction(FileCreateRequest request) throws HederaException { + Objects.requireNonNull(request, "request must not be null"); + Objects.requireNonNull(request.contents(), "content must not be null"); + if(request.contents().length > FileCreateRequest.FILE_CREATE_MAX_SIZE) { + throw new HederaException("File contents of 1 transaction must be less than " + FileCreateRequest.FILE_CREATE_MAX_SIZE + " bytes. Use FileAppend for larger files."); + } final FileCreateTransaction transaction = new FileCreateTransaction() .setContents(request.contents()) .setMaxTransactionFee(request.maxTransactionFee()) .setTransactionValidDuration(request.transactionValidDuration()) .setTransactionMemo(request.fileMemo()) .setKeys(Objects.requireNonNull(client.getOperatorPublicKey())); + if(request.expirationTime() != null) { + transaction.setExpirationTime(request.expirationTime()); + } final TransactionReceipt receipt = executeTransactionAndWaitOnReceipt(transaction); return new FileCreateResult(receipt.transactionId, receipt.status, receipt.fileId); } + @Override + public FileUpdateResult executeFileUpdateRequestTransaction(FileUpdateRequest request) throws HederaException { + Objects.requireNonNull(request, "request must not be null"); + if(request.contents() != null && request.contents().length > FileCreateRequest.FILE_CREATE_MAX_SIZE) { + throw new HederaException("File contents of 1 transaction must be less than " + FileCreateRequest.FILE_CREATE_MAX_SIZE + " bytes. Use FileAppend for larger files."); + } + final FileUpdateTransaction transaction = new FileUpdateTransaction() + .setFileId(request.fileId()) + .setMaxTransactionFee(request.maxTransactionFee()) + .setTransactionValidDuration(request.transactionValidDuration()) + .setTransactionMemo(request.fileMemo()); + if(request.contents() != null) { + transaction.setContents(request.contents()); + } + if(request.expirationTime() != null) { + transaction.setExpirationTime(request.expirationTime()); + } + final TransactionReceipt receipt = executeTransactionAndWaitOnReceipt(transaction); + return new FileUpdateResult(receipt.transactionId, receipt.status); + } + @Override public FileAppendResult executeFileAppendRequestTransaction(FileAppendRequest request) throws HederaException { + Objects.requireNonNull(request, "request must not be null"); + Objects.requireNonNull(request.contents(), "content must not be null"); + if(request.contents().length > FileCreateRequest.FILE_CREATE_MAX_SIZE) { + throw new HederaException("File contents of 1 transaction must be less than " + FileCreateRequest.FILE_CREATE_MAX_SIZE + " bytes. Use multiple FileAppend for larger files."); + } final FileAppendTransaction transaction = new FileAppendTransaction() .setFileId(request.fileId()) .setContents(request.contents()) diff --git a/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileContentsResponse.java b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileContentsResponse.java index fe9bf4e8..25c6c8ae 100644 --- a/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileContentsResponse.java +++ b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileContentsResponse.java @@ -1,4 +1,6 @@ package com.openelements.hedera.base.protocol; -public record FileContentsResponse(byte[] contents) { +import com.hedera.hashgraph.sdk.FileId; + +public record FileContentsResponse(FileId fileId, byte[] contents) { } diff --git a/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileCreateRequest.java b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileCreateRequest.java index 58ce565b..024cfaa7 100644 --- a/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileCreateRequest.java +++ b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileCreateRequest.java @@ -2,26 +2,35 @@ import com.hedera.hashgraph.sdk.Hbar; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; import java.time.Duration; +import java.time.Instant; import java.util.Objects; public record FileCreateRequest(Hbar maxTransactionFee, Duration transactionValidDuration, @NonNull byte[] contents, + @Nullable Instant expirationTime, String fileMemo) implements TransactionRequest { private static final String DEFAULT_FILE_MEMO = ""; - public static final int FILE_CREATE_MAX_BYTES = 2048; + public static final int FILE_CREATE_MAX_SIZE = 2048; + + public static final int FILE_MAX_SIZE = 1_024_000; public FileCreateRequest { Objects.requireNonNull(contents, "File contents are required"); - if (contents.length > FILE_CREATE_MAX_BYTES) { - throw new IllegalArgumentException("File contents must be less than " + FILE_CREATE_MAX_BYTES + " bytes"); + if (contents.length > FILE_CREATE_MAX_SIZE) { + throw new IllegalArgumentException("File contents must be less than " + FILE_CREATE_MAX_SIZE + " bytes"); } } public static FileCreateRequest of(@NonNull byte[] contents) { - return new FileCreateRequest(DEFAULT_MAX_TRANSACTION_FEE, DEFAULT_TRANSACTION_VALID_DURATION, contents, DEFAULT_FILE_MEMO); + return new FileCreateRequest(DEFAULT_MAX_TRANSACTION_FEE, DEFAULT_TRANSACTION_VALID_DURATION, contents, null, DEFAULT_FILE_MEMO); + } + + public static FileCreateRequest of(@NonNull byte[] contents, @NonNull Instant expirationTime) { + return new FileCreateRequest(DEFAULT_MAX_TRANSACTION_FEE, DEFAULT_TRANSACTION_VALID_DURATION, contents, expirationTime, DEFAULT_FILE_MEMO); } } diff --git a/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileInfoRequest.java b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileInfoRequest.java new file mode 100644 index 00000000..2aacf590 --- /dev/null +++ b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileInfoRequest.java @@ -0,0 +1,35 @@ +package com.openelements.hedera.base.protocol; + +import com.hedera.hashgraph.sdk.FileId; +import com.hedera.hashgraph.sdk.Hbar; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Objects; + +public record FileInfoRequest(@NonNull FileId fileId, @Nullable Hbar queryPayment, @Nullable Hbar maxQueryPayment) implements QueryRequest { + + public FileInfoRequest { + Objects.requireNonNull(fileId, "fileId must not be null"); + } + + @NonNull + public static FileInfoRequest of(@NonNull String fileId) { + Objects.requireNonNull(fileId, "fileId must not be null"); + return of(FileId.fromString(fileId)); + } + + @NonNull + public static FileInfoRequest of(@NonNull FileId fileId) { + return new FileInfoRequest(fileId, null, null); + } + + @Override + public Hbar queryPayment() { + return queryPayment; + } + + @Override + public Hbar maxQueryPayment() { + return maxQueryPayment; + } +} diff --git a/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileInfoResponse.java b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileInfoResponse.java new file mode 100644 index 00000000..299099e3 --- /dev/null +++ b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileInfoResponse.java @@ -0,0 +1,7 @@ +package com.openelements.hedera.base.protocol; + +import com.hedera.hashgraph.sdk.FileId; +import java.time.Instant; + +public record FileInfoResponse(FileId fileId, int size, boolean deleted, Instant expirationTime){ +} diff --git a/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileUpdateRequest.java b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileUpdateRequest.java new file mode 100644 index 00000000..f7cb835b --- /dev/null +++ b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileUpdateRequest.java @@ -0,0 +1,39 @@ +package com.openelements.hedera.base.protocol; + +import com.hedera.hashgraph.sdk.FileId; +import com.hedera.hashgraph.sdk.Hbar; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.time.Duration; +import java.time.Instant; +import java.util.Objects; + +public record FileUpdateRequest(Hbar maxTransactionFee, + + Duration transactionValidDuration, + + FileId fileId, + + @Nullable byte[] contents, + + @Nullable Instant expirationTime, + String fileMemo) implements TransactionRequest { + + private static final String DEFAULT_FILE_MEMO = ""; + + public static final int FILE_CREATE_MAX_BYTES = 2048; + + public FileUpdateRequest { + if (contents != null && contents.length > FILE_CREATE_MAX_BYTES) { + throw new IllegalArgumentException("File contents must be less than " + FILE_CREATE_MAX_BYTES + " bytes"); + } + } + + public static FileUpdateRequest of(@NonNull FileId fileId, @NonNull byte[] contents) { + return new FileUpdateRequest(DEFAULT_MAX_TRANSACTION_FEE, DEFAULT_TRANSACTION_VALID_DURATION, fileId, contents, null, DEFAULT_FILE_MEMO); + } + + public static FileUpdateRequest of(@NonNull FileId fileId, @NonNull Instant expirationTime) { + return new FileUpdateRequest(DEFAULT_MAX_TRANSACTION_FEE, DEFAULT_TRANSACTION_VALID_DURATION, fileId, null, expirationTime, DEFAULT_FILE_MEMO); + } +} diff --git a/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileUpdateResult.java b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileUpdateResult.java new file mode 100644 index 00000000..ba2ae0e1 --- /dev/null +++ b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/FileUpdateResult.java @@ -0,0 +1,9 @@ +package com.openelements.hedera.base.protocol; + +import com.hedera.hashgraph.sdk.FileId; +import com.hedera.hashgraph.sdk.Status; +import com.hedera.hashgraph.sdk.TransactionId; + +public record FileUpdateResult(TransactionId transactionId, Status status) implements TransactionResult{ + +} diff --git a/hedera-base/src/main/java/com/openelements/hedera/base/protocol/ProtocolLayerClient.java b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/ProtocolLayerClient.java index df9f4503..236f7e09 100644 --- a/hedera-base/src/main/java/com/openelements/hedera/base/protocol/ProtocolLayerClient.java +++ b/hedera-base/src/main/java/com/openelements/hedera/base/protocol/ProtocolLayerClient.java @@ -11,6 +11,7 @@ public interface ProtocolLayerClient { /** * Execute an account balance query. + * * @param request the request * @return the response * @throws HederaException if the query could not be executed @@ -20,6 +21,7 @@ public interface ProtocolLayerClient { /** * Execute a file contents query. + * * @param request the request * @return the response * @throws HederaException if the query could not be executed @@ -29,6 +31,7 @@ public interface ProtocolLayerClient { /** * Execute a file append transaction. + * * @param request the request * @return the result * @throws HederaException if the transaction could not be executed @@ -38,6 +41,7 @@ public interface ProtocolLayerClient { /** * Execute a file delete transaction. + * * @param request the request * @return the result * @throws HederaException if the transaction could not be executed @@ -47,6 +51,7 @@ public interface ProtocolLayerClient { /** * Execute a file create transaction. + * * @param request the request * @return the result * @throws HederaException if the transaction could not be executed @@ -54,17 +59,22 @@ public interface ProtocolLayerClient { @NonNull FileCreateResult executeFileCreateTransaction(@NonNull FileCreateRequest request) throws HederaException; + FileUpdateResult executeFileUpdateRequestTransaction(FileUpdateRequest request) throws HederaException; + /** * Execute a contract create transaction. + * * @param request the request * @return the result * @throws HederaException if the transaction could not be executed */ @NonNull - ContractCreateResult executeContractCreateTransaction(@NonNull ContractCreateRequest request) throws HederaException; + ContractCreateResult executeContractCreateTransaction(@NonNull ContractCreateRequest request) + throws HederaException; /** * Execute a contract call transaction. + * * @param request the request * @return the result * @throws HederaException if the transaction could not be executed @@ -72,4 +82,5 @@ public interface ProtocolLayerClient { @NonNull ContractCallResult executeContractCallTransaction(@NonNull ContractCallRequest request) throws HederaException; + public FileInfoResponse executeFileInfoQuery(FileInfoRequest request) throws HederaException; } diff --git a/spring-hedera/src/test/java/com/openelements/hedera/spring/test/FileClientTests.java b/spring-hedera/src/test/java/com/openelements/hedera/spring/test/FileClientTests.java index 0007e14e..8a3210d0 100644 --- a/spring-hedera/src/test/java/com/openelements/hedera/spring/test/FileClientTests.java +++ b/spring-hedera/src/test/java/com/openelements/hedera/spring/test/FileClientTests.java @@ -3,6 +3,10 @@ import com.hedera.hashgraph.sdk.FileId; import com.openelements.hedera.base.FileClient; import com.openelements.hedera.base.HederaException; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAmount; import java.util.stream.IntStream; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -115,6 +119,21 @@ void testDeleteFileByFileId() throws Exception { Assertions.assertDoesNotThrow(() -> fileClient.deleteFile(fileId)); } + @Test + void testUpdateFileByFileId() throws Exception { + //given + final byte[] contents = "Hello, Hedera!".getBytes(); + final FileId fileId = fileClient.createFile(contents); + final String newContent = "Hello, Hedera! Updated"; + + //when + fileClient.updateFile(fileId, newContent.getBytes()); + + //then + final byte[] readContents = fileClient.readFile(fileId); + Assertions.assertArrayEquals(newContent.getBytes(), readContents); + } + @Test void testDeleteFileByStringId() throws Exception { //given @@ -151,4 +170,64 @@ void testDeleteNotExistingFile() throws Exception { //when Assertions.assertThrows(HederaException.class, () -> fileClient.deleteFile(fileId)); } + + @Test + void testDeleteState() throws Exception { + //given + final byte[] contents = "Hello, Hedera!".getBytes(); + final FileId fileId = fileClient.createFile(contents); + fileClient.deleteFile(fileId); + + //when + final boolean deleted = fileClient.isDeleted(fileId); + + //when + Assertions.assertTrue(deleted); + } + + @Test + void testGetExpirationTime() throws Exception { + //given + final byte[] contents = "Hello, Hedera!".getBytes(); + final Instant definedExpirationTime = Instant.now().plus(Duration.ofDays(2)); + final FileId fileId = fileClient.createFile(contents, definedExpirationTime); + + //when + final Instant expirationTime = fileClient.getExpirationTime(fileId); + + //then + Assertions.assertTrue(expirationTime.isAfter(definedExpirationTime.minusSeconds(1))); + Assertions.assertTrue(expirationTime.isBefore(definedExpirationTime.plusSeconds(1))); + } + + @Test + void testUpdateExpirationTime() throws Exception { + //given + final byte[] contents = "Hello, Hedera!".getBytes(); + final Instant definedExpirationTime = Instant.now().plus(Duration.of(20, ChronoUnit.MINUTES)); + final FileId fileId = fileClient.createFile(contents); + fileClient.updateExpirationTime(fileId, definedExpirationTime); + + //when + final Instant expirationTime = fileClient.getExpirationTime(fileId); + + //then + Assertions.assertTrue(expirationTime.isAfter(definedExpirationTime.minusSeconds(1))); + Assertions.assertTrue(expirationTime.isBefore(definedExpirationTime.plusSeconds(1))); + } + + @Test + void testUpdateExpirationTimeDoesNotChangeContent() throws Exception { + //given + final byte[] contents = "Hello, Hedera!".getBytes(); + final Instant definedExpirationTime = Instant.now().plus(Duration.of(20, ChronoUnit.MINUTES)); + final FileId fileId = fileClient.createFile(contents); + fileClient.updateExpirationTime(fileId, definedExpirationTime); + + + final byte[] result = fileClient.readFile(fileId); + + //then + Assertions.assertArrayEquals(contents, result); + } } diff --git a/spring-hedera/src/test/java/com/openelements/hedera/spring/test/ProtocolLayerClientTests.java b/spring-hedera/src/test/java/com/openelements/hedera/spring/test/ProtocolLayerClientTests.java index 3aab824a..11a351a2 100644 --- a/spring-hedera/src/test/java/com/openelements/hedera/spring/test/ProtocolLayerClientTests.java +++ b/spring-hedera/src/test/java/com/openelements/hedera/spring/test/ProtocolLayerClientTests.java @@ -6,13 +6,18 @@ import com.openelements.hedera.base.protocol.AccountBalanceResponse; import com.openelements.hedera.base.protocol.ContractCreateRequest; import com.openelements.hedera.base.protocol.ContractCreateResult; +import com.openelements.hedera.base.protocol.FileAppendRequest; import com.openelements.hedera.base.protocol.FileContentsRequest; import com.openelements.hedera.base.protocol.FileContentsResponse; import com.openelements.hedera.base.protocol.FileCreateRequest; import com.openelements.hedera.base.protocol.FileCreateResult; import com.openelements.hedera.base.protocol.FileDeleteRequest; import com.openelements.hedera.base.protocol.FileDeleteResult; +import com.openelements.hedera.base.protocol.FileInfoRequest; +import com.openelements.hedera.base.protocol.FileInfoResponse; +import com.openelements.hedera.base.protocol.FileUpdateRequest; import com.openelements.hedera.base.protocol.ProtocolLayerClient; +import java.io.File; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -80,6 +85,23 @@ void testFileContents() throws Exception { Assertions.assertArrayEquals(contents, fileContentsResponse.contents()); } + @Test + void testFileInfo() throws Exception { + //given + final byte[] contents = "Hello, Hedera!".getBytes(); + final FileCreateRequest request = FileCreateRequest.of(contents); + final FileCreateResult result = protocolLayerClient.executeFileCreateTransaction(request); + final FileId fileId = result.fileId(); + final FileInfoRequest infoRequest = FileInfoRequest.of(fileId); + + //when + final FileInfoResponse infoResponse = protocolLayerClient.executeFileInfoQuery(infoRequest); + + //then + Assertions.assertNotNull(infoResponse); + Assertions.assertEquals(contents.length, infoResponse.size()); + } + @Test void testFileDelete() throws Exception { //given @@ -94,6 +116,8 @@ void testFileDelete() throws Exception { //then Assertions.assertNotNull(deleteResponse); + Assertions.assertEquals(Status.SUCCESS, deleteResponse.status()); + Assertions.assertNotNull(deleteResponse.transactionId()); } @Test @@ -112,6 +136,32 @@ void testContractCreate() throws Exception { //then Assertions.assertNotNull(contractCreateResult); + Assertions.assertEquals(Status.SUCCESS, contractCreateResult.status()); Assertions.assertNotNull(contractCreateResult.transactionId()); + Assertions.assertNotNull(contractCreateResult.contractId()); + } + + @Test + void testTooLargeFile() { + //given + final byte[] contents = new byte[FileCreateRequest.FILE_MAX_SIZE + 1]; + final FileId fakeId = FileId.fromString("1.2.3"); + + //then + Assertions.assertThrows(IllegalArgumentException.class, () -> protocolLayerClient.executeFileCreateTransaction(FileCreateRequest.of(contents))); + Assertions.assertThrows(IllegalArgumentException.class, () -> protocolLayerClient.executeFileAppendRequestTransaction(FileAppendRequest.of(fakeId, contents))); + Assertions.assertThrows(IllegalArgumentException.class, () -> protocolLayerClient.executeFileUpdateRequestTransaction(FileUpdateRequest.of(fakeId, contents))); + } + + @Test + void testTooLargeFileForOneTransaction() { + //given + final byte[] contents = new byte[FileCreateRequest.FILE_CREATE_MAX_SIZE + 1]; + final FileId fakeId = FileId.fromString("1.2.3"); + + //then + Assertions.assertThrows(IllegalArgumentException.class, () -> protocolLayerClient.executeFileCreateTransaction(FileCreateRequest.of(contents))); + Assertions.assertThrows(IllegalArgumentException.class, () -> protocolLayerClient.executeFileAppendRequestTransaction(FileAppendRequest.of(fakeId, contents))); + Assertions.assertThrows(IllegalArgumentException.class, () -> protocolLayerClient.executeFileUpdateRequestTransaction(FileUpdateRequest.of(fakeId, contents))); } }