Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit ecbb2b8

Browse files
author
jofriedm-msft
authored
Merge branch 'dev' into fileencryption
2 parents 6dea7a9 + 2c63650 commit ecbb2b8

31 files changed

+1377
-138
lines changed

ChangeLog.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
1-
2017.XX.XX Version X.X.0
1+
2017.XX.XX Version X.X.X
2+
* Added ErrorReceivingResponseEvent which fires when a network error occurs before the responseReceivedEvent fires. If the responseReceivedEvent fires sucessfully, this new event will not fire.
3+
* For Premium Accounts only, added support for getting and setting the tier on a page blob. The tier can also be set when creating or copying from an existing page blob.
24
* Added support for server side encryption for File Service.
5+
6+
2017.06.21 Version 5.3.1
7+
* Fixed a bug in specific upload case for block blobs. This only affects uploads greater than the max put blob threshold, that have increased the streamWriteSizeInBytes beyond the 4 MB and storeBlobContentMD5 has been disabled.
8+
* In some cases in the above mentioned upload path, fixed a bug where StorageExceptions were being thrown instead of IOExceptions.
9+
10+
2017.06.13 Version 5.3.0
11+
* Fixed a bug where the transactional MD5 check would fail when downloading a range of blob or file and the recovery action is performed on a subsection of the range.
12+
* Fixed leaking connections for table requests.
13+
* Fixed a bug where retries happened immediately when experiencing a network exception uploading data or getting the response.
14+
* Fixed a bug where the response stream was not being closed on nonretryable exceptions.
15+
316
2017.05.23 Version 5.2.0
417
* Fixed Exists() calls on Shares and Directories to now populate metadata. This was already being done for Files.
518
* Changed blob constants to support up to 256 MB on put blob for block blobs. The default value for put blob threshold has also been updated to half of the maximum, or 128 MB currently.

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ To get the binaries of this library as distributed by Microsoft, ready for use w
3030
<dependency>
3131
<groupId>com.microsoft.azure</groupId>
3232
<artifactId>azure-storage</artifactId>
33-
<version>5.2.0</version>
33+
<version>5.3.1</version>
3434
</dependency>
3535
```
3636

@@ -127,6 +127,8 @@ If you would like to become an active contributor to this project please follow
127127

128128
If you encounter any bugs with the library please file an issue in the [Issues](https://github.com/Azure/azure-storage-java/issues) section of the project.
129129

130+
When sending pull requests, please send non-breaking PRs to the dev branch and breaking changes to the dev_breaking branch. Do not make PRs against master.
131+
130132
# Learn More
131133

132134
* [Azure Developer Center](http://azure.microsoft.com/en-us/develop/java/)

microsoft-azure-storage-samples/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<dependency>
2727
<groupId>com.microsoft.azure</groupId>
2828
<artifactId>azure-storage</artifactId>
29-
<version>5.2.0</version>
29+
<version>5.3.1</version>
3030
</dependency>
3131
<dependency>
3232
<groupId>com.microsoft.azure</groupId>

microsoft-azure-storage-test/res/TestConfigurations.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<TestConfigurations>
22
<TargetTestTenant>ProductionTenant</TargetTestTenant>
3+
<TargetPremiumBlobTenant>ProductionTenant</TargetPremiumBlobTenant>
34
<TenantConfigurations>
45
<TenantConfiguration>
56
<TenantName>DevStore</TenantName>

microsoft-azure-storage-test/src/com/microsoft/azure/storage/EventFiringTests.java

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,20 @@
1414
*/
1515
package com.microsoft.azure.storage;
1616

17-
import com.microsoft.azure.storage.blob.BlobRequestOptions;
18-
import com.microsoft.azure.storage.blob.CloudBlobClient;
19-
import com.microsoft.azure.storage.blob.CloudBlobContainer;
17+
import com.microsoft.azure.storage.blob.*;
2018
import com.microsoft.azure.storage.core.SR;
2119
import com.microsoft.azure.storage.TestRunners.CloudTests;
2220
import com.microsoft.azure.storage.TestRunners.DevFabricTests;
2321
import com.microsoft.azure.storage.TestRunners.DevStoreTests;
2422

23+
import org.apache.http.protocol.HTTP;
2524
import org.junit.Test;
2625
import org.junit.experimental.categories.Category;
2726

27+
import java.io.ByteArrayInputStream;
28+
import java.io.IOException;
2829
import java.net.HttpURLConnection;
30+
import java.net.SocketException;
2931
import java.net.URISyntaxException;
3032
import java.util.ArrayList;
3133

@@ -111,6 +113,22 @@ public void eventOccurred(ResponseReceivedEvent eventArg) {
111113
}
112114
});
113115

116+
eventContext.getErrorReceivingResponseEventHandler().addListener(new StorageEvent<ErrorReceivingResponseEvent>() {
117+
118+
@Override
119+
public void eventOccurred(ErrorReceivingResponseEvent eventArg) {
120+
fail("This event should not trigger");
121+
}
122+
});
123+
124+
OperationContext.getGlobalErrorReceivingResponseEventHandler().addListener(new StorageEvent<ErrorReceivingResponseEvent>() {
125+
126+
@Override
127+
public void eventOccurred(ErrorReceivingResponseEvent eventArg) {
128+
fail("This event should not trigger");
129+
}
130+
});
131+
114132
assertEquals(0, callList.size());
115133
assertEquals(0, globalCallList.size());
116134

@@ -138,6 +156,85 @@ public void eventOccurred(ResponseReceivedEvent eventArg) {
138156
assertEquals(2, globalCallList.size());
139157
}
140158

159+
@Test
160+
public void testErrorReceivingResponseEvent() throws URISyntaxException, StorageException {
161+
final ArrayList<Boolean> callList = new ArrayList<Boolean>();
162+
final ArrayList<Boolean> globalCallList = new ArrayList<Boolean>();
163+
164+
OperationContext eventContext = new OperationContext();
165+
BlobRequestOptions options = new BlobRequestOptions();
166+
options.setRetryPolicyFactory(new RetryNoRetry());
167+
168+
// setting the sending request event handler to trigger an exception.
169+
// this is a retryable exception
170+
eventContext.getSendingRequestEventHandler().addListener(new StorageEvent<SendingRequestEvent>() {
171+
@Override
172+
public void eventOccurred(SendingRequestEvent eventArg) {
173+
HttpURLConnection connection = (HttpURLConnection) eventArg.getConnectionObject();
174+
connection.setFixedLengthStreamingMode(0);
175+
}
176+
});
177+
178+
eventContext.getErrorReceivingResponseEventHandler().addListener(new StorageEvent<ErrorReceivingResponseEvent>() {
179+
@Override
180+
public void eventOccurred(ErrorReceivingResponseEvent eventArg) {
181+
assertEquals(eventArg.getRequestResult(), eventArg.getOpContext().getLastResult());
182+
callList.add(true);
183+
}
184+
});
185+
186+
OperationContext.getGlobalErrorReceivingResponseEventHandler().addListener(new StorageEvent<ErrorReceivingResponseEvent>() {
187+
@Override
188+
public void eventOccurred(ErrorReceivingResponseEvent eventArg) {
189+
assertEquals(eventArg.getRequestResult(), eventArg.getOpContext().getLastResult());
190+
globalCallList.add(true);
191+
}
192+
});
193+
194+
CloudBlobClient blobClient = TestHelper.createCloudBlobClient();
195+
CloudBlobContainer container = blobClient.getContainerReference("container1");
196+
container.createIfNotExists();
197+
198+
try {
199+
CloudBlockBlob blob1 = container.getBlockBlobReference("blob1");
200+
try {
201+
String blockID = String.format("%08d", 1);
202+
blob1.uploadBlock(blockID, BlobTestHelper.getRandomDataStream(10), 10, null, options, eventContext);
203+
} catch (Exception e) { }
204+
205+
// make sure both the local and globab context update
206+
assertEquals(1, callList.size());
207+
assertEquals(1, globalCallList.size());
208+
209+
// make sure only global updates by replacing the local with a no-op event
210+
eventContext
211+
.setErrorReceivingResponseEventHandler(new StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>>());
212+
try {
213+
String blockID2 = String.format("%08d", 2);
214+
blob1.uploadBlock(blockID2, BlobTestHelper.getRandomDataStream(10), 10, null, options, eventContext);
215+
} catch (Exception e) { }
216+
217+
assertEquals(1, callList.size());
218+
assertEquals(2, globalCallList.size());
219+
220+
// make sure global does not update by replacing the global with a no-op
221+
OperationContext
222+
.setGlobalErrorReceivingResponseEventHandler(new StorageEventMultiCaster<ErrorReceivingResponseEvent, StorageEvent<ErrorReceivingResponseEvent>>());
223+
224+
// make sure neither update
225+
try {
226+
String blockID3 = String.format("%08d", 3);
227+
blob1.uploadBlock(blockID3, BlobTestHelper.getRandomDataStream(10), 10, null, options, eventContext);
228+
} catch (Exception e) { }
229+
230+
assertEquals(1, callList.size());
231+
assertEquals(2, globalCallList.size());
232+
}
233+
finally {
234+
container.deleteIfExists();
235+
}
236+
}
237+
141238
@Test
142239
public void testRequestCompletedEvents() throws URISyntaxException, StorageException {
143240
final ArrayList<Boolean> callList = new ArrayList<Boolean>();

microsoft-azure-storage-test/src/com/microsoft/azure/storage/TestHelper.java

Lines changed: 105 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package com.microsoft.azure.storage;
1616

1717
import static org.junit.Assert.*;
18+
import static org.junit.Assume.assumeNotNull;
1819

1920
import java.io.ByteArrayInputStream;
2021
import java.io.File;
@@ -39,6 +40,7 @@
3940
import javax.xml.parsers.DocumentBuilderFactory;
4041
import javax.xml.parsers.ParserConfigurationException;
4142

43+
import org.junit.AssumptionViolatedException;
4244
import org.w3c.dom.DOMException;
4345
import org.w3c.dom.Document;
4446
import org.w3c.dom.Node;
@@ -58,6 +60,9 @@ public class TestHelper {
5860
private static Tenant tenant;
5961
private static StorageCredentialsAccountAndKey credentials;
6062
private static CloudStorageAccount account;
63+
private static Tenant premiumBlobTenant;
64+
private static StorageCredentialsAccountAndKey premiumBlobCredentials;
65+
private static CloudStorageAccount premiumBlobAccount;
6166

6267
private final static boolean enableFiddler = true;
6368
private final static boolean requireSecondaryEndpoint = false;
@@ -67,6 +72,11 @@ public static CloudBlobClient createCloudBlobClient() throws StorageException {
6772
return client;
6873
}
6974

75+
public static CloudBlobClient createPremiumCloudBlobClient() throws StorageException {
76+
CloudBlobClient client = getPremiumBlobAccount().createCloudBlobClient();
77+
return client;
78+
}
79+
7080
public static CloudBlobClient createCloudBlobClient(SharedAccessAccountPolicy policy, boolean useHttps)
7181
throws StorageException, InvalidKeyException, URISyntaxException {
7282

@@ -328,12 +338,12 @@ private static CloudStorageAccount getAccount() throws StorageException {
328338
account = CloudStorageAccount.parse(cloudAccount);
329339
}
330340
else if (accountConfig != null) {
331-
tenant = readTestConfigsFromXml(new File(accountConfig));
341+
readTestConfigsFromXml(new File(accountConfig), false);
332342
setAccountAndCredentials();
333343
}
334344
else {
335345
URL localTestConfig = TestHelper.class.getClassLoader().getResource("TestConfigurations.xml");
336-
tenant = readTestConfigsFromXml(new File(localTestConfig.getPath()));
346+
readTestConfigsFromXml(new File(localTestConfig.getPath()), false);
337347
setAccountAndCredentials();
338348
}
339349
}
@@ -344,6 +354,47 @@ else if (accountConfig != null) {
344354
return account;
345355
}
346356

357+
private static CloudStorageAccount getPremiumBlobAccount() throws StorageException {
358+
// Only do this the first time TestBase is called as storage account is static
359+
if (premiumBlobAccount == null) {
360+
//enable fiddler
361+
if (enableFiddler)
362+
enableFiddler();
363+
364+
// try to get the environment variable with the test configuration file path
365+
String accountConfig;
366+
try {
367+
accountConfig = System.getenv("storageTestConfiguration");
368+
}
369+
catch (SecurityException e) {
370+
accountConfig = null;
371+
}
372+
373+
// if storageConnection is set, use that as an account string
374+
// if storageTestConfiguration is set, use that as a path to the configurations file
375+
// if neither are set, use the local configurations file at TestConfigurations.xml
376+
try {
377+
if (accountConfig != null) {
378+
readTestConfigsFromXml(new File(accountConfig), true);
379+
setAccountAndCredentials();
380+
}
381+
else {
382+
URL localTestConfig = TestHelper.class.getClassLoader().getResource("TestConfigurations.xml");
383+
readTestConfigsFromXml(new File(localTestConfig.getPath()), true);
384+
setAccountAndCredentials();
385+
}
386+
}
387+
catch (AssumptionViolatedException e) {
388+
throw e;
389+
}
390+
catch (Exception e) {
391+
throw StorageException.translateClientException(e);
392+
}
393+
}
394+
395+
return premiumBlobAccount;
396+
}
397+
347398
private static void setAccountAndCredentials() {
348399
if (requireSecondaryEndpoint)
349400
tenant.assertSecondaryEndpoint();
@@ -353,9 +404,17 @@ private static void setAccountAndCredentials() {
353404
tenant.getQueueServiceSecondaryEndpoint()), new StorageUri(tenant.getTableServiceEndpoint(),
354405
tenant.getTableServiceSecondaryEndpoint()), new StorageUri(tenant.getFileServiceEndpoint(),
355406
tenant.getFileServiceSecondaryEndpoint()));
407+
408+
if (premiumBlobTenant != null) {
409+
premiumBlobCredentials = new StorageCredentialsAccountAndKey(premiumBlobTenant.getAccountName(), premiumBlobTenant.getAccountKey());
410+
premiumBlobAccount = new CloudStorageAccount(premiumBlobCredentials, new StorageUri(premiumBlobTenant.getBlobServiceEndpoint(), premiumBlobTenant.getBlobServiceSecondaryEndpoint()),
411+
null,
412+
null,
413+
null);
414+
}
356415
}
357416

358-
private static Tenant readTestConfigsFromXml(File testConfigurations) throws ParserConfigurationException,
417+
private static void readTestConfigsFromXml(File testConfigurations, boolean premiumBlob) throws ParserConfigurationException,
359418
SAXException, IOException, DOMException, URISyntaxException {
360419

361420
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
@@ -372,7 +431,14 @@ private static Tenant readTestConfigsFromXml(File testConfigurations) throws Par
372431
throw new IllegalArgumentException("No TargetTestTenant specified.");
373432
}
374433

375-
Tenant tenant = null;
434+
Node premiumBlobTenantNode = testConfigs.getElementsByTagName("TargetPremiumBlobTenant").item(0);
435+
String premiumBlobTenantName = null;
436+
if (premiumBlobTenantNode != null) {
437+
premiumBlobTenantName = premiumBlobTenantNode.getTextContent();
438+
}
439+
440+
tenant = null;
441+
premiumBlobTenant = null;
376442
final NodeList tenantNodes = testConfigs.getElementsByTagName("TenantName");
377443
for (int i = 0; i < tenantNodes.getLength(); i++) {
378444
if (tenantNodes.item(i).getTextContent().equals(targetTenant)) {
@@ -436,18 +502,50 @@ else if (name.equals("TableHttpsPortOverride")) {
436502
else if (name.equals("FileHttpsPortOverride")) {
437503
tenant.setFileHttpsPortOverride(Integer.parseInt(node.getTextContent()));
438504
}
439-
else {
505+
else if (!premiumBlob){
440506
throw new IllegalArgumentException(String.format(
441507
"Invalid child of TenantConfiguration with name: %s", name));
442508
}
443509
}
444510
}
445511
}
512+
513+
if (tenantNodes.item(i).getTextContent().equals(premiumBlobTenantName)) {
514+
premiumBlobTenant = new Tenant();
515+
Node parent = tenantNodes.item(i).getParentNode();
516+
final NodeList childNodes = parent.getChildNodes();
517+
for (int j = 0; j < childNodes.getLength(); j++) {
518+
final Node node = childNodes.item(j);
519+
520+
if (node.getNodeType() != Node.ELEMENT_NODE) {
521+
// do nothing
522+
} else {
523+
final String name = node.getNodeName();
524+
525+
if (name.equals("TenantName")) {
526+
premiumBlobTenant.setTenantName(node.getTextContent());
527+
} else if (name.equals("TenantType")) {
528+
// do nothing, we don't track this field
529+
} else if (name.equals("AccountName")) {
530+
premiumBlobTenant.setAccountName(node.getTextContent());
531+
} else if (name.equals("AccountKey")) {
532+
premiumBlobTenant.setAccountKey(node.getTextContent());
533+
} else if (name.equals("BlobServiceEndpoint")) {
534+
premiumBlobTenant.setBlobServiceEndpoint(new URI(node.getTextContent()));
535+
} else if (name.equals("BlobServiceSecondaryEndpoint")) {
536+
premiumBlobTenant.setBlobServiceSecondaryEndpoint(new URI(node.getTextContent()));
537+
}
538+
}
539+
}
540+
}
446541
}
447542

448-
if (tenant == null) {
543+
if (tenant == null && !premiumBlob) {
449544
throw new IllegalArgumentException("TargetTestTenant specified did not exist in TenantConfigurations.");
450545
}
451-
return tenant;
546+
547+
if (premiumBlobTenant == null && premiumBlob) {
548+
assumeNotNull(premiumBlobTenant);
549+
}
452550
}
453551
}

0 commit comments

Comments
 (0)