public QueueListenerTests()
        {
            CloudQueue queue = new CloudQueue(new Uri("https://test.queue.core.windows.net/testqueue"));
            Mock<IStorageQueue> mockQueue = new Mock<IStorageQueue>(MockBehavior.Strict);
            mockQueue.Setup(p => p.SdkObject).Returns(queue);

            _mockTriggerExecutor = new Mock<ITriggerExecutor<IStorageQueueMessage>>(MockBehavior.Strict);
            Mock<IDelayStrategy> mockDelayStrategy = new Mock<IDelayStrategy>(MockBehavior.Strict);
            Mock<IBackgroundExceptionDispatcher> mockExceptionDispatcher = new Mock<IBackgroundExceptionDispatcher>(MockBehavior.Strict);
            TestTraceWriter log = new TestTraceWriter(TraceLevel.Verbose);
            Mock<IQueueProcessorFactory> mockQueueProcessorFactory = new Mock<IQueueProcessorFactory>(MockBehavior.Strict);
            JobHostQueuesConfiguration queuesConfig = new JobHostQueuesConfiguration();
            QueueProcessorFactoryContext context = new QueueProcessorFactoryContext(queue, log, queuesConfig);

            _mockQueueProcessor = new Mock<QueueProcessor>(MockBehavior.Strict, context);
            JobHostQueuesConfiguration queueConfig = new JobHostQueuesConfiguration
            {
                MaxDequeueCount = 5,
                QueueProcessorFactory = mockQueueProcessorFactory.Object
            };

            mockQueueProcessorFactory.Setup(p => p.Create(It.IsAny<QueueProcessorFactoryContext>())).Returns(_mockQueueProcessor.Object);

            _listener = new QueueListener(mockQueue.Object, null, _mockTriggerExecutor.Object, mockDelayStrategy.Object, mockExceptionDispatcher.Object, log, null, queueConfig);

            CloudQueueMessage cloudMessage = new CloudQueueMessage("TestMessage");
            _storageMessage = new StorageQueueMessage(cloudMessage);
        }
        public async Task CreateAsync_SkipsDisabledFunctions(Type jobType, string methodName)
        {
            Environment.SetEnvironmentVariable("EnvironmentSettingTrue", "True");

            Mock<IFunctionDefinition> mockFunctionDefinition = new Mock<IFunctionDefinition>();
            Mock<IFunctionInstanceFactory> mockInstanceFactory = new Mock<IFunctionInstanceFactory>(MockBehavior.Strict);
            Mock<IListenerFactory> mockListenerFactory = new Mock<IListenerFactory>(MockBehavior.Strict);
            SingletonManager singletonManager = new SingletonManager();
            TestTraceWriter traceWriter = new TestTraceWriter(TraceLevel.Verbose);

            // create a bunch of function definitions that are disabled
            List<FunctionDefinition> functions = new List<FunctionDefinition>();
            FunctionDescriptor descriptor = new FunctionDescriptor
            {
                Method = jobType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static),
                ShortName = string.Format("{0}.{1}", jobType.Name, methodName)
            };
            FunctionDefinition definition = new FunctionDefinition(descriptor, mockInstanceFactory.Object, mockListenerFactory.Object);
            functions.Add(definition);

            // Create the composite listener - this will fail if any of the
            // function definitions indicate that they are not disabled
            HostListenerFactory factory = new HostListenerFactory(functions, singletonManager, DefaultJobActivator.Instance, null, traceWriter);
            IListener listener = await factory.CreateAsync(CancellationToken.None);

            Assert.Equal(1, traceWriter.Traces.Count);
            Assert.Equal(TraceLevel.Info, traceWriter.Traces[0].Level);
            Assert.Equal(TraceSource.Host, traceWriter.Traces[0].Source);
            Assert.Equal(string.Format("Function '{0}' is disabled", descriptor.ShortName), traceWriter.Traces[0].Message);

            Environment.SetEnvironmentVariable("EnvironmentSettingTrue", null);
        }
        public FunctionExecutorTests()
        {
            _descriptor = new FunctionDescriptor();
            _mockFunctionInstance = new Mock<IFunctionInstance>(MockBehavior.Strict);
            _mockFunctionInstance.Setup(p => p.FunctionDescriptor).Returns(_descriptor);

            _cancellationTokenSource = new CancellationTokenSource();
            _traceWriter = new TestTraceWriter(TraceLevel.Verbose);
        }
        public void Constructor_DefaultsValues()
        {
            CloudQueue queue = new CloudQueue(new Uri("https://test.queue.core.windows.net/testqueue"));
            CloudQueue poisonQueue = new CloudQueue(new Uri("https://test.queue.core.windows.net/poisonqueue"));
            TestTraceWriter log = new TestTraceWriter(TraceLevel.Verbose);
            JobHostQueuesConfiguration queuesConfig = new JobHostQueuesConfiguration();

            QueueProcessorFactoryContext context = new QueueProcessorFactoryContext(queue, log, queuesConfig, poisonQueue);

            Assert.Same(queue, context.Queue);
            Assert.Same(log, context.Trace);
            Assert.Same(poisonQueue, context.PoisonQueue);

            Assert.Equal(queuesConfig.BatchSize, context.BatchSize);
            Assert.Equal(queuesConfig.NewBatchThreshold, context.NewBatchThreshold);
            Assert.Equal(queuesConfig.MaxDequeueCount, context.MaxDequeueCount);
        }
        public static FunctionIndexer Create(CloudStorageAccount account = null, INameResolver nameResolver = null, IExtensionRegistry extensionRegistry = null)
        {
            Mock<IServiceProvider> services = new Mock<IServiceProvider>(MockBehavior.Strict);
            StorageClientFactory clientFactory = new StorageClientFactory();
            services.Setup(p => p.GetService(typeof(StorageClientFactory))).Returns(clientFactory);
            IStorageAccount storageAccount = account != null ? new StorageAccount(account, services.Object) : null;
            IStorageAccountProvider storageAccountProvider = new SimpleStorageAccountProvider(services.Object)
            {
                StorageAccount = account
            };
            IExtensionTypeLocator extensionTypeLocator = new NullExtensionTypeLocator();
            ContextAccessor<IMessageEnqueuedWatcher> messageEnqueuedWatcherAccessor =
                new ContextAccessor<IMessageEnqueuedWatcher>();
            ContextAccessor<IBlobWrittenWatcher> blobWrittenWatcherAccessor =
                new ContextAccessor<IBlobWrittenWatcher>();
            ISharedContextProvider sharedContextProvider = new SharedContextProvider();
            TestTraceWriter logger = new TestTraceWriter(TraceLevel.Verbose);
            SingletonManager singletonManager = new SingletonManager();
            ITriggerBindingProvider triggerBindingProvider = DefaultTriggerBindingProvider.Create(nameResolver,
                storageAccountProvider, extensionTypeLocator,
                new FixedHostIdProvider("test"), new SimpleQueueConfiguration(maxDequeueCount: 5),
                BackgroundExceptionDispatcher.Instance, messageEnqueuedWatcherAccessor, blobWrittenWatcherAccessor,
                sharedContextProvider, new DefaultExtensionRegistry(), singletonManager, logger);
            IBindingProvider bindingProvider = DefaultBindingProvider.Create(nameResolver, storageAccountProvider,
                extensionTypeLocator, messageEnqueuedWatcherAccessor,
                blobWrittenWatcherAccessor, new DefaultExtensionRegistry());

            TraceWriter trace = new TestTraceWriter(TraceLevel.Verbose);
            IFunctionOutputLoggerProvider outputLoggerProvider = new NullFunctionOutputLoggerProvider();
            IFunctionOutputLogger outputLogger = outputLoggerProvider.GetAsync(CancellationToken.None).Result;
            IFunctionExecutor executor = new FunctionExecutor(new NullFunctionInstanceLogger(), outputLogger, BackgroundExceptionDispatcher.Instance, trace, null);

            if (extensionRegistry == null)
            {
                extensionRegistry = new DefaultExtensionRegistry();
            }

            return new FunctionIndexer(triggerBindingProvider, bindingProvider, DefaultJobActivator.Instance, executor, extensionRegistry, new SingletonManager(), trace);
        }
        public static FunctionIndexer Create(CloudStorageAccount account = null, INameResolver nameResolver = null, IExtensionRegistry extensionRegistry = null)
        {
            IStorageAccount storageAccount = account != null ? new StorageAccount(account) : null;
            IStorageAccountProvider storageAccountProvider = new SimpleStorageAccountProvider
            {
                StorageAccount = account
            };
            IExtensionTypeLocator extensionTypeLocator = new NullExtensionTypeLocator();
            ContextAccessor<IMessageEnqueuedWatcher> messageEnqueuedWatcherAccessor =
                new ContextAccessor<IMessageEnqueuedWatcher>();
            ContextAccessor<IBlobWrittenWatcher> blobWrittenWatcherAccessor =
                new ContextAccessor<IBlobWrittenWatcher>();
            ISharedContextProvider sharedContextProvider = new SharedContextProvider();
            TestTraceWriter logger = new TestTraceWriter(TraceLevel.Verbose);
            ITriggerBindingProvider triggerBindingProvider = DefaultTriggerBindingProvider.Create(nameResolver,
                storageAccountProvider, extensionTypeLocator,
                new FixedHostIdProvider("test"), new SimpleQueueConfiguration(maxDequeueCount: 5),
                BackgroundExceptionDispatcher.Instance, messageEnqueuedWatcherAccessor, blobWrittenWatcherAccessor,
                sharedContextProvider, new DefaultExtensionRegistry(), logger);
            IBindingProvider bindingProvider = DefaultBindingProvider.Create(nameResolver, storageAccountProvider,
                extensionTypeLocator, messageEnqueuedWatcherAccessor,
                blobWrittenWatcherAccessor, new DefaultExtensionRegistry());

            IFunctionOutputLoggerProvider outputLoggerProvider = new NullFunctionOutputLoggerProvider();
            var task = outputLoggerProvider.GetAsync(CancellationToken.None);
            task.Wait();
            IFunctionOutputLogger outputLogger = task.Result;
            IFunctionExecutor executor = new FunctionExecutor(new NullFunctionInstanceLogger(), outputLogger, BackgroundExceptionDispatcher.Instance, new TestTraceWriter(TraceLevel.Verbose));

            if (extensionRegistry == null)
            {
                extensionRegistry = new DefaultExtensionRegistry();
            }

            return new FunctionIndexer(triggerBindingProvider, bindingProvider, DefaultJobActivator.Instance, executor, extensionRegistry, new SingletonManager());
        }
        public async Task CustomMessageProcessorTest()
        {
            try
            {
                TestTraceWriter trace = new TestTraceWriter(TraceLevel.Info);
                _serviceBusConfig = new ServiceBusConfiguration();
                _serviceBusConfig.MessagingProvider = new CustomMessagingProvider(_serviceBusConfig, trace);

                JobHostConfiguration config = new JobHostConfiguration()
                {
                    NameResolver = _nameResolver,
                    TypeLocator = new FakeTypeLocator(typeof(ServiceBusTestJobs))
                };
                config.Tracing.Tracers.Add(trace);
                config.UseServiceBus(_serviceBusConfig);
                JobHost host = new JobHost(config);

                await ServiceBusEndToEndInternal(typeof(ServiceBusTestJobs), host: host);

                // in addition to verifying that our custom processor was called, we're also
                // verifying here that extensions can log to the TraceWriter
                Assert.Equal(4, trace.Traces.Count(p => p.Message.Contains("Custom processor Begin called!")));
                Assert.Equal(4, trace.Traces.Count(p => p.Message.Contains("Custom processor End called!")));
            }
            finally
            {
                Cleanup();
            }
        }
        public void IndexingExceptions_CanBeHandledByTraceWriter()
        {
            JobHostConfiguration config = new JobHostConfiguration();
            TestTraceWriter traceWriter = new TestTraceWriter(TraceLevel.Verbose);
            config.Tracing.Tracers.Add(traceWriter);
            config.TypeLocator = new FakeTypeLocator(typeof(BindingErrorsProgram));

            FunctionErrorTraceWriter errorTraceWriter = new FunctionErrorTraceWriter(TraceLevel.Error);
            config.Tracing.Tracers.Add(errorTraceWriter);

            JobHost host = new JobHost(config);
            host.Start();

            // verify the handled binding error
            FunctionIndexingException fex = errorTraceWriter.Errors.SingleOrDefault() as FunctionIndexingException;
            Assert.True(fex.Handled);
            Assert.Equal("BindingErrorsProgram.Invalid", fex.MethodName);

            // verify that the binding error was logged
            Assert.Equal(5, traceWriter.Traces.Count);
            TraceEvent traceEvent = traceWriter.Traces[0];
            Assert.Equal("Error indexing method 'BindingErrorsProgram.Invalid'", traceEvent.Message);
            Assert.Same(fex, traceEvent.Exception);
            Assert.Equal("Invalid container name: invalid$=+1", traceEvent.Exception.InnerException.Message);

            // verify that the valid function was still indexed
            traceEvent = traceWriter.Traces[1];
            Assert.True(traceEvent.Message.Contains("Found the following functions"));
            Assert.True(traceEvent.Message.Contains("BindingErrorsProgram.Valid"));

            // verify that the job host was started successfully
            traceEvent = traceWriter.Traces[4];
            Assert.Equal("Job host started", traceEvent.Message);

            host.Stop();
            host.Dispose();
        }
        public void CreateQueueProcessor_CreatesProcessorCorrectly()
        {
            CloudQueue poisonQueue = null;
            TestTraceWriter log = new TestTraceWriter(TraceLevel.Verbose);
            bool poisonMessageHandlerInvoked = false;
            EventHandler poisonMessageEventHandler = (sender, e) => { poisonMessageHandlerInvoked = true; };
            Mock<IQueueProcessorFactory> mockQueueProcessorFactory = new Mock<IQueueProcessorFactory>(MockBehavior.Strict);
            JobHostQueuesConfiguration queueConfig = new JobHostQueuesConfiguration
            {
                MaxDequeueCount = 7,
                QueueProcessorFactory = mockQueueProcessorFactory.Object
            };
            QueueProcessor expectedQueueProcessor = null;
            bool processorFactoryInvoked = false;

            // create for a host queue - don't expect custom factory to be invoked
            CloudQueue queue = new CloudQueue(new Uri(string.Format("https://test.queue.core.windows.net/{0}", HostQueueNames.GetHostQueueName("12345"))));
            QueueProcessor queueProcessor = QueueListener.CreateQueueProcessor(queue, poisonQueue, log, queueConfig, poisonMessageEventHandler);
            Assert.False(processorFactoryInvoked);
            Assert.NotSame(expectedQueueProcessor, queueProcessor);
            queueProcessor.OnMessageAddedToPoisonQueue(new EventArgs());
            Assert.True(poisonMessageHandlerInvoked);

            QueueProcessorFactoryContext processorFactoryContext = null;
            mockQueueProcessorFactory.Setup(p => p.Create(It.IsAny<QueueProcessorFactoryContext>()))
                .Callback<QueueProcessorFactoryContext>((mockProcessorContext) =>
                {
                    processorFactoryInvoked = true;

                    Assert.Same(queue, mockProcessorContext.Queue);
                    Assert.Same(poisonQueue, mockProcessorContext.PoisonQueue);
                    Assert.Equal(queueConfig.MaxDequeueCount, mockProcessorContext.MaxDequeueCount);
                    Assert.Same(log, mockProcessorContext.Trace);

                    processorFactoryContext = mockProcessorContext;
                })
                .Returns(() => 
                {
                    expectedQueueProcessor = new QueueProcessor(processorFactoryContext);
                    return expectedQueueProcessor;
                });

            // when storage host is "localhost" we invoke the processor factory even for
            // host queues (this enables local test mocking)
            processorFactoryInvoked = false;
            queue = new CloudQueue(new Uri(string.Format("https://localhost/{0}", HostQueueNames.GetHostQueueName("12345"))));
            queueProcessor = QueueListener.CreateQueueProcessor(queue, poisonQueue, log, queueConfig, poisonMessageEventHandler);
            Assert.True(processorFactoryInvoked);
            Assert.Same(expectedQueueProcessor, queueProcessor);

            // create for application queue - expect processor factory to be invoked
            poisonMessageHandlerInvoked = false;
            processorFactoryInvoked = false;
            queue = new CloudQueue(new Uri("https://test.queue.core.windows.net/testqueue"));
            queueProcessor = QueueListener.CreateQueueProcessor(queue, poisonQueue, log, queueConfig, poisonMessageEventHandler);
            Assert.True(processorFactoryInvoked);
            Assert.Same(expectedQueueProcessor, queueProcessor);
            queueProcessor.OnMessageAddedToPoisonQueue(new EventArgs());
            Assert.True(poisonMessageHandlerInvoked);

            // if poison message watcher not specified, event not subscribed to
            poisonMessageHandlerInvoked = false;
            processorFactoryInvoked = false;
            queueProcessor = QueueListener.CreateQueueProcessor(queue, poisonQueue, log, queueConfig, null);
            Assert.True(processorFactoryInvoked);
            Assert.Same(expectedQueueProcessor, queueProcessor);
            queueProcessor.OnMessageAddedToPoisonQueue(new EventArgs());
            Assert.False(poisonMessageHandlerInvoked);
        }
 public TraceWriterFunctionInstanceLoggerTests()
 {
     _traceWriter = new TestTraceWriter(TraceLevel.Verbose);
     _logger = new TraceWriterFunctionInstanceLogger(_traceWriter);
 }
        public async Task MultipleAccountTest()
        {
            try
            {
                TestTraceWriter trace = new TestTraceWriter(TraceLevel.Info);
                _serviceBusConfig = new ServiceBusConfiguration();
                _serviceBusConfig.MessagingProvider = new CustomMessagingProvider(_serviceBusConfig, trace);

                JobHostConfiguration config = new JobHostConfiguration()
                {
                    NameResolver = _nameResolver,
                    TypeLocator = new FakeTypeLocator(typeof(ServiceBusTestJobs))
                };
                config.Tracing.Tracers.Add(trace);
                config.UseServiceBus(_serviceBusConfig);
                JobHost host = new JobHost(config);

                string queueName = ResolveName(StartQueueName);
                string queuePrefix = queueName.Replace("-queue-start", "");
                string firstTopicName = string.Format("{0}-topic/Subscriptions/{0}-queue-topic-1", queuePrefix);

                WriteQueueMessage(_secondaryNamespaceManager, _secondaryConnectionString, queueName, "Test");

                _topicSubscriptionCalled1 = new ManualResetEvent(initialState: false);

                await host.StartAsync();

                _topicSubscriptionCalled1.WaitOne(SBTimeout);

                // ensure all logs have had a chance to flush
                await Task.Delay(3000);

                // Wait for the host to terminate
                await host.StopAsync();
                host.Dispose();

                Assert.Equal("Test-topic-1", _resultMessage1);
            }
            finally
            {
                Cleanup();
            }
        }