Skip to content

Commit

Permalink
WebJobs Extension: Allow binding to BlobContainerClient without blob (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
aishwaryabh authored Jun 26, 2023
1 parent 50ee8c1 commit 8c4faba
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

## 5.1.2 (2023-04-27)
- Fixed bug where the blob container would scan from the beginning due not correctly updating the latest scan time. (#35145)
- Loosen parameter binding data parsing and validation to allow binding BlobContainerClient without blob name. (#37124)

## 5.1.1 (2023-03-24)
- Bumped Azure.Core dependency from 1.28 and 1.30, fixing issue with headers being non-resilient to double dispose of the request.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ public override string ToString()
return result;
}

public static BlobPath ParseAndValidate(string value, bool isContainerBinding = false)
public static BlobPath ParseAndValidate(string value, bool isContainerBinding = false, bool isParameterBindingData = false)
{
string errorMessage;
BlobPath path;

if (!TryParseAndValidate(value, out errorMessage, out path, isContainerBinding))
if (!TryParseAndValidate(value, out errorMessage, out path, isContainerBinding, isParameterBindingData))
{
throw new FormatException(errorMessage);
}
Expand Down Expand Up @@ -82,7 +82,7 @@ public static bool TryParseAbsUrl(string blobUrl, out BlobPath path)
return false;
}

public static bool TryParse(string value, bool isContainerBinding, out BlobPath path)
public static bool TryParse(string value, bool isContainerBinding, bool isParameterBindingData, out BlobPath path)
{
path = null;

Expand All @@ -92,7 +92,7 @@ public static bool TryParse(string value, bool isContainerBinding, out BlobPath
}

int slashIndex = value.IndexOf('/');
if (!isContainerBinding && slashIndex <= 0)
if (!isParameterBindingData && !isContainerBinding && slashIndex <= 0)
{
return false;
}
Expand All @@ -111,7 +111,7 @@ public static bool TryParse(string value, bool isContainerBinding, out BlobPath
return true;
}

private static bool TryParseAndValidate(string value, out string errorMessage, out BlobPath path, bool isContainerBinding = false)
private static bool TryParseAndValidate(string value, out string errorMessage, out BlobPath path, bool isContainerBinding = false, bool isParameterBindingData = false)
{
BlobPath possiblePath;

Expand All @@ -122,7 +122,7 @@ private static bool TryParseAndValidate(string value, out string errorMessage, o
return true;
}

if (!TryParse(value, isContainerBinding, out possiblePath))
if (!TryParse(value, isContainerBinding, isParameterBindingData, out possiblePath))
{
errorMessage = $"Invalid blob path specified : '{value}'. Blob identifiers must be in the format 'container/blob'.";
path = null;
Expand All @@ -136,9 +136,9 @@ private static bool TryParseAndValidate(string value, out string errorMessage, o
return false;
}

// for container bindings, we allow an empty blob name/path
// for container bindings or parameter binding data, we allow an empty blob name/path
string possibleErrorMessage;
if (!(isContainerBinding && string.IsNullOrEmpty(possiblePath.BlobName)) &&
if (!((isContainerBinding || isParameterBindingData) && string.IsNullOrEmpty(possiblePath.BlobName)) &&
!BlobClientExtensions.IsValidBlobName(possiblePath.BlobName, out possibleErrorMessage))
{
errorMessage = possibleErrorMessage;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ private async Task<T> CreateBlobReference<T>(BlobAttribute blobAttribute, Cancel

private ParameterBindingData ConvertToParameterBindingData(BlobAttribute blobAttribute)
{
var blobPath = BlobPath.ParseAndValidate(blobAttribute.BlobPath);
var blobPath = BlobPath.ParseAndValidate(blobAttribute.BlobPath, isParameterBindingData: true);
return CreateParameterBindingData(blobAttribute.Connection, blobPath.BlobName, blobPath.ContainerName);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public BlobPath ToBlobPath()
}

BlobPath blobPath;
if (!BlobPath.TryParse(path, false, out blobPath))
if (!BlobPath.TryParse(path, false, false, out blobPath))
{
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ private static IDictionary<string, string> Match(string a, string b)
{
var pathA = BlobPathSource.Create(a);
BlobPath pathB = null;
BlobPath.TryParse(b, false, out pathB);
BlobPath.TryParse(b, false, false, out pathB);

IReadOnlyDictionary<string, object> bindingData = pathA.CreateBindingData(pathB);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Specialized;
using Azure.Storage.Queues;
using BenchmarkDotNet.Engines;
using Microsoft.Azure.WebJobs.Extensions.Storage.Common.Tests;
using Microsoft.Extensions.Azure;
using Microsoft.Extensions.Configuration;
Expand Down Expand Up @@ -41,7 +42,7 @@ public async Task Blob_IfBoundToCloudBlockBlob_BindsAndCreatesContainerButNotBlo
{
// Act
var prog = new BindToCloudBlockBlobProgram();
IHost host = new HostBuilder()
var host = new HostBuilder()
.ConfigureDefaultTestHost<BindToCloudBlockBlobProgram>(prog, builder =>
{
builder.AddAzureStorageBlobs()
Expand Down Expand Up @@ -70,7 +71,7 @@ public async Task Blob_IfBoundToBlobClient_BindsAndCreatesContainerButNotBlob()
{
// Act
var prog = new BindToBlobClientProgram();
IHost host = new HostBuilder()
var host = new HostBuilder()
.ConfigureDefaultTestHost<BindToBlobClientProgram>(prog, builder =>
{
builder.AddAzureStorageBlobs()
Expand Down Expand Up @@ -126,7 +127,7 @@ public async Task Blob_IfBoundToParameterBindingData_CreatesParameterBindingData
}).Build();

var program = new BindToParameterBindingData();
IHost host = new HostBuilder()
var host = new HostBuilder()
.ConfigureDefaultTestHost<BindToParameterBindingData>(program, builder =>
{
builder.AddAzureStorageBlobs()
Expand Down Expand Up @@ -154,6 +155,46 @@ public async Task Blob_IfBoundToParameterBindingData_CreatesParameterBindingData
Assert.AreEqual(BlobName, resultBlobName);
}

[Test]
public async Task Blob_IfBoundToParameterBindingData_Container_CreatesParameterBindingData()
{
// Arrange
string connectionString = AzuriteNUnitFixture.Instance.GetAzureAccount().ConnectionString;
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>()
{
{ "ConnectionStrings:AzureWebJobsStorage", connectionString }
}).Build();

var program = new BindToParameterBindingDataBlobContainer();
var host = new HostBuilder()
.ConfigureDefaultTestHost<BindToParameterBindingDataBlobContainer>(program, builder =>
{
builder.AddAzureStorageBlobs()
.UseStorageServicesWithConfiguration(blobServiceClient, queueServiceClient, configuration);
})
.Build();

var jobHost = host.GetJobHost<BindToParameterBindingDataBlobContainer>();

// Act
await jobHost.CallAsync(nameof(BindToParameterBindingDataBlobContainer.Run));
ParameterBindingData result = program.Result;

Assert.NotNull(result);

var blobData = result?.Content.ToObjectFromJson<Dictionary<string, string>>();

// Assert
Assert.True(blobData.TryGetValue("Connection", out var resultConnection));
Assert.True(blobData.TryGetValue("ContainerName", out var resultContainerName));
Assert.True(blobData.TryGetValue("BlobName", out var resultBlobName));

Assert.AreEqual(ConnectionName, resultConnection);
Assert.AreEqual(ContainerName, resultContainerName);
Assert.IsEmpty(resultBlobName);
}

[Test]
public async Task Blob_IfBoundToParameterBindingDataEnumerable_CreatesParameterBindingDataArray()
{
Expand All @@ -166,7 +207,7 @@ public async Task Blob_IfBoundToParameterBindingDataEnumerable_CreatesParameterB

// Arrange
var program = new BindToParameterBindingDataEnumerable();
IHost host = new HostBuilder()
var host = new HostBuilder()
.ConfigureDefaultTestHost<BindToParameterBindingDataEnumerable>(program, builder =>
{
builder.AddAzureStorageBlobs()
Expand Down Expand Up @@ -213,7 +254,7 @@ public async Task Blob_IfBoundToStringArray_CreatesStringArray()

// Arrange
var program = new BindToStringArray();
IHost host = new HostBuilder()
var host = new HostBuilder()
.ConfigureDefaultTestHost<BindToStringArray>(program, builder =>
{
builder.AddAzureStorageBlobs()
Expand Down Expand Up @@ -252,7 +293,7 @@ public async Task Blob_IfBoundToParameterBindingDataArray_CreatesParameterBindin

// Arrange
var program = new BindToParameterBindingDataArray();
IHost host = new HostBuilder()
var host = new HostBuilder()
.ConfigureDefaultTestHost<BindToParameterBindingDataArray>(program, builder =>
{
builder.AddAzureStorageBlobs()
Expand Down Expand Up @@ -364,6 +405,17 @@ public void Run(
}
}

private class BindToParameterBindingDataBlobContainer
{
public ParameterBindingData Result { get; set; }

public void Run(
[Blob(ContainerName)] ParameterBindingData blobData)
{
this.Result = blobData;
}
}

private class BindToParameterBindingDataEnumerable
{
public IEnumerable<ParameterBindingData> Result { get; set; }
Expand Down

0 comments on commit 8c4faba

Please sign in to comment.