Skip to content

Commit 4c331c5

Browse files
authored
[Storage] Make Specialized Blob Clients retrieval mockable. (#15105)
* Prepare Storage for release * pr feedback. * PR feedback. * pr feedback. * make open write work with using. * move recordings to right place * pr feedback. * make specialized clients retrieval mockable. * pr feedback. * export api. * record mode...
1 parent 7ad9435 commit 4c331c5

13 files changed

+192
-54
lines changed

sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,15 @@ public BlobContainerClient(System.Uri blobContainerUri, Azure.Storage.StorageSha
8888
public virtual System.Threading.Tasks.Task<Azure.Response<bool>> ExistsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
8989
public virtual Azure.Response<Azure.Storage.Blobs.Models.BlobContainerAccessPolicy> GetAccessPolicy(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9090
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Storage.Blobs.Models.BlobContainerAccessPolicy>> GetAccessPolicyAsync(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
91+
protected internal virtual Azure.Storage.Blobs.Specialized.AppendBlobClient GetAppendBlobClientCore(string blobName) { throw null; }
9192
public virtual Azure.Storage.Blobs.BlobClient GetBlobClient(string blobName) { throw null; }
93+
protected internal virtual Azure.Storage.Blobs.Specialized.BlobLeaseClient GetBlobLeaseClientCore(string leaseId) { throw null; }
9294
public virtual Azure.Pageable<Azure.Storage.Blobs.Models.BlobItem> GetBlobs(Azure.Storage.Blobs.Models.BlobTraits traits = Azure.Storage.Blobs.Models.BlobTraits.None, Azure.Storage.Blobs.Models.BlobStates states = Azure.Storage.Blobs.Models.BlobStates.None, string prefix = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9395
public virtual Azure.AsyncPageable<Azure.Storage.Blobs.Models.BlobItem> GetBlobsAsync(Azure.Storage.Blobs.Models.BlobTraits traits = Azure.Storage.Blobs.Models.BlobTraits.None, Azure.Storage.Blobs.Models.BlobStates states = Azure.Storage.Blobs.Models.BlobStates.None, string prefix = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9496
public virtual Azure.Pageable<Azure.Storage.Blobs.Models.BlobHierarchyItem> GetBlobsByHierarchy(Azure.Storage.Blobs.Models.BlobTraits traits = Azure.Storage.Blobs.Models.BlobTraits.None, Azure.Storage.Blobs.Models.BlobStates states = Azure.Storage.Blobs.Models.BlobStates.None, string delimiter = null, string prefix = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9597
public virtual Azure.AsyncPageable<Azure.Storage.Blobs.Models.BlobHierarchyItem> GetBlobsByHierarchyAsync(Azure.Storage.Blobs.Models.BlobTraits traits = Azure.Storage.Blobs.Models.BlobTraits.None, Azure.Storage.Blobs.Models.BlobStates states = Azure.Storage.Blobs.Models.BlobStates.None, string delimiter = null, string prefix = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
98+
protected internal virtual Azure.Storage.Blobs.Specialized.BlockBlobClient GetBlockBlobClientCore(string blobName) { throw null; }
99+
protected internal virtual Azure.Storage.Blobs.Specialized.PageBlobClient GetPageBlobClientCore(string blobName) { throw null; }
96100
public virtual Azure.Response<Azure.Storage.Blobs.Models.BlobContainerProperties> GetProperties(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
97101
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Storage.Blobs.Models.BlobContainerProperties>> GetPropertiesAsync(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
98102
public virtual Azure.Response<Azure.Storage.Blobs.Models.BlobContainerInfo> SetAccessPolicy(Azure.Storage.Blobs.Models.PublicAccessType accessType = Azure.Storage.Blobs.Models.PublicAccessType.None, System.Collections.Generic.IEnumerable<Azure.Storage.Blobs.Models.BlobSignedIdentifier> permissions = null, Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
@@ -1225,6 +1229,7 @@ public BlobBaseClient(System.Uri blobUri, Azure.Storage.StorageSharedKeyCredenti
12251229
public virtual System.Threading.Tasks.Task<Azure.Response> DownloadToAsync(string path, System.Threading.CancellationToken cancellationToken) { throw null; }
12261230
public virtual Azure.Response<bool> Exists(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
12271231
public virtual System.Threading.Tasks.Task<Azure.Response<bool>> ExistsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
1232+
protected internal virtual Azure.Storage.Blobs.Specialized.BlobLeaseClient GetBlobLeaseClientCore(string leaseId) { throw null; }
12281233
public virtual Azure.Response<Azure.Storage.Blobs.Models.BlobProperties> GetProperties(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
12291234
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Storage.Blobs.Models.BlobProperties>> GetPropertiesAsync(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
12301235
public virtual Azure.Response<Azure.Storage.Blobs.Models.GetBlobTagResult> GetTags(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }

sdk/storage/Azure.Storage.Blobs/src/AppendBlobClient.cs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,23 +1589,7 @@ public static AppendBlobClient GetAppendBlobClient(
15891589
this BlobContainerClient client,
15901590
string blobName)
15911591
{
1592-
if (client.ClientSideEncryption != default)
1593-
{
1594-
throw Errors.ClientSideEncryption.TypeNotSupported(typeof(AppendBlobClient));
1595-
}
1596-
1597-
BlobUriBuilder blobUriBuilder = new BlobUriBuilder(client.Uri)
1598-
{
1599-
BlobName = blobName
1600-
};
1601-
1602-
return new AppendBlobClient(
1603-
blobUriBuilder.ToUri(),
1604-
client.Pipeline,
1605-
client.Version,
1606-
client.ClientDiagnostics,
1607-
client.CustomerProvidedKey,
1608-
client.EncryptionScope);
1592+
return client.GetAppendBlobClientCore(blobName);
16091593
}
16101594
}
16111595
}

sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,16 @@ private protected virtual BlobBaseClient WithVersionCore(string versionId)
449449
EncryptionScope);
450450
}
451451

452+
/// <summary>
453+
/// Initializes a new instance of the <see cref="BlobLeaseClient"/> class.
454+
/// </summary>
455+
/// <param name="leaseId">
456+
/// An optional lease ID. If no lease ID is provided, a random lease
457+
/// ID will be created.
458+
/// </param>
459+
protected internal virtual BlobLeaseClient GetBlobLeaseClientCore(string leaseId) =>
460+
new BlobLeaseClient(this, leaseId);
461+
452462
/// <summary>
453463
/// Sets the various name fields if they are currently null.
454464
/// </summary>

sdk/storage/Azure.Storage.Blobs/src/BlobContainerClient.cs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,108 @@ public virtual BlobClient GetBlobClient(string blobName)
405405
EncryptionScope);
406406
}
407407

408+
/// <summary>
409+
/// Create a new <see cref="BlockBlobClient"/> object by
410+
/// concatenating <paramref name="blobName"/> to
411+
/// the end of the <see cref="Uri"/>. The new
412+
/// <see cref="BlockBlobClient"/>
413+
/// uses the same request policy pipeline as the
414+
/// <see cref="BlobContainerClient"/>.
415+
/// </summary>
416+
/// <param name="blobName">The name of the block blob.</param>
417+
/// <returns>A new <see cref="BlockBlobClient"/> instance.</returns>
418+
protected internal virtual BlockBlobClient GetBlockBlobClientCore(string blobName)
419+
{
420+
if (ClientSideEncryption != default)
421+
{
422+
throw Errors.ClientSideEncryption.TypeNotSupported(typeof(BlockBlobClient));
423+
}
424+
425+
BlobUriBuilder blobUriBuilder = new BlobUriBuilder(Uri)
426+
{
427+
BlobName = blobName
428+
};
429+
430+
return new BlockBlobClient(
431+
blobUriBuilder.ToUri(),
432+
Pipeline,
433+
Version,
434+
ClientDiagnostics,
435+
CustomerProvidedKey,
436+
EncryptionScope);
437+
}
438+
439+
/// <summary>
440+
/// Create a new <see cref="AppendBlobClient"/> object by
441+
/// concatenating <paramref name="blobName"/> to
442+
/// the end of the <see cref="BlobContainerClient.Uri"/>. The new
443+
/// <see cref="AppendBlobClient"/>
444+
/// uses the same request policy pipeline as the
445+
/// <see cref="BlobContainerClient"/>.
446+
/// </summary>
447+
/// <param name="blobName">The name of the append blob.</param>
448+
/// <returns>A new <see cref="AppendBlobClient"/> instance.</returns>
449+
protected internal virtual AppendBlobClient GetAppendBlobClientCore(string blobName)
450+
{
451+
if (ClientSideEncryption != default)
452+
{
453+
throw Errors.ClientSideEncryption.TypeNotSupported(typeof(AppendBlobClient));
454+
}
455+
456+
BlobUriBuilder blobUriBuilder = new BlobUriBuilder(Uri)
457+
{
458+
BlobName = blobName
459+
};
460+
461+
return new AppendBlobClient(
462+
blobUriBuilder.ToUri(),
463+
Pipeline,
464+
Version,
465+
ClientDiagnostics,
466+
CustomerProvidedKey,
467+
EncryptionScope);
468+
}
469+
470+
/// <summary>
471+
/// Create a new <see cref="PageBlobClient"/> object by
472+
/// concatenating <paramref name="blobName"/> to
473+
/// the end of the <see cref="BlobContainerClient.Uri"/>. The new
474+
/// <see cref="PageBlobClient"/>
475+
/// uses the same request policy pipeline as the
476+
/// <see cref="BlobContainerClient"/>.
477+
/// </summary>
478+
/// <param name="blobName">The name of the page blob.</param>
479+
/// <returns>A new <see cref="PageBlobClient"/> instance.</returns>
480+
protected internal virtual PageBlobClient GetPageBlobClientCore(string blobName)
481+
{
482+
if (ClientSideEncryption != default)
483+
{
484+
throw Errors.ClientSideEncryption.TypeNotSupported(typeof(PageBlobClient));
485+
}
486+
487+
BlobUriBuilder blobUriBuilder = new BlobUriBuilder(Uri)
488+
{
489+
BlobName = blobName
490+
};
491+
492+
return new PageBlobClient(
493+
blobUriBuilder.ToUri(),
494+
Pipeline,
495+
Version,
496+
ClientDiagnostics,
497+
CustomerProvidedKey,
498+
EncryptionScope);
499+
}
500+
501+
/// <summary>
502+
/// Initializes a new instance of the <see cref="BlobLeaseClient"/> class.
503+
/// </summary>
504+
/// <param name="leaseId">
505+
/// An optional lease ID. If no lease ID is provided, a random lease
506+
/// ID will be created.
507+
/// </param>
508+
protected internal virtual BlobLeaseClient GetBlobLeaseClientCore(string leaseId) =>
509+
new BlobLeaseClient(this, leaseId);
408510

409511
/// <summary>
410512
/// Sets the various name fields if they are currently null.

sdk/storage/Azure.Storage.Blobs/src/BlobLeaseClient.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,7 +1185,7 @@ public static partial class SpecializedBlobExtensions
11851185
public static BlobLeaseClient GetBlobLeaseClient(
11861186
this BlobBaseClient client,
11871187
string leaseId = null) =>
1188-
new BlobLeaseClient(client, leaseId);
1188+
client.GetBlobLeaseClientCore(leaseId);
11891189

11901190
/// <summary>
11911191
/// Initializes a new instance of the <see cref="BlobLeaseClient"/> class.
@@ -1201,6 +1201,6 @@ public static BlobLeaseClient GetBlobLeaseClient(
12011201
public static BlobLeaseClient GetBlobLeaseClient(
12021202
this BlobContainerClient client,
12031203
string leaseId = null) =>
1204-
new BlobLeaseClient(client, leaseId);
1204+
client.GetBlobLeaseClientCore(leaseId);
12051205
}
12061206
}

sdk/storage/Azure.Storage.Blobs/src/BlockBlobClient.cs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2235,23 +2235,7 @@ public static BlockBlobClient GetBlockBlobClient(
22352235
this BlobContainerClient client,
22362236
string blobName)
22372237
{
2238-
if (client.ClientSideEncryption != default)
2239-
{
2240-
throw Errors.ClientSideEncryption.TypeNotSupported(typeof(BlockBlobClient));
2241-
}
2242-
2243-
BlobUriBuilder blobUriBuilder = new BlobUriBuilder(client.Uri)
2244-
{
2245-
BlobName = blobName
2246-
};
2247-
2248-
return new BlockBlobClient(
2249-
blobUriBuilder.ToUri(),
2250-
client.Pipeline,
2251-
client.Version,
2252-
client.ClientDiagnostics,
2253-
client.CustomerProvidedKey,
2254-
client.EncryptionScope);
2238+
return client.GetBlockBlobClientCore(blobName);
22552239
}
22562240
}
22572241
}

sdk/storage/Azure.Storage.Blobs/src/PageBlobClient.cs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3114,23 +3114,7 @@ public static PageBlobClient GetPageBlobClient(
31143114
this BlobContainerClient client,
31153115
string blobName)
31163116
{
3117-
if (client.ClientSideEncryption != default)
3118-
{
3119-
throw Errors.ClientSideEncryption.TypeNotSupported(typeof(PageBlobClient));
3120-
}
3121-
3122-
BlobUriBuilder blobUriBuilder = new BlobUriBuilder(client.Uri)
3123-
{
3124-
BlobName = blobName
3125-
};
3126-
3127-
return new PageBlobClient(
3128-
blobUriBuilder.ToUri(),
3129-
client.Pipeline,
3130-
client.Version,
3131-
client.ClientDiagnostics,
3132-
client.CustomerProvidedKey,
3133-
client.EncryptionScope);
3117+
return client.GetPageBlobClientCore(blobName);
31343118
}
31353119
}
31363120
}

sdk/storage/Azure.Storage.Blobs/tests/BlobBaseClientTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
using Azure.Storage.Sas;
2121
using Azure.Storage.Test;
2222
using Azure.Storage.Test.Shared;
23+
using Moq;
24+
using Moq.Protected;
2325
using NUnit.Framework;
2426
using TestConstants = Azure.Storage.Test.TestConstants;
2527

@@ -5556,6 +5558,23 @@ public void WithVersion()
55565558
Assert.AreEqual(versionUri, blobUriBuilder.ToUri());
55575559
}
55585560

5561+
[Test]
5562+
public void CanMockBlobLeaseClientRetrieval()
5563+
{
5564+
// Arrange
5565+
string leaseId = "leaseId";
5566+
Mock<BlobBaseClient> blobBaseClientMock = new Mock<BlobBaseClient>();
5567+
Mock<BlobLeaseClient> blobLeaseClientMock = new Mock<BlobLeaseClient>();
5568+
blobBaseClientMock.Protected().Setup<BlobLeaseClient>("GetBlobLeaseClientCore", leaseId).Returns(blobLeaseClientMock.Object);
5569+
5570+
// Act
5571+
var blobLeaseClient = blobBaseClientMock.Object.GetBlobLeaseClient(leaseId);
5572+
5573+
// Assert
5574+
Assert.IsNotNull(blobLeaseClient);
5575+
Assert.AreSame(blobLeaseClientMock.Object, blobLeaseClient);
5576+
}
5577+
55595578
private async Task<BlobBaseClient> GetNewBlobClient(BlobContainerClient container, string blobName = default)
55605579
{
55615580
blobName ??= GetNewBlobName();

sdk/storage/Azure.Storage.Blobs/tests/ContainerClientTests.cs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Collections.Generic;
66
using System.IO;
77
using System.Linq;
8-
using System.Reflection.Metadata;
98
using System.Text;
109
using System.Threading;
1110
using System.Threading.Tasks;
@@ -17,6 +16,8 @@
1716
using Azure.Storage.Sas;
1817
using Azure.Storage.Test;
1918
using Azure.Storage.Test.Shared;
19+
using Moq;
20+
using Moq.Protected;
2021
using NUnit.Framework;
2122

2223
namespace Azure.Storage.Blobs.Test
@@ -2512,6 +2513,39 @@ public async Task GetBlobClients_SpecialCharacters(string blobName)
25122513
Assert.AreEqual(blobName, pageBlobClientFromConnectionString.Name);
25132514
}
25142515

2516+
[Test]
2517+
public void CanMockBlobClientsRetrieval()
2518+
{
2519+
// Arrange
2520+
string blobName = "test";
2521+
string leaseId = "leaseId";
2522+
Mock<BlobContainerClient> containerClientMock = new Mock<BlobContainerClient>();
2523+
Mock<BlockBlobClient> blockBlobClientMock = new Mock<BlockBlobClient>();
2524+
Mock<AppendBlobClient> appendBlobClientMock = new Mock<AppendBlobClient>();
2525+
Mock<PageBlobClient> pageBlobClientMock = new Mock<PageBlobClient>();
2526+
Mock<BlobLeaseClient> blobLeaseClientMock = new Mock<BlobLeaseClient>();
2527+
containerClientMock.Protected().Setup<BlockBlobClient>("GetBlockBlobClientCore", blobName).Returns(blockBlobClientMock.Object);
2528+
containerClientMock.Protected().Setup<AppendBlobClient>("GetAppendBlobClientCore", blobName).Returns(appendBlobClientMock.Object);
2529+
containerClientMock.Protected().Setup<PageBlobClient>("GetPageBlobClientCore", blobName).Returns(pageBlobClientMock.Object);
2530+
containerClientMock.Protected().Setup<BlobLeaseClient>("GetBlobLeaseClientCore", leaseId).Returns(blobLeaseClientMock.Object);
2531+
2532+
// Act
2533+
var blockBlobClient = containerClientMock.Object.GetBlockBlobClient(blobName);
2534+
var appendBlobClient = containerClientMock.Object.GetAppendBlobClient(blobName);
2535+
var pageBlobClient = containerClientMock.Object.GetPageBlobClient(blobName);
2536+
var blobLeaseClient = containerClientMock.Object.GetBlobLeaseClient(leaseId);
2537+
2538+
// Assert
2539+
Assert.IsNotNull(blockBlobClient);
2540+
Assert.AreSame(blockBlobClientMock.Object, blockBlobClient);
2541+
Assert.IsNotNull(appendBlobClient);
2542+
Assert.AreSame(appendBlobClientMock.Object, appendBlobClient);
2543+
Assert.IsNotNull(pageBlobClient);
2544+
Assert.AreSame(pageBlobClientMock.Object, pageBlobClient);
2545+
Assert.IsNotNull(blobLeaseClient);
2546+
Assert.AreSame(blobLeaseClientMock.Object, blobLeaseClient);
2547+
}
2548+
25152549
#region Secondary Storage
25162550
[Test]
25172551
public async Task ListContainersSegmentAsync_SecondaryStorageFirstRetrySuccessful()

sdk/storage/Azure.Storage.Blobs/tests/SessionRecords/BlobBaseClientTests/CanMockBlobLeaseClientRetrieval.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)