public SingletonManagerTests()
        {
            _mockAccountProvider        = new Mock <IStorageAccountProvider>(MockBehavior.Strict);
            _mockBlobDirectory          = new Mock <IStorageBlobDirectory>(MockBehavior.Strict);
            _mockSecondaryBlobDirectory = new Mock <IStorageBlobDirectory>(MockBehavior.Strict);
            _mockStorageAccount         = new Mock <IStorageAccount>(MockBehavior.Strict);
            _mockStorageAccount.SetupGet(a => a.Type).Returns(StorageAccountType.GeneralPurpose);
            _mockSecondaryStorageAccount = new Mock <IStorageAccount>(MockBehavior.Strict);
            _mockSecondaryStorageAccount.SetupGet(a => a.Type).Returns(StorageAccountType.GeneralPurpose);
            Mock <IStorageBlobClient>    mockBlobClient          = new Mock <IStorageBlobClient>(MockBehavior.Strict);
            Mock <IStorageBlobClient>    mockSecondaryBlobClient = new Mock <IStorageBlobClient>(MockBehavior.Strict);
            Mock <IStorageBlobContainer> mockBlobContainer       = new Mock <IStorageBlobContainer>(MockBehavior.Strict);

            mockBlobContainer.Setup(p => p.GetDirectoryReference(HostDirectoryNames.SingletonLocks)).Returns(_mockBlobDirectory.Object);
            mockBlobClient.Setup(p => p.GetContainerReference(HostContainerNames.Hosts)).Returns(mockBlobContainer.Object);
            Mock <IStorageBlobContainer> mockSecondaryBlobContainer = new Mock <IStorageBlobContainer>(MockBehavior.Strict);

            mockSecondaryBlobContainer.Setup(p => p.GetDirectoryReference(HostDirectoryNames.SingletonLocks)).Returns(_mockSecondaryBlobDirectory.Object);
            mockSecondaryBlobClient.Setup(p => p.GetContainerReference(HostContainerNames.Hosts)).Returns(mockSecondaryBlobContainer.Object);
            _mockStorageAccount.Setup(p => p.CreateBlobClient(null)).Returns(mockBlobClient.Object);
            _mockSecondaryStorageAccount.Setup(p => p.CreateBlobClient(null)).Returns(mockSecondaryBlobClient.Object);
            _mockAccountProvider.Setup(p => p.TryGetAccountAsync(ConnectionStringNames.Storage, It.IsAny <CancellationToken>()))
            .ReturnsAsync(_mockStorageAccount.Object);
            _mockAccountProvider.Setup(p => p.TryGetAccountAsync(Secondary, It.IsAny <CancellationToken>()))
            .ReturnsAsync(_mockSecondaryStorageAccount.Object);
            _mockExceptionDispatcher = new Mock <IWebJobsExceptionHandler>(MockBehavior.Strict);

            _mockStorageBlob  = new Mock <IStorageBlockBlob>(MockBehavior.Strict);
            _mockBlobMetadata = new Dictionary <string, string>();
            _mockBlobDirectory.Setup(p => p.GetBlockBlobReference(TestLockId)).Returns(_mockStorageBlob.Object);

            _singletonConfig = new SingletonConfiguration();

            // use reflection to bypass the normal validations (so tests can run fast)
            TestHelpers.SetField(_singletonConfig, "_lockAcquisitionPollingInterval", TimeSpan.FromMilliseconds(25));
            TestHelpers.SetField(_singletonConfig, "_lockPeriod", TimeSpan.FromMilliseconds(500));
            _singletonConfig.LockAcquisitionTimeout = TimeSpan.FromMilliseconds(200);

            _nameResolver = new TestNameResolver();

            ILoggerFactory loggerFactory = new LoggerFactory();
            // We want to see all logs, so set the default level to Trace.
            LogCategoryFilter filter = new LogCategoryFilter {
                DefaultLevel = Extensions.Logging.LogLevel.Trace
            };

            _loggerProvider = new TestLoggerProvider(filter.Filter);
            loggerFactory.AddProvider(_loggerProvider);

            var logger = loggerFactory?.CreateLogger(LogCategories.Singleton);

            _core = new BlobLeaseDistributedLockManager.DedicatedStorage(_mockAccountProvider.Object, logger);

            _singletonManager = new SingletonManager(_core, _singletonConfig, _mockExceptionDispatcher.Object, loggerFactory, new FixedHostIdProvider(TestHostId), _nameResolver);

            _singletonManager.MinimumLeaseRenewalInterval = TimeSpan.FromMilliseconds(250);
        }
        // Static initialization. Returns a service provider with some new services initialized.
        // The new services:
        // - can retrieve static config like binders and converters; but the listeners haven't yet started.
        // - can be flowed into the runtime initialization to get a JobHost spun up and running.
        // This is just static initialization and should not need to make any network calls,
        // and so this method should not need to be async.
        // This can be called multiple times on a config, which is why it returns a new ServiceProviderWrapper
        // instead of modifying the config.
        public static ServiceProviderWrapper CreateStaticServices(this JobHostConfiguration config)
        {
            var services = new ServiceProviderWrapper(config);

            var consoleProvider = services.GetService <IConsoleProvider>();
            var nameResolver    = services.GetService <INameResolver>();
            IWebJobsExceptionHandler exceptionHandler   = services.GetService <IWebJobsExceptionHandler>();
            IQueueConfiguration      queueConfiguration = services.GetService <IQueueConfiguration>();
            var blobsConfiguration = config.Blobs;

            IStorageAccountProvider storageAccountProvider = services.GetService <IStorageAccountProvider>();
            IBindingProvider        bindingProvider        = services.GetService <IBindingProvider>();
            SingletonManager        singletonManager       = services.GetService <SingletonManager>();

            IHostIdProvider hostIdProvider = services.GetService <IHostIdProvider>();
            var             hostId         = config.HostId;

            if (hostId != null)
            {
                hostIdProvider = new FixedHostIdProvider(hostId);
            }

            // Need a deferred getter since the IFunctionIndexProvider service isn't created until later.
            Func <IFunctionIndexProvider> deferredGetter = () => services.GetService <IFunctionIndexProvider>();

            if (hostIdProvider == null)
            {
                hostIdProvider = new DynamicHostIdProvider(storageAccountProvider, deferredGetter);
            }
            services.AddService <IHostIdProvider>(hostIdProvider);

            AzureStorageDeploymentValidator.Validate();

            IExtensionTypeLocator extensionTypeLocator = services.GetService <IExtensionTypeLocator>();

            if (extensionTypeLocator == null)
            {
                extensionTypeLocator = new ExtensionTypeLocator(services.GetService <ITypeLocator>());
                services.AddService <IExtensionTypeLocator>(extensionTypeLocator);
            }

            ContextAccessor <IMessageEnqueuedWatcher> messageEnqueuedWatcherAccessor = new ContextAccessor <IMessageEnqueuedWatcher>();

            services.AddService(messageEnqueuedWatcherAccessor);
            ContextAccessor <IBlobWrittenWatcher> blobWrittenWatcherAccessor = new ContextAccessor <IBlobWrittenWatcher>();
            ISharedContextProvider sharedContextProvider = new SharedContextProvider();

            // Create a wrapper TraceWriter that delegates to both the user
            // TraceWriters specified via config (if present), as well as to Console
            TraceWriter trace = new ConsoleTraceWriter(config.Tracing, consoleProvider.Out);

            services.AddService <TraceWriter>(trace);

            // Add built-in extensions
            var metadataProvider = new JobHostMetadataProvider(deferredGetter);

            metadataProvider.AddAttributesFromAssembly(typeof(TableAttribute).Assembly);

            var  exts          = config.GetExtensions();
            bool builtinsAdded = exts.GetExtensions <IExtensionConfigProvider>().OfType <TableExtension>().Any();

            if (!builtinsAdded)
            {
                config.AddExtension(new TableExtension());
                config.AddExtension(new QueueExtension());
            }

            ExtensionConfigContext context = new ExtensionConfigContext
            {
                Config          = config,
                Trace           = trace,
                PerHostServices = services
            };

            InvokeExtensionConfigProviders(context);

            // After this point, all user configuration has been set.

            if (singletonManager == null)
            {
                var logger = config.LoggerFactory?.CreateLogger(LogCategories.Singleton);

                IDistributedLockManager lockManager = services.GetService <IDistributedLockManager>();
                if (lockManager == null)
                {
                    lockManager = new BlobLeaseDistributedLockManager(
                        storageAccountProvider,
                        trace,
                        logger);
                    services.AddService <IDistributedLockManager>(lockManager);
                }

                singletonManager = new SingletonManager(
                    lockManager,
                    config.Singleton,
                    trace,
                    exceptionHandler,
                    config.LoggerFactory,
                    hostIdProvider,
                    services.GetService <INameResolver>());
                services.AddService <SingletonManager>(singletonManager);
            }

            IExtensionRegistry      extensions             = services.GetExtensions();
            ITriggerBindingProvider triggerBindingProvider = DefaultTriggerBindingProvider.Create(nameResolver,
                                                                                                  storageAccountProvider, extensionTypeLocator, hostIdProvider, queueConfiguration, blobsConfiguration, exceptionHandler,
                                                                                                  messageEnqueuedWatcherAccessor, blobWrittenWatcherAccessor, sharedContextProvider, extensions, singletonManager, trace, config.LoggerFactory);

            services.AddService <ITriggerBindingProvider>(triggerBindingProvider);

            if (bindingProvider == null)
            {
                bindingProvider = DefaultBindingProvider.Create(nameResolver, config.LoggerFactory, storageAccountProvider, extensionTypeLocator, blobWrittenWatcherAccessor, extensions);
                services.AddService <IBindingProvider>(bindingProvider);
            }

            var converterManager = (ConverterManager)config.ConverterManager;

            metadataProvider.Initialize(bindingProvider, converterManager, exts);
            services.AddService <IJobHostMetadataProvider>(metadataProvider);

            return(services);
        }