Skip to content

Commit 6c8e344

Browse files
authored
Fix httpworker indexing in webhost (#6077)
1 parent 432a2a8 commit 6c8e344

File tree

3 files changed

+55
-6
lines changed

3 files changed

+55
-6
lines changed

src/WebJobs.Script/Host/FunctionMetadataManager.cs

+11-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class FunctionMetadataManager : IFunctionMetadataManager
2323
private readonly IFunctionMetadataProvider _functionMetadataProvider;
2424
private bool _isHttpWorker;
2525
private bool _servicesReset = false;
26+
private bool _jobHostServicesInitialized = false;
2627
private ILogger _logger;
2728
private IOptions<ScriptJobHostOptions> _scriptOptions;
2829
private ImmutableArray<FunctionMetadata> _functionMetadataArray;
@@ -42,7 +43,14 @@ public FunctionMetadataManager(IOptions<ScriptJobHostOptions> scriptOptions, IFu
4243

4344
// Every time script host is re-intializing, we also need to re-initialize
4445
// services that change with the scope of the script host.
45-
scriptHostManager.HostInitializing += (s, e) => InitializeServices();
46+
scriptHostManager.HostInitializing += (s, e) =>
47+
{
48+
InitializeServices();
49+
50+
// Once ScriptHost has initialized, functionMetadata has loaded the new services,
51+
// it now works under the context of ScriptHost using the ScriptHost level config
52+
_jobHostServicesInitialized = true;
53+
};
4654
}
4755

4856
public ImmutableDictionary<string, ImmutableArray<string>> Errors { get; private set; }
@@ -99,6 +107,7 @@ internal ImmutableArray<FunctionMetadata> LoadFunctionMetadata(bool forceRefresh
99107

100108
var immutableFunctionMetadata = _functionMetadataProvider.GetFunctionMetadata(forceRefresh);
101109
var functionMetadataList = new List<FunctionMetadata>();
110+
_functionErrors = new Dictionary<string, ICollection<string>>();
102111

103112
if (!immutableFunctionMetadata.IsDefaultOrEmpty)
104113
{
@@ -137,7 +146,7 @@ internal bool IsScriptFileDetermined(FunctionMetadata functionMetadata)
137146
{
138147
try
139148
{
140-
if (string.IsNullOrEmpty(functionMetadata.ScriptFile) && !_isHttpWorker && !functionMetadata.IsProxy())
149+
if (string.IsNullOrEmpty(functionMetadata.ScriptFile) && !_isHttpWorker && !functionMetadata.IsProxy() && _jobHostServicesInitialized)
141150
{
142151
throw new FunctionConfigurationException(_functionConfigurationErrorMessage);
143152
}

test/WebJobs.Script.Tests.Shared/TestFunctionMetadataManager.cs

+6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ public static FunctionMetadataManager GetFunctionMetadataManager(IOptions<Script
2424
{
2525
var managerMock = new Mock<IScriptHostManager>();
2626

27+
return GetFunctionMetadataManager(jobHostOptions, managerMock, functionMetadataProvider, functionProviders, httpOptions, loggerFactory);
28+
}
29+
30+
public static FunctionMetadataManager GetFunctionMetadataManager(IOptions<ScriptJobHostOptions> jobHostOptions, Mock<IScriptHostManager> managerMock,
31+
IFunctionMetadataProvider functionMetadataProvider, IList<IFunctionProvider> functionProviders, IOptions<HttpWorkerOptions> httpOptions, ILoggerFactory loggerFactory)
32+
{
2733
managerMock.As<IServiceProvider>().Setup(m => m.GetService(typeof(IEnumerable<IFunctionProvider>))).Returns(functionProviders);
2834
managerMock.As<IServiceProvider>().Setup(m => m.GetService(typeof(IOptions<ScriptJobHostOptions>))).Returns(jobHostOptions);
2935
managerMock.As<IServiceProvider>().Setup(m => m.GetService(typeof(IOptions<HttpWorkerOptions>))).Returns(httpOptions);

test/WebJobs.Script.Tests/FunctionMetadataManagerTests.cs

+38-4
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,17 @@ public class FunctionMetadataManagerTests
2424
private Mock<IFunctionMetadataProvider> _mockFunctionMetadataProvider;
2525
private FunctionMetadataManager _testFunctionMetadataManager;
2626
private HttpWorkerOptions _defaultHttpWorkerOptions;
27+
private Mock<IScriptHostManager> _mockScriptHostManager;
2728

2829
public FunctionMetadataManagerTests()
2930
{
3031
_mockFunctionMetadataProvider = new Mock<IFunctionMetadataProvider>();
3132
string functionsPath = Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\sample\node");
3233
_defaultHttpWorkerOptions = new HttpWorkerOptions();
3334
_scriptJobHostOptions.RootScriptPath = functionsPath;
34-
_testFunctionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(_scriptJobHostOptions),
35+
36+
_mockScriptHostManager = new Mock<IScriptHostManager>();
37+
_testFunctionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(_scriptJobHostOptions), _mockScriptHostManager,
3538
_mockFunctionMetadataProvider.Object, new List<IFunctionProvider>(), new OptionsWrapper<HttpWorkerOptions>(_defaultHttpWorkerOptions), MockNullLoggerFactory.CreateLoggerFactory());
3639
}
3740

@@ -40,6 +43,7 @@ public FunctionMetadataManagerTests()
4043
[InlineData(null)]
4144
public void IsScriptFileDetermined_ScriptFile_Emtpy_False(string scriptFile)
4245
{
46+
_mockScriptHostManager.Raise(m => m.HostInitializing += null, new EventArgs());
4347
FunctionMetadata functionMetadata = GetTestFunctionMetadata(scriptFile);
4448
Assert.False(_testFunctionMetadataManager.IsScriptFileDetermined(functionMetadata));
4549
}
@@ -57,8 +61,11 @@ public void FunctionMetadataManager_Verify_FunctionErrors(string scriptFile)
5761
mockFunctionMetadataProvider.Setup(m => m.GetFunctionMetadata(false)).Returns(functionMetadataCollection.ToImmutableArray());
5862
mockFunctionMetadataProvider.Setup(m => m.FunctionErrors).Returns(mockFunctionErrors);
5963

60-
FunctionMetadataManager testFunctionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(_scriptJobHostOptions),
64+
var managerMock = new Mock<IScriptHostManager>();
65+
FunctionMetadataManager testFunctionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(_scriptJobHostOptions), managerMock,
6166
mockFunctionMetadataProvider.Object, new List<IFunctionProvider>(), new OptionsWrapper<HttpWorkerOptions>(_defaultHttpWorkerOptions), MockNullLoggerFactory.CreateLoggerFactory());
67+
68+
managerMock.Raise(m => m.HostInitializing += null, new EventArgs());
6269
Assert.Empty(testFunctionMetadataManager.LoadFunctionMetadata());
6370

6471
Assert.True(testFunctionMetadataManager.Errors.Count == 1);
@@ -87,8 +94,12 @@ public void FunctionMetadataManager_Verify_FunctionErrors_FromFunctionProviders(
8794
mockFunctionProvider.Setup(m => m.GetFunctionMetadataAsync()).ReturnsAsync(functionMetadataCollection.ToImmutableArray());
8895
mockFunctionProvider.Setup(m => m.FunctionErrors).Returns(mockFunctionErrors.ToImmutableDictionary());
8996

90-
FunctionMetadataManager testFunctionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(_scriptJobHostOptions),
97+
var managerMock = new Mock<IScriptHostManager>();
98+
FunctionMetadataManager testFunctionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(_scriptJobHostOptions), managerMock,
9199
mockFunctionMetadataProvider.Object, new List<IFunctionProvider>() { mockFunctionProvider.Object }, new OptionsWrapper<HttpWorkerOptions>(_defaultHttpWorkerOptions), MockNullLoggerFactory.CreateLoggerFactory());
100+
101+
managerMock.Raise(m => m.HostInitializing += null, new EventArgs());
102+
92103
testFunctionMetadataManager.LoadFunctionMetadata();
93104

94105
Assert.Equal(2, testFunctionMetadataManager.Errors.Count);
@@ -97,6 +108,25 @@ public void FunctionMetadataManager_Verify_FunctionErrors_FromFunctionProviders(
97108
Assert.True(functionErrors.Contains("error"));
98109
}
99110

111+
[Fact]
112+
public void FunctionMetadataManager_DoesNotError_MissingScriptFile_InWebHostMode()
113+
{
114+
var mockFunctionMetadataProvider = new Mock<IFunctionMetadataProvider>();
115+
var mockFunctionProvider = new Mock<IFunctionProvider>();
116+
117+
var testMetadata = GetTestFunctionMetadata(null);
118+
119+
var managerMock = new Mock<IScriptHostManager>();
120+
FunctionMetadataManager testFunctionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(_scriptJobHostOptions), managerMock,
121+
mockFunctionMetadataProvider.Object, new List<IFunctionProvider>() { mockFunctionProvider.Object }, new OptionsWrapper<HttpWorkerOptions>(_defaultHttpWorkerOptions), MockNullLoggerFactory.CreateLoggerFactory());
122+
123+
Assert.True(testFunctionMetadataManager.IsScriptFileDetermined(testMetadata));
124+
125+
managerMock.Raise(m => m.HostInitializing += null, new EventArgs());
126+
127+
Assert.False(testFunctionMetadataManager.IsScriptFileDetermined(testMetadata));
128+
}
129+
100130
[Fact]
101131
public void FunctionMetadataManager_GetsMetadata_FromFunctionProviders()
102132
{
@@ -156,8 +186,12 @@ public void FunctionMetadataManager_ThrowsError_DuplicateFunctions_FromFunctionP
156186
public void IsScriptFileDetermined_ScriptFile_Emtpy_HttpWorker_Returns_True(string scriptFile)
157187
{
158188
FunctionMetadata functionMetadata = GetTestFunctionMetadata(scriptFile);
159-
FunctionMetadataManager testFunctionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(_scriptJobHostOptions),
189+
190+
var managerMock = new Mock<IScriptHostManager>();
191+
192+
FunctionMetadataManager testFunctionMetadataManager = TestFunctionMetadataManager.GetFunctionMetadataManager(new OptionsWrapper<ScriptJobHostOptions>(_scriptJobHostOptions), managerMock,
160193
_mockFunctionMetadataProvider.Object, new List<IFunctionProvider>(), new OptionsWrapper<HttpWorkerOptions>(GetTestHttpWorkerOptions()), MockNullLoggerFactory.CreateLoggerFactory());
194+
managerMock.Raise(m => m.HostInitializing += null, new EventArgs());
161195

162196
Assert.True(testFunctionMetadataManager.IsScriptFileDetermined(functionMetadata));
163197
}

0 commit comments

Comments
 (0)