Skip to content

Commit b50cba3

Browse files
authored
Ensuring ScriptTypeLocator does not return an uninitialized types collection. (#11153)
1 parent e9c622f commit b50cba3

File tree

2 files changed

+75
-7
lines changed

2 files changed

+75
-7
lines changed

src/WebJobs.Script/Config/ScriptTypeLocator.cs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,58 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Linq;
6+
using System.Threading;
77

88
namespace Microsoft.Azure.WebJobs.Script.Config
99
{
10-
public class ScriptTypeLocator : ITypeLocator
10+
public class ScriptTypeLocator : ITypeLocator, IDisposable
1111
{
12+
private readonly ManualResetEventSlim _typesSetEvent;
13+
private readonly TimeSpan _setWaitTimeout;
1214
private Type[] _types;
15+
private bool _disposed;
1316

1417
public ScriptTypeLocator()
18+
: this(TimeSpan.FromMinutes(2))
19+
{ }
20+
21+
internal ScriptTypeLocator(TimeSpan setWaitTimeout)
1522
{
16-
_types = Array.Empty<Type>();
23+
_typesSetEvent = new ManualResetEventSlim(false);
24+
_setWaitTimeout = setWaitTimeout;
1725
}
1826

1927
public IReadOnlyList<Type> GetTypes()
2028
{
29+
if (!_typesSetEvent.Wait(_setWaitTimeout))
30+
{
31+
throw new TimeoutException($"Timeout waiting for types to be set in {nameof(ScriptTypeLocator)}.");
32+
}
33+
2134
return _types;
2235
}
2336

2437
internal void SetTypes(IEnumerable<Type> types)
2538
{
26-
if (types == null)
39+
ArgumentNullException.ThrowIfNull(types);
40+
41+
_types = [.. types];
42+
_typesSetEvent.Set();
43+
}
44+
45+
public void Dispose() => Dispose(true);
46+
47+
protected virtual void Dispose(bool disposing)
48+
{
49+
if (!_disposed)
2750
{
28-
throw new ArgumentNullException(nameof(types));
29-
}
51+
if (disposing)
52+
{
53+
_typesSetEvent.Dispose();
54+
}
3055

31-
_types = types.ToArray();
56+
_disposed = true;
57+
}
3258
}
3359
}
3460
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
8+
namespace Microsoft.Azure.WebJobs.Script.Config.Tests
9+
{
10+
public class ScriptTypeLocatorTests
11+
{
12+
[Fact]
13+
public void GetTypes_ThrowsTimeoutException_WhenSetTypesNotCalled()
14+
{
15+
var locator = new ScriptTypeLocator(TimeSpan.FromSeconds(3));
16+
17+
Assert.Throws<TimeoutException>(() => locator.GetTypes());
18+
}
19+
20+
[Fact]
21+
public void GetTypes_ReturnsTypes_WhenSetTypesCalled()
22+
{
23+
var locator = new ScriptTypeLocator();
24+
var expectedTypes = new[] { typeof(string), typeof(int) };
25+
26+
Task.Run(() => locator.SetTypes(expectedTypes));
27+
var types = locator.GetTypes();
28+
29+
Assert.Equal(expectedTypes, types);
30+
}
31+
32+
[Fact]
33+
public void Dispose_DisposesManualResetEventSlim()
34+
{
35+
var locator = new ScriptTypeLocator();
36+
37+
locator.Dispose();
38+
39+
Assert.Throws<ObjectDisposedException>(() => locator.GetTypes());
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)