-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement unexpectlengthexception in azure core #5108
Conversation
…into unexpectedException
sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java
Outdated
Show resolved
Hide resolved
.../azure-core/src/main/java/com/azure/core/implementation/annotation/ServiceClientBuilder.java
Outdated
Show resolved
Hide resolved
…into unexpectedException
Could you turn on the unit tests in Blobs that use UnexpectedLengthException and make sure those pass with this change. |
|
||
<testResources> | ||
<testResource> | ||
<directory>${basedir}/src/test/resources</directory> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this doing? I'm not super familiar with maven, but we don't have this in the blob pom even though we have the same folders in that project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is how groovy use the test resource folder. I did not see any file operation in blob. @alzimmermsft do you know how you do this in blob groovy test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blobs doesn't use any file resources as part of testing, aside from the session-records which the playback framework handles the logic for that. Blobs generates and tears down file creation for the tests that need it.
@@ -18,12 +21,14 @@ import com.azure.storage.file.ShareClientBuilder | |||
import com.azure.storage.file.models.ListSharesOptions | |||
import spock.lang.Specification | |||
|
|||
import java.util.function.Supplier |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are all these imports added when all you did is remove a line?
@@ -195,6 +191,23 @@ class FileAPITests extends APISpec { | |||
FileTestHelper.assertExceptionStatusCodeAndMessage(e, 416, StorageErrorCode.INVALID_RANGE) | |||
} | |||
|
|||
@Unroll | |||
def "Upload data length mismatch"() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can you put a blank line before each block label so it's easier to read?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! A little annoying if I have this in this PR. Will do in the issue.
#5066
where: | ||
size | errMsg | ||
6 | "more bytes than" | ||
8 | "less bytes than" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: align.
@@ -141,6 +142,26 @@ class FileAsyncAPITests extends APISpec { | |||
defaultData.clear() | |||
} | |||
|
|||
@Unroll | |||
def "Upload data length mismatch"() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comments as on the sync test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
File downloadFile = new File(testFolder.getPath() + "/testDownload") | ||
def testFolder = getClass().getClassLoader().getResource("testfiles") | ||
File uploadFile = new File(testFolder.getPath(), "/helloworld") | ||
File downloadFile = new File(testFolder.getPath(), "/testDownload") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Here you use "/helloworld"
and in the sync tests you use "helloworld"
. They should both be the same but we may as well be consistent. Since the second argument is meant to be the file name, I'd say remove the slash here.
@@ -202,10 +204,15 @@ class FileTestHelper { | |||
|
|||
static String createRandomFileWithLength(int size, String folder, String fileName) { | |||
def path = Paths.get(folder) | |||
if (path == null) { | |||
logger.logExceptionAsError("The folder path does not exist.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can't work. The method accepts a RuntimeException and you pass it a string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Fixed
@@ -202,10 +204,15 @@ class FileTestHelper { | |||
|
|||
static String createRandomFileWithLength(int size, String folder, String fileName) { | |||
def path = Paths.get(folder) | |||
if (path == null) { | |||
logger.logExceptionAsError("The folder path does not exist.") | |||
return null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we fail to make a file, I'd rather throw with a useful message instead of getting a null ref exception later in the test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed and throw
sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java
Outdated
Show resolved
Hide resolved
sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java
Outdated
Show resolved
Hide resolved
...torage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceClientBuilder.java
Outdated
Show resolved
Hide resolved
sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/AppendBlobAPITest.groovy
Outdated
Show resolved
Hide resolved
sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/Utility.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple reversions to make and a question that may involve moving some stuff.
@@ -325,6 +325,8 @@ class AppendBlobAPITest extends APISpec { | |||
ByteArrayOutputStream downloadStream = new ByteArrayOutputStream(1024) | |||
destURL.download(downloadStream) | |||
downloadStream.toByteArray() == Arrays.copyOfRange(data, 2 * 1024, 3 * 1024) | |||
cleanup: | |||
defaultInputStream.get().reset() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defaultInputStream
is a Supplier<InputStream>
that news up a stream of the bytes of a preset string and just gives us that. These cleanup blocks are just getting a brand new stream only to call reset()
and discard the reference for the GC to pick up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert it back.
@@ -50,7 +51,7 @@ class BlobAPITest extends APISpec { | |||
HttpHeaders headers = response.headers() | |||
|
|||
then: | |||
body == defaultData | |||
defaultData.compareTo(body) == 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was already idiomatic to groovy. ==
checks to see if Comparable
is implemented and calls objA.compareTo(objB) == 0
if so. Otherwise, it calls objA.equals(objB)
.
(future reference: if you want to compare reference equality in groovy, you write objA.is(objB)
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert the changes back. Thanks for the info!
* @throws UnexpectedLengthException when input data length mismatch input length. | ||
* @throws RuntimeException When I/O error occurs. | ||
*/ | ||
public static Flux<ByteBuffer> convertStreamToByteBuffer(InputStream data, long length, int blockSize) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this is a common enough case that this should be in core? We can't be the only library moving data and need to do this conversion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will discuss with @JonathanGiles if we can put up the helper method in Azure core. Leave it here right now as only storage has this kind of needs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double check the Utility methods. There are bunch a few which do not specific to storage. We can several of them into Azure core based on the needs of other clients. It is better to limit the scope of the utility to storage before preview 3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just re-run the failed test step, MacOS has a transient test failure due to timing issues.
@@ -159,24 +161,14 @@ public AppendBlobItem appendBlock(InputStream data, long length) { | |||
* @param context Additional context that is passed through the Http pipeline during the service call. | |||
* | |||
* @return A {@link Response} whose {@link Response#value() value} contains the append blob operation. | |||
* @throws UnexpectedLengthException when the length of data does not match the input {@code length}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You cannot throw UnexpectedLengthException here as it is not public API. You either need to make it public API, or not throw it from public API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put the exception in public exception folder
|
||
return Flux.defer(() -> { | ||
Long expectedLength = Long.valueOf(request.headers().value("Content-Length")); | ||
final long[] currentTotalLength = new long[1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess what we're doing here is correct. I asked the question in SOF and got a response from David (the main contributor of rx) - https://stackoverflow.com/questions/57776012/mutating-array-elements-in-reactive-publisher-onnext-doonnext-methods/
The last thing to rule out is whether to use volatile keyword to ensure immediate update visibility across thread, waiting for his response.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we're good, David confirmed that framework takes care of memory visibility, no need for volatile. https://stackoverflow.com/questions/57776012/mutating-array-elements-in-reactive-publisher-onnext-doonnext-methods/57786588?noredirect=1#comment102032427_57786588
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Anu for taking care of this! Learned a lot from the thread.
return ByteBuffer.wrap(cache); | ||
})); | ||
Objects.requireNonNull(body); | ||
long length = pageRange.end() - pageRange.start() + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: final modifier for unmodifiable variable.
…into unexpectedException
…into unexpectedException
Make changes in azure core. Added tests in storage.
Will make up more tests in azure core unit tests.