re-enabling skipped tests
This commit is contained in:
Родитель
11fdc64435
Коммит
e30f8544e6
|
@ -27,8 +27,7 @@ namespace Microsoft.Azure.WebJobs.Host.Blobs.Listeners
|
|||
do
|
||||
{
|
||||
result = await client.ListBlobsSegmentedAsync(prefix, useFlatBlobListing, blobListingDetails,
|
||||
maxResults: null, currentToken: continuationToken, options: null, operationContext: null
|
||||
);
|
||||
maxResults: null, currentToken: continuationToken, options: null, operationContext: null);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
|
@ -44,6 +43,6 @@ namespace Microsoft.Azure.WebJobs.Host.Blobs.Listeners
|
|||
while (result != null && continuationToken != null);
|
||||
|
||||
return allResults;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,12 +85,26 @@ namespace FakeStorage
|
|||
return props;
|
||||
}
|
||||
|
||||
public static BlobProperties SetLeaseState(this BlobProperties props, LeaseState state)
|
||||
{
|
||||
props.SetInternalProperty(nameof(BlobProperties.LeaseState), state);
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
public static BlobProperties SetLeaseStatus(this BlobProperties props, LeaseStatus status)
|
||||
{
|
||||
props.SetInternalProperty(nameof(BlobProperties.LeaseStatus), status);
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
public static BlobResultSegment NewBlobResultSegment(
|
||||
BlobContinuationToken continuationToken,
|
||||
IEnumerable<ICloudBlob> results)
|
||||
{
|
||||
IEnumerable<IListBlobItem> l = results;
|
||||
var result = new BlobResultSegment(results, continuationToken );
|
||||
var result = new BlobResultSegment(results, continuationToken);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -131,7 +145,7 @@ namespace FakeStorage
|
|||
}
|
||||
}
|
||||
|
||||
static class MoreStorageExtensions
|
||||
internal static class MoreStorageExtensions
|
||||
{
|
||||
public static string DownloadText(this ICloudBlob blob)
|
||||
{
|
||||
|
|
|
@ -19,7 +19,6 @@ using Microsoft.Azure.WebJobs.Logging;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Blob;
|
||||
using Microsoft.WindowsAzure.Storage.Queue;
|
||||
|
@ -152,23 +151,16 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
}
|
||||
}
|
||||
|
||||
/* $$$
|
||||
[Fact]
|
||||
public async Task AsyncChainEndToEnd_CustomFactories()
|
||||
{
|
||||
using (_functionCompletedEvent = new ManualResetEvent(initialState: false))
|
||||
{
|
||||
CustomQueueProcessorFactory queueProcessorFactory = new CustomQueueProcessorFactory();
|
||||
CustomStorageClientFactory storageClientFactory = new CustomStorageClientFactory();
|
||||
|
||||
_hostBuilder.ConfigureServices(services =>
|
||||
{
|
||||
services.Configure<JobHostQueuesOptions>(o =>
|
||||
{
|
||||
o.QueueProcessorFactory = queueProcessorFactory;
|
||||
});
|
||||
|
||||
services.AddSingleton<StorageClientFactory>(storageClientFactory);
|
||||
services.AddSingleton<IQueueProcessorFactory>(queueProcessorFactory);
|
||||
});
|
||||
|
||||
await AsyncChainEndToEndInternal(_hostBuilder);
|
||||
|
@ -179,7 +171,6 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
Assert.True(queueProcessorFactory.CustomQueueProcessors.Sum(p => p.CompleteProcessingCount) >= 2);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
[Fact]
|
||||
public async Task LoggerLogging()
|
||||
|
@ -626,7 +617,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
using (IHost host = hostBuilder.Build())
|
||||
{
|
||||
JobHost jobHost = host.GetJobHost();
|
||||
|
||||
|
||||
await host.StartAsync();
|
||||
|
||||
IHostIdProvider idProvider = host.Services.GetService<IHostIdProvider>();
|
||||
|
|
|
@ -12,7 +12,6 @@ using Microsoft.Azure.WebJobs.Host.Executors;
|
|||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Blob;
|
||||
using Newtonsoft.Json;
|
||||
|
@ -355,7 +354,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
}
|
||||
|
||||
[NoAutomaticTrigger]
|
||||
public async static Task CloudBlobDirectoryBinding(
|
||||
public static async Task CloudBlobDirectoryBinding(
|
||||
[Blob(HierarchicalBlobContainerName + "/sub")] CloudBlobDirectory directory)
|
||||
{
|
||||
var directoryItems = await directory.ListBlobsSegmentedAsync(null);
|
||||
|
@ -392,7 +391,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
}
|
||||
|
||||
[NoAutomaticTrigger]
|
||||
public async static Task IEnumerableCloudBlockBlobBinding_WithPrefixFilter(
|
||||
public static async Task IEnumerableCloudBlockBlobBinding_WithPrefixFilter(
|
||||
[Blob(ContainerName + "/blo")] IEnumerable<CloudBlockBlob> blobs)
|
||||
{
|
||||
foreach (var blob in blobs)
|
||||
|
@ -411,7 +410,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
}
|
||||
|
||||
[NoAutomaticTrigger]
|
||||
public async static Task IEnumerableCloudBlockBlobBinding_WithPrefixFilter_HierarchicalBlobs(
|
||||
public static async Task IEnumerableCloudBlockBlobBinding_WithPrefixFilter_HierarchicalBlobs(
|
||||
[Blob(HierarchicalBlobContainerName + "/sub/bl")] IEnumerable<CloudBlockBlob> blobs)
|
||||
{
|
||||
foreach (var blob in blobs)
|
||||
|
@ -426,7 +425,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
// sub directries, blobs within those sub directories are returned. Users can bind
|
||||
// to CloudBlobDirectory if they want to operate on directories.
|
||||
[NoAutomaticTrigger]
|
||||
public async static Task IEnumerableCloudBlockBlobBinding_WithPrefixFilter_HierarchicalBlobs_UsesFlatBlobListing(
|
||||
public static async Task IEnumerableCloudBlockBlobBinding_WithPrefixFilter_HierarchicalBlobs_UsesFlatBlobListing(
|
||||
[Blob(HierarchicalBlobContainerName + "/sub")] IEnumerable<CloudBlockBlob> blobs)
|
||||
{
|
||||
foreach (var blob in blobs)
|
||||
|
@ -438,7 +437,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
}
|
||||
|
||||
[NoAutomaticTrigger]
|
||||
public async static Task IEnumerableCloudBlockBlobBinding_WithModelBinding(
|
||||
public static async Task IEnumerableCloudBlockBlobBinding_WithModelBinding(
|
||||
[QueueTrigger("testqueue")] TestPoco poco,
|
||||
[Blob("{A}/{B}ob")] IEnumerable<CloudBlockBlob> blobs)
|
||||
{
|
||||
|
@ -451,7 +450,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
}
|
||||
|
||||
[NoAutomaticTrigger]
|
||||
public async static Task IEnumerableCloudPageBlobBinding(
|
||||
public static async Task IEnumerableCloudPageBlobBinding(
|
||||
[Blob(PageBlobContainerName)] IEnumerable<CloudPageBlob> blobs)
|
||||
{
|
||||
foreach (var blob in blobs)
|
||||
|
@ -465,7 +464,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
}
|
||||
|
||||
[NoAutomaticTrigger]
|
||||
public async static Task IEnumerableCloudAppendBlobBinding(
|
||||
public static async Task IEnumerableCloudAppendBlobBinding(
|
||||
[Blob(AppendBlobContainerName)] IEnumerable<CloudAppendBlob> blobs)
|
||||
{
|
||||
foreach (var blob in blobs)
|
||||
|
@ -827,7 +826,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
await Host.StopAsync();
|
||||
|
||||
// $$$ reenalbe this
|
||||
// VerifyLockState("WebJobs.Internal.Blobs.Listener", LeaseState.Available, LeaseStatus.Unlocked).Wait();
|
||||
VerifyLockState("WebJobs.Internal.Blobs.Listener", LeaseState.Available, LeaseStatus.Unlocked).Wait();
|
||||
|
||||
CloudBlobClient blobClient = StorageAccount.CreateCloudBlobClient();
|
||||
foreach (var testContainer in (await blobClient.ListContainersSegmentedAsync(TestArtifactPrefix, null)).Results)
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
_output = output;
|
||||
}
|
||||
|
||||
[Fact(Skip = "Brettsam investigating")]
|
||||
[Fact(Skip = "Fix DispatchQueue")]
|
||||
// same trigger type, multiple functions
|
||||
public async Task DispatchQueueBatchTriggerTest()
|
||||
{
|
||||
|
@ -99,7 +99,7 @@ namespace Microsoft.Azure.WebJobs.Host.EndToEndTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact(Skip = "Brettsam investigating")]
|
||||
[Fact(Skip = "Fix DispatchQueue")]
|
||||
public async void PoisonQueueTest()
|
||||
{
|
||||
_host = new HostBuilder()
|
||||
|
|
|
@ -3,123 +3,115 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs.Host.Dispatch;
|
||||
using Microsoft.Azure.WebJobs.Host.Executors;
|
||||
using Microsoft.Azure.WebJobs.Host.FunctionalTests.TestDoubles;
|
||||
using Microsoft.Azure.WebJobs.Host.Listeners;
|
||||
using Microsoft.Azure.WebJobs.Host.Protocols;
|
||||
using Microsoft.Azure.WebJobs.Host.Queues;
|
||||
using Microsoft.Azure.WebJobs.Host.Queues.Listeners;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Azure.WebJobs.Host.Timers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
||||
{
|
||||
#if false // $$$ enable this
|
||||
public class DispatchQueueTests
|
||||
{
|
||||
private const string HostId = "functionalTestHost";
|
||||
|
||||
// provide default mock
|
||||
private Mock<IHostIdProvider> _hostIdMock;
|
||||
private Mock<IWebJobsExceptionHandler> _exceptionMock;
|
||||
private Mock<IContextSetter<IMessageEnqueuedWatcher>> _messageEnqueueSetterMock;
|
||||
private Mock<IStorageAccountProvider> _accountProviderMock;
|
||||
private readonly Mock<IHostIdProvider> _hostIdMock;
|
||||
private readonly Mock<IWebJobsExceptionHandler> _exceptionMock;
|
||||
//private Mock<IContextSetter<IMessageEnqueuedWatcher>> _messageEnqueueSetterMock;
|
||||
//private Mock<IStorageAccountProvider> _accountProviderMock;
|
||||
|
||||
private JobHostQueuesOptions _queueConfiguration;
|
||||
private ISharedContextProvider _sharedContextProvider;
|
||||
//private readonly JobHostQueuesOptions _queueConfiguration;
|
||||
private readonly ISharedContextProvider _sharedContextProvider;
|
||||
private SharedQueueHandler _sharedQueue;
|
||||
|
||||
private TestLoggerProvider _loggerProvider = new TestLoggerProvider();
|
||||
private readonly TestLoggerProvider _loggerProvider = new TestLoggerProvider();
|
||||
|
||||
public DispatchQueueTests()
|
||||
{
|
||||
_accountProviderMock = new Mock<IStorageAccountProvider>();
|
||||
IStorageAccountProvider accountProvider = new FakeStorageAccountProvider
|
||||
{
|
||||
StorageAccount = new FakeStorageAccount()
|
||||
};
|
||||
_accountProviderMock.Setup(m => m.TryGetAccountAsync(ConnectionStringNames.Storage, It.IsAny<CancellationToken>()))
|
||||
.Returns<string, CancellationToken>((name, cancel) => accountProvider.TryGetAccountAsync(name, cancel));
|
||||
//_accountProviderMock = new Mock<IStorageAccountProvider>();
|
||||
//IStorageAccountProvider accountProvider = new FakeStorageAccountProvider
|
||||
//{
|
||||
// StorageAccount = new FakeStorageAccount()
|
||||
//};
|
||||
//_accountProviderMock.Setup(m => m.TryGetAccountAsync(ConnectionStringNames.Storage, It.IsAny<CancellationToken>()))
|
||||
// .Returns<string, CancellationToken>((name, cancel) => accountProvider.TryGetAccountAsync(name, cancel));
|
||||
|
||||
_hostIdMock = new Mock<IHostIdProvider>();
|
||||
_hostIdMock.Setup(m => m.GetHostIdAsync(It.IsAny<CancellationToken>())).ReturnsAsync(HostId);
|
||||
//_hostIdMock = new Mock<IHostIdProvider>();
|
||||
//_hostIdMock.Setup(m => m.GetHostIdAsync(It.IsAny<CancellationToken>())).ReturnsAsync(HostId);
|
||||
|
||||
_exceptionMock = new Mock<IWebJobsExceptionHandler>();
|
||||
//_exceptionMock = new Mock<IWebJobsExceptionHandler>();
|
||||
|
||||
_queueConfiguration = new FakeQueuesOptionsFactory(accountProvider).Create(string.Empty);
|
||||
//_queueConfiguration = new FakeQueuesOptionsFactory(accountProvider).Create(string.Empty);
|
||||
|
||||
_sharedContextProvider = new SharedContextProvider();
|
||||
//_sharedContextProvider = new SharedContextProvider();
|
||||
|
||||
_messageEnqueueSetterMock = new Mock<IContextSetter<IMessageEnqueuedWatcher>>();
|
||||
//_messageEnqueueSetterMock = new Mock<IContextSetter<IMessageEnqueuedWatcher>>();
|
||||
|
||||
ILoggerFactory factory = new LoggerFactory();
|
||||
factory.AddProvider(_loggerProvider);
|
||||
//ILoggerFactory factory = new LoggerFactory();
|
||||
//factory.AddProvider(_loggerProvider);
|
||||
|
||||
_sharedQueue = new SharedQueueHandler(_accountProviderMock.Object,
|
||||
_hostIdMock.Object,
|
||||
_exceptionMock.Object,
|
||||
factory,
|
||||
new OptionsWrapper<JobHostQueuesOptions>(_queueConfiguration),
|
||||
_sharedContextProvider,
|
||||
_messageEnqueueSetterMock.Object
|
||||
);
|
||||
//_sharedQueue = new SharedQueueHandler(_accountProviderMock.Object,
|
||||
// _hostIdMock.Object,
|
||||
// _exceptionMock.Object,
|
||||
// factory,
|
||||
// new OptionsWrapper<JobHostQueuesOptions>(_queueConfiguration),
|
||||
// _sharedContextProvider,
|
||||
// _messageEnqueueSetterMock.Object
|
||||
// );
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Skip = "Fix DispatchQueue")]
|
||||
public async Task InMemoryDispatchQueueHandlerTest()
|
||||
{
|
||||
string error = "no storage account found";
|
||||
_accountProviderMock.Setup(m => m.TryGetAccountAsync(ConnectionStringNames.Storage, It.IsAny<CancellationToken>())).
|
||||
ThrowsAsync(new Exception(error));
|
||||
//string error = "no storage account found";
|
||||
//_accountProviderMock.Setup(m => m.TryGetAccountAsync(ConnectionStringNames.Storage, It.IsAny<CancellationToken>())).
|
||||
// ThrowsAsync(new Exception(error));
|
||||
|
||||
await _sharedQueue.InitializeAsync(CancellationToken.None);
|
||||
Assert.Empty(_loggerProvider.GetAllLogMessages());
|
||||
//await _sharedQueue.InitializeAsync(CancellationToken.None);
|
||||
//Assert.Empty(_loggerProvider.GetAllLogMessages());
|
||||
|
||||
// listenercontext should return inMemoryDispatchQueueHandler when there's no storage account
|
||||
var descriptorMock = new Mock<FunctionDescriptor>();
|
||||
var triggerExecutorMock = new Mock<ITriggeredFunctionExecutor>();
|
||||
ListenerFactoryContext context = new ListenerFactoryContext(
|
||||
descriptorMock.Object,
|
||||
triggerExecutorMock.Object,
|
||||
_sharedQueue,
|
||||
CancellationToken.None);
|
||||
//// listenercontext should return inMemoryDispatchQueueHandler when there's no storage account
|
||||
//var descriptorMock = new Mock<FunctionDescriptor>();
|
||||
//var triggerExecutorMock = new Mock<ITriggeredFunctionExecutor>();
|
||||
//ListenerFactoryContext context = new ListenerFactoryContext(
|
||||
// descriptorMock.Object,
|
||||
// triggerExecutorMock.Object,
|
||||
// _sharedQueue,
|
||||
// CancellationToken.None);
|
||||
|
||||
var messageHandlerMock = new Mock<IMessageHandler>();
|
||||
var condition = new AutoResetEvent(false);
|
||||
messageHandlerMock.Setup(m => m.TryExecuteAsync(It.IsAny<JObject>(), It.IsAny<CancellationToken>()))
|
||||
.Returns(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
condition.Set(); // will run asynchronously
|
||||
return new FunctionResult(true);
|
||||
});
|
||||
//var messageHandlerMock = new Mock<IMessageHandler>();
|
||||
//var condition = new AutoResetEvent(false);
|
||||
//messageHandlerMock.Setup(m => m.TryExecuteAsync(It.IsAny<JObject>(), It.IsAny<CancellationToken>()))
|
||||
// .Returns(async () =>
|
||||
// {
|
||||
// await Task.Yield();
|
||||
// condition.Set(); // will run asynchronously
|
||||
// return new FunctionResult(true);
|
||||
// });
|
||||
|
||||
var dispatchQueue = context.GetDispatchQueue(messageHandlerMock.Object);
|
||||
// make sure initialization error is traced
|
||||
Assert.Equal(error, _loggerProvider.GetAllLogMessages().Single().Exception.Message);
|
||||
Assert.Equal(SharedQueueHandler.InitErrorMessage, _loggerProvider.GetAllLogMessages().Single().FormattedMessage);
|
||||
Assert.IsType<InMemoryDispatchQueueHandler>(dispatchQueue);
|
||||
//var dispatchQueue = context.GetDispatchQueue(messageHandlerMock.Object);
|
||||
//// make sure initialization error is traced
|
||||
//Assert.Equal(error, _loggerProvider.GetAllLogMessages().Single().Exception.Message);
|
||||
//Assert.Equal(SharedQueueHandler.InitErrorMessage, _loggerProvider.GetAllLogMessages().Single().FormattedMessage);
|
||||
//Assert.IsType<InMemoryDispatchQueueHandler>(dispatchQueue);
|
||||
|
||||
await dispatchQueue.EnqueueAsync(JObject.Parse("{}"), CancellationToken.None);
|
||||
// without storage account, it is still possible to perform local enqueue, dequeue
|
||||
Assert.True(condition.WaitOne(200));
|
||||
//await dispatchQueue.EnqueueAsync(JObject.Parse("{}"), CancellationToken.None);
|
||||
//// without storage account, it is still possible to perform local enqueue, dequeue
|
||||
//Assert.True(condition.WaitOne(200));
|
||||
|
||||
// following two should be NOOP, inner queueListener was never created
|
||||
await _sharedQueue.StartQueueAsync(CancellationToken.None);
|
||||
await _sharedQueue.StopQueueAsync(CancellationToken.None);
|
||||
// no NullPointerException
|
||||
//// following two should be NOOP, inner queueListener was never created
|
||||
//await _sharedQueue.StartQueueAsync(CancellationToken.None);
|
||||
//await _sharedQueue.StopQueueAsync(CancellationToken.None);
|
||||
//// no NullPointerException
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Skip = "Fix DispatchQueue")]
|
||||
public async Task QueueInitializationTest()
|
||||
{
|
||||
// first initialization should be fine
|
||||
|
@ -132,50 +124,50 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Skip = "Fix DispatchQueue")]
|
||||
public async Task HotPathNotificationTest()
|
||||
{
|
||||
await _sharedQueue.InitializeAsync(CancellationToken.None);
|
||||
//await _sharedQueue.InitializeAsync(CancellationToken.None);
|
||||
|
||||
var messageHandlerMock = new Mock<IMessageHandler>();
|
||||
var calls = 0;
|
||||
messageHandlerMock.Setup(m => m.TryExecuteAsync(It.IsAny<JObject>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(() =>
|
||||
{
|
||||
calls++; // executed sequentially, no need interlocked
|
||||
return new FunctionResult(true);
|
||||
});
|
||||
//var messageHandlerMock = new Mock<IMessageHandler>();
|
||||
//var calls = 0;
|
||||
//messageHandlerMock.Setup(m => m.TryExecuteAsync(It.IsAny<JObject>(), It.IsAny<CancellationToken>()))
|
||||
// .ReturnsAsync(() =>
|
||||
// {
|
||||
// calls++; // executed sequentially, no need interlocked
|
||||
// return new FunctionResult(true);
|
||||
// });
|
||||
|
||||
Assert.True(_sharedQueue.RegisterHandler("mockFunction1", messageHandlerMock.Object));
|
||||
//Assert.True(_sharedQueue.RegisterHandler("mockFunction1", messageHandlerMock.Object));
|
||||
|
||||
// register another INotificationHandler to sharedQueueWatcher
|
||||
// so that we can tell when the sharedQueueListener is notified
|
||||
var notifies = 0;
|
||||
var notificationMock = new Mock<INotificationCommand>();
|
||||
notificationMock.Setup(m => m.Notify()).Callback(() => Interlocked.Increment(ref notifies));
|
||||
_sharedContextProvider.GetOrCreateInstance<SharedQueueWatcher>(null)
|
||||
.Register(HostQueueNames.GetHostSharedQueueName(HostId), notificationMock.Object);
|
||||
//// register another INotificationHandler to sharedQueueWatcher
|
||||
//// so that we can tell when the sharedQueueListener is notified
|
||||
//var notifies = 0;
|
||||
//var notificationMock = new Mock<INotificationCommand>();
|
||||
//notificationMock.Setup(m => m.Notify()).Callback(() => Interlocked.Increment(ref notifies));
|
||||
//_sharedContextProvider.GetOrCreateInstance<SharedQueueWatcher>(null)
|
||||
// .Register(HostQueueNames.GetHostSharedQueueName(HostId), notificationMock.Object);
|
||||
|
||||
await _sharedQueue.StartQueueAsync(CancellationToken.None);
|
||||
//await _sharedQueue.StartQueueAsync(CancellationToken.None);
|
||||
|
||||
int max = 10;
|
||||
var enqueue = new List<Task>();
|
||||
for (int i = 0; i < max; i++)
|
||||
{
|
||||
JObject message = JObject.Parse("{count:" + i + "}");
|
||||
enqueue.Add(_sharedQueue.EnqueueAsync(message, "mockFunction1", CancellationToken.None));
|
||||
}
|
||||
//int max = 10;
|
||||
//var enqueue = new List<Task>();
|
||||
//for (int i = 0; i < max; i++)
|
||||
//{
|
||||
// JObject message = JObject.Parse("{count:" + i + "}");
|
||||
// enqueue.Add(_sharedQueue.EnqueueAsync(message, "mockFunction1", CancellationToken.None));
|
||||
//}
|
||||
|
||||
await Task.WhenAll(enqueue);
|
||||
// wait for dequeue
|
||||
await TestHelpers.Await(() => calls >= max, 1000, 200);
|
||||
await _sharedQueue.StopQueueAsync(CancellationToken.None);
|
||||
//await Task.WhenAll(enqueue);
|
||||
//// wait for dequeue
|
||||
//await TestHelpers.Await(() => calls >= max, 1000, 200);
|
||||
//await _sharedQueue.StopQueueAsync(CancellationToken.None);
|
||||
|
||||
Assert.Equal(max, notifies);
|
||||
Assert.Equal(max, calls);
|
||||
//Assert.Equal(max, notifies);
|
||||
//Assert.Equal(max, calls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Skip = "Fix DispatchQueue")]
|
||||
public async Task DequeueBehaviorTests()
|
||||
{
|
||||
await _sharedQueue.InitializeAsync(CancellationToken.None);
|
||||
|
@ -251,5 +243,4 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
return Task.WhenAll(enqueues);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs.Host.Executors;
|
||||
using Microsoft.Azure.WebJobs.Host.Indexers;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Executors
|
||||
{
|
||||
#if false // $$$ Is this test still meaningful?
|
||||
// Tests behavior when getting a storage account fails.
|
||||
public class DynamicHostIdProviderTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetHostIdAsync_IfStorageAccountProviderThrowsInvalidOperationException_WrapsException()
|
||||
{
|
||||
// Arrange
|
||||
Mock<XStorageAccountProvider> storageAccountProviderMock = new Mock<XStorageAccountProvider>(
|
||||
MockBehavior.Strict);
|
||||
|
||||
InvalidOperationException innerException = new InvalidOperationException();
|
||||
storageAccountProviderMock
|
||||
.Setup(p => p.Get(It.IsAny<string>()))
|
||||
.Throws(innerException);
|
||||
var storageAccountProvider = storageAccountProviderMock.Object;
|
||||
|
||||
IFunctionIndexProvider functionIndexProvider = CreateDummyFunctionIndexProvider();
|
||||
|
||||
IHostIdProvider product = new DynamicHostIdProvider(storageAccountProvider, functionIndexProvider);
|
||||
CancellationToken cancellationToken = CancellationToken.None;
|
||||
|
||||
// Act & Assert
|
||||
InvalidOperationException exception = Assert.Throws<InvalidOperationException>(
|
||||
() => product.GetHostIdAsync(cancellationToken).GetAwaiter().GetResult());
|
||||
Assert.Equal("A host ID is required. Either set JobHostConfiguration.HostId or provide a valid storage " +
|
||||
"connection string.", exception.Message);
|
||||
Assert.Same(innerException, exception.InnerException);
|
||||
}
|
||||
|
||||
private static IFunctionIndexProvider CreateDummyFunctionIndexProvider()
|
||||
{
|
||||
return new Mock<IFunctionIndexProvider>(MockBehavior.Strict).Object;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -8,13 +8,11 @@ using System.Reflection;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs.Host.Executors;
|
||||
using Microsoft.Azure.WebJobs.Host.Loggers;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
|
@ -22,38 +20,40 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
{
|
||||
public class JobHostOptionsTests
|
||||
{
|
||||
// TODO: DI: Change to use IHostingEnvironment
|
||||
//[Theory]
|
||||
//[InlineData(null, false)]
|
||||
//[InlineData("Blah", false)]
|
||||
//[InlineData("Development", true)]
|
||||
//[InlineData("development", true)]
|
||||
//public void IsDevelopment_ReturnsCorrectValue(string settingValue, bool expected)
|
||||
//{
|
||||
// using (EnvVarHolder.Set(Constants.EnvironmentSettingName, settingValue))
|
||||
// {
|
||||
// JobHostOptions config = new JobHostOptions();
|
||||
// Assert.Equal(config.IsDevelopment, expected);
|
||||
// }
|
||||
//}
|
||||
// TODO: DI: private readonly Change to private readonly use IHostingEnvironment
|
||||
// TODO: Missing feature tracked by https://github.com/Azure/azure-webjobs-sdk/issues/1869
|
||||
[Theory(Skip = "Development settings not being applied")]
|
||||
[InlineData(null, false)]
|
||||
[InlineData("Blah", false)]
|
||||
[InlineData("Development", true)]
|
||||
[InlineData("development", true)]
|
||||
public void IsDevelopment_ReturnsCorrectValue(string settingValue, bool expected)
|
||||
{
|
||||
//using (EnvVarHolder.Set(Constants.EnvironmentSettingName, settingValue))
|
||||
//{
|
||||
// JobHostOptions config = new JobHostOptions();
|
||||
// Assert.Equal(config.IsDevelopment, expected);
|
||||
//}
|
||||
}
|
||||
|
||||
//public void UseDevelopmentSettings_ConfiguresCorrectValues()
|
||||
//{
|
||||
// using (EnvVarHolder.Set(Constants.EnvironmentSettingName, "Development"))
|
||||
// {
|
||||
// JobHostOptions config = new JobHostOptions();
|
||||
// Assert.False(config.UsingDevelopmentSettings);
|
||||
[Fact(Skip = "Development settings not being applied")]
|
||||
public void UseDevelopmentSettings_ConfiguresCorrectValues()
|
||||
{
|
||||
//using (EnvVarHolder.Set(Constants.EnvironmentSettingName, "Development"))
|
||||
//{
|
||||
// JobHostOptions config = new JobHostOptions();
|
||||
// Assert.False(config.UsingDevelopmentSettings);
|
||||
|
||||
// if (config.IsDevelopment)
|
||||
// {
|
||||
// config.UseDevelopmentSettings();
|
||||
// }
|
||||
// if (config.IsDevelopment)
|
||||
// {
|
||||
// config.UseDevelopmentSettings();
|
||||
// }
|
||||
|
||||
// Assert.True(config.UsingDevelopmentSettings);
|
||||
// Assert.Equal(TimeSpan.FromSeconds(2), config.Queues.MaxPollingInterval);
|
||||
// Assert.Equal(TimeSpan.FromSeconds(15), config.Singleton.ListenerLockPeriod);
|
||||
// }
|
||||
//}
|
||||
// Assert.True(config.UsingDevelopmentSettings);
|
||||
// Assert.Equal(TimeSpan.FromSeconds(2), config.Queues.MaxPollingInterval);
|
||||
// Assert.Equal(TimeSpan.FromSeconds(15), config.Singleton.ListenerLockPeriod);
|
||||
//}
|
||||
}
|
||||
|
||||
private class FastLogger : IAsyncCollector<FunctionInstanceLogEntry>, IEventCollectorFactory
|
||||
{
|
||||
|
@ -194,7 +194,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
})
|
||||
.ConfigureTypeLocator(typeof(BasicTest))
|
||||
.Build();
|
||||
|
||||
|
||||
var randomValue = Guid.NewGuid().ToString();
|
||||
|
||||
StringBuilder sbLoggingCallbacks = new StringBuilder();
|
||||
|
@ -233,7 +233,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
Assert.Equal(2, endMsg.Arguments.Count);
|
||||
Assert.True(endMsg.Arguments.ContainsKey("log"));
|
||||
Assert.Equal(randomValue, endMsg.Arguments["value"]);
|
||||
|
||||
|
||||
Assert.Equal("val=" + randomValue, endMsg.LogOutput.Trim());
|
||||
|
||||
Assert.Same(FastLogger.FlushEntry, fastLogger.List[2]);
|
||||
|
|
|
@ -14,9 +14,9 @@ using Microsoft.Azure.WebJobs.Host.Executors;
|
|||
using Microsoft.Azure.WebJobs.Host.Indexers;
|
||||
using Microsoft.Azure.WebJobs.Host.Listeners;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Blob;
|
||||
using Microsoft.WindowsAzure.Storage.Queue;
|
||||
|
@ -25,10 +25,10 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
||||
{
|
||||
// TODO: Are these meant to be tests?
|
||||
public class JobHostTests
|
||||
{
|
||||
// Checks that we write the marker file when we call the host
|
||||
[Fact]
|
||||
public void TestSdkMarkerIsWrittenWhenInAzureWebSites()
|
||||
{
|
||||
// Arrange
|
||||
|
@ -39,7 +39,9 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
|
||||
File.Delete(path);
|
||||
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(new JobHostOptions()), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder().ConfigureDefaultTestHost().Build();
|
||||
|
||||
using (host)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -59,68 +61,91 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
public void StartAsync_WhenNotStarted_DoesNotThrow()
|
||||
[Fact]
|
||||
public async Task StartAsync_WhenNotStarted_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(new JobHostOptions()), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder().ConfigureDefaultTestHost().Build().GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
// Act & Assert
|
||||
host.StartAsync().GetAwaiter().GetResult();
|
||||
await host.StartAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public void StartAsync_WhenStarted_Throws()
|
||||
[Fact]
|
||||
public async Task StartAsync_WhenStarted_Throws()
|
||||
{
|
||||
// Arrange
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(new JobHostOptions()), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder().ConfigureDefaultTestHost().Build().GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
host.Start();
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsInvalidOperation(() => host.StartAsync(), "Start has already been called.");
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => host.StartAsync());
|
||||
Assert.Equal("Start has already been called.", exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartAsync_WhenStopped_Throws()
|
||||
[Fact]
|
||||
public async Task StartAsync_WhenStopped_Throws()
|
||||
{
|
||||
// Arrange
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(new JobHostOptions()), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder().ConfigureDefaultTestHost().Build().GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
host.Start();
|
||||
host.Stop();
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsInvalidOperation(() => host.StartAsync(), "Start has already been called.");
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => host.StartAsync());
|
||||
Assert.Equal("Start has already been called.", exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void StartAsync_WhenStarting_Throws()
|
||||
[Fact]
|
||||
public async Task StartAsync_WhenStarting_Throws()
|
||||
{
|
||||
// Arrange
|
||||
// TaskCompletionSource<IStorageAccount> getAccountTaskSource = new TaskCompletionSource<IStorageAccount>();
|
||||
//JobHostOptions configuration = CreateConfiguration(new LambdaStorageAccountProvider(
|
||||
// (i1, i2) => getAccountTaskSource.Task));
|
||||
// Create a way to block StartAsync.
|
||||
TaskCompletionSource<JobHostContext> createTaskSource = new TaskCompletionSource<JobHostContext>();
|
||||
var provider = new LambdaJobHostContextFactory((a, b) => createTaskSource.Task);
|
||||
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(new JobHostOptions()), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost()
|
||||
.ConfigureServices(s =>
|
||||
{
|
||||
s.AddSingleton<IJobHostContextFactory>(_ => provider);
|
||||
})
|
||||
.Build()
|
||||
.GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
Task starting = host.StartAsync();
|
||||
Assert.False(starting.IsCompleted); // Guard
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsInvalidOperation(() => host.StartAsync(), "Start has already been called.");
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => host.StartAsync());
|
||||
Assert.Equal("Start has already been called.", exception.Message);
|
||||
|
||||
// Cleanup
|
||||
// getAccountTaskSource.SetResult(null);
|
||||
starting.GetAwaiter().GetResult();
|
||||
createTaskSource.SetResult(new JobHostContext(null, null, new Mock<IListener>().Object, null, null));
|
||||
await starting;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void StartAsync_WhenStopping_Throws()
|
||||
[Fact]
|
||||
public async Task StartAsync_WhenStopping_Throws()
|
||||
{
|
||||
// Arrange
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(new JobHostOptions()), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder().ConfigureDefaultTestHost().Build().GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
host.Start();
|
||||
|
||||
|
@ -137,7 +162,8 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
Task stopping = host.StopAsync();
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsInvalidOperation(() => host.StartAsync(), "Start has already been called.");
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => host.StartAsync());
|
||||
Assert.Equal("Start has already been called.", exception.Message);
|
||||
|
||||
// Cleanup
|
||||
stopTaskSource.SetResult(null);
|
||||
|
@ -145,10 +171,13 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StopAsync_WhenStarted_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(new JobHostOptions()), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder().ConfigureDefaultTestHost().Build().GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
host.Start();
|
||||
|
||||
|
@ -157,10 +186,13 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StopAsync_WhenStopped_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(new JobHostOptions()), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder().ConfigureDefaultTestHost().Build().GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
host.Start();
|
||||
host.Stop();
|
||||
|
@ -170,41 +202,59 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
public void StopAsync_WhenNotStarted_Throws()
|
||||
[Fact]
|
||||
public async Task StopAsync_WhenNotStarted_Throws()
|
||||
{
|
||||
// Arrange
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(new JobHostOptions()), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder().ConfigureDefaultTestHost().Build().GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsInvalidOperation(() => host.StopAsync(), "The host has not yet started.");
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => host.StopAsync());
|
||||
Assert.Equal("The host has not yet started.", exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public void StopAsync_WhenStarting_Throws()
|
||||
[Fact]
|
||||
public async Task StopAsync_WhenStarting_Throws()
|
||||
{
|
||||
// Arrange
|
||||
// TaskCompletionSource<IStorageAccount> getAccountTaskSource = new TaskCompletionSource<IStorageAccount>();
|
||||
JobHostOptions configuration = null; // CreateConfiguration(new LambdaStorageAccountProvider(
|
||||
// (i1, i2) => getAccountTaskSource.Task));
|
||||
// Create a way to block StartAsync.
|
||||
TaskCompletionSource<JobHostContext> createTaskSource = new TaskCompletionSource<JobHostContext>();
|
||||
var provider = new LambdaJobHostContextFactory((a, b) => createTaskSource.Task);
|
||||
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(configuration), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost()
|
||||
.ConfigureServices(s =>
|
||||
{
|
||||
s.AddSingleton<IJobHostContextFactory>(_ => provider);
|
||||
})
|
||||
.Build()
|
||||
.GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
Task starting = host.StartAsync();
|
||||
Assert.False(starting.IsCompleted); // Guard
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsInvalidOperation(() => host.StopAsync(), "The host has not yet started.");
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => host.StopAsync());
|
||||
Assert.Equal("The host has not yet started.", exception.Message);
|
||||
|
||||
// Cleanup
|
||||
// getAccountTaskSource.SetResult(null);
|
||||
createTaskSource.SetResult(new JobHostContext(null, null, new Mock<IListener>().Object, null, null));
|
||||
starting.GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StopAsync_WhenWaiting_ReturnsIncompleteTask()
|
||||
{
|
||||
// Arrange
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(new JobHostOptions()), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder().ConfigureDefaultTestHost().Build().GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
host.Start();
|
||||
|
||||
|
@ -230,11 +280,13 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StopAsync_WhenAlreadyStopping_ReturnsSameTask()
|
||||
{
|
||||
// Arrange
|
||||
JobHostOptions configuration = null;
|
||||
using (JobHost host = new JobHost(new OptionsWrapper<JobHostOptions>(configuration), new Mock<IJobHostContextFactory>().Object))
|
||||
var host = new HostBuilder().ConfigureDefaultTestHost().Build().GetJobHost();
|
||||
|
||||
using (host)
|
||||
{
|
||||
host.Start();
|
||||
|
||||
|
@ -262,6 +314,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SimpleInvoke_WithDictionary()
|
||||
{
|
||||
var host = JobHostFactory.Create<ProgramSimple>(null);
|
||||
|
@ -274,6 +327,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
Assert.Equal(x, ProgramSimple._value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SimpleInvoke_WithObject()
|
||||
{
|
||||
var host = JobHostFactory.Create<ProgramSimple>(null);
|
||||
|
@ -286,6 +340,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
Assert.Equal(x, ProgramSimple._value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CallAsyncWithCancellationToken_PassesCancellationTokenToMethod()
|
||||
{
|
||||
// Arrange
|
||||
|
@ -304,6 +359,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Call_WhenMethodThrows_PreservesStackTrace()
|
||||
{
|
||||
try
|
||||
|
@ -330,25 +386,37 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BlobTrigger_ProvidesBlobTriggerBindingData()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Arrange
|
||||
CloudStorageAccount account = CloudStorageAccount.DevelopmentStorageAccount;
|
||||
var host = JobHostFactory.Create<BlobTriggerBindingDataProgram>(account);
|
||||
MethodInfo methodInfo = typeof(BlobTriggerBindingDataProgram).GetMethod("OnBlob");
|
||||
string containerName = "a";
|
||||
string blobName = "b";
|
||||
string expectedPath = containerName + "/" + blobName;
|
||||
CloudBlobContainer container = account.CreateCloudBlobClient().GetContainerReference(containerName);
|
||||
ICloudBlob blob = container.GetBlockBlobReference(blobName);
|
||||
var host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost<BlobTriggerBindingDataProgram>(c =>
|
||||
{
|
||||
c.AddAzureStorage();
|
||||
})
|
||||
.Build()
|
||||
.GetJobHost();
|
||||
|
||||
// Act
|
||||
host.Call(methodInfo, new { blob = blob });
|
||||
using (host)
|
||||
{
|
||||
CloudStorageAccount account = CloudStorageAccount.DevelopmentStorageAccount;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedPath, BlobTriggerBindingDataProgram.BlobTrigger);
|
||||
MethodInfo methodInfo = typeof(BlobTriggerBindingDataProgram).GetMethod(nameof(BlobTriggerBindingDataProgram.OnBlob));
|
||||
string containerName = "a";
|
||||
string blobName = "b";
|
||||
string expectedPath = containerName + "/" + blobName;
|
||||
CloudBlobContainer container = account.CreateCloudBlobClient().GetContainerReference(containerName);
|
||||
ICloudBlob blob = container.GetBlockBlobReference(blobName);
|
||||
|
||||
// Act
|
||||
host.Call(methodInfo, new { blob = blob });
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedPath, BlobTriggerBindingDataProgram.BlobTrigger);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -356,21 +424,31 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueueTrigger_ProvidesQueueTriggerBindingData()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Arrange
|
||||
var host = JobHostFactory.Create<QueueTriggerBindingDataProgram>(
|
||||
CloudStorageAccount.DevelopmentStorageAccount);
|
||||
MethodInfo methodInfo = typeof(QueueTriggerBindingDataProgram).GetMethod("OnQueue");
|
||||
string expectedMessage = "a";
|
||||
var host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost<QueueTriggerBindingDataProgram>(c =>
|
||||
{
|
||||
c.AddAzureStorage();
|
||||
})
|
||||
.Build()
|
||||
.GetJobHost();
|
||||
|
||||
// Act
|
||||
host.Call(methodInfo, new { message = expectedMessage });
|
||||
using (host)
|
||||
{
|
||||
MethodInfo methodInfo = typeof(QueueTriggerBindingDataProgram).GetMethod(nameof(QueueTriggerBindingDataProgram.OnQueue));
|
||||
string expectedMessage = "a";
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedMessage, QueueTriggerBindingDataProgram.QueueTrigger);
|
||||
// Act
|
||||
host.Call(methodInfo, new { message = expectedMessage });
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedMessage, QueueTriggerBindingDataProgram.QueueTrigger);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -378,23 +456,33 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueueTrigger_WithTextualByteArrayMessage_ProvidesQueueTriggerBindingData()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Arrange
|
||||
var host = JobHostFactory.Create<QueueTriggerBindingDataProgram>(
|
||||
CloudStorageAccount.DevelopmentStorageAccount);
|
||||
MethodInfo methodInfo = typeof(QueueTriggerBindingDataProgram).GetMethod("OnQueue");
|
||||
string expectedMessage = "abc";
|
||||
CloudQueueMessage message = new CloudQueueMessage(expectedMessage);
|
||||
Assert.Equal(expectedMessage, message.AsString); // Guard
|
||||
var host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost<QueueTriggerBindingDataProgram>(c =>
|
||||
{
|
||||
c.AddAzureStorage();
|
||||
})
|
||||
.Build()
|
||||
.GetJobHost();
|
||||
|
||||
// Act
|
||||
host.Call(methodInfo, new { message = message });
|
||||
using (host)
|
||||
{
|
||||
MethodInfo methodInfo = typeof(QueueTriggerBindingDataProgram).GetMethod(nameof(QueueTriggerBindingDataProgram.OnQueue));
|
||||
string expectedMessage = "abc";
|
||||
CloudQueueMessage message = new CloudQueueMessage(expectedMessage);
|
||||
Assert.Equal(expectedMessage, message.AsString); // Guard
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedMessage, QueueTriggerBindingDataProgram.QueueTrigger);
|
||||
// Act
|
||||
host.Call(methodInfo, new { message });
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedMessage, QueueTriggerBindingDataProgram.QueueTrigger);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -402,25 +490,35 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueueTrigger_WithNonTextualByteArrayMessageUsingQueueTriggerBindingData_Throws()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Arrange
|
||||
var host = JobHostFactory.Create<QueueTriggerBindingDataProgram>(
|
||||
CloudStorageAccount.DevelopmentStorageAccount);
|
||||
MethodInfo methodInfo = typeof(QueueTriggerBindingDataProgram).GetMethod("OnQueue");
|
||||
byte[] contents = new byte[] { 0x00, 0xFF }; // Not valid UTF-8
|
||||
CloudQueueMessage message = CloudQueueMessage.CreateCloudQueueMessageFromByteArray(contents);
|
||||
var host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost<QueueTriggerBindingDataProgram>(c =>
|
||||
{
|
||||
c.AddAzureStorage();
|
||||
})
|
||||
.Build()
|
||||
.GetJobHost();
|
||||
|
||||
// Act & Assert
|
||||
FunctionInvocationException exception = Assert.Throws<FunctionInvocationException>(
|
||||
() => host.Call(methodInfo, new { message = message }));
|
||||
// This exeption shape/message could be better, but it's meets a minimum acceptibility threshold.
|
||||
Assert.Equal("Exception binding parameter 'queueTrigger'", exception.InnerException.Message);
|
||||
Exception innerException = exception.InnerException.InnerException;
|
||||
Assert.IsType<InvalidOperationException>(innerException);
|
||||
Assert.Equal("Binding data does not contain expected value 'queueTrigger'.", innerException.Message);
|
||||
using (host)
|
||||
{
|
||||
MethodInfo methodInfo = typeof(QueueTriggerBindingDataProgram).GetMethod(nameof(QueueTriggerBindingDataProgram.OnQueue));
|
||||
byte[] contents = new byte[] { 0x00, 0xFF }; // Not valid UTF-8
|
||||
CloudQueueMessage message = CloudQueueMessage.CreateCloudQueueMessageFromByteArray(contents);
|
||||
|
||||
// Act & Assert
|
||||
FunctionInvocationException exception = Assert.Throws<FunctionInvocationException>(
|
||||
() => host.Call(methodInfo, new { message = message }));
|
||||
// This exeption shape/message could be better, but it's meets a minimum acceptibility threshold.
|
||||
Assert.Equal("Exception binding parameter 'queueTrigger'", exception.InnerException.Message);
|
||||
Exception innerException = exception.InnerException.InnerException;
|
||||
Assert.IsType<InvalidOperationException>(innerException);
|
||||
Assert.Equal("Binding data does not contain expected value 'queueTrigger'.", innerException.Message);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -428,22 +526,32 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueueTrigger_WithNonTextualByteArrayMessageNotUsingQueueTriggerBindingData_DoesNotThrow()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Arrange
|
||||
var host = JobHostFactory.Create<QueueTriggerBindingDataProgram>(
|
||||
CloudStorageAccount.DevelopmentStorageAccount);
|
||||
MethodInfo methodInfo = typeof(QueueTriggerBindingDataProgram).GetMethod("ProcessQueueAsBytes");
|
||||
byte[] expectedBytes = new byte[] { 0x00, 0xFF }; // Not valid UTF-8
|
||||
CloudQueueMessage message = CloudQueueMessage.CreateCloudQueueMessageFromByteArray(expectedBytes);
|
||||
var host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost<QueueTriggerBindingDataProgram>(c =>
|
||||
{
|
||||
c.AddAzureStorage();
|
||||
})
|
||||
.Build()
|
||||
.GetJobHost();
|
||||
|
||||
// Act
|
||||
host.Call(methodInfo, new { message = message });
|
||||
using (host)
|
||||
{
|
||||
MethodInfo methodInfo = typeof(QueueTriggerBindingDataProgram).GetMethod(nameof(QueueTriggerBindingDataProgram.ProcessQueueAsBytes));
|
||||
byte[] expectedBytes = new byte[] { 0x00, 0xFF }; // Not valid UTF-8
|
||||
CloudQueueMessage message = CloudQueueMessage.CreateCloudQueueMessageFromByteArray(expectedBytes);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(QueueTriggerBindingDataProgram.Bytes, expectedBytes);
|
||||
// Act
|
||||
host.Call(methodInfo, new { message = message });
|
||||
|
||||
// Assert
|
||||
Assert.Equal(QueueTriggerBindingDataProgram.Bytes, expectedBytes);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -484,7 +592,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
|
||||
// verify that the binding error was logged
|
||||
Assert.Equal(5, errorLogger.GetLogMessages().Count);
|
||||
|
||||
|
||||
// Skip validating the initial 'Starting JobHost' message.
|
||||
|
||||
LogMessage logMessage = errorLogger.GetLogMessages()[1];
|
||||
|
@ -531,28 +639,20 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
/* $$$
|
||||
private class LambdaStorageAccountProvider : IStorageAccountProvider
|
||||
private class LambdaJobHostContextFactory : IJobHostContextFactory
|
||||
{
|
||||
private readonly Func<string, CancellationToken, Task<IStorageAccount>> _getAccountAsync;
|
||||
private readonly Func<CancellationToken, CancellationToken, Task<JobHostContext>> _create;
|
||||
|
||||
public LambdaStorageAccountProvider(Func<string, CancellationToken, Task<IStorageAccount>> getAccountAsync)
|
||||
public LambdaJobHostContextFactory(Func<CancellationToken, CancellationToken, Task<JobHostContext>> create)
|
||||
{
|
||||
_getAccountAsync = getAccountAsync;
|
||||
_create = create;
|
||||
}
|
||||
|
||||
public string StorageConnectionString => throw new NotImplementedException();
|
||||
|
||||
public string DashboardConnectionString => throw new NotImplementedException();
|
||||
|
||||
public string InternalSasStorage => throw new NotImplementedException();
|
||||
|
||||
public Task<IStorageAccount> TryGetAccountAsync(string connectionStringName,
|
||||
CancellationToken cancellationToken)
|
||||
public Task<JobHostContext> Create(CancellationToken shutdownToken, CancellationToken cancellationToken)
|
||||
{
|
||||
return _getAccountAsync.Invoke(connectionStringName, cancellationToken);
|
||||
return _create.Invoke(shutdownToken, cancellationToken);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private class ProgramWithCancellationToken
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FakeStorage;
|
||||
using Microsoft.Azure.WebJobs.Host.Executors;
|
||||
using Microsoft.Azure.WebJobs.Host.Indexers;
|
||||
using Microsoft.Azure.WebJobs.Host.Protocols;
|
||||
|
@ -54,34 +55,28 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Singleton
|
|||
private SingletonManager _singletonManager;
|
||||
private SingletonOptions _singletonConfig;
|
||||
|
||||
// private Mock<IStorageAccountProvider> _mockAccountProvider;
|
||||
private CloudBlobDirectory _mockBlobDirectory;
|
||||
private CloudBlobDirectory _mockSecondaryBlobDirectory;
|
||||
|
||||
//private Mock<IStorageAccount> _mockStorageAccount;
|
||||
//private Mock<IStorageAccount> _mockSecondaryStorageAccount;
|
||||
internal FakeStorage.FakeAccount _account1 = new FakeStorage.FakeAccount();
|
||||
internal FakeStorage.FakeAccount _account2 = new FakeStorage.FakeAccount();
|
||||
internal FakeAccount _account1 = new FakeAccount();
|
||||
internal FakeAccount _account2 = new FakeAccount();
|
||||
|
||||
private Mock<IWebJobsExceptionHandler> _mockExceptionDispatcher;
|
||||
private Mock<CloudBlockBlob> _mockStorageBlob;
|
||||
private TestLoggerProvider _loggerProvider;
|
||||
private Dictionary<string, string> _mockBlobMetadata;
|
||||
private readonly Dictionary<string, string> _mockBlobMetadata;
|
||||
private TestNameResolver _nameResolver;
|
||||
|
||||
//private CloudBlobDirectory _mockBlobDirectory;
|
||||
//private CloudBlobDirectory _mockSecondaryBlobDirectory;
|
||||
|
||||
class FakeLeaseProvidder : StorageBaseDistributedLockManager
|
||||
private class FakeLeaseProvider : StorageBaseDistributedLockManager
|
||||
{
|
||||
internal FakeStorage.FakeAccount _account1 = new FakeStorage.FakeAccount();
|
||||
internal FakeStorage.FakeAccount _account2 = new FakeStorage.FakeAccount();
|
||||
internal FakeAccount _account1 = new FakeAccount();
|
||||
internal FakeAccount _account2 = new FakeAccount();
|
||||
|
||||
public FakeLeaseProvidder(ILoggerFactory logger) : base(logger) { }
|
||||
public FakeLeaseProvider(ILoggerFactory logger) : base(logger) { }
|
||||
|
||||
protected override CloudBlobContainer GetContainer(string accountName)
|
||||
{
|
||||
FakeStorage.FakeAccount account;
|
||||
FakeAccount account;
|
||||
if (string.IsNullOrEmpty(accountName) || accountName == ConnectionStringNames.Storage)
|
||||
{
|
||||
account = _account1;
|
||||
|
@ -108,7 +103,7 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Singleton
|
|||
var logger = loggerFactory?.CreateLogger(LogCategories.Singleton);
|
||||
|
||||
|
||||
var leaseProvider = new FakeLeaseProvidder(loggerFactory);
|
||||
var leaseProvider = new FakeLeaseProvider(loggerFactory);
|
||||
_mockBlobDirectory = leaseProvider._account1.CreateCloudBlobClient().GetContainerReference(HostContainerNames.Hosts).GetDirectoryReference(HostDirectoryNames.SingletonLocks);
|
||||
_mockSecondaryBlobDirectory = leaseProvider._account2.CreateCloudBlobClient().GetContainerReference(HostContainerNames.Hosts).GetDirectoryReference(HostDirectoryNames.SingletonLocks);
|
||||
|
||||
|
@ -290,36 +285,36 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Singleton
|
|||
_mockStorageBlob.VerifyAll();
|
||||
}
|
||||
|
||||
// Helper to setup moc since the signatures are very complex
|
||||
void MockAcquireLeaseAsync(Action fpAction, Func<string> returns)
|
||||
// Helper to setup mock since the signatures are very complex
|
||||
private void MockAcquireLeaseAsync(Action fpAction, Func<string> returns)
|
||||
{
|
||||
_mockStorageBlob.Setup(
|
||||
p => p.AcquireLeaseAsync(_singletonConfig.LockPeriod, null, It.IsAny<AccessCondition>(), It.IsAny<BlobRequestOptions>(), It.IsAny<OperationContext>(), It.IsAny<CancellationToken>())
|
||||
)
|
||||
.Callback<TimeSpan?, string, AccessCondition, BlobRequestOptions, OperationContext, CancellationToken>(
|
||||
.Callback<TimeSpan?, string, AccessCondition, BlobRequestOptions, OperationContext, CancellationToken>(
|
||||
(mockPeriod, mockLeaseId, accessCondition, blobRequest, opCtx, cancelToken) =>
|
||||
{
|
||||
fpAction?.Invoke();
|
||||
}).Returns(() =>
|
||||
{
|
||||
var retResult = returns();
|
||||
return Task.FromResult<string>(retResult);
|
||||
});
|
||||
{
|
||||
fpAction?.Invoke();
|
||||
}).Returns(() =>
|
||||
{
|
||||
var retResult = returns();
|
||||
return Task.FromResult<string>(retResult);
|
||||
});
|
||||
}
|
||||
|
||||
void MockFetchAttributesAsync(Action fpAction)
|
||||
private void MockFetchAttributesAsync(Action fpAction)
|
||||
{
|
||||
_mockStorageBlob.Setup(
|
||||
p => p.FetchAttributesAsync(It.IsAny<AccessCondition>(), It.IsAny<BlobRequestOptions>(), It.IsAny<OperationContext>(), It.IsAny<CancellationToken>())
|
||||
)
|
||||
p => p.FetchAttributesAsync(It.IsAny<AccessCondition>(), It.IsAny<BlobRequestOptions>(), It.IsAny<OperationContext>(), It.IsAny<CancellationToken>())
|
||||
)
|
||||
.Callback<AccessCondition, BlobRequestOptions, OperationContext, CancellationToken>(
|
||||
(accessCondition, blobRequest, opCtx, cancelToken) =>
|
||||
{
|
||||
fpAction?.Invoke();
|
||||
}).Returns(() =>
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
(accessCondition, blobRequest, opCtx, cancelToken) =>
|
||||
{
|
||||
fpAction?.Invoke();
|
||||
}).Returns(() =>
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -368,65 +363,38 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Singleton
|
|||
mockRenewalTimer.VerifyAll();
|
||||
}
|
||||
|
||||
/* $$$ How to mock BlobProperties?
|
||||
|
||||
[Fact]
|
||||
public async Task GetLockOwnerAsync_LeaseLocked_ReturnsOwner()
|
||||
{
|
||||
CancellationToken cancellationToken = new CancellationToken();
|
||||
// _mockStorageBlob.SetupGet(p => p.Metadata).Returns(_mockBlobMetadata);
|
||||
var metadata = _mockStorageBlob.Object.Metadata;
|
||||
MockFetchAttributesAsync(null);
|
||||
|
||||
// _mockStorageBlob.Setup(p => p.FetchAttributesAsync(cancellationToken)).Returns(Task.FromResult(true));
|
||||
MockFetchAttributesAsync(() =>
|
||||
{
|
||||
|
||||
});
|
||||
|
||||
// Properties can't be mocked since it's really blob.attributes.Properties, and they're all internal classes with no setters.
|
||||
var props = _mockStorageBlob.Object.Properties;
|
||||
props.SetInternalField(nameof(BlobProperties.LeaseState), LeaseState.Leased);
|
||||
|
||||
//Mock<IStorageBlobProperties> mockBlobProperties = new Mock<IStorageBlobProperties>(MockBehavior.Strict);
|
||||
//mockBlobProperties.Setup(p => p.LeaseState).Returns(LeaseState.Leased);
|
||||
//_mockStorageBlob.SetupGet(p => p.Properties).Returns(mockBlobProperties.Object);
|
||||
_mockStorageBlob.Object.Properties.SetLeaseState(LeaseState.Leased);
|
||||
|
||||
SingletonAttribute attribute = new SingletonAttribute();
|
||||
string lockOwner = await _singletonManager.GetLockOwnerAsync(attribute, TestLockId, CancellationToken.None);
|
||||
Assert.Equal(null, lockOwner);
|
||||
|
||||
metadata.Add(BlobLeaseDistributedLockManager.FunctionInstanceMetadataKey, TestLockId);
|
||||
_mockStorageBlob.Object.Metadata.Add(StorageBaseDistributedLockManager.FunctionInstanceMetadataKey, TestLockId);
|
||||
lockOwner = await _singletonManager.GetLockOwnerAsync(attribute, TestLockId, CancellationToken.None);
|
||||
Assert.Equal(TestLockId, lockOwner);
|
||||
|
||||
// mockBlobProperties.VerifyAll();
|
||||
_mockStorageBlob.VerifyAll();
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task GetLockOwnerAsync_LeaseAvailable_ReturnsNull()
|
||||
{
|
||||
CancellationToken cancellationToken = new CancellationToken();
|
||||
_mockStorageBlob.Setup(p => p.FetchAttributesAsync(cancellationToken)).Returns(Task.FromResult(true));
|
||||
MockFetchAttributesAsync(null);
|
||||
|
||||
BlobProperties mockBlobProperties = new BlobProperties();
|
||||
mockBlobProperties
|
||||
mockBlobProperties.LeaseState = LeaseState.Available;
|
||||
|
||||
mockBlobProperties.Setup(p => p.LeaseState).Returns(LeaseState.Available);
|
||||
mockBlobProperties.Setup(p => p.LeaseStatus).Returns(LeaseStatus.Unlocked);
|
||||
_mockStorageBlob.SetupGet(p => p.Properties).Returns(mockBlobProperties.Object);
|
||||
_mockStorageBlob.Object.Properties.SetLeaseState(LeaseState.Available);
|
||||
_mockStorageBlob.Object.Properties.SetLeaseStatus(LeaseStatus.Unlocked);
|
||||
|
||||
SingletonAttribute attribute = new SingletonAttribute();
|
||||
string lockOwner = await _singletonManager.GetLockOwnerAsync(attribute, TestLockId, CancellationToken.None);
|
||||
Assert.Equal(null, lockOwner);
|
||||
|
||||
mockBlobProperties.VerifyAll();
|
||||
_mockStorageBlob.VerifyAll();
|
||||
}
|
||||
*/
|
||||
|
||||
[Theory]
|
||||
[InlineData(SingletonScope.Function, null, "TestHostId/Microsoft.Azure.WebJobs.Host.UnitTests.Singleton.SingletonManagerTests.TestJob")]
|
||||
|
|
|
@ -1,373 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs.Host.Executors;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Auth;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Executors
|
||||
{
|
||||
#if false // $$$ renable in new model?
|
||||
public class DefaultStorageAccountProviderTests
|
||||
{
|
||||
[Fact]
|
||||
public void ConnectionStringProvider_NoDashboardConnectionString_Throws()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{ "Dashboard", null }
|
||||
})
|
||||
.Build();
|
||||
|
||||
IStorageAccountProvider product = new DefaultStorageAccountProvider(new AmbientConnectionStringProvider(configuration), new StorageAccountParser(new StorageClientFactory()), new DefaultStorageCredentialsValidator())
|
||||
{
|
||||
StorageConnectionString = new CloudStorageAccount(new StorageCredentials("Test", string.Empty, "key"), true).ToString(exportSecrets: true)
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsInvalidOperation(() =>
|
||||
product.GetDashboardAccountAsync(CancellationToken.None).GetAwaiter().GetResult(),
|
||||
"Microsoft Azure WebJobs SDK 'Dashboard' connection string is missing or empty. The Microsoft Azure Storage account connection string can be set in the following ways:" + Environment.NewLine +
|
||||
"1. Set the connection string named 'AzureWebJobsDashboard' in the connectionStrings section of the .config file in the following format " +
|
||||
"<add name=\"AzureWebJobsDashboard\" connectionString=\"DefaultEndpointsProtocol=http|https;AccountName=NAME;AccountKey=KEY\" />, or" + Environment.NewLine +
|
||||
"2. Set the environment variable named 'AzureWebJobsDashboard', or" + Environment.NewLine +
|
||||
"3. Set corresponding property of JobHostConfiguration.");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Dashboard")]
|
||||
[InlineData("Storage")]
|
||||
public void GetAccountAsync_WhenReadFromConfig_ReturnsParsedAccount(string connectionStringName)
|
||||
{
|
||||
string connectionString = "valid-ignore";
|
||||
IStorageAccount parsedAccount = Mock.Of<IStorageAccount>();
|
||||
|
||||
Mock<IConnectionStringProvider> connectionStringProviderMock = new Mock<IConnectionStringProvider>(MockBehavior.Strict);
|
||||
connectionStringProviderMock.Setup(p => p.GetConnectionString(connectionStringName))
|
||||
.Returns(connectionString)
|
||||
.Verifiable();
|
||||
IConnectionStringProvider connectionStringProvider = connectionStringProviderMock.Object;
|
||||
|
||||
Mock<IStorageAccountParser> parserMock = new Mock<IStorageAccountParser>(MockBehavior.Strict);
|
||||
IServiceProvider services = CreateServices();
|
||||
parserMock.Setup(p => p.ParseAccount(connectionString, connectionStringName))
|
||||
.Returns(parsedAccount)
|
||||
.Verifiable();
|
||||
IStorageAccountParser parser = parserMock.Object;
|
||||
|
||||
Mock<IStorageCredentialsValidator> validatorMock = new Mock<IStorageCredentialsValidator>(
|
||||
MockBehavior.Strict);
|
||||
validatorMock.Setup(v => v.ValidateCredentialsAsync(parsedAccount, It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.FromResult(0))
|
||||
.Verifiable();
|
||||
IStorageCredentialsValidator validator = validatorMock.Object;
|
||||
|
||||
IStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
|
||||
IStorageAccount actualAccount = provider.TryGetAccountAsync(
|
||||
connectionStringName, CancellationToken.None).GetAwaiter().GetResult();
|
||||
|
||||
Assert.Same(parsedAccount, actualAccount);
|
||||
connectionStringProviderMock.Verify();
|
||||
parserMock.Verify();
|
||||
validatorMock.Verify();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Dashboard")]
|
||||
[InlineData("Storage")]
|
||||
public void GetAccountAsync_WhenInvalidConfig_PropagatesParserException(string connectionStringName)
|
||||
{
|
||||
string connectionString = "invalid-ignore";
|
||||
Exception expectedException = new InvalidOperationException();
|
||||
IConnectionStringProvider connectionStringProvider = CreateConnectionStringProvider(connectionStringName,
|
||||
connectionString);
|
||||
Mock<IStorageAccountParser> parserMock = new Mock<IStorageAccountParser>(MockBehavior.Strict);
|
||||
IServiceProvider services = CreateServices();
|
||||
parserMock.Setup(p => p.ParseAccount(connectionString, connectionStringName))
|
||||
.Throws(expectedException);
|
||||
IStorageAccountParser parser = parserMock.Object;
|
||||
|
||||
IStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser);
|
||||
|
||||
Exception actualException = Assert.Throws<InvalidOperationException>(
|
||||
() => provider.TryGetAccountAsync(connectionStringName, CancellationToken.None).GetAwaiter().GetResult());
|
||||
|
||||
Assert.Same(expectedException, actualException);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Dashboard")]
|
||||
[InlineData("Storage")]
|
||||
public void GetAccountAsync_WhenInvalidCredentials_PropagatesValidatorException(string connectionStringName)
|
||||
{
|
||||
string connectionString = "invalid-ignore";
|
||||
IStorageAccount parsedAccount = Mock.Of<IStorageAccount>();
|
||||
Exception expectedException = new InvalidOperationException();
|
||||
IConnectionStringProvider connectionStringProvider = CreateConnectionStringProvider(connectionStringName, connectionString);
|
||||
IServiceProvider services = CreateServices();
|
||||
IStorageAccountParser parser = CreateParser(services, connectionStringName, connectionString, parsedAccount);
|
||||
Mock<IStorageCredentialsValidator> validatorMock = new Mock<IStorageCredentialsValidator>(
|
||||
MockBehavior.Strict);
|
||||
validatorMock.Setup(v => v.ValidateCredentialsAsync(parsedAccount, It.IsAny<CancellationToken>()))
|
||||
.Throws(expectedException);
|
||||
IStorageCredentialsValidator validator = validatorMock.Object;
|
||||
IStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
|
||||
Exception actualException = Assert.Throws<InvalidOperationException>(
|
||||
() => provider.TryGetAccountAsync(connectionStringName, CancellationToken.None).GetAwaiter().GetResult());
|
||||
|
||||
Assert.Same(expectedException, actualException);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAccountAsync_WhenDashboardOverridden_ReturnsParsedAccount()
|
||||
{
|
||||
IConnectionStringProvider connectionStringProvider = CreateDummyConnectionStringProvider();
|
||||
string connectionString = "valid-ignore";
|
||||
IStorageAccount parsedAccount = Mock.Of<IStorageAccount>();
|
||||
IServiceProvider services = CreateServices();
|
||||
IStorageAccountParser parser = CreateParser(services, ConnectionStringNames.Dashboard, connectionString, parsedAccount);
|
||||
IStorageCredentialsValidator validator = CreateValidator(parsedAccount);
|
||||
DefaultStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
provider.DashboardConnectionString = connectionString;
|
||||
IStorageAccount actualAccount = provider.TryGetAccountAsync(
|
||||
ConnectionStringNames.Dashboard, CancellationToken.None).GetAwaiter().GetResult();
|
||||
|
||||
Assert.Same(parsedAccount, actualAccount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAccountAsync_WhenStorageOverridden_ReturnsParsedAccount()
|
||||
{
|
||||
IConnectionStringProvider connectionStringProvider = CreateDummyConnectionStringProvider();
|
||||
string connectionString = "valid-ignore";
|
||||
IStorageAccount parsedAccount = Mock.Of<IStorageAccount>();
|
||||
IServiceProvider services = CreateServices();
|
||||
IStorageAccountParser parser = CreateParser(services, ConnectionStringNames.Storage, connectionString, parsedAccount);
|
||||
IStorageCredentialsValidator validator = CreateValidator(parsedAccount);
|
||||
DefaultStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
provider.StorageConnectionString = connectionString;
|
||||
|
||||
IStorageAccount actualAccount = provider.TryGetAccountAsync(
|
||||
ConnectionStringNames.Storage, CancellationToken.None).GetAwaiter().GetResult();
|
||||
|
||||
Assert.Same(parsedAccount, actualAccount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAccountAsync_WhenDashboardOverriddenWithNull_ReturnsNull()
|
||||
{
|
||||
DefaultStorageAccountProvider provider = CreateProductUnderTest();
|
||||
provider.DashboardConnectionString = null;
|
||||
|
||||
IStorageAccount actualAccount = provider.TryGetAccountAsync(
|
||||
ConnectionStringNames.Dashboard, CancellationToken.None).GetAwaiter().GetResult();
|
||||
|
||||
Assert.Null(actualAccount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAccountAsync_WhenStorageOverriddenWithNull_Succeeds()
|
||||
{
|
||||
DefaultStorageAccountProvider provider = CreateProductUnderTest();
|
||||
provider.StorageConnectionString = null;
|
||||
|
||||
var account = await provider.TryGetAccountAsync(ConnectionStringNames.Storage, CancellationToken.None);
|
||||
Assert.Null(account);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAccountAsync_WhenNoStorage_Succeeds()
|
||||
{
|
||||
DefaultStorageAccountProvider provider = CreateProductUnderTest();
|
||||
provider.DashboardConnectionString = null;
|
||||
provider.StorageConnectionString = null;
|
||||
|
||||
var dashboardAccount = await provider.TryGetAccountAsync(ConnectionStringNames.Dashboard, CancellationToken.None);
|
||||
Assert.Null(dashboardAccount);
|
||||
|
||||
var storageAccount = await provider.TryGetAccountAsync(ConnectionStringNames.Storage, CancellationToken.None);
|
||||
Assert.Null(storageAccount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAccountAsync_WhenWebJobsStorageAccountNotGeneral_Throws()
|
||||
{
|
||||
string connectionString = "valid-ignore";
|
||||
var connStringMock = new Mock<IConnectionStringProvider>();
|
||||
connStringMock.Setup(c => c.GetConnectionString(ConnectionStringNames.Storage)).Returns(connectionString);
|
||||
var connectionStringProvider = connStringMock.Object;
|
||||
var accountMock = new Mock<IStorageAccount>();
|
||||
accountMock.SetupGet(s => s.Type).Returns(StorageAccountType.BlobOnly);
|
||||
accountMock.SetupGet(s => s.Credentials).Returns(new StorageCredentials("name", string.Empty));
|
||||
var parsedAccount = accountMock.Object;
|
||||
IServiceProvider services = CreateServices();
|
||||
IStorageAccountParser parser = CreateParser(services, ConnectionStringNames.Storage, connectionString, parsedAccount);
|
||||
IStorageCredentialsValidator validator = CreateValidator(parsedAccount);
|
||||
DefaultStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => provider.GetStorageAccountAsync(CancellationToken.None));
|
||||
|
||||
Assert.Equal("Storage account 'name' is of unsupported type 'Blob-Only/ZRS'. Supported types are 'General Purpose'", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAccountAsync_WhenWebJobsDashboardAccountNotGeneral_Throws()
|
||||
{
|
||||
string connectionString = "valid-ignore";
|
||||
var connStringMock = new Mock<IConnectionStringProvider>();
|
||||
connStringMock.Setup(c => c.GetConnectionString(ConnectionStringNames.Dashboard)).Returns(connectionString);
|
||||
var connectionStringProvider = connStringMock.Object;
|
||||
var accountMock = new Mock<IStorageAccount>();
|
||||
accountMock.SetupGet(s => s.Type).Returns(StorageAccountType.Premium);
|
||||
accountMock.SetupGet(s => s.Credentials).Returns(new StorageCredentials("name", string.Empty));
|
||||
var parsedAccount = accountMock.Object;
|
||||
IServiceProvider services = CreateServices();
|
||||
IStorageAccountParser parser = CreateParser(services, ConnectionStringNames.Dashboard, connectionString, parsedAccount);
|
||||
IStorageCredentialsValidator validator = CreateValidator(parsedAccount);
|
||||
DefaultStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => provider.GetDashboardAccountAsync(CancellationToken.None));
|
||||
|
||||
Assert.Equal("Storage account 'name' is of unsupported type 'Premium'. Supported types are 'General Purpose'", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStorageAccountAsyncTest()
|
||||
{
|
||||
string cxEmpty = "";
|
||||
var accountDefault = new Mock<IStorageAccount>().Object;
|
||||
|
||||
string cxReal = "MyAccount";
|
||||
var accountReal = new Mock<IStorageAccount>().Object;
|
||||
|
||||
var provider = new Mock<IStorageAccountProvider>();
|
||||
provider.Setup(c => c.TryGetAccountAsync(ConnectionStringNames.Storage, CancellationToken.None)).Returns(Task.FromResult<IStorageAccount>(accountDefault));
|
||||
provider.Setup(c => c.TryGetAccountAsync(cxReal, CancellationToken.None)).Returns(Task.FromResult<IStorageAccount>(accountReal));
|
||||
|
||||
var account = await StorageAccountProviderExtensions.GetStorageAccountAsync(provider.Object, cxEmpty, CancellationToken.None);
|
||||
Assert.Equal(accountDefault, account);
|
||||
|
||||
account = await StorageAccountProviderExtensions.GetStorageAccountAsync(provider.Object, cxReal, CancellationToken.None);
|
||||
Assert.Equal(accountReal, account);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAccountAsync_CachesAccounts()
|
||||
{
|
||||
var services = CreateServices();
|
||||
var accountMock = new Mock<IStorageAccount>();
|
||||
var storageMock = new Mock<IStorageAccount>();
|
||||
|
||||
var csProvider = CreateConnectionStringProvider("account", "cs");
|
||||
var parser = CreateParser(services, "account", "cs", accountMock.Object);
|
||||
|
||||
// strick mock tests that validate does not occur twice
|
||||
Mock<IStorageCredentialsValidator> validatorMock = new Mock<IStorageCredentialsValidator>(MockBehavior.Strict);
|
||||
validatorMock.Setup(v => v.ValidateCredentialsAsync(accountMock.Object, It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.CompletedTask);
|
||||
validatorMock.Setup(v => v.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
DefaultStorageAccountProvider provider = CreateProductUnderTest(services, csProvider, parser, validatorMock.Object);
|
||||
var account = await provider.TryGetAccountAsync("account", CancellationToken.None);
|
||||
var account2 = await provider.TryGetAccountAsync("account", CancellationToken.None);
|
||||
|
||||
Assert.Equal(account, account2);
|
||||
validatorMock.Verify(v => v.ValidateCredentialsAsync(accountMock.Object, It.IsAny<CancellationToken>()), Times.Once());
|
||||
}
|
||||
|
||||
private static IConnectionStringProvider CreateConnectionStringProvider(string connectionStringName,
|
||||
string connectionString)
|
||||
{
|
||||
Mock<IConnectionStringProvider> mock = new Mock<IConnectionStringProvider>(MockBehavior.Strict);
|
||||
mock.Setup(p => p.GetConnectionString(connectionStringName))
|
||||
.Returns(connectionString);
|
||||
return mock.Object;
|
||||
}
|
||||
|
||||
private static IConnectionStringProvider CreateDummyConnectionStringProvider()
|
||||
{
|
||||
return new Mock<IConnectionStringProvider>(MockBehavior.Strict).Object;
|
||||
}
|
||||
|
||||
private static IStorageAccountParser CreateDummyParser()
|
||||
{
|
||||
return new Mock<IStorageAccountParser>(MockBehavior.Strict).Object;
|
||||
}
|
||||
|
||||
private static IStorageCredentialsValidator CreateDummyValidator()
|
||||
{
|
||||
return new Mock<IStorageCredentialsValidator>(MockBehavior.Strict).Object;
|
||||
}
|
||||
|
||||
private static IServiceProvider CreateServices()
|
||||
{
|
||||
Mock<IServiceProvider> servicesMock = new Mock<IServiceProvider>(MockBehavior.Strict);
|
||||
StorageClientFactory clientFactory = new StorageClientFactory();
|
||||
servicesMock.Setup(p => p.GetService(typeof(StorageClientFactory))).Returns(clientFactory);
|
||||
|
||||
return servicesMock.Object;
|
||||
}
|
||||
|
||||
private static IStorageAccountParser CreateParser(IServiceProvider services, string connectionStringName, string connectionString, IStorageAccount parsedAccount)
|
||||
{
|
||||
Mock<IStorageAccountParser> mock = new Mock<IStorageAccountParser>(MockBehavior.Strict);
|
||||
mock.Setup(p => p.ParseAccount(connectionString, connectionStringName)).Returns(parsedAccount);
|
||||
return mock.Object;
|
||||
}
|
||||
|
||||
private static DefaultStorageAccountProvider CreateProductUnderTest()
|
||||
{
|
||||
return CreateProductUnderTest(CreateServices(), CreateDummyConnectionStringProvider(), CreateDummyParser());
|
||||
}
|
||||
|
||||
private static DefaultStorageAccountProvider CreateProductUnderTest(IServiceProvider services,
|
||||
IConnectionStringProvider ambientConnectionStringProvider, IStorageAccountParser storageAccountParser)
|
||||
{
|
||||
return CreateProductUnderTest(services, ambientConnectionStringProvider, storageAccountParser, CreateDummyValidator());
|
||||
}
|
||||
|
||||
private static DefaultStorageAccountProvider CreateProductUnderTest(IServiceProvider services,
|
||||
IConnectionStringProvider ambientConnectionStringProvider, IStorageAccountParser storageAccountParser,
|
||||
IStorageCredentialsValidator storageCredentialsValidator)
|
||||
{
|
||||
return new DefaultStorageAccountProvider(ambientConnectionStringProvider, storageAccountParser, storageCredentialsValidator);
|
||||
}
|
||||
|
||||
private static IStorageCredentialsValidator CreateValidator(IStorageAccount account)
|
||||
{
|
||||
Mock<IStorageCredentialsValidator> mock = new Mock<IStorageCredentialsValidator>(MockBehavior.Strict);
|
||||
mock.Setup(v => v.ValidateCredentialsAsync(account, It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.FromResult(0));
|
||||
return mock.Object;
|
||||
}
|
||||
|
||||
[StorageAccount("class")]
|
||||
private class AccountOverrides
|
||||
{
|
||||
[StorageAccount("method")]
|
||||
private void ParamOverride([StorageAccount("param")] string s)
|
||||
{
|
||||
}
|
||||
|
||||
[StorageAccount("method")]
|
||||
private void MethodOverride(string s)
|
||||
{
|
||||
}
|
||||
|
||||
private void ClassOverride(string s)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,204 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Microsoft.Azure.WebJobs.Host.Executors;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Auth;
|
||||
using Microsoft.WindowsAzure.Storage.Shared.Protocol;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Executors
|
||||
{
|
||||
#if false // $$$ re-enable
|
||||
public class DefaultStorageCredentialsValidatorTests
|
||||
{
|
||||
[Fact]
|
||||
public void UseReflectionToAccessIsDevStoreAccountFromCloudStorageAccount()
|
||||
{
|
||||
var isDevStoreAccountProperty = typeof(CloudStorageAccount).GetProperty("IsDevStoreAccount", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
Assert.NotNull(isDevStoreAccountProperty);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("UseDevelopmentStorage=true")]
|
||||
[InlineData("UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://myProxyUri")]
|
||||
public void StorageAccount_IsDevStoreAccount_StorageEmulatorRunning(string connectionString)
|
||||
{
|
||||
var validator = new DefaultStorageCredentialsValidator();
|
||||
|
||||
var storageMock = new Mock<IStorageAccount>(MockBehavior.Strict);
|
||||
var blobClientMock = new Mock<IStorageBlobClient>();
|
||||
var queueClientMock = new Mock<IStorageQueueClient>();
|
||||
var queueMock = new Mock<IStorageQueue>();
|
||||
|
||||
storageMock.Setup(s => s.Credentials)
|
||||
.Returns(new StorageCredentials("name", string.Empty));
|
||||
|
||||
storageMock.Setup(s => s.CreateBlobClient(null))
|
||||
.Returns(blobClientMock.Object)
|
||||
.Verifiable();
|
||||
|
||||
storageMock.Setup(s => s.SdkObject)
|
||||
.Returns(() => CloudStorageAccount.Parse(connectionString));
|
||||
|
||||
blobClientMock.Setup(b => b.GetServicePropertiesAsync(It.IsAny<CancellationToken>()))
|
||||
.Throws(new StorageException(""));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => validator.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()).GetAwaiter().GetResult());
|
||||
Assert.Equal(Constants.CheckAzureStorageEmulatorMessage, exception.Message);
|
||||
storageMock.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StorageAccount_GetPropertiesThrows_InvalidCredentials()
|
||||
{
|
||||
var validator = new DefaultStorageCredentialsValidator();
|
||||
|
||||
var storageMock = new Mock<IStorageAccount>(MockBehavior.Strict);
|
||||
var blobClientMock = new Mock<IStorageBlobClient>();
|
||||
var queueClientMock = new Mock<IStorageQueueClient>();
|
||||
var queueMock = new Mock<IStorageQueue>();
|
||||
|
||||
storageMock.Setup(s => s.Credentials)
|
||||
.Returns(new StorageCredentials("name", string.Empty));
|
||||
|
||||
storageMock.Setup(s => s.CreateBlobClient(null))
|
||||
.Returns(blobClientMock.Object)
|
||||
.Verifiable();
|
||||
|
||||
storageMock.Setup(s => s.SdkObject)
|
||||
.Returns(new CloudStorageAccount(new StorageCredentials("name", string.Empty), false));
|
||||
|
||||
blobClientMock.Setup(b => b.GetServicePropertiesAsync(It.IsAny<CancellationToken>()))
|
||||
.Throws(new StorageException(""));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => validator.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()).GetAwaiter().GetResult());
|
||||
Assert.Equal("Invalid storage account 'name'. Please make sure your credentials are correct.", exception.Message);
|
||||
storageMock.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StorageAccount_QueueCheckThrows_BlobOnly_WhenCatchingNameResolutionFailure()
|
||||
{
|
||||
var validator = new DefaultStorageCredentialsValidator();
|
||||
|
||||
var storageMock = new Mock<IStorageAccount>(MockBehavior.Strict);
|
||||
var blobClientMock = new Mock<IStorageBlobClient>();
|
||||
var queueClientMock = new Mock<IStorageQueueClient>();
|
||||
var queueMock = new Mock<IStorageQueue>();
|
||||
|
||||
storageMock.Setup(s => s.Credentials)
|
||||
.Returns(new StorageCredentials());
|
||||
|
||||
storageMock.Setup(s => s.CreateBlobClient(null))
|
||||
.Returns(blobClientMock.Object)
|
||||
.Verifiable();
|
||||
|
||||
blobClientMock.Setup(b => b.GetServicePropertiesAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((ServiceProperties)null);
|
||||
|
||||
storageMock.Setup(s => s.CreateQueueClient(null))
|
||||
.Returns(queueClientMock.Object)
|
||||
.Verifiable();
|
||||
|
||||
queueClientMock.Setup(q => q.GetQueueReference(It.IsAny<string>()))
|
||||
.Returns(queueMock.Object);
|
||||
|
||||
queueMock.Setup(q => q.ExistsAsync(It.IsAny<CancellationToken>()))
|
||||
.Throws(new StorageException("", new WebException("Remote name could not be resolved", WebExceptionStatus.NameResolutionFailure)));
|
||||
|
||||
storageMock.SetupSet(s => s.Type = StorageAccountType.BlobOnly);
|
||||
|
||||
validator.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()).GetAwaiter().GetResult();
|
||||
|
||||
storageMock.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StorageAccount_QueueCheckThrows_BlobOnly_WhenCatchingWinHttpNameNotResolved()
|
||||
{
|
||||
var validator = new DefaultStorageCredentialsValidator();
|
||||
|
||||
var storageMock = new Mock<IStorageAccount>(MockBehavior.Strict);
|
||||
var blobClientMock = new Mock<IStorageBlobClient>();
|
||||
var queueClientMock = new Mock<IStorageQueueClient>();
|
||||
var queueMock = new Mock<IStorageQueue>();
|
||||
|
||||
storageMock.Setup(s => s.Credentials)
|
||||
.Returns(new StorageCredentials());
|
||||
|
||||
storageMock.Setup(s => s.CreateBlobClient(null))
|
||||
.Returns(blobClientMock.Object)
|
||||
.Verifiable();
|
||||
|
||||
blobClientMock.Setup(b => b.GetServicePropertiesAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((ServiceProperties)null);
|
||||
|
||||
storageMock.Setup(s => s.CreateQueueClient(null))
|
||||
.Returns(queueClientMock.Object)
|
||||
.Verifiable();
|
||||
|
||||
queueClientMock.Setup(q => q.GetQueueReference(It.IsAny<string>()))
|
||||
.Returns(queueMock.Object);
|
||||
|
||||
queueMock.Setup(q => q.ExistsAsync(It.IsAny<CancellationToken>()))
|
||||
.Throws(new StorageException("", new MockHttpRequestException(0x2ee7)));
|
||||
|
||||
storageMock.SetupSet(s => s.Type = StorageAccountType.BlobOnly);
|
||||
|
||||
validator.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()).GetAwaiter().GetResult();
|
||||
|
||||
storageMock.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StorageAccount_QueueCheckThrowsUnexpectedStorage()
|
||||
{
|
||||
var validator = new DefaultStorageCredentialsValidator();
|
||||
|
||||
var storageMock = new Mock<IStorageAccount>(MockBehavior.Strict);
|
||||
var blobClientMock = new Mock<IStorageBlobClient>();
|
||||
var queueClientMock = new Mock<IStorageQueueClient>();
|
||||
var queueMock = new Mock<IStorageQueue>();
|
||||
|
||||
storageMock.Setup(s => s.Credentials)
|
||||
.Returns(new StorageCredentials());
|
||||
|
||||
storageMock.Setup(s => s.CreateBlobClient(null))
|
||||
.Returns(blobClientMock.Object)
|
||||
.Verifiable();
|
||||
|
||||
blobClientMock.Setup(b => b.GetServicePropertiesAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((ServiceProperties)null);
|
||||
|
||||
storageMock.Setup(s => s.CreateQueueClient(null))
|
||||
.Returns(queueClientMock.Object)
|
||||
.Verifiable();
|
||||
|
||||
queueClientMock.Setup(q => q.GetQueueReference(It.IsAny<string>()))
|
||||
.Returns(queueMock.Object);
|
||||
|
||||
queueMock.Setup(q => q.ExistsAsync(It.IsAny<CancellationToken>()))
|
||||
.Throws(new StorageException("some other storage exception", null));
|
||||
|
||||
var storageException = Assert.Throws<StorageException>(() => validator.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()).GetAwaiter().GetResult());
|
||||
Assert.Equal("some other storage exception", storageException.Message);
|
||||
storageMock.Verify();
|
||||
}
|
||||
|
||||
internal class MockHttpRequestException : HttpRequestException
|
||||
{
|
||||
public MockHttpRequestException(int hresult)
|
||||
{
|
||||
HResult = hresult;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Azure.WebJobs.Host.Executors;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Executors
|
||||
{
|
||||
#if false // $$$ Storage account parser tests?
|
||||
public class StorageAccountParserTests
|
||||
{
|
||||
[Fact]
|
||||
public void TryParseAccount_WithEmpty_Fails()
|
||||
{
|
||||
string connectionString = string.Empty;
|
||||
CloudStorageAccount ignore;
|
||||
|
||||
StorageAccountParseResult result = StorageAccountParser.TryParseAccount(connectionString, out ignore);
|
||||
|
||||
Assert.Equal(StorageAccountParseResult.MissingOrEmptyConnectionStringError, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseAccount_WithNull_Fails()
|
||||
{
|
||||
string connectionString = null;
|
||||
CloudStorageAccount ignore;
|
||||
|
||||
StorageAccountParseResult result = StorageAccountParser.TryParseAccount(connectionString, out ignore);
|
||||
|
||||
Assert.Equal(StorageAccountParseResult.MissingOrEmptyConnectionStringError, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseAccount_WithMalformed_Fails()
|
||||
{
|
||||
string connectionString = "DefaultEndpointsProtocol=https;AccountName=[NOVALUE];AccountKey=[NOVALUE]";
|
||||
CloudStorageAccount ignore;
|
||||
|
||||
StorageAccountParseResult result = StorageAccountParser.TryParseAccount(connectionString, out ignore);
|
||||
|
||||
Assert.Equal(StorageAccountParseResult.MalformedConnectionStringError, result);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using Microsoft.WindowsAzure.Storage.Auth;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Storage
|
||||
{
|
||||
#if false // $$$ still meaningful?
|
||||
public class StorageAccountExtensionsTests
|
||||
{
|
||||
private IStorageAccount account;
|
||||
private Mock<IStorageAccount> accountMock;
|
||||
|
||||
public StorageAccountExtensionsTests()
|
||||
{
|
||||
accountMock = new Mock<IStorageAccount>();
|
||||
account = accountMock.Object;
|
||||
accountMock.SetupGet(acc => acc.Credentials)
|
||||
.Returns(new StorageCredentials("name", string.Empty, "key"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AssertTypeOneOf_Succeeds()
|
||||
{
|
||||
account.AssertTypeOneOf(StorageAccountType.GeneralPurpose);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AssertTypeOneOf_Throws_Unsupported()
|
||||
{
|
||||
accountMock.SetupGet(acc => acc.Type).Returns(StorageAccountType.BlobOnly);
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => account.AssertTypeOneOf(StorageAccountType.GeneralPurpose));
|
||||
Assert.Equal("Storage account 'name' is of unsupported type 'Blob-Only/ZRS'. Supported types are 'General Purpose'", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AssertTypeOneOf_Throws_MultipleSuggestions()
|
||||
{
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => account.AssertTypeOneOf(StorageAccountType.BlobOnly, StorageAccountType.Premium));
|
||||
Assert.Equal("Storage account 'name' is of unsupported type 'General Purpose'. Supported types are 'Blob-Only/ZRS', 'Premium'", exception.Message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -8,11 +8,9 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs.Host.Blobs.Bindings;
|
||||
using Microsoft.Azure.WebJobs.Host.Protocols;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Blob;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using Xunit.Extensions;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Bindings
|
||||
{
|
||||
|
@ -1602,97 +1600,6 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Bindings
|
|||
Assert.Same(expectedException, task.Exception.InnerException);
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
//public void CommitAsync_CancelToken_WhenNotCompletedSynchronously_DelegatesToCancel()
|
||||
//{
|
||||
// // Arrange
|
||||
// Mock<CloudBlobStream> innerStreamMock = CreateMockInnerStream();
|
||||
// CancellableAsyncCompletionSource spy = new CancellableAsyncCompletionSource();
|
||||
// innerStreamMock.Setup(m => m.CommitAsync())
|
||||
// .SetupBeginCommit()
|
||||
// .ReturnsCompletingAsynchronously(spy);
|
||||
// innerStreamMock.SetupEndCommit();
|
||||
// CloudBlobStream innerStream = innerStreamMock.Object;
|
||||
// WatchableCloudBlobStream product = CreateProductUnderTest(innerStream);
|
||||
|
||||
// using (CancellationTokenSource tokenSource = new CancellationTokenSource())
|
||||
// {
|
||||
// CancellationToken cancellationToken = tokenSource.Token;
|
||||
|
||||
// Task task = product.CommitAsync(cancellationToken);
|
||||
// Assert.NotNull(task); // Guard
|
||||
|
||||
// // Act
|
||||
// tokenSource.Cancel();
|
||||
|
||||
// // Assert
|
||||
// Assert.True(spy.Canceled);
|
||||
|
||||
// // Cleanup
|
||||
// spy.Complete();
|
||||
// task.GetAwaiter().GetResult();
|
||||
// }
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void CommitAsync_CancelToken_AfterCompletion_DoesNotCallCancellableAsyncResultCancel()
|
||||
//{
|
||||
// // Arrange
|
||||
// Mock<CloudBlobStream> innerStreamMock = CreateMockInnerStream();
|
||||
// CompletedCancellationSpy spy = new CompletedCancellationSpy();
|
||||
// innerStreamMock
|
||||
// .SetupBeginCommit()
|
||||
// .ReturnsCompletedSynchronously(spy);
|
||||
// innerStreamMock.SetupEndCommit();
|
||||
// CloudBlobStream innerStream = innerStreamMock.Object;
|
||||
// WatchableCloudBlobStream product = CreateProductUnderTest(innerStream);
|
||||
|
||||
// using (CancellationTokenSource tokenSource = new CancellationTokenSource())
|
||||
// {
|
||||
// CancellationToken cancellationToken = tokenSource.Token;
|
||||
|
||||
// Task task = product.CommitAsync(cancellationToken);
|
||||
// Assert.NotNull(task); // Guard
|
||||
|
||||
// // Act
|
||||
// tokenSource.Cancel();
|
||||
|
||||
// // Assert
|
||||
// Assert.False(spy.Canceled);
|
||||
// task.GetAwaiter().GetResult();
|
||||
// }
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void CommitAsync_WhenNotCompletedSynchronously_CancelTokenDuringEndCommit_DoesNotCallAsyncResultCancel()
|
||||
//{
|
||||
// // Arrange
|
||||
// using (CancellationTokenSource tokenSource = new CancellationTokenSource())
|
||||
// {
|
||||
// Mock<CloudBlobStream> innerStreamMock = CreateMockInnerStream();
|
||||
// CancellableAsyncCompletionSource spy = new CancellableAsyncCompletionSource();
|
||||
// innerStreamMock
|
||||
// .SetupBeginCommit()
|
||||
// .ReturnsCompletingAsynchronously(spy);
|
||||
// innerStreamMock
|
||||
// .SetupEndCommit()
|
||||
// .Callback(() => tokenSource.Cancel());
|
||||
// CloudBlobStream innerStream = innerStreamMock.Object;
|
||||
// WatchableCloudBlobStream product = CreateProductUnderTest(innerStream);
|
||||
// CancellationToken cancellationToken = tokenSource.Token;
|
||||
|
||||
// Task task = product.CommitAsync(cancellationToken);
|
||||
// Assert.NotNull(task); // Guard
|
||||
|
||||
// // Act
|
||||
// spy.Complete();
|
||||
|
||||
// // Assert
|
||||
// Assert.False(spy.Canceled);
|
||||
// task.GetAwaiter().GetResult();
|
||||
// }
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public void CommitAsync_IfCommittedActionIsNotNull_CallsCommittedAction()
|
||||
{
|
||||
|
@ -1732,65 +1639,6 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Bindings
|
|||
product.CommitAsync(CancellationToken.None).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
|
||||
//[Fact]
|
||||
//public void CompleteAsync_WhenChanged_DelegatesToBeginEndCommit()
|
||||
//{
|
||||
// // Arrange
|
||||
// Mock<CloudBlobStream> innerStreamMock = CreateMockInnerStream();
|
||||
// CompletedCancellationSpy spy = new CompletedCancellationSpy();
|
||||
// innerStreamMock.Setup(s => s.WriteByte(It.IsAny<byte>()));
|
||||
// innerStreamMock
|
||||
// .SetupBeginCommit()
|
||||
// .ReturnsCompletedSynchronously(spy)
|
||||
// .Verifiable();
|
||||
// innerStreamMock
|
||||
// .Setup(s => s.EndCommit(It.Is<IAsyncResult>((ar) => ar == spy.AsyncResult)))
|
||||
// .Verifiable();
|
||||
// CloudBlobStream innerStream = innerStreamMock.Object;
|
||||
// WatchableCloudBlobStream product = CreateProductUnderTest(innerStream);
|
||||
|
||||
// product.WriteByte(0x00);
|
||||
|
||||
// CancellationToken cancellationToken = CancellationToken.None;
|
||||
|
||||
// // Act
|
||||
// Task task = product.CompleteAsync(cancellationToken);
|
||||
|
||||
// // Assert
|
||||
// innerStreamMock.Verify();
|
||||
// Assert.NotNull(task);
|
||||
// Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
||||
//}
|
||||
|
||||
//[Fact]
|
||||
//public void CompleteAsync_WhenChangedAndCancellationIsRequested_CallsCancellableAsyncResultCancel()
|
||||
//{
|
||||
// // Arrange
|
||||
// Mock<CloudBlobStream> innerStreamMock = CreateMockInnerStream();
|
||||
// CancellableAsyncCompletionSource spy = new CancellableAsyncCompletionSource();
|
||||
// innerStreamMock.Setup(s => s.WriteByte(It.IsAny<byte>()));
|
||||
// innerStreamMock
|
||||
// .SetupBeginCommit()
|
||||
// .ReturnsCompletingAsynchronously(spy);
|
||||
// innerStreamMock.SetupEndCommit();
|
||||
// CloudBlobStream innerStream = innerStreamMock.Object;
|
||||
// WatchableCloudBlobStream product = CreateProductUnderTest(innerStream);
|
||||
|
||||
// product.WriteByte(0x00);
|
||||
|
||||
// CancellationToken cancellationToken = new CancellationToken(canceled: true);
|
||||
// Task task = product.CompleteAsync(cancellationToken);
|
||||
|
||||
// // Act
|
||||
// spy.Complete();
|
||||
|
||||
// // Assert
|
||||
// Assert.True(spy.Canceled);
|
||||
// Assert.NotNull(task);
|
||||
// Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
||||
//}
|
||||
|
||||
[Fact]
|
||||
public void CompleteAsync_WhenChangedAndCommitted_DoesNotCommitAgainButStillReturnsTrue()
|
||||
{
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
public async Task Blob_IfBoundToCloudBlockBlob_BindsAndCreatesContainerButNotBlob()
|
||||
{
|
||||
// Act
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
|
||||
var prog = new BindToCloudBlockBlobProgram();
|
||||
IHost host = new HostBuilder()
|
||||
|
@ -73,7 +73,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
|
||||
private static StorageAccount CreateFakeStorageAccount()
|
||||
{
|
||||
return new XFakeStorageAccount();
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private static CloudQueue CreateQueue(StorageAccount account, string queueName)
|
||||
|
|
|
@ -98,7 +98,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
|
||||
private static StorageAccount CreateFakeStorageAccount()
|
||||
{
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
|
||||
// make sure our system containers are present
|
||||
var container = CreateContainer(account, "azure-webjobs-hosts");
|
||||
|
|
|
@ -5,10 +5,11 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Host.Config;
|
||||
using Microsoft.Azure.WebJobs.Host.FunctionalTests.TestDoubles;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
||||
|
@ -34,6 +35,8 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
builder.AddAzureStorage()
|
||||
.UseStorage(account)
|
||||
.ConfigureCatchFailures(src, signalOnFirst, ignoreFailureFunctions);
|
||||
|
||||
builder.Services.AddSingleton<IConfigureOptions<QueuesOptions>, FakeQueuesOptionsSetup>();
|
||||
}, programType)
|
||||
.Build();
|
||||
|
||||
|
|
|
@ -368,11 +368,11 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
|||
Assert.True(task.Result.Succeeded);
|
||||
}
|
||||
|
||||
private static XFakeStorageAccount CreateAccount()
|
||||
private static FakeStorageAccount CreateAccount()
|
||||
{
|
||||
//StorageClientFactory clientFactory = new StorageClientFactory();
|
||||
//return new StorageAccount(CloudStorageAccount.DevelopmentStorageAccount, clientFactory);
|
||||
return new XFakeStorageAccount();
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private static CloudBlockBlob CreateBlobReference()
|
||||
|
|
|
@ -296,7 +296,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests.Blobs.Listeners
|
|||
|
||||
private static StorageAccount CreateFakeStorageAccount()
|
||||
{
|
||||
return new XFakeStorageAccount();
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private void AssertLogPollStrategyUsed(IBlobListenerStrategy product, int containerCount)
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests.Blobs.Listeners
|
|||
|
||||
private static StorageAccount CreateFakeStorageAccount()
|
||||
{
|
||||
return new XFakeStorageAccount();
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private class LambdaBlobTriggerExecutor : ITriggerExecutor<ICloudBlob>
|
||||
|
|
|
@ -12,9 +12,9 @@ using Microsoft.WindowsAzure.Storage.Blob;
|
|||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
||||
{
|
||||
#if false // $$$ Is this just testing the test?
|
||||
public class StorageBlobClientExtensionsTests
|
||||
{
|
||||
[Theory]
|
||||
|
@ -22,15 +22,15 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
|||
[InlineData(30000)]
|
||||
public async Task ListBlobsAsync_FollowsContinuationTokensToEnd(int blobCount)
|
||||
{
|
||||
Mock<IStorageBlobClient> mockClient = new Mock<IStorageBlobClient>(MockBehavior.Strict);
|
||||
Mock<CloudBlobClient> mockClient = new Mock<CloudBlobClient>(MockBehavior.Strict, new Uri("https://fakestorage"));
|
||||
|
||||
int maxResults = 5000;
|
||||
List<IStorageListBlobItem> blobs = GetMockBlobs(blobCount);
|
||||
List<IListBlobItem> blobs = GetMockBlobs(blobCount);
|
||||
int numPages = (int)Math.Ceiling(((decimal)blobCount / maxResults));
|
||||
|
||||
// create the test data pages with continuation tokens
|
||||
List<IStorageBlobResultSegment> blobSegments = new List<IStorageBlobResultSegment>();
|
||||
IStorageBlobResultSegment initialSegement = null;
|
||||
List<BlobResultSegment> blobSegments = new List<BlobResultSegment>();
|
||||
BlobResultSegment initialSegement = null;
|
||||
for (int i = 0; i < numPages; i++)
|
||||
{
|
||||
BlobContinuationToken continuationToken = null;
|
||||
|
@ -43,26 +43,26 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
|||
};
|
||||
}
|
||||
|
||||
Mock<IStorageBlobResultSegment> mockSegment = new Mock<IStorageBlobResultSegment>(MockBehavior.Strict);
|
||||
mockSegment.SetupGet(p => p.Results).Returns(blobs.Skip(i * maxResults).Take(maxResults).ToArray());
|
||||
mockSegment.SetupGet(p => p.ContinuationToken).Returns(continuationToken);
|
||||
BlobResultSegment segment = new BlobResultSegment(
|
||||
blobs.Skip(i * maxResults).Take(maxResults).ToArray(),
|
||||
continuationToken);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
initialSegement = mockSegment.Object;
|
||||
initialSegement = segment;
|
||||
}
|
||||
else
|
||||
{
|
||||
blobSegments.Add(mockSegment.Object);
|
||||
blobSegments.Add(segment);
|
||||
}
|
||||
}
|
||||
|
||||
// Mock the List function to return the correct blob page
|
||||
HashSet<BlobContinuationToken> seenTokens = new HashSet<BlobContinuationToken>();
|
||||
IStorageBlobResultSegment resultSegment = null;
|
||||
mockClient.Setup(p => p.ListBlobsSegmentedAsync("test", true, BlobListingDetails.None, null, It.IsAny<BlobContinuationToken>(), null, null, CancellationToken.None))
|
||||
.Callback<string, bool, BlobListingDetails, int?, BlobContinuationToken, BlobRequestOptions, OperationContext, CancellationToken>(
|
||||
(prefix, useFlatBlobListing, blobListingDetails, maxResultsValue, currentToken, options, operationContext, cancellationToken) =>
|
||||
BlobResultSegment resultSegment = null;
|
||||
mockClient.Setup(p => p.ListBlobsSegmentedAsync("test", true, BlobListingDetails.None, null, It.IsAny<BlobContinuationToken>(), null, null))
|
||||
.Callback<string, bool, BlobListingDetails, int?, BlobContinuationToken, BlobRequestOptions, OperationContext>(
|
||||
(prefix, useFlatBlobListing, blobListingDetails, maxResultsValue, currentToken, options, operationContext) =>
|
||||
{
|
||||
// Previously this is where a bug existed - ListBlobsAsync wasn't handling
|
||||
// continuation tokens properly and kept sending the same initial token
|
||||
|
@ -81,18 +81,25 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
|||
})
|
||||
.Returns(() => { return Task.FromResult(resultSegment); });
|
||||
|
||||
IEnumerable<IStorageListBlobItem> results = await mockClient.Object.ListBlobsAsync("test", true, BlobListingDetails.None, CancellationToken.None);
|
||||
IEnumerable<IListBlobItem> results = await mockClient.Object.ListBlobsAsync("test", true, BlobListingDetails.None, CancellationToken.None);
|
||||
|
||||
Assert.Equal(blobCount, results.Count());
|
||||
}
|
||||
|
||||
private class FakeBlobItem : IStorageListBlobItem
|
||||
private class FakeBlobItem : IListBlobItem
|
||||
{
|
||||
public Uri Uri => throw new NotImplementedException();
|
||||
|
||||
public StorageUri StorageUri => throw new NotImplementedException();
|
||||
|
||||
public CloudBlobDirectory Parent => throw new NotImplementedException();
|
||||
|
||||
public CloudBlobContainer Container => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private List<IStorageListBlobItem> GetMockBlobs(int count)
|
||||
private List<IListBlobItem> GetMockBlobs(int count)
|
||||
{
|
||||
List<IStorageListBlobItem> blobs = new List<IStorageListBlobItem>();
|
||||
List<IListBlobItem> blobs = new List<IListBlobItem>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
blobs.Add(new FakeBlobItem());
|
||||
|
@ -100,5 +107,4 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
|||
return blobs;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
||||
{
|
||||
#if false // $$$ Is this just testing the test?
|
||||
public class StorageBlobContainerExtensionsTests
|
||||
{
|
||||
[Theory]
|
||||
|
@ -22,15 +21,15 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
|||
[InlineData(30000)]
|
||||
public async Task ListBlobsAsync_FollowsContinuationTokensToEnd(int blobCount)
|
||||
{
|
||||
Mock<IStorageBlobContainer> mockContainer = new Mock<IStorageBlobContainer>(MockBehavior.Strict);
|
||||
Mock<CloudBlobContainer> mockContainer = new Mock<CloudBlobContainer>(MockBehavior.Strict, new Uri("https://fakeaddress"));
|
||||
|
||||
int maxResults = 5000;
|
||||
List<IStorageListBlobItem> blobs = GetMockBlobs(blobCount);
|
||||
List<IListBlobItem> blobs = GetMockBlobs(blobCount);
|
||||
int numPages = (int)Math.Ceiling(((decimal)blobCount / maxResults));
|
||||
|
||||
// create the test data pages with continuation tokens
|
||||
List<IStorageBlobResultSegment> blobSegments = new List<IStorageBlobResultSegment>();
|
||||
IStorageBlobResultSegment initialSegement = null;
|
||||
List<BlobResultSegment> blobSegments = new List<BlobResultSegment>();
|
||||
BlobResultSegment initialSegement = null;
|
||||
for (int i = 0; i < numPages; i++)
|
||||
{
|
||||
BlobContinuationToken continuationToken = null;
|
||||
|
@ -43,23 +42,23 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
|||
};
|
||||
}
|
||||
|
||||
Mock<IStorageBlobResultSegment> mockSegment = new Mock<IStorageBlobResultSegment>(MockBehavior.Strict);
|
||||
mockSegment.SetupGet(p => p.Results).Returns(blobs.Skip(i * maxResults).Take(maxResults).ToArray());
|
||||
mockSegment.SetupGet(p => p.ContinuationToken).Returns(continuationToken);
|
||||
BlobResultSegment segment = new BlobResultSegment(
|
||||
blobs.Skip(i * maxResults).Take(maxResults).ToArray(),
|
||||
continuationToken);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
initialSegement = mockSegment.Object;
|
||||
initialSegement = segment;
|
||||
}
|
||||
else
|
||||
{
|
||||
blobSegments.Add(mockSegment.Object);
|
||||
blobSegments.Add(segment);
|
||||
}
|
||||
}
|
||||
|
||||
// Mock the List function to return the correct blob page
|
||||
HashSet<BlobContinuationToken> seenTokens = new HashSet<BlobContinuationToken>();
|
||||
IStorageBlobResultSegment resultSegment = null;
|
||||
BlobResultSegment resultSegment = null;
|
||||
mockContainer.Setup(p => p.ListBlobsSegmentedAsync(null, true, BlobListingDetails.None, null, It.IsAny<BlobContinuationToken>(), null, null, CancellationToken.None))
|
||||
.Callback<string, bool, BlobListingDetails, int?, BlobContinuationToken, BlobRequestOptions, OperationContext, CancellationToken>(
|
||||
(prefix, useFlatBlobListing, blobListingDetails, maxResultsValue, currentToken, options, operationContext, cancellationToken) =>
|
||||
|
@ -81,18 +80,25 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
|||
})
|
||||
.Returns(() => { return Task.FromResult(resultSegment); });
|
||||
|
||||
IEnumerable<IStorageListBlobItem> results = await mockContainer.Object.ListBlobsAsync(null, true, CancellationToken.None);
|
||||
IEnumerable<IListBlobItem> results = await mockContainer.Object.ListBlobsAsync(null, true, CancellationToken.None);
|
||||
|
||||
Assert.Equal(blobCount, results.Count());
|
||||
}
|
||||
|
||||
private class FakeBlobItem : IStorageListBlobItem
|
||||
private class FakeBlobItem : IListBlobItem
|
||||
{
|
||||
public Uri Uri => throw new NotImplementedException();
|
||||
|
||||
public StorageUri StorageUri => throw new NotImplementedException();
|
||||
|
||||
public CloudBlobDirectory Parent => throw new NotImplementedException();
|
||||
|
||||
public CloudBlobContainer Container => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private List<IStorageListBlobItem> GetMockBlobs(int count)
|
||||
private List<IListBlobItem> GetMockBlobs(int count)
|
||||
{
|
||||
List<IStorageListBlobItem> blobs = new List<IStorageListBlobItem>();
|
||||
List<IListBlobItem> blobs = new List<IListBlobItem>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
blobs.Add(new FakeBlobItem());
|
||||
|
@ -100,5 +106,4 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Blobs.Listeners
|
|||
return blobs;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests.Blobs.Listeners
|
|||
string storageAccountName = Guid.NewGuid().ToString();
|
||||
string containerName = Guid.NewGuid().ToString();
|
||||
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
var client = account.CreateCloudBlobClient();
|
||||
|
||||
// by default there is no table in this client
|
||||
|
@ -38,7 +38,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests.Blobs.Listeners
|
|||
string storageAccountName = Guid.NewGuid().ToString();
|
||||
string containerName = Guid.NewGuid().ToString();
|
||||
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
var client = account.CreateCloudBlobClient();
|
||||
var container = client.GetContainerReference(HostContainerNames.Hosts);
|
||||
await container.CreateIfNotExistsAsync();
|
||||
|
@ -57,7 +57,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests.Blobs.Listeners
|
|||
string storageAccountName = "account=" + Guid.NewGuid().ToString();
|
||||
string containerName = "container-" + Guid.NewGuid().ToString();
|
||||
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
var client = account.CreateCloudBlobClient();
|
||||
var container = client.GetContainerReference(HostContainerNames.Hosts);
|
||||
await container.CreateIfNotExistsAsync();
|
||||
|
@ -79,7 +79,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests.Blobs.Listeners
|
|||
string storageAccountName = Guid.NewGuid().ToString();
|
||||
string containerName = Guid.NewGuid().ToString();
|
||||
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
var client = account.CreateCloudBlobClient();
|
||||
var container = client.GetContainerReference(HostContainerNames.Hosts);
|
||||
await container.CreateIfNotExistsAsync();
|
||||
|
@ -104,7 +104,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests.Blobs.Listeners
|
|||
string storageAccountName = Guid.NewGuid().ToString();
|
||||
string containerName = Guid.NewGuid().ToString();
|
||||
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
var client = account.CreateCloudBlobClient();
|
||||
var container = client.GetContainerReference(HostContainerNames.Hosts);
|
||||
await container.CreateIfNotExistsAsync();
|
||||
|
|
|
@ -0,0 +1,362 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Executors
|
||||
{
|
||||
public class DefaultStorageAccountProviderTests
|
||||
{
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public void ConnectionStringProvider_NoDashboardConnectionString_Throws()
|
||||
{
|
||||
//var configuration = new ConfigurationBuilder()
|
||||
// .AddInMemoryCollection(new Dictionary<string, string>
|
||||
// {
|
||||
// { "Dashboard", null }
|
||||
// })
|
||||
// .Build();
|
||||
|
||||
//IStorageAccountProvider product = new DefaultStorageAccountProvider(new AmbientConnectionStringProvider(configuration), new StorageAccountParser(new StorageClientFactory()), new DefaultStorageCredentialsValidator())
|
||||
//{
|
||||
// StorageConnectionString = new CloudStorageAccount(new StorageCredentials("Test", string.Empty, "key"), true).ToString(exportSecrets: true)
|
||||
//};
|
||||
|
||||
//// Act & Assert
|
||||
//ExceptionAssert.ThrowsInvalidOperation(() =>
|
||||
// product.GetDashboardAccountAsync(CancellationToken.None).GetAwaiter().GetResult(),
|
||||
// "Microsoft Azure WebJobs SDK 'Dashboard' connection string is missing or empty. The Microsoft Azure Storage account connection string can be set in the following ways:" + Environment.NewLine +
|
||||
// "1. Set the connection string named 'AzureWebJobsDashboard' in the connectionStrings section of the .config file in the following format " +
|
||||
// "<add name=\"AzureWebJobsDashboard\" connectionString=\"DefaultEndpointsProtocol=http|https;AccountName=NAME;AccountKey=KEY\" />, or" + Environment.NewLine +
|
||||
// "2. Set the environment variable named 'AzureWebJobsDashboard', or" + Environment.NewLine +
|
||||
// "3. Set corresponding property of JobHostConfiguration.");
|
||||
}
|
||||
|
||||
[Theory(Skip = "Missing StorageAccountParser")]
|
||||
[InlineData("Dashboard")]
|
||||
[InlineData("Storage")]
|
||||
public void GetAccountAsync_WhenReadFromConfig_ReturnsParsedAccount(string connectionStringName)
|
||||
{
|
||||
//string connectionString = "valid-ignore";
|
||||
//IStorageAccount parsedAccount = Mock.Of<IStorageAccount>();
|
||||
|
||||
//Mock<IConnectionStringProvider> connectionStringProviderMock = new Mock<IConnectionStringProvider>(MockBehavior.Strict);
|
||||
//connectionStringProviderMock.Setup(p => p.GetConnectionString(connectionStringName))
|
||||
// .Returns(connectionString)
|
||||
// .Verifiable();
|
||||
//IConnectionStringProvider connectionStringProvider = connectionStringProviderMock.Object;
|
||||
|
||||
//Mock<IStorageAccountParser> parserMock = new Mock<IStorageAccountParser>(MockBehavior.Strict);
|
||||
//IServiceProvider services = CreateServices();
|
||||
//parserMock.Setup(p => p.ParseAccount(connectionString, connectionStringName))
|
||||
// .Returns(parsedAccount)
|
||||
// .Verifiable();
|
||||
//IStorageAccountParser parser = parserMock.Object;
|
||||
|
||||
//Mock<IStorageCredentialsValidator> validatorMock = new Mock<IStorageCredentialsValidator>(
|
||||
// MockBehavior.Strict);
|
||||
//validatorMock.Setup(v => v.ValidateCredentialsAsync(parsedAccount, It.IsAny<CancellationToken>()))
|
||||
// .Returns(Task.FromResult(0))
|
||||
// .Verifiable();
|
||||
//IStorageCredentialsValidator validator = validatorMock.Object;
|
||||
|
||||
//IStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
|
||||
//IStorageAccount actualAccount = provider.TryGetAccountAsync(
|
||||
// connectionStringName, CancellationToken.None).GetAwaiter().GetResult();
|
||||
|
||||
//Assert.Same(parsedAccount, actualAccount);
|
||||
//connectionStringProviderMock.Verify();
|
||||
//parserMock.Verify();
|
||||
//validatorMock.Verify();
|
||||
}
|
||||
|
||||
[Theory(Skip = "Missing StorageAccountParser")]
|
||||
[InlineData("Dashboard")]
|
||||
[InlineData("Storage")]
|
||||
public void GetAccountAsync_WhenInvalidConfig_PropagatesParserException(string connectionStringName)
|
||||
{
|
||||
//string connectionString = "invalid-ignore";
|
||||
//Exception expectedException = new InvalidOperationException();
|
||||
//IConnectionStringProvider connectionStringProvider = CreateConnectionStringProvider(connectionStringName,
|
||||
// connectionString);
|
||||
//Mock<IStorageAccountParser> parserMock = new Mock<IStorageAccountParser>(MockBehavior.Strict);
|
||||
//IServiceProvider services = CreateServices();
|
||||
//parserMock.Setup(p => p.ParseAccount(connectionString, connectionStringName))
|
||||
// .Throws(expectedException);
|
||||
//IStorageAccountParser parser = parserMock.Object;
|
||||
|
||||
//IStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser);
|
||||
|
||||
//Exception actualException = Assert.Throws<InvalidOperationException>(
|
||||
// () => provider.TryGetAccountAsync(connectionStringName, CancellationToken.None).GetAwaiter().GetResult());
|
||||
|
||||
//Assert.Same(expectedException, actualException);
|
||||
}
|
||||
|
||||
[Theory(Skip = "Missing StorageAccountParser")]
|
||||
[InlineData("Dashboard")]
|
||||
[InlineData("Storage")]
|
||||
public void GetAccountAsync_WhenInvalidCredentials_PropagatesValidatorException(string connectionStringName)
|
||||
{
|
||||
//string connectionString = "invalid-ignore";
|
||||
//IStorageAccount parsedAccount = Mock.Of<IStorageAccount>();
|
||||
//Exception expectedException = new InvalidOperationException();
|
||||
//IConnectionStringProvider connectionStringProvider = CreateConnectionStringProvider(connectionStringName, connectionString);
|
||||
//IServiceProvider services = CreateServices();
|
||||
//IStorageAccountParser parser = CreateParser(services, connectionStringName, connectionString, parsedAccount);
|
||||
//Mock<IStorageCredentialsValidator> validatorMock = new Mock<IStorageCredentialsValidator>(
|
||||
// MockBehavior.Strict);
|
||||
//validatorMock.Setup(v => v.ValidateCredentialsAsync(parsedAccount, It.IsAny<CancellationToken>()))
|
||||
// .Throws(expectedException);
|
||||
//IStorageCredentialsValidator validator = validatorMock.Object;
|
||||
//IStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
|
||||
//Exception actualException = Assert.Throws<InvalidOperationException>(
|
||||
// () => provider.TryGetAccountAsync(connectionStringName, CancellationToken.None).GetAwaiter().GetResult());
|
||||
|
||||
//Assert.Same(expectedException, actualException);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public void GetAccountAsync_WhenDashboardOverridden_ReturnsParsedAccount()
|
||||
{
|
||||
//IConnectionStringProvider connectionStringProvider = CreateDummyConnectionStringProvider();
|
||||
//string connectionString = "valid-ignore";
|
||||
//IStorageAccount parsedAccount = Mock.Of<IStorageAccount>();
|
||||
//IServiceProvider services = CreateServices();
|
||||
//IStorageAccountParser parser = CreateParser(services, ConnectionStringNames.Dashboard, connectionString, parsedAccount);
|
||||
//IStorageCredentialsValidator validator = CreateValidator(parsedAccount);
|
||||
//DefaultStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
//provider.DashboardConnectionString = connectionString;
|
||||
//IStorageAccount actualAccount = provider.TryGetAccountAsync(
|
||||
// ConnectionStringNames.Dashboard, CancellationToken.None).GetAwaiter().GetResult();
|
||||
|
||||
//Assert.Same(parsedAccount, actualAccount);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public void GetAccountAsync_WhenStorageOverridden_ReturnsParsedAccount()
|
||||
{
|
||||
//IConnectionStringProvider connectionStringProvider = CreateDummyConnectionStringProvider();
|
||||
//string connectionString = "valid-ignore";
|
||||
//IStorageAccount parsedAccount = Mock.Of<IStorageAccount>();
|
||||
//IServiceProvider services = CreateServices();
|
||||
//IStorageAccountParser parser = CreateParser(services, ConnectionStringNames.Storage, connectionString, parsedAccount);
|
||||
//IStorageCredentialsValidator validator = CreateValidator(parsedAccount);
|
||||
//DefaultStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
//provider.StorageConnectionString = connectionString;
|
||||
|
||||
//IStorageAccount actualAccount = provider.TryGetAccountAsync(
|
||||
// ConnectionStringNames.Storage, CancellationToken.None).GetAwaiter().GetResult();
|
||||
|
||||
//Assert.Same(parsedAccount, actualAccount);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public void GetAccountAsync_WhenDashboardOverriddenWithNull_ReturnsNull()
|
||||
{
|
||||
//DefaultStorageAccountProvider provider = CreateProductUnderTest();
|
||||
//provider.DashboardConnectionString = null;
|
||||
|
||||
//IStorageAccount actualAccount = provider.TryGetAccountAsync(
|
||||
// ConnectionStringNames.Dashboard, CancellationToken.None).GetAwaiter().GetResult();
|
||||
|
||||
//Assert.Null(actualAccount);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public async Task GetAccountAsync_WhenStorageOverriddenWithNull_Succeeds()
|
||||
{
|
||||
//DefaultStorageAccountProvider provider = CreateProductUnderTest();
|
||||
//provider.StorageConnectionString = null;
|
||||
|
||||
//var account = await provider.TryGetAccountAsync(ConnectionStringNames.Storage, CancellationToken.None);
|
||||
//Assert.Null(account);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public async Task GetAccountAsync_WhenNoStorage_Succeeds()
|
||||
{
|
||||
//DefaultStorageAccountProvider provider = CreateProductUnderTest();
|
||||
//provider.DashboardConnectionString = null;
|
||||
//provider.StorageConnectionString = null;
|
||||
|
||||
//var dashboardAccount = await provider.TryGetAccountAsync(ConnectionStringNames.Dashboard, CancellationToken.None);
|
||||
//Assert.Null(dashboardAccount);
|
||||
|
||||
//var storageAccount = await provider.TryGetAccountAsync(ConnectionStringNames.Storage, CancellationToken.None);
|
||||
//Assert.Null(storageAccount);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public async Task GetAccountAsync_WhenWebJobsStorageAccountNotGeneral_Throws()
|
||||
{
|
||||
//string connectionString = "valid-ignore";
|
||||
//var connStringMock = new Mock<IConnectionStringProvider>();
|
||||
//connStringMock.Setup(c => c.GetConnectionString(ConnectionStringNames.Storage)).Returns(connectionString);
|
||||
//var connectionStringProvider = connStringMock.Object;
|
||||
//var accountMock = new Mock<IStorageAccount>();
|
||||
//accountMock.SetupGet(s => s.Type).Returns(StorageAccountType.BlobOnly);
|
||||
//accountMock.SetupGet(s => s.Credentials).Returns(new StorageCredentials("name", string.Empty));
|
||||
//var parsedAccount = accountMock.Object;
|
||||
//IServiceProvider services = CreateServices();
|
||||
//IStorageAccountParser parser = CreateParser(services, ConnectionStringNames.Storage, connectionString, parsedAccount);
|
||||
//IStorageCredentialsValidator validator = CreateValidator(parsedAccount);
|
||||
//DefaultStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
//var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => provider.GetStorageAccountAsync(CancellationToken.None));
|
||||
|
||||
//Assert.Equal("Storage account 'name' is of unsupported type 'Blob-Only/ZRS'. Supported types are 'General Purpose'", exception.Message);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public async Task GetAccountAsync_WhenWebJobsDashboardAccountNotGeneral_Throws()
|
||||
{
|
||||
// string connectionString = "valid-ignore";
|
||||
// var connStringMock = new Mock<IConnectionStringProvider>();
|
||||
// connStringMock.Setup(c => c.GetConnectionString(ConnectionStringNames.Dashboard)).Returns(connectionString);
|
||||
// var connectionStringProvider = connStringMock.Object;
|
||||
// var accountMock = new Mock<IStorageAccount>();
|
||||
// accountMock.SetupGet(s => s.Type).Returns(StorageAccountType.Premium);
|
||||
// accountMock.SetupGet(s => s.Credentials).Returns(new StorageCredentials("name", string.Empty));
|
||||
// var parsedAccount = accountMock.Object;
|
||||
// IServiceProvider services = CreateServices();
|
||||
// IStorageAccountParser parser = CreateParser(services, ConnectionStringNames.Dashboard, connectionString, parsedAccount);
|
||||
// IStorageCredentialsValidator validator = CreateValidator(parsedAccount);
|
||||
// DefaultStorageAccountProvider provider = CreateProductUnderTest(services, connectionStringProvider, parser, validator);
|
||||
// var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => provider.GetDashboardAccountAsync(CancellationToken.None));
|
||||
|
||||
// Assert.Equal("Storage account 'name' is of unsupported type 'Premium'. Supported types are 'General Purpose'", exception.Message);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public async Task GetStorageAccountAsyncTest()
|
||||
{
|
||||
//string cxEmpty = "";
|
||||
//var accountDefault = new Mock<IStorageAccount>().Object;
|
||||
|
||||
//string cxReal = "MyAccount";
|
||||
//var accountReal = new Mock<IStorageAccount>().Object;
|
||||
|
||||
//var provider = new Mock<IStorageAccountProvider>();
|
||||
//provider.Setup(c => c.TryGetAccountAsync(ConnectionStringNames.Storage, CancellationToken.None)).Returns(Task.FromResult<IStorageAccount>(accountDefault));
|
||||
//provider.Setup(c => c.TryGetAccountAsync(cxReal, CancellationToken.None)).Returns(Task.FromResult<IStorageAccount>(accountReal));
|
||||
|
||||
//var account = await StorageAccountProviderExtensions.GetStorageAccountAsync(provider.Object, cxEmpty, CancellationToken.None);
|
||||
//Assert.Equal(accountDefault, account);
|
||||
|
||||
//account = await StorageAccountProviderExtensions.GetStorageAccountAsync(provider.Object, cxReal, CancellationToken.None);
|
||||
//Assert.Equal(accountReal, account);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public async Task GetAccountAsync_CachesAccounts()
|
||||
{
|
||||
//var services = CreateServices();
|
||||
//var accountMock = new Mock<IStorageAccount>();
|
||||
//var storageMock = new Mock<IStorageAccount>();
|
||||
|
||||
//var csProvider = CreateConnectionStringProvider("account", "cs");
|
||||
//var parser = CreateParser(services, "account", "cs", accountMock.Object);
|
||||
|
||||
//// strick mock tests that validate does not occur twice
|
||||
//Mock<IStorageCredentialsValidator> validatorMock = new Mock<IStorageCredentialsValidator>(MockBehavior.Strict);
|
||||
//validatorMock.Setup(v => v.ValidateCredentialsAsync(accountMock.Object, It.IsAny<CancellationToken>()))
|
||||
// .Returns(Task.CompletedTask);
|
||||
//validatorMock.Setup(v => v.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()))
|
||||
// .Returns(Task.CompletedTask);
|
||||
|
||||
//DefaultStorageAccountProvider provider = CreateProductUnderTest(services, csProvider, parser, validatorMock.Object);
|
||||
//var account = await provider.TryGetAccountAsync("account", CancellationToken.None);
|
||||
//var account2 = await provider.TryGetAccountAsync("account", CancellationToken.None);
|
||||
|
||||
//Assert.Equal(account, account2);
|
||||
//validatorMock.Verify(v => v.ValidateCredentialsAsync(accountMock.Object, It.IsAny<CancellationToken>()), Times.Once());
|
||||
}
|
||||
|
||||
//private static IConnectionStringProvider CreateConnectionStringProvider(string connectionStringName,
|
||||
// string connectionString)
|
||||
//{
|
||||
// Mock<IConnectionStringProvider> mock = new Mock<IConnectionStringProvider>(MockBehavior.Strict);
|
||||
// mock.Setup(p => p.GetConnectionString(connectionStringName))
|
||||
// .Returns(connectionString);
|
||||
// return mock.Object;
|
||||
//}
|
||||
|
||||
//private static IConnectionStringProvider CreateDummyConnectionStringProvider()
|
||||
//{
|
||||
// return new Mock<IConnectionStringProvider>(MockBehavior.Strict).Object;
|
||||
//}
|
||||
|
||||
//private static IStorageAccountParser CreateDummyParser()
|
||||
//{
|
||||
// return new Mock<IStorageAccountParser>(MockBehavior.Strict).Object;
|
||||
//}
|
||||
|
||||
//private static IStorageCredentialsValidator CreateDummyValidator()
|
||||
//{
|
||||
// return new Mock<IStorageCredentialsValidator>(MockBehavior.Strict).Object;
|
||||
//}
|
||||
|
||||
//private static IServiceProvider CreateServices()
|
||||
//{
|
||||
// Mock<IServiceProvider> servicesMock = new Mock<IServiceProvider>(MockBehavior.Strict);
|
||||
// StorageClientFactory clientFactory = new StorageClientFactory();
|
||||
// servicesMock.Setup(p => p.GetService(typeof(StorageClientFactory))).Returns(clientFactory);
|
||||
|
||||
// return servicesMock.Object;
|
||||
//}
|
||||
|
||||
//private static IStorageAccountParser CreateParser(IServiceProvider services, string connectionStringName, string connectionString, IStorageAccount parsedAccount)
|
||||
//{
|
||||
// Mock<IStorageAccountParser> mock = new Mock<IStorageAccountParser>(MockBehavior.Strict);
|
||||
// mock.Setup(p => p.ParseAccount(connectionString, connectionStringName)).Returns(parsedAccount);
|
||||
// return mock.Object;
|
||||
//}
|
||||
|
||||
//private static DefaultStorageAccountProvider CreateProductUnderTest()
|
||||
//{
|
||||
// return CreateProductUnderTest(CreateServices(), CreateDummyConnectionStringProvider(), CreateDummyParser());
|
||||
//}
|
||||
|
||||
//private static DefaultStorageAccountProvider CreateProductUnderTest(IServiceProvider services,
|
||||
// IConnectionStringProvider ambientConnectionStringProvider, IStorageAccountParser storageAccountParser)
|
||||
//{
|
||||
// return CreateProductUnderTest(services, ambientConnectionStringProvider, storageAccountParser, CreateDummyValidator());
|
||||
//}
|
||||
|
||||
//private static DefaultStorageAccountProvider CreateProductUnderTest(IServiceProvider services,
|
||||
// IConnectionStringProvider ambientConnectionStringProvider, IStorageAccountParser storageAccountParser,
|
||||
// IStorageCredentialsValidator storageCredentialsValidator)
|
||||
//{
|
||||
// return new DefaultStorageAccountProvider(ambientConnectionStringProvider, storageAccountParser, storageCredentialsValidator);
|
||||
//}
|
||||
|
||||
//private static IStorageCredentialsValidator CreateValidator(IStorageAccount account)
|
||||
//{
|
||||
// Mock<IStorageCredentialsValidator> mock = new Mock<IStorageCredentialsValidator>(MockBehavior.Strict);
|
||||
// mock.Setup(v => v.ValidateCredentialsAsync(account, It.IsAny<CancellationToken>()))
|
||||
// .Returns(Task.FromResult(0));
|
||||
// return mock.Object;
|
||||
//}
|
||||
|
||||
//[StorageAccount("class")]
|
||||
//private class AccountOverrides
|
||||
//{
|
||||
// [StorageAccount("method")]
|
||||
// private void ParamOverride([StorageAccount("param")] string s)
|
||||
// {
|
||||
// }
|
||||
|
||||
// [StorageAccount("method")]
|
||||
// private void MethodOverride(string s)
|
||||
// {
|
||||
// }
|
||||
|
||||
// private void ClassOverride(string s)
|
||||
// {
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Executors
|
||||
{
|
||||
public class DefaultStorageCredentialsValidatorTests
|
||||
{
|
||||
[Fact]
|
||||
public void UseReflectionToAccessIsDevStoreAccountFromCloudStorageAccount()
|
||||
{
|
||||
var isDevStoreAccountProperty = typeof(CloudStorageAccount).GetProperty("IsDevStoreAccount", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
Assert.NotNull(isDevStoreAccountProperty);
|
||||
}
|
||||
|
||||
[Theory(Skip = "Missing StorageCredentialsValidator")]
|
||||
[InlineData("UseDevelopmentStorage=true")]
|
||||
[InlineData("UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://myProxyUri")]
|
||||
public void StorageAccount_IsDevStoreAccount_StorageEmulatorRunning(string connectionString)
|
||||
{
|
||||
//var validator = new DefaultStorageCredentialsValidator();
|
||||
|
||||
//var storageMock = new Mock<IStorageAccount>(MockBehavior.Strict);
|
||||
//var blobClientMock = new Mock<IStorageBlobClient>();
|
||||
//var queueClientMock = new Mock<IStorageQueueClient>();
|
||||
//var queueMock = new Mock<IStorageQueue>();
|
||||
|
||||
//storageMock.Setup(s => s.Credentials)
|
||||
// .Returns(new StorageCredentials("name", string.Empty));
|
||||
|
||||
//storageMock.Setup(s => s.CreateBlobClient(null))
|
||||
// .Returns(blobClientMock.Object)
|
||||
// .Verifiable();
|
||||
|
||||
//storageMock.Setup(s => s.SdkObject)
|
||||
// .Returns(() => CloudStorageAccount.Parse(connectionString));
|
||||
|
||||
//blobClientMock.Setup(b => b.GetServicePropertiesAsync(It.IsAny<CancellationToken>()))
|
||||
// .Throws(new StorageException(""));
|
||||
|
||||
//var exception = Assert.Throws<InvalidOperationException>(() => validator.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()).GetAwaiter().GetResult());
|
||||
//Assert.Equal(Constants.CheckAzureStorageEmulatorMessage, exception.Message);
|
||||
//storageMock.Verify();
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageCredentialsValidator")]
|
||||
public void StorageAccount_GetPropertiesThrows_InvalidCredentials()
|
||||
{
|
||||
//var validator = new DefaultStorageCredentialsValidator();
|
||||
|
||||
//var storageMock = new Mock<IStorageAccount>(MockBehavior.Strict);
|
||||
//var blobClientMock = new Mock<IStorageBlobClient>();
|
||||
//var queueClientMock = new Mock<IStorageQueueClient>();
|
||||
//var queueMock = new Mock<IStorageQueue>();
|
||||
|
||||
//storageMock.Setup(s => s.Credentials)
|
||||
// .Returns(new StorageCredentials("name", string.Empty));
|
||||
|
||||
//storageMock.Setup(s => s.CreateBlobClient(null))
|
||||
// .Returns(blobClientMock.Object)
|
||||
// .Verifiable();
|
||||
|
||||
//storageMock.Setup(s => s.SdkObject)
|
||||
// .Returns(new CloudStorageAccount(new StorageCredentials("name", string.Empty), false));
|
||||
|
||||
//blobClientMock.Setup(b => b.GetServicePropertiesAsync(It.IsAny<CancellationToken>()))
|
||||
// .Throws(new StorageException(""));
|
||||
|
||||
//var exception = Assert.Throws<InvalidOperationException>(() => validator.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()).GetAwaiter().GetResult());
|
||||
//Assert.Equal("Invalid storage account 'name'. Please make sure your credentials are correct.", exception.Message);
|
||||
//storageMock.Verify();
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageCredentialsValidator")]
|
||||
public void StorageAccount_QueueCheckThrows_BlobOnly_WhenCatchingNameResolutionFailure()
|
||||
{
|
||||
//var validator = new DefaultStorageCredentialsValidator();
|
||||
|
||||
//var storageMock = new Mock<IStorageAccount>(MockBehavior.Strict);
|
||||
//var blobClientMock = new Mock<IStorageBlobClient>();
|
||||
//var queueClientMock = new Mock<IStorageQueueClient>();
|
||||
//var queueMock = new Mock<IStorageQueue>();
|
||||
|
||||
//storageMock.Setup(s => s.Credentials)
|
||||
// .Returns(new StorageCredentials());
|
||||
|
||||
//storageMock.Setup(s => s.CreateBlobClient(null))
|
||||
// .Returns(blobClientMock.Object)
|
||||
// .Verifiable();
|
||||
|
||||
//blobClientMock.Setup(b => b.GetServicePropertiesAsync(It.IsAny<CancellationToken>()))
|
||||
// .ReturnsAsync((ServiceProperties)null);
|
||||
|
||||
//storageMock.Setup(s => s.CreateQueueClient(null))
|
||||
// .Returns(queueClientMock.Object)
|
||||
// .Verifiable();
|
||||
|
||||
//queueClientMock.Setup(q => q.GetQueueReference(It.IsAny<string>()))
|
||||
// .Returns(queueMock.Object);
|
||||
|
||||
//queueMock.Setup(q => q.ExistsAsync(It.IsAny<CancellationToken>()))
|
||||
// .Throws(new StorageException("", new WebException("Remote name could not be resolved", WebExceptionStatus.NameResolutionFailure)));
|
||||
|
||||
//storageMock.SetupSet(s => s.Type = StorageAccountType.BlobOnly);
|
||||
|
||||
//validator.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()).GetAwaiter().GetResult();
|
||||
|
||||
//storageMock.Verify();
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageCredentialsValidator")]
|
||||
public void StorageAccount_QueueCheckThrows_BlobOnly_WhenCatchingWinHttpNameNotResolved()
|
||||
{
|
||||
//var validator = new DefaultStorageCredentialsValidator();
|
||||
|
||||
//var storageMock = new Mock<IStorageAccount>(MockBehavior.Strict);
|
||||
//var blobClientMock = new Mock<IStorageBlobClient>();
|
||||
//var queueClientMock = new Mock<IStorageQueueClient>();
|
||||
//var queueMock = new Mock<IStorageQueue>();
|
||||
|
||||
//storageMock.Setup(s => s.Credentials)
|
||||
// .Returns(new StorageCredentials());
|
||||
|
||||
//storageMock.Setup(s => s.CreateBlobClient(null))
|
||||
// .Returns(blobClientMock.Object)
|
||||
// .Verifiable();
|
||||
|
||||
//blobClientMock.Setup(b => b.GetServicePropertiesAsync(It.IsAny<CancellationToken>()))
|
||||
// .ReturnsAsync((ServiceProperties)null);
|
||||
|
||||
//storageMock.Setup(s => s.CreateQueueClient(null))
|
||||
// .Returns(queueClientMock.Object)
|
||||
// .Verifiable();
|
||||
|
||||
//queueClientMock.Setup(q => q.GetQueueReference(It.IsAny<string>()))
|
||||
// .Returns(queueMock.Object);
|
||||
|
||||
//queueMock.Setup(q => q.ExistsAsync(It.IsAny<CancellationToken>()))
|
||||
// .Throws(new StorageException("", new MockHttpRequestException(0x2ee7)));
|
||||
|
||||
//storageMock.SetupSet(s => s.Type = StorageAccountType.BlobOnly);
|
||||
|
||||
//validator.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()).GetAwaiter().GetResult();
|
||||
|
||||
//storageMock.Verify();
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageCredentialsValidator")]
|
||||
public void StorageAccount_QueueCheckThrowsUnexpectedStorage()
|
||||
{
|
||||
//var validator = new DefaultStorageCredentialsValidator();
|
||||
|
||||
//var storageMock = new Mock<IStorageAccount>(MockBehavior.Strict);
|
||||
//var blobClientMock = new Mock<IStorageBlobClient>();
|
||||
//var queueClientMock = new Mock<IStorageQueueClient>();
|
||||
//var queueMock = new Mock<IStorageQueue>();
|
||||
|
||||
//storageMock.Setup(s => s.Credentials)
|
||||
// .Returns(new StorageCredentials());
|
||||
|
||||
//storageMock.Setup(s => s.CreateBlobClient(null))
|
||||
// .Returns(blobClientMock.Object)
|
||||
// .Verifiable();
|
||||
|
||||
//blobClientMock.Setup(b => b.GetServicePropertiesAsync(It.IsAny<CancellationToken>()))
|
||||
// .ReturnsAsync((ServiceProperties)null);
|
||||
|
||||
//storageMock.Setup(s => s.CreateQueueClient(null))
|
||||
// .Returns(queueClientMock.Object)
|
||||
// .Verifiable();
|
||||
|
||||
//queueClientMock.Setup(q => q.GetQueueReference(It.IsAny<string>()))
|
||||
// .Returns(queueMock.Object);
|
||||
|
||||
//queueMock.Setup(q => q.ExistsAsync(It.IsAny<CancellationToken>()))
|
||||
// .Throws(new StorageException("some other storage exception", null));
|
||||
|
||||
//var storageException = Assert.Throws<StorageException>(() => validator.ValidateCredentialsAsync(storageMock.Object, It.IsAny<CancellationToken>()).GetAwaiter().GetResult());
|
||||
//Assert.Equal("some other storage exception", storageException.Message);
|
||||
//storageMock.Verify();
|
||||
}
|
||||
|
||||
internal class MockHttpRequestException : HttpRequestException
|
||||
{
|
||||
public MockHttpRequestException(int hresult)
|
||||
{
|
||||
HResult = hresult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,7 +41,7 @@ namespace Microsoft.Azure.WebJobs
|
|||
// $$$ Rationalize with AddFakeStorageAccountProvider in FunctionTests.
|
||||
public static IWebJobsBuilder UseFakeStorage(this IWebJobsBuilder builder)
|
||||
{
|
||||
return builder.UseStorage(new XFakeStorageAccount());
|
||||
return builder.UseStorage(new FakeStorageAccount());
|
||||
}
|
||||
|
||||
public static IWebJobsBuilder UseStorage(this IWebJobsBuilder builder, StorageAccount account)
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace Microsoft.Azure.WebJobs
|
|||
}
|
||||
}
|
||||
|
||||
public class XFakeStorageAccount : StorageAccount
|
||||
public class FakeStorageAccount : StorageAccount
|
||||
{
|
||||
private FakeStorage.FakeAccount _account2 = new FakeStorage.FakeAccount();
|
||||
|
||||
|
@ -46,7 +46,7 @@ namespace Microsoft.Azure.WebJobs
|
|||
}
|
||||
|
||||
// Helpeful test extensions
|
||||
public static class XFakeStorageAccountExtensions
|
||||
public static class FakeStorageAccountExtensions
|
||||
{
|
||||
public static async Task AddQueueMessageAsync(this StorageAccount account, CloudQueueMessage message, string queueName)
|
||||
{
|
||||
|
|
|
@ -1315,7 +1315,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
|
||||
private static StorageAccount CreateFakeStorageAccount()
|
||||
{
|
||||
return new XFakeStorageAccount();
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private static ITableEntity CreateTableEntity(string partitionKey, string rowKey, string propertyName,
|
||||
|
|
|
@ -1,555 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Blob;
|
||||
using Microsoft.WindowsAzure.Storage.Shared.Protocol;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs
|
||||
{
|
||||
#if false // $$$
|
||||
internal class MemoryBlobStore
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, Container> _items = new ConcurrentDictionary<string, Container>();
|
||||
private ServiceProperties _properties = new ServiceProperties(new LoggingProperties(), new MetricsProperties(), new MetricsProperties(), new CorsProperties());
|
||||
|
||||
public string AcquireLease(string containerName, string blobName, TimeSpan? leaseTime)
|
||||
{
|
||||
return _items[containerName].AcquireLease(blobName, leaseTime);
|
||||
}
|
||||
|
||||
public void CreateIfNotExists(string containerName)
|
||||
{
|
||||
_items.AddOrUpdate(containerName, new Container(), (_, existing) => existing);
|
||||
}
|
||||
|
||||
public bool Exists(string containerName)
|
||||
{
|
||||
return _items.ContainsKey(containerName);
|
||||
}
|
||||
|
||||
public bool Exists(string containerName, string blobName)
|
||||
{
|
||||
if (!_items.ContainsKey(containerName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _items[containerName].Exists(blobName);
|
||||
}
|
||||
|
||||
public BlobAttributes FetchAttributes(string containerName, string blobName)
|
||||
{
|
||||
if (!_items.ContainsKey(containerName))
|
||||
{
|
||||
throw StorageExceptionFactory.Create(404);
|
||||
}
|
||||
|
||||
return _items[containerName].FetchAttributes(blobName);
|
||||
}
|
||||
|
||||
public ICloudBlob GetBlobReferenceFromServer(CloudBlobContainer parent, string containerName, string blobName)
|
||||
{
|
||||
if (!_items.ContainsKey(containerName))
|
||||
{
|
||||
throw StorageExceptionFactory.Create(404);
|
||||
}
|
||||
|
||||
return _items[containerName].GetBlobReferenceFromServer(this, parent, blobName);
|
||||
}
|
||||
|
||||
public ServiceProperties GetServiceProperties()
|
||||
{
|
||||
return Clone(_properties);
|
||||
}
|
||||
|
||||
public BlobResultSegment ListBlobsSegmented(Func<string, CloudBlobContainer> containerFactory,
|
||||
string prefix, bool useFlatBlobListing, BlobListingDetails blobListingDetails, int? maxResults,
|
||||
BlobContinuationToken currentToken)
|
||||
{
|
||||
if (prefix == null)
|
||||
{
|
||||
throw new ArgumentNullException("prefix");
|
||||
}
|
||||
|
||||
if (!useFlatBlobListing)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
if (blobListingDetails != BlobListingDetails.None && blobListingDetails != BlobListingDetails.Metadata)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
if (prefix.StartsWith("$logs/"))
|
||||
{
|
||||
return MoreStorageExtensions.NewBlobResultSegment(null, new List<ICloudBlob>());
|
||||
}
|
||||
|
||||
if (prefix.Contains("/"))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
if (!_items.ContainsKey(prefix))
|
||||
{
|
||||
// if there are no blobs with the criteria, azure storage return empty list not null object
|
||||
return MoreStorageExtensions.NewBlobResultSegment(null, new List<ICloudBlob>());
|
||||
}
|
||||
|
||||
CloudBlobContainer parent = containerFactory.Invoke(prefix);
|
||||
List<ICloudBlob> results = _items[prefix].ListBlobs(this, parent, blobListingDetails).ToList();
|
||||
|
||||
// handle token
|
||||
// in this mock up token.NextMarker is going to be assumed the last blob returned in the last
|
||||
// call, we will remove everything before and send the rest with a new token that is the last
|
||||
// element in the new list
|
||||
if (currentToken != null)
|
||||
{
|
||||
var edgeMarker = results.FindIndex(r => r.Name == currentToken.NextMarker);
|
||||
|
||||
// if it is not the last element then filter all before the marker including the marker
|
||||
if (!(edgeMarker == results.Count - 1))
|
||||
{
|
||||
results.RemoveRange(0, edgeMarker + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// handle maxResults
|
||||
if (maxResults.HasValue && results.ToList().Count > maxResults.Value)
|
||||
{
|
||||
int realMaxResults = maxResults.Value;
|
||||
List<IStorageBlob> filteredResult = (List<IStorageBlob>)results;
|
||||
filteredResult.RemoveRange(realMaxResults, (filteredResult.Count - realMaxResults));
|
||||
BlobContinuationToken token = new BlobContinuationToken();
|
||||
token.NextMarker = filteredResult.Last().Name;
|
||||
return new StorageBlobResultSegment(token, results);
|
||||
}
|
||||
|
||||
|
||||
return new StorageBlobResultSegment(null, results);
|
||||
}
|
||||
|
||||
public Stream OpenRead(string containerName, string blobName)
|
||||
{
|
||||
if (!_items.ContainsKey(containerName))
|
||||
{
|
||||
throw StorageExceptionFactory.Create(404);
|
||||
}
|
||||
|
||||
return _items[containerName].OpenRead(blobName);
|
||||
}
|
||||
|
||||
public CloudBlobStream OpenWriteBlock(string containerName, string blobName,
|
||||
IDictionary<string, string> metadata)
|
||||
{
|
||||
if (!_items.ContainsKey(containerName))
|
||||
{
|
||||
throw StorageExceptionFactory.Create(404, "ContainerNotFound");
|
||||
}
|
||||
|
||||
return _items[containerName].OpenWriteBlock(blobName, metadata);
|
||||
}
|
||||
|
||||
public CloudBlobStream OpenWritePage(string containerName, string blobName, long? size,
|
||||
IDictionary<string, string> metadata)
|
||||
{
|
||||
return _items[containerName].OpenWritePage(blobName, size, metadata);
|
||||
}
|
||||
|
||||
public CloudBlobStream OpenWriteAppend(string containerName, string blobName,
|
||||
IDictionary<string, string> metadata)
|
||||
{
|
||||
return _items[containerName].OpenWriteAppend(blobName, metadata);
|
||||
}
|
||||
|
||||
public void ReleaseLease(string containerName, string blobName, string leaseId)
|
||||
{
|
||||
_items[containerName].ReleaseLease(blobName, leaseId);
|
||||
}
|
||||
|
||||
public void SetMetadata(string containerName, string blobName, IDictionary<string, string> metadata,
|
||||
string leaseId)
|
||||
{
|
||||
_items[containerName].SetMetadata(blobName, metadata, leaseId);
|
||||
}
|
||||
|
||||
public void SetServiceProperties(ServiceProperties properties)
|
||||
{
|
||||
_properties = Clone(properties);
|
||||
}
|
||||
|
||||
private static ServiceProperties Clone(ServiceProperties properties)
|
||||
{
|
||||
if (properties == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ServiceProperties
|
||||
{
|
||||
Cors = Clone(properties.Cors),
|
||||
DefaultServiceVersion = properties.DefaultServiceVersion,
|
||||
HourMetrics = Clone(properties.HourMetrics),
|
||||
Logging = Clone(properties.Logging),
|
||||
MinuteMetrics = Clone(properties.MinuteMetrics)
|
||||
};
|
||||
}
|
||||
|
||||
private static CorsProperties Clone(CorsProperties cors)
|
||||
{
|
||||
if (cors == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
CorsProperties cloned = new CorsProperties();
|
||||
|
||||
foreach (CorsRule rule in cors.CorsRules)
|
||||
{
|
||||
cloned.CorsRules.Add(Clone(rule));
|
||||
}
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
private static CorsRule Clone(CorsRule rule)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static MetricsProperties Clone(MetricsProperties metrics)
|
||||
{
|
||||
if (metrics == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MetricsProperties
|
||||
{
|
||||
MetricsLevel = metrics.MetricsLevel,
|
||||
RetentionDays = metrics.RetentionDays,
|
||||
Version = metrics.Version
|
||||
};
|
||||
}
|
||||
|
||||
private static LoggingProperties Clone(LoggingProperties logging)
|
||||
{
|
||||
if (logging == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new LoggingProperties
|
||||
{
|
||||
LoggingOperations = logging.LoggingOperations,
|
||||
RetentionDays = logging.RetentionDays,
|
||||
Version = logging.Version
|
||||
};
|
||||
}
|
||||
|
||||
private class Container
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, Blob> _items = new ConcurrentDictionary<string, Blob>();
|
||||
|
||||
public string AcquireLease(string blobName, TimeSpan? leaseTime)
|
||||
{
|
||||
if (!Exists(blobName))
|
||||
{
|
||||
RequestResult result = new RequestResult
|
||||
{
|
||||
HttpStatusCode = 404
|
||||
};
|
||||
throw new StorageException(result, "Blob does not exist", null);
|
||||
}
|
||||
|
||||
return _items[blobName].AcquireLease(leaseTime);
|
||||
}
|
||||
|
||||
public bool Exists(string blobName)
|
||||
{
|
||||
return _items.ContainsKey(blobName);
|
||||
}
|
||||
|
||||
public BlobAttributes FetchAttributes(string blobName)
|
||||
{
|
||||
if (!_items.ContainsKey(blobName))
|
||||
{
|
||||
throw StorageExceptionFactory.Create(404);
|
||||
}
|
||||
|
||||
return _items[blobName].FetchAttributes();
|
||||
}
|
||||
|
||||
public ICloudBlob GetBlobReferenceFromServer(MemoryBlobStore store, CloudBlobContainer parent, string blobName)
|
||||
{
|
||||
if (!_items.ContainsKey(blobName))
|
||||
{
|
||||
throw StorageExceptionFactory.Create(404);
|
||||
}
|
||||
|
||||
Blob blob = _items[blobName];
|
||||
|
||||
switch (blob.BlobType)
|
||||
{
|
||||
case StorageBlobType.BlockBlob:
|
||||
return new FakeStorageBlockBlob(store, blobName, parent);
|
||||
case StorageBlobType.PageBlob:
|
||||
return new FakeStoragePageBlob(store, blobName, parent);
|
||||
case StorageBlobType.AppendBlob:
|
||||
return new FakeStorageAppendBlob(store, blobName, parent);
|
||||
default:
|
||||
throw new InvalidOperationException(string.Format("Type '{0}' is not supported.", blob.BlobType));
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IStorageBlob> ListBlobs(MemoryBlobStore store, IStorageBlobContainer parent,
|
||||
BlobListingDetails blobListingDetails)
|
||||
{
|
||||
if (blobListingDetails != BlobListingDetails.None && blobListingDetails != BlobListingDetails.Metadata)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
List<IStorageBlob> results = new List<IStorageBlob>();
|
||||
|
||||
foreach (KeyValuePair<string, Blob> item in _items)
|
||||
{
|
||||
string blobName = item.Key;
|
||||
|
||||
// Etag and LastModifiedTime is always passed in listBlobs
|
||||
FakeStorageBlobProperties properties = new FakeStorageBlobProperties()
|
||||
{
|
||||
ETag = item.Value.ETag,
|
||||
LastModified = item.Value.LastModified,
|
||||
};
|
||||
|
||||
IStorageBlob blob = new FakeStorageBlockBlob(store, blobName, parent, properties);
|
||||
if ((blobListingDetails | BlobListingDetails.Metadata) == BlobListingDetails.Metadata)
|
||||
{
|
||||
Blob storeBlob = item.Value;
|
||||
IReadOnlyDictionary<string, string> storeMetadata = storeBlob.Metadata;
|
||||
|
||||
foreach (KeyValuePair<string, string> pair in storeMetadata)
|
||||
{
|
||||
blob.Metadata.Add(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
results.Add(blob);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public Stream OpenRead(string blobName)
|
||||
{
|
||||
if (!_items.ContainsKey(blobName))
|
||||
{
|
||||
throw StorageExceptionFactory.Create(404, "BlobNotFound");
|
||||
}
|
||||
|
||||
return new MemoryStream(_items[blobName].Contents, writable: false);
|
||||
}
|
||||
|
||||
public CloudBlobStream OpenWriteBlock(string blobName, IDictionary<string, string> metadata)
|
||||
{
|
||||
if (_items.ContainsKey(blobName))
|
||||
{
|
||||
_items[blobName].ThrowIfLeased();
|
||||
}
|
||||
|
||||
return new MemoryCloudBlockBlobStream((bytes) => _items[blobName] =
|
||||
new Blob(StorageBlobType.BlockBlob, bytes, metadata, null, null));
|
||||
}
|
||||
|
||||
public CloudBlobStream OpenWritePage(string blobName, long? size, IDictionary<string, string> metadata)
|
||||
{
|
||||
if (!size.HasValue)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
if (size.Value % 512 != 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (_items.ContainsKey(blobName))
|
||||
{
|
||||
_items[blobName].ThrowIfLeased();
|
||||
}
|
||||
|
||||
return new MemoryCloudPageBlobStream((bytes) => _items[blobName] =
|
||||
new Blob(StorageBlobType.PageBlob, bytes, metadata, null, null));
|
||||
}
|
||||
|
||||
public CloudBlobStream OpenWriteAppend(string blobName, IDictionary<string, string> metadata)
|
||||
{
|
||||
if (_items.ContainsKey(blobName))
|
||||
{
|
||||
_items[blobName].ThrowIfLeased();
|
||||
}
|
||||
|
||||
return new MemoryCloudAppendBlobStream((bytes) => _items[blobName] =
|
||||
new Blob(StorageBlobType.AppendBlob, bytes, metadata, null, null));
|
||||
}
|
||||
|
||||
public void ReleaseLease(string blobName, string leaseId)
|
||||
{
|
||||
if (!_items.ContainsKey(blobName))
|
||||
{
|
||||
throw StorageExceptionFactory.Create(404, "BlobNotFound");
|
||||
}
|
||||
|
||||
_items[blobName].ReleaseLease(leaseId);
|
||||
}
|
||||
|
||||
public void SetMetadata(string blobName, IDictionary<string, string> metadata, string leaseId)
|
||||
{
|
||||
Blob existing;
|
||||
if (!_items.TryRemove(blobName, out existing))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (leaseId == null)
|
||||
{
|
||||
existing.ThrowIfLeased();
|
||||
}
|
||||
else
|
||||
{
|
||||
existing.ThrowIfLeaseMismatch(leaseId);
|
||||
}
|
||||
|
||||
_items[blobName] = new Blob(existing.BlobType, existing.Contents, metadata, existing.LeaseId,
|
||||
existing.LeaseExpires);
|
||||
}
|
||||
}
|
||||
|
||||
private class Blob
|
||||
{
|
||||
private readonly StorageBlobType _blobType;
|
||||
private readonly byte[] _contents;
|
||||
private readonly string _eTag;
|
||||
private readonly DateTimeOffset _lastModified;
|
||||
private readonly IReadOnlyDictionary<string, string> _metadata;
|
||||
|
||||
public Blob(StorageBlobType blobType, byte[] contents, IDictionary<string, string> metadata, string leaseId,
|
||||
DateTime? leaseExpires)
|
||||
{
|
||||
if (blobType == StorageBlobType.PageBlob && contents.Length % 512 != 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
_blobType = blobType;
|
||||
_contents = new byte[contents.LongLength];
|
||||
_eTag = Guid.NewGuid().ToString();
|
||||
_lastModified = DateTimeOffset.Now;
|
||||
Array.Copy(contents, _contents, _contents.LongLength);
|
||||
_metadata = new Dictionary<string, string>(metadata);
|
||||
LeaseId = leaseId;
|
||||
LeaseExpires = leaseExpires;
|
||||
}
|
||||
|
||||
public StorageBlobType BlobType
|
||||
{
|
||||
get { return _blobType; }
|
||||
}
|
||||
|
||||
public byte[] Contents
|
||||
{
|
||||
get { return _contents; }
|
||||
}
|
||||
|
||||
public string ETag
|
||||
{
|
||||
get { return _eTag; }
|
||||
}
|
||||
|
||||
public DateTimeOffset LastModified
|
||||
{
|
||||
get { return _lastModified; }
|
||||
}
|
||||
|
||||
public string LeaseId { get; private set; }
|
||||
|
||||
public DateTime? LeaseExpires { get; private set; }
|
||||
|
||||
public IReadOnlyDictionary<string, string> Metadata
|
||||
{
|
||||
get { return _metadata; }
|
||||
}
|
||||
|
||||
public string AcquireLease(TimeSpan? leaseTime)
|
||||
{
|
||||
ThrowIfLeased();
|
||||
|
||||
string leaseId = Guid.NewGuid().ToString();
|
||||
LeaseId = leaseId;
|
||||
|
||||
if (leaseTime.HasValue)
|
||||
{
|
||||
LeaseExpires = DateTime.UtcNow.Add(leaseTime.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
LeaseExpires = null;
|
||||
}
|
||||
|
||||
return leaseId;
|
||||
}
|
||||
|
||||
public BlobAttributes FetchAttributes()
|
||||
{
|
||||
return new BlobAttributes(_eTag, _lastModified, _metadata);
|
||||
}
|
||||
|
||||
public void ReleaseLease(string leaseId)
|
||||
{
|
||||
if (LeaseId != leaseId)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
LeaseId = null;
|
||||
LeaseExpires = null;
|
||||
}
|
||||
|
||||
public void ThrowIfLeased()
|
||||
{
|
||||
if (LeaseId != null)
|
||||
{
|
||||
if (!LeaseExpires.HasValue || LeaseExpires.Value > DateTime.UtcNow)
|
||||
{
|
||||
RequestResult result = new RequestResult
|
||||
{
|
||||
HttpStatusCode = 409
|
||||
};
|
||||
throw new StorageException(result, "Blob is leased", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ThrowIfLeaseMismatch(string leaseId)
|
||||
{
|
||||
if (leaseId == null)
|
||||
{
|
||||
throw new ArgumentNullException("leaseId");
|
||||
}
|
||||
|
||||
if (LeaseId != leaseId)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs.Host.Bindings;
|
||||
using Microsoft.Azure.WebJobs.Host.Bindings.Path;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Xunit;
|
||||
using Microsoft.Azure.WebJobs.Description;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests
|
||||
{
|
||||
#if false // $$$ AttributeCloner is internal
|
||||
public class ODataFilterResolutionPolicyTests
|
||||
{
|
||||
public class AttributeWithResolutionPolicy : Attribute
|
||||
{
|
||||
[AutoResolve(ResolutionPolicyType = typeof(ODataFilterResolutionPolicy))]
|
||||
public string PropWithMarkerPolicy { get; set; }
|
||||
|
||||
internal string ResolutionData { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPolicy_ReturnsODataFilterPolicy_ForMarkerType()
|
||||
{
|
||||
// This is a special-case marker type to handle TableAttribute.Filter. We cannot directly list ODataFilterResolutionPolicy
|
||||
// because BindingTemplate doesn't exist in the core assembly.
|
||||
PropertyInfo propInfo = typeof(AttributeWithResolutionPolicy).GetProperty(nameof(AttributeWithResolutionPolicy.PropWithMarkerPolicy));
|
||||
|
||||
AutoResolveAttribute attr = propInfo.GetCustomAttribute<AutoResolveAttribute>();
|
||||
IResolutionPolicy policy = AttributeCloner<AttributeWithResolutionPolicy>.GetPolicy(attr.ResolutionPolicyType, propInfo);
|
||||
|
||||
Assert.IsType<Host.Bindings.ODataFilterResolutionPolicy>(policy);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -32,7 +32,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
|
||||
private static StorageAccount CreateFakeStorageAccount()
|
||||
{
|
||||
return new XFakeStorageAccount();
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private static CloudQueue CreateQueue(StorageAccount account, string queueName)
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs.Host.Executors;
|
||||
using Microsoft.Azure.WebJobs.Host.Queues;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.WindowsAzure.Storage.Queue;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.FunctionalTests.TestDoubles
|
||||
{
|
||||
#if false // $$$ enable
|
||||
internal class FakeQueuesOptionsFactory : IOptionsFactory<JobHostQueuesOptions>
|
||||
{
|
||||
private readonly FakeQueueProcessorFactory _queueProcessorFactory;
|
||||
|
||||
public FakeQueuesOptionsFactory(IStorageAccountProvider accountProvider)
|
||||
{
|
||||
_queueProcessorFactory = new FakeQueueProcessorFactory(accountProvider);
|
||||
}
|
||||
|
||||
public JobHostQueuesOptions Create(string name)
|
||||
{
|
||||
return new JobHostQueuesOptions
|
||||
{
|
||||
BatchSize = 2,
|
||||
MaxPollingInterval = TimeSpan.FromSeconds(10),
|
||||
MaxDequeueCount = 3,
|
||||
VisibilityTimeout = TimeSpan.Zero,
|
||||
QueueProcessorFactory = _queueProcessorFactory
|
||||
};
|
||||
}
|
||||
|
||||
private class FakeQueueProcessorFactory : DefaultQueueProcessorFactory
|
||||
{
|
||||
private IStorageAccount _storageAccount;
|
||||
|
||||
public FakeQueueProcessorFactory(IStorageAccountProvider accountProvider)
|
||||
{
|
||||
CancellationToken token = new CancellationToken();
|
||||
Task<IStorageAccount> task = accountProvider.GetStorageAccountAsync(token);
|
||||
_storageAccount = task.Result;
|
||||
}
|
||||
|
||||
public override QueueProcessor Create(QueueProcessorFactoryContext context)
|
||||
{
|
||||
return new FakeQueueProcessor(context, _storageAccount);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This QueueProcessor mocks out the queue storage operations by mapping back from
|
||||
/// CloudQueueMessage to the fake message instances, and using the mock IStorageQueue
|
||||
/// implementations.
|
||||
/// </summary>
|
||||
private class FakeQueueProcessor : QueueProcessor
|
||||
{
|
||||
private IStorageQueue _queue;
|
||||
private IStorageQueue _poisonQueue;
|
||||
|
||||
public FakeQueueProcessor(QueueProcessorFactoryContext context, IStorageAccount storageAccount) :
|
||||
base(context)
|
||||
{
|
||||
// map the queue names from the context to fake queues
|
||||
IStorageQueueClient client = storageAccount.CreateQueueClient();
|
||||
_queue = client.GetQueueReference(context.Queue.Name);
|
||||
if (context.PoisonQueue != null)
|
||||
{
|
||||
_poisonQueue = client.GetQueueReference(context.PoisonQueue.Name);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task CopyMessageToPoisonQueueAsync(CloudQueueMessage message, CloudQueue poisonQueue, CancellationToken cancellationToken)
|
||||
{
|
||||
FakeStorageQueueMessage fakeMessage = new FakeStorageQueueMessage(message);
|
||||
|
||||
await _poisonQueue.CreateIfNotExistsAsync(cancellationToken);
|
||||
await _poisonQueue.AddMessageAsync(fakeMessage, cancellationToken);
|
||||
|
||||
OnMessageAddedToPoisonQueue(new PoisonMessageEventArgs(message, poisonQueue));
|
||||
}
|
||||
|
||||
protected override async Task ReleaseMessageAsync(CloudQueueMessage message, FunctionResult result, TimeSpan visibilityTimeout, CancellationToken cancellationToken)
|
||||
{
|
||||
FakeStorageQueueMessage fakeMessage = new FakeStorageQueueMessage(message);
|
||||
|
||||
await _queue.UpdateMessageAsync(fakeMessage, visibilityTimeout, MessageUpdateFields.Visibility, cancellationToken);
|
||||
}
|
||||
|
||||
protected override async Task DeleteMessageAsync(CloudQueueMessage message, CancellationToken cancellationToken)
|
||||
{
|
||||
FakeStorageQueueMessage fakeMessage = new FakeStorageQueueMessage(message);
|
||||
await _queue.DeleteMessageAsync(fakeMessage, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.FunctionalTests.TestDoubles
|
||||
{
|
||||
internal class FakeQueuesOptionsSetup : IConfigureOptions<QueuesOptions>
|
||||
{
|
||||
public void Configure(QueuesOptions options)
|
||||
{
|
||||
options.BatchSize = 2;
|
||||
options.MaxPollingInterval = TimeSpan.FromSeconds(10);
|
||||
options.MaxDequeueCount = 3;
|
||||
options.VisibilityTimeout = TimeSpan.Zero;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,117 +1,91 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.WindowsAzure.Storage.Queue;
|
||||
using Xunit;
|
||||
|
||||
#if false // $$$ enable - testing Host.STop(); Should this be in core tests?
|
||||
namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
||||
{
|
||||
public class HostStopTests
|
||||
{
|
||||
private const string QueueName = "input";
|
||||
private static readonly TaskCompletionSource<object> _functionStarted = new TaskCompletionSource<object>();
|
||||
private static readonly TaskCompletionSource<object> _stopHostCalled = new TaskCompletionSource<object>();
|
||||
private static readonly TaskCompletionSource<bool> _testTaskSource = new TaskCompletionSource<bool>();
|
||||
|
||||
[Fact]
|
||||
public void Stop_TriggersCancellationToken()
|
||||
public async Task Stop_TriggersCancellationToken()
|
||||
{
|
||||
// Arrange
|
||||
IStorageAccount account = CreateFakeStorageAccount();
|
||||
IStorageQueue queue = CreateQueue(account, QueueName);
|
||||
IStorageQueueMessage message = queue.CreateMessage("ignore");
|
||||
queue.AddMessage(message);
|
||||
StorageAccount account = new FakeStorageAccount();
|
||||
CloudQueue queue = await CreateQueueAsync(account, QueueName);
|
||||
CloudQueueMessage message = new CloudQueueMessage("ignore");
|
||||
await queue.AddMessageAsync(message);
|
||||
|
||||
// Act
|
||||
Task stopTask = null;
|
||||
bool result = RunTrigger<bool>(account, typeof(CallbackCancellationTokenProgram),
|
||||
(s) => CallbackCancellationTokenProgram.TaskSource = s,
|
||||
(t) => CallbackCancellationTokenProgram.Start = t, (h) => stopTask = h.StopAsync());
|
||||
var host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost<CallbackCancellationTokenProgram>(c =>
|
||||
{
|
||||
c.AddAzureStorage();
|
||||
c.Services.AddSingleton<StorageAccountProvider>(_ => new FakeStorageAccountProvider(account));
|
||||
})
|
||||
.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
stopTask.WaitUntilCompleted(3 * 1000);
|
||||
Assert.Equal(TaskStatus.RanToCompletion, stopTask.Status);
|
||||
using (host)
|
||||
{
|
||||
int secondsToWait = 5;
|
||||
|
||||
// Start and wait for the function to be invoked.
|
||||
await host.StartAsync();
|
||||
bool completed = _functionStarted.Task.WaitUntilCompleted(secondsToWait * 1000);
|
||||
Assert.True(completed, $"Function did not start in {secondsToWait} seconds.");
|
||||
|
||||
// Stop the host and let the function know it can continue.
|
||||
Task stopTask = host.StopAsync();
|
||||
_stopHostCalled.TrySetResult(null);
|
||||
|
||||
completed = _testTaskSource.Task.WaitUntilCompleted(secondsToWait * 1000);
|
||||
Assert.True(completed, $"Host did not shut down in {secondsToWait} seconds.");
|
||||
|
||||
// Give a nicer test failure message for faulted tasks.
|
||||
if (_testTaskSource.Task.Status == TaskStatus.Faulted)
|
||||
{
|
||||
await _testTaskSource.Task;
|
||||
}
|
||||
|
||||
Assert.Equal(TaskStatus.RanToCompletion, _testTaskSource.Task.Status);
|
||||
|
||||
stopTask.WaitUntilCompleted(3 * 1000);
|
||||
Assert.Equal(TaskStatus.RanToCompletion, stopTask.Status);
|
||||
}
|
||||
}
|
||||
|
||||
private static IStorageAccount CreateFakeStorageAccount()
|
||||
private static async Task<CloudQueue> CreateQueueAsync(StorageAccount account, string queueName)
|
||||
{
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private static IStorageQueue CreateQueue(IStorageAccount account, string queueName)
|
||||
{
|
||||
IStorageQueueClient client = account.CreateQueueClient();
|
||||
IStorageQueue queue = client.GetQueueReference(queueName);
|
||||
queue.CreateIfNotExists();
|
||||
CloudQueueClient client = account.CreateCloudQueueClient();
|
||||
CloudQueue queue = client.GetQueueReference(queueName);
|
||||
await queue.CreateIfNotExistsAsync();
|
||||
return queue;
|
||||
}
|
||||
|
||||
// Stops running the host as soon as the program marks the task as completed.
|
||||
private static TResult RunTrigger<TResult>(IStorageAccount account, Type programType,
|
||||
Action<TaskCompletionSource<TResult>> setTaskSource, Action<Task> setStartTask, Action<JobHost> callback)
|
||||
{
|
||||
TaskCompletionSource<object> startTaskSource = new TaskCompletionSource<object>();
|
||||
setStartTask.Invoke(startTaskSource.Task);
|
||||
|
||||
// Arrange
|
||||
try
|
||||
{
|
||||
TaskCompletionSource<TResult> taskSource = new TaskCompletionSource<TResult>();
|
||||
var serviceProvider = FunctionalTest.CreateConfigurationForManualCompletion<TResult>(
|
||||
account, programType, taskSource);
|
||||
Task<TResult> task = taskSource.Task;
|
||||
setTaskSource.Invoke(taskSource);
|
||||
|
||||
try
|
||||
{
|
||||
// Arrange
|
||||
JobHost host = serviceProvider.GetJobHost();
|
||||
host.Start();
|
||||
callback.Invoke(host);
|
||||
startTaskSource.TrySetResult(null);
|
||||
int secondsToWait = 5;
|
||||
|
||||
// Act
|
||||
bool completed = task.WaitUntilCompleted(secondsToWait * 1000);
|
||||
|
||||
// Assert
|
||||
Assert.True(completed, $"Host did not shut down in {secondsToWait} seconds.");
|
||||
|
||||
// Give a nicer test failure message for faulted tasks.
|
||||
if (task.Status == TaskStatus.Faulted)
|
||||
{
|
||||
task.GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
||||
return task.Result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
setTaskSource.Invoke(null);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
setStartTask.Invoke(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CallbackCancellationTokenProgram
|
||||
{
|
||||
public static Task Start { get; set; }
|
||||
public static TaskCompletionSource<bool> TaskSource { get; set; }
|
||||
|
||||
public static void CallbackCancellationToken([QueueTrigger(QueueName)] string ignore,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
bool started = Start.WaitUntilCompleted(3 * 1000);
|
||||
// Signal that we've entered the function.
|
||||
_functionStarted.TrySetResult(null);
|
||||
|
||||
// Wait to continue until the StopHost has been called.
|
||||
bool started = _stopHostCalled.Task.WaitUntilCompleted(3 * 1000);
|
||||
Assert.True(started); // Guard
|
||||
TaskSource.TrySetResult(cancellationToken.IsCancellationRequested);
|
||||
|
||||
// Signal the test is complete with the actual value.
|
||||
_testTaskSource.TrySetResult(cancellationToken.IsCancellationRequested);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -21,7 +21,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
// Arrange
|
||||
string expectedGuid = Guid.NewGuid().ToString();
|
||||
CloudQueueMessage expectedMessage = new CloudQueueMessage(expectedGuid);
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
await account.AddQueueMessageAsync(expectedMessage, QueueName);
|
||||
|
||||
var prog = new InstanceProgram();
|
||||
|
@ -58,7 +58,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
// Arrange
|
||||
string expectedGuid = Guid.NewGuid().ToString();
|
||||
CloudQueueMessage expectedMessage = new CloudQueueMessage(expectedGuid);
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
await account.AddQueueMessageAsync(expectedMessage, QueueName);
|
||||
|
||||
var prog = new InstanceAsyncProgram();
|
||||
|
@ -95,7 +95,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
{
|
||||
// Arrange
|
||||
CloudQueueMessage expectedMessage = new CloudQueueMessage("ignore");
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
await account.AddQueueMessageAsync(expectedMessage, QueueName);
|
||||
|
||||
IHost host = new HostBuilder()
|
||||
|
@ -141,7 +141,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
IJobActivator activator = activatorMock.Object;
|
||||
|
||||
CloudQueueMessage message = new CloudQueueMessage("ignore");
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
await account.AddQueueMessageAsync(message, QueueName);
|
||||
|
||||
IHost host = new HostBuilder()
|
||||
|
|
|
@ -8,11 +8,9 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.WindowsAzure.Storage.Queue;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
|
@ -294,57 +292,55 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
#if false // $$$ enable
|
||||
// Nice failure when no storage account is set
|
||||
[Fact]
|
||||
[Fact(Skip = "Re-enable when StorageAccountParser returns")]
|
||||
public void Fails_When_No_Storage_is_set()
|
||||
{
|
||||
// TODO: We shouldn't have to do this, but our default parser
|
||||
// does not allow for null Storage/Dashboard.
|
||||
var mockParser = new Mock<IStorageAccountParser>();
|
||||
mockParser
|
||||
.Setup(p => p.ParseAccount(null, It.IsAny<string>()))
|
||||
.Returns<string>(null);
|
||||
//var mockParser = new Mock<IStorageAccountParser>();
|
||||
//mockParser
|
||||
// .Setup(p => p.ParseAccount(null, It.IsAny<string>()))
|
||||
// .Returns<string>(null);
|
||||
|
||||
// no storage account!
|
||||
IHost host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost<ProgramSimple>()
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddSingleton<IStorageAccountParser>(mockParser.Object);
|
||||
})
|
||||
.ConfigureAppConfiguration(config =>
|
||||
{
|
||||
config.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{ "AzureWebJobsStorge", null },
|
||||
{ "AzureWebJobsDashboard", null }
|
||||
});
|
||||
})
|
||||
.Build();
|
||||
//// no storage account!
|
||||
//IHost host = new HostBuilder()
|
||||
// .ConfigureDefaultTestHost<ProgramSimple>()
|
||||
// .ConfigureServices(services =>
|
||||
// {
|
||||
// services.AddSingleton<IStorageAccountParser>(mockParser.Object);
|
||||
// })
|
||||
// .ConfigureAppConfiguration(config =>
|
||||
// {
|
||||
// config.AddInMemoryCollection(new Dictionary<string, string>
|
||||
// {
|
||||
// { "AzureWebJobsStorge", null },
|
||||
// { "AzureWebJobsDashboard", null }
|
||||
// });
|
||||
// })
|
||||
// .Build();
|
||||
|
||||
string message = StorageAccountParser.FormatParseAccountErrorMessage(StorageAccountParseResult.MissingOrEmptyConnectionStringError, "Storage");
|
||||
TestHelpers.AssertIndexingError(() => host.GetJobHost().Call<ProgramSimple>("Func"), "ProgramSimple.Func", message);
|
||||
//string message = StorageAccountParser.FormatParseAccountErrorMessage(StorageAccountParseResult.MissingOrEmptyConnectionStringError, "Storage");
|
||||
//TestHelpers.AssertIndexingError(() => host.GetJobHost().Call<ProgramSimple>("Func"), "ProgramSimple.Func", message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Skip = "Re-enable when StorageAccountParser returns")]
|
||||
public void Sanitizes_Exception_If_Connection_String()
|
||||
{
|
||||
// people accidentally use their connection string; we want to make sure we sanitize it
|
||||
IHost host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost<ProgramSimple2>()
|
||||
.Build();
|
||||
//// people accidentally use their connection string; we want to make sure we sanitize it
|
||||
//IHost host = new HostBuilder()
|
||||
// .ConfigureDefaultTestHost<ProgramSimple2>()
|
||||
// .Build();
|
||||
|
||||
string message = StorageAccountParser.FormatParseAccountErrorMessage(StorageAccountParseResult.MissingOrEmptyConnectionStringError, ProgramSimple2.ConnectionString);
|
||||
//string message = StorageAccountParser.FormatParseAccountErrorMessage(StorageAccountParseResult.MissingOrEmptyConnectionStringError, ProgramSimple2.ConnectionString);
|
||||
|
||||
TestHelpers.AssertIndexingError(() => host.GetJobHost().Call<ProgramSimple2>(nameof(ProgramSimple2.Func2)),
|
||||
"ProgramSimple2.Func2", message);
|
||||
//TestHelpers.AssertIndexingError(() => host.GetJobHost().Call<ProgramSimple2>(nameof(ProgramSimple2.Func2)),
|
||||
// "ProgramSimple2.Func2", message);
|
||||
|
||||
Assert.DoesNotContain(ProgramSimple2.ConnectionString, message);
|
||||
Assert.DoesNotContain("AzureWebJobs", message); // prefix should not be added
|
||||
Assert.Contains("[Hidden Credential]", message);
|
||||
//Assert.DoesNotContain(ProgramSimple2.ConnectionString, message);
|
||||
//Assert.DoesNotContain("AzureWebJobs", message); // prefix should not be added
|
||||
//Assert.Contains("[Hidden Credential]", message);
|
||||
}
|
||||
#endif
|
||||
|
||||
public class ProgramBadContract
|
||||
{
|
||||
|
@ -471,7 +467,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
|
||||
private static StorageAccount CreateFakeStorageAccount()
|
||||
{
|
||||
return new XFakeStorageAccount();
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private static async Task<CloudQueue> CreateQueue(CloudQueueClient client, string queueName)
|
||||
|
|
|
@ -6,10 +6,13 @@ using System.Collections.Generic;
|
|||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using FakeStorage;
|
||||
using Microsoft.Azure.WebJobs.Host.FunctionalTests.TestDoubles;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.WindowsAzure.Storage.Queue;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
using FakeStorage;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
||||
{
|
||||
|
@ -68,7 +71,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
[Fact]
|
||||
public async Task QueueTrigger_IfBoundToStringAndMessageIsEmpty_Binds()
|
||||
{
|
||||
await TestBindToString(String.Empty);
|
||||
await TestBindToString(string.Empty);
|
||||
}
|
||||
|
||||
private static async Task TestBindToString(string expectedContent)
|
||||
|
@ -497,19 +500,17 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
var account = CreateFakeStorageAccount();
|
||||
await SetupAsync(account, expectedContents);
|
||||
|
||||
// Act
|
||||
// Act
|
||||
RunTrigger<object>(account, typeof(MaxDequeueCountProgram),
|
||||
(s) => MaxDequeueCountProgram.TaskSource = s,
|
||||
new string[] { typeof(MaxDequeueCountProgram).FullName + ".PutInPoisonQueue" });
|
||||
|
||||
// Assert
|
||||
var storageAccountProvider = new FakeStorageAccountProvider(account);
|
||||
|
||||
// These tests use the FakeQueueOptionsFactory, so compare dequeue count to that
|
||||
|
||||
// $$$ enable
|
||||
//JobHostQueuesOptions options = new FakeQueuesOptionsFactory(storageAccountProvider).Create(string.Empty);
|
||||
// Assert.Equal(options.MaxDequeueCount, MaxDequeueCountProgram.DequeueCount);
|
||||
// These tests use the FakeQueuesOptionsSetup, so compare dequeue count to that
|
||||
FakeQueuesOptionsSetup optionsSetup = new FakeQueuesOptionsSetup();
|
||||
QueuesOptions options = new QueuesOptions();
|
||||
optionsSetup.Configure(options);
|
||||
Assert.Equal(options.MaxDequeueCount, MaxDequeueCountProgram.DequeueCount);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -723,7 +724,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
private static TResult CallQueueTrigger<TResult>(object message, Type programType,
|
||||
Action<TaskCompletionSource<TResult>> setTaskSource)
|
||||
{
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
var method = programType.GetMethod("Run");
|
||||
Assert.NotNull(method);
|
||||
|
||||
|
@ -737,7 +738,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
|
||||
private static StorageAccount CreateFakeStorageAccount()
|
||||
{
|
||||
return new XFakeStorageAccount();
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private static async Task<CloudQueue> CreateQueue(StorageAccount account, string queueName)
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.WindowsAzure.Storage.Blob;
|
||||
using Xunit;
|
||||
|
||||
#if false // $$$ Enable
|
||||
namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
||||
{
|
||||
public class ScenarioTests
|
||||
|
@ -19,43 +19,43 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
private const string QueueName = "queue";
|
||||
|
||||
[Fact]
|
||||
public void BlobTriggerToQueueTriggerToBlob_WritesFinalBlob()
|
||||
public async Task BlobTriggerToQueueTriggerToBlob_WritesFinalBlob()
|
||||
{
|
||||
// Arrange
|
||||
IStorageAccount account = CreateFakeStorageAccount();
|
||||
IStorageBlobContainer container = CreateContainer(account, ContainerName);
|
||||
IStorageBlockBlob inputBlob = container.GetBlockBlobReference(BlobName);
|
||||
inputBlob.UploadText("15");
|
||||
StorageAccount account = await CreateFakeStorageAccountAsync();
|
||||
CloudBlobContainer container = await CreateContainerAsync(account, ContainerName);
|
||||
CloudBlockBlob inputBlob = container.GetBlockBlobReference(BlobName);
|
||||
await inputBlob.UploadTextAsync("15");
|
||||
|
||||
// Act
|
||||
RunTrigger<object>(account, typeof(BlobTriggerToQueueTriggerToBlobProgram),
|
||||
(s) => BlobTriggerToQueueTriggerToBlobProgram.TaskSource = s);
|
||||
|
||||
// Assert
|
||||
IStorageBlockBlob outputBlob = container.GetBlockBlobReference(OutputBlobName);
|
||||
CloudBlockBlob outputBlob = container.GetBlockBlobReference(OutputBlobName);
|
||||
string content = outputBlob.DownloadText();
|
||||
Assert.Equal("16", content);
|
||||
}
|
||||
|
||||
private static IStorageBlobContainer CreateContainer(IStorageAccount account, string containerName)
|
||||
private static async Task<CloudBlobContainer> CreateContainerAsync(StorageAccount account, string containerName)
|
||||
{
|
||||
IStorageBlobClient client = account.CreateBlobClient();
|
||||
IStorageBlobContainer container = client.GetContainerReference(containerName);
|
||||
container.CreateIfNotExists();
|
||||
CloudBlobClient client = account.CreateCloudBlobClient();
|
||||
CloudBlobContainer container = client.GetContainerReference(containerName);
|
||||
await container.CreateIfNotExistsAsync();
|
||||
return container;
|
||||
}
|
||||
|
||||
private static IStorageAccount CreateFakeStorageAccount()
|
||||
private static async Task<StorageAccount> CreateFakeStorageAccountAsync()
|
||||
{
|
||||
var account = new FakeStorageAccount();
|
||||
|
||||
// make sure our system containers are present
|
||||
var container = CreateContainer(account, "azure-webjobs-hosts");
|
||||
var container = await CreateContainerAsync(account, "azure-webjobs-hosts");
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
private static TResult RunTrigger<TResult>(IStorageAccount account, Type programType,
|
||||
private static TResult RunTrigger<TResult>(StorageAccount account, Type programType,
|
||||
Action<TaskCompletionSource<TResult>> setTaskSource)
|
||||
{
|
||||
return FunctionalTest.RunTrigger<TResult>(account, programType, setTaskSource);
|
||||
|
@ -70,7 +70,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
public static void StepOne([BlobTrigger(BlobPath)] TextReader input, [Queue(QueueName)] out Payload output)
|
||||
{
|
||||
string content = input.ReadToEnd();
|
||||
int value = Int32.Parse(content);
|
||||
int value = int.Parse(content);
|
||||
output = new Payload
|
||||
{
|
||||
Value = value + 1,
|
||||
|
@ -83,7 +83,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
{
|
||||
Assert.Equal(input.Value, value);
|
||||
output.Write(value);
|
||||
committed = String.Empty;
|
||||
committed = string.Empty;
|
||||
}
|
||||
|
||||
public static void StepThree([QueueTrigger(CommittedQueueName)] string ignore)
|
||||
|
@ -99,5 +99,4 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
public string Output { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Storage
|
||||
{
|
||||
public class StorageAccountExtensionsTests
|
||||
{
|
||||
//private IStorageAccount account;
|
||||
//private Mock<IStorageAccount> accountMock;
|
||||
|
||||
//public StorageAccountExtensionsTests()
|
||||
//{
|
||||
// accountMock = new Mock<IStorageAccount>();
|
||||
// account = accountMock.Object;
|
||||
// accountMock.SetupGet(acc => acc.Credentials)
|
||||
// .Returns(new StorageCredentials("name", string.Empty, "key"));
|
||||
//}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountType")]
|
||||
public void AssertTypeOneOf_Succeeds()
|
||||
{
|
||||
//account.AssertTypeOneOf(StorageAccountType.GeneralPurpose);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountType")]
|
||||
public void AssertTypeOneOf_Throws_Unsupported()
|
||||
{
|
||||
//accountMock.SetupGet(acc => acc.Type).Returns(StorageAccountType.BlobOnly);
|
||||
//var exception = Assert.Throws<InvalidOperationException>(() => account.AssertTypeOneOf(StorageAccountType.GeneralPurpose));
|
||||
//Assert.Equal("Storage account 'name' is of unsupported type 'Blob-Only/ZRS'. Supported types are 'General Purpose'", exception.Message);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountType")]
|
||||
public void AssertTypeOneOf_Throws_MultipleSuggestions()
|
||||
{
|
||||
// var exception = Assert.Throws<InvalidOperationException>(() => account.AssertTypeOneOf(StorageAccountType.BlobOnly, StorageAccountType.Premium));
|
||||
// Assert.Equal("Storage account 'name' is of unsupported type 'General Purpose'. Supported types are 'Blob-Only/ZRS', 'Premium'", exception.Message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Host.UnitTests.Executors
|
||||
{
|
||||
public class StorageAccountParserTests
|
||||
{
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public void TryParseAccount_WithEmpty_Fails()
|
||||
{
|
||||
//string connectionString = string.Empty;
|
||||
|
||||
//StorageAccountParseResult result = StorageAccountParser.TryParseAccount(connectionString, out CloudStorageAccount ignore);
|
||||
|
||||
//Assert.Equal(StorageAccountParseResult.MissingOrEmptyConnectionStringError, result);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public void TryParseAccount_WithNull_Fails()
|
||||
{
|
||||
//string connectionString = null;
|
||||
|
||||
//StorageAccountParseResult result = StorageAccountParser.TryParseAccount(connectionString, out CloudStorageAccount ignore);
|
||||
|
||||
//Assert.Equal(StorageAccountParseResult.MissingOrEmptyConnectionStringError, result);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Missing StorageAccountParser")]
|
||||
public void TryParseAccount_WithMalformed_Fails()
|
||||
{
|
||||
//string connectionString = "DefaultEndpointsProtocol=https;AccountName=[NOVALUE];AccountKey=[NOVALUE]";
|
||||
|
||||
//StorageAccountParseResult result = StorageAccountParser.TryParseAccount(connectionString, out CloudStorageAccount ignore);
|
||||
|
||||
//Assert.Equal(StorageAccountParseResult.MalformedConnectionStringError, result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,11 +4,14 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.WebJobs.Host.Queues;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Queue;
|
||||
using Xunit;
|
||||
|
||||
#if false // $$$
|
||||
namespace Microsoft.Azure.WebJobs.Storage.IntegrationTests
|
||||
{
|
||||
[Trait("SecretsRequired", "true")]
|
||||
|
@ -18,17 +21,21 @@ namespace Microsoft.Azure.WebJobs.Storage.IntegrationTests
|
|||
public async Task CloudQueueCreate_IfNotExist_CreatesQueue()
|
||||
{
|
||||
// Arrange
|
||||
CloudStorageAccount sdkAccount = CreateSdkAccount();
|
||||
StorageAccount storageAccount = CreateStorageAccount();
|
||||
CloudStorageAccount sdkAccount = storageAccount.SdkObject;
|
||||
string queueName = GetQueueName("create-queue");
|
||||
|
||||
CloudQueue sdkQueue = CreateSdkQueue(sdkAccount, queueName);
|
||||
// Initialize using the SdkAccount directly.
|
||||
CloudQueue sdkQueue = GetQueueReference(sdkAccount, queueName);
|
||||
await sdkQueue.DeleteIfExistsAsync();
|
||||
Assert.False(await sdkQueue.ExistsAsync());
|
||||
|
||||
try
|
||||
{
|
||||
IStorageAccount product = CreateProductUnderTest(sdkAccount);
|
||||
IStorageQueueClient client = product.CreateQueueClient();
|
||||
// Make sure that using our StorageAccount uses the underlying SdkAccount
|
||||
CloudQueueClient client = storageAccount.CreateCloudQueueClient();
|
||||
Assert.NotNull(client); // Guard
|
||||
IStorageQueue queue = client.GetQueueReference(queueName);
|
||||
CloudQueue queue = client.GetQueueReference(queueName);
|
||||
Assert.NotNull(queue); // Guard
|
||||
|
||||
// Act
|
||||
|
@ -50,27 +57,28 @@ namespace Microsoft.Azure.WebJobs.Storage.IntegrationTests
|
|||
public async Task CloudQueueAddMessage_AddsMessage()
|
||||
{
|
||||
// Arrange
|
||||
CloudStorageAccount sdkAccount = CreateSdkAccount();
|
||||
StorageAccount storageAccount = CreateStorageAccount();
|
||||
CloudStorageAccount sdkAccount = storageAccount.SdkObject;
|
||||
string queueName = GetQueueName("add-message");
|
||||
|
||||
CloudQueue sdkQueue = CreateSdkQueue(sdkAccount, queueName);
|
||||
// Initialize using the SdkAccount directly.
|
||||
CloudQueue sdkQueue = GetQueueReference(sdkAccount, queueName);
|
||||
await sdkQueue.CreateIfNotExistsAsync();
|
||||
|
||||
try
|
||||
{
|
||||
string expectedContent = "hello";
|
||||
|
||||
IStorageAccount product = CreateProductUnderTest(sdkAccount);
|
||||
IStorageQueueClient client = product.CreateQueueClient();
|
||||
CloudQueueClient client = storageAccount.CreateCloudQueueClient();
|
||||
Assert.NotNull(client); // Guard
|
||||
IStorageQueue queue = client.GetQueueReference(queueName);
|
||||
CloudQueue queue = client.GetQueueReference(queueName);
|
||||
Assert.NotNull(queue); // Guard
|
||||
|
||||
IStorageQueueMessage message = queue.CreateMessage(expectedContent);
|
||||
CloudQueueMessage message = new CloudQueueMessage(expectedContent);
|
||||
Assert.NotNull(message); // Guard
|
||||
|
||||
// Act
|
||||
queue.AddMessageAsync(message, CancellationToken.None).GetAwaiter().GetResult();
|
||||
await queue.AddMessageAsync(message, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
CloudQueueMessage sdkMessage = await sdkQueue.GetMessageAsync();
|
||||
|
@ -83,47 +91,30 @@ namespace Microsoft.Azure.WebJobs.Storage.IntegrationTests
|
|||
}
|
||||
}
|
||||
|
||||
private static IStorageAccount CreateProductUnderTest(CloudStorageAccount account)
|
||||
private static StorageAccount CreateStorageAccount()
|
||||
{
|
||||
StorageClientFactory clientFactory = new StorageClientFactory();
|
||||
return new StorageAccount(account, clientFactory);
|
||||
var host = new HostBuilder()
|
||||
.ConfigureDefaultTestHost(c =>
|
||||
{
|
||||
c.AddAzureStorage();
|
||||
})
|
||||
.Build();
|
||||
|
||||
StorageAccount account = host.Services.GetService<StorageAccountProvider>().GetHost();
|
||||
Assert.NotNull(account);
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
private static CloudStorageAccount CreateSdkAccount()
|
||||
{
|
||||
return CloudStorageAccount.Parse(GetConnectionString());
|
||||
}
|
||||
|
||||
private static CloudQueue CreateSdkQueue(CloudStorageAccount sdkAccount, string queueName)
|
||||
private static CloudQueue GetQueueReference(CloudStorageAccount sdkAccount, string queueName)
|
||||
{
|
||||
CloudQueueClient sdkClient = sdkAccount.CreateCloudQueueClient();
|
||||
return sdkClient.GetQueueReference(queueName);
|
||||
}
|
||||
|
||||
private static string GetConnectionString()
|
||||
{
|
||||
const string name = "AzureWebJobsStorage";
|
||||
string value = GetConnectionString(name);
|
||||
|
||||
if (String.IsNullOrEmpty(value))
|
||||
{
|
||||
string message = String.Format(
|
||||
"This test needs an Azure storage connection string to run. Please set the '{0}' environment " +
|
||||
"variable or App.config connection string before running this test.", name);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static string GetConnectionString(string connectionStringName)
|
||||
=> ConfigurationUtility.GetConnectionString(connectionStringName);
|
||||
|
||||
private static string GetQueueName(string infix)
|
||||
{
|
||||
return String.Format("test-{0}-{1:N}", infix, Guid.NewGuid());
|
||||
return string.Format("test-{0}-{1:N}", infix, Guid.NewGuid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.Azure.WebJobs.Host.Converters;
|
||||
using Microsoft.Azure.WebJobs.Host.Tables;
|
||||
using Microsoft.Azure.WebJobs.Host.TestCommon;
|
||||
using Microsoft.WindowsAzure.Storage.Table;
|
||||
|
@ -1311,13 +1310,6 @@ namespace Microsoft.Azure.WebJobs.Host.UnitTests.Tables
|
|||
get { return null; }
|
||||
set { }
|
||||
}
|
||||
}
|
||||
|
||||
//private class PocoWithPartitionKeyAndOtherProperty
|
||||
//{
|
||||
// public string PartitionKey { get; set; }
|
||||
|
||||
// public int? OtherProperty { get; set; }
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -257,7 +257,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
|
||||
private static StorageAccount CreateFakeStorageAccount()
|
||||
{
|
||||
return new XFakeStorageAccount();
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private static void RunTrigger(StorageAccount account, Type programType)
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests.Tables
|
|||
public void FlushAfterAdd_PersistsEntity()
|
||||
{
|
||||
// Arrange
|
||||
var account = new XFakeStorageAccount();
|
||||
var account = new FakeStorageAccount();
|
||||
var client = account.CreateCloudTableClient();
|
||||
var table = client.GetTableReference("Table");
|
||||
|
||||
|
|
|
@ -418,7 +418,7 @@ namespace Microsoft.Azure.WebJobs.Host.FunctionalTests
|
|||
|
||||
private static StorageAccount CreateFakeStorageAccount()
|
||||
{
|
||||
return new XFakeStorageAccount();
|
||||
return new FakeStorageAccount();
|
||||
}
|
||||
|
||||
private static void RunTrigger(StorageAccount account, Type programType)
|
||||
|
|
Загрузка…
Ссылка в новой задаче