public async Task GetHostIdAsync_ReturnsExpectedResult()
        {
            // ensure that the below job method is discovered and this test
            // assembly is used to generate the ID
            var type           = GetType();
            var firstJobMethod = FunctionIndexer.GetJobMethods(type).FirstOrDefault();

            Assert.NotNull(firstJobMethod);

            var mockTypeLocator = new Mock <ITypeLocator>(MockBehavior.Strict);

            mockTypeLocator.Setup(p => p.GetTypes()).Returns(new Type[] { type });
            var idProvider = new DefaultHostIdProvider(mockTypeLocator.Object);

            // as long as this test assembly name stays the same, the ID
            // computed should remain static. If this test is failing
            // it likely means we've changed the ID computation algorithm
            // which would be a BREAKING CHANGE
            string expected = "be6b3849f12290e0f182b27aa6f10fff";

            var id = await idProvider.GetHostIdAsync(CancellationToken.None);

            Assert.Equal(expected, id);

            // ensure the same ID is returned each time
            mockTypeLocator = new Mock <ITypeLocator>(MockBehavior.Strict);
            mockTypeLocator.Setup(p => p.GetTypes()).Returns(new Type[] { type });
            idProvider = new DefaultHostIdProvider(mockTypeLocator.Object);
            Assert.Equal(expected, await idProvider.GetHostIdAsync(CancellationToken.None));

            // ensure once the ID is computed, a cached result is returned
            Assert.Equal(expected, await idProvider.GetHostIdAsync(CancellationToken.None));
            Assert.Equal(expected, await idProvider.GetHostIdAsync(CancellationToken.None));
            mockTypeLocator.Verify(p => p.GetTypes(), Times.Once);
        }
        public async Task GetHostIdAsync_NoJobMethodsFound_ReturnsExpectedResult()
        {
            // pick a type that returns no job methods
            var type           = typeof(FunctionNameAttribute);
            var firstJobMethod = FunctionIndexer.GetJobMethods(type).FirstOrDefault();

            Assert.Null(firstJobMethod);

            var mockTypeLocator = new Mock <ITypeLocator>(MockBehavior.Strict);

            mockTypeLocator.Setup(p => p.GetTypes()).Returns(new Type[] { type });
            var idProvider = new DefaultHostIdProvider(mockTypeLocator.Object);

            // as long as this test assembly name stays the same, the ID
            // computed should remain static. If this test is failing
            // it likely means we've changed the ID computation algorithm
            // which would be a BREAKING CHANGE
            string expected = "943b1888c56ce8f0c96b2e66e1c74a7e";

            var id = await idProvider.GetHostIdAsync(CancellationToken.None);

            Assert.Equal(expected, id);

            // ensure the same ID is returned each time
            mockTypeLocator = new Mock <ITypeLocator>(MockBehavior.Strict);
            mockTypeLocator.Setup(p => p.GetTypes()).Returns(new Type[] { type });
            idProvider = new DefaultHostIdProvider(mockTypeLocator.Object);
            Assert.Equal(expected, await idProvider.GetHostIdAsync(CancellationToken.None));
        }
        private string ComputeHostId()
        {
            // Search through all types for the first job method.
            // The reason we have to do this rather than attempt to use the entry assembly
            // (Assembly.GetEntryAssembly) is because that doesn't work for WebApps, and the
            // SDK supports both WebApp and Console app hosts.
            MethodInfo firstJobMethod = null;

            foreach (var type in _typeLocator.GetTypes())
            {
                firstJobMethod = FunctionIndexer.GetJobMethods(type).FirstOrDefault();
                if (firstJobMethod != null)
                {
                    break;
                }
            }

            // Compute hash and map to Guid
            // If the job host doesn't yet have any job methods (e.g. it's a new project)
            // then a default ID is generated
            string hostName = firstJobMethod?.DeclaringType.Assembly.FullName ?? "Unknown";
            Guid   id;

            using (var md5 = MD5.Create())
            {
                var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(hostName));
                id = new Guid(hash);
            }

            return(id.ToString("N"));
        }