This commit is contained in:
Brett Samblanet 2018-09-12 08:28:36 -07:00
Родитель 11fdc64435
Коммит e30f8544e6
46 изменённых файлов: 1300 добавлений и 2186 удалений

Просмотреть файл

@ -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)